mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
279 lines
5.7 KiB
C
279 lines
5.7 KiB
C
|
#include <u.h>
|
||
|
#include <libc.h>
|
||
|
#include <bio.h>
|
||
|
#include "sky.h"
|
||
|
|
||
|
static void qtree_expand(Biobuf*, uchar*, int, int, uchar*);
|
||
|
static void qtree_copy(uchar*, int, int, uchar*, int);
|
||
|
static void qtree_bitins(uchar*, int, int, Pix*, int, int);
|
||
|
static void read_bdirect(Biobuf*, Pix*, int, int, int, uchar*, int);
|
||
|
|
||
|
void
|
||
|
qtree_decode(Biobuf *infile, Pix *a, int n, int nqx, int nqy, int nbitplanes)
|
||
|
{
|
||
|
int log2n, k, bit, b, nqmax;
|
||
|
int nx,ny,nfx,nfy,c;
|
||
|
int nqx2, nqy2;
|
||
|
unsigned char *scratch;
|
||
|
|
||
|
/*
|
||
|
* log2n is log2 of max(nqx,nqy) rounded up to next power of 2
|
||
|
*/
|
||
|
nqmax = nqy;
|
||
|
if(nqx > nqmax)
|
||
|
nqmax = nqx;
|
||
|
log2n = log(nqmax)/LN2+0.5;
|
||
|
if (nqmax > (1<<log2n))
|
||
|
log2n++;
|
||
|
|
||
|
/*
|
||
|
* allocate scratch array for working space
|
||
|
*/
|
||
|
nqx2 = (nqx+1)/2;
|
||
|
nqy2 = (nqy+1)/2;
|
||
|
scratch = (uchar*)malloc(nqx2*nqy2);
|
||
|
if(scratch == nil) {
|
||
|
fprint(2, "qtree_decode: insufficient memory\n");
|
||
|
exits("memory");
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* now decode each bit plane, starting at the top
|
||
|
* A is assumed to be initialized to zero
|
||
|
*/
|
||
|
for(bit = nbitplanes-1; bit >= 0; bit--) {
|
||
|
/*
|
||
|
* Was bitplane was quadtree-coded or written directly?
|
||
|
*/
|
||
|
b = input_nybble(infile);
|
||
|
if(b == 0) {
|
||
|
/*
|
||
|
* bit map was written directly
|
||
|
*/
|
||
|
read_bdirect(infile, a, n, nqx, nqy, scratch, bit);
|
||
|
} else
|
||
|
if(b != 0xf) {
|
||
|
fprint(2, "qtree_decode: bad format code %x\n",b);
|
||
|
exits("format");
|
||
|
} else {
|
||
|
/*
|
||
|
* bitmap was quadtree-coded, do log2n expansions
|
||
|
* read first code
|
||
|
*/
|
||
|
|
||
|
scratch[0] = input_huffman(infile);
|
||
|
|
||
|
/*
|
||
|
* do log2n expansions, reading codes from file as necessary
|
||
|
*/
|
||
|
nx = 1;
|
||
|
ny = 1;
|
||
|
nfx = nqx;
|
||
|
nfy = nqy;
|
||
|
c = 1<<log2n;
|
||
|
for(k = 1; k<log2n; k++) {
|
||
|
/*
|
||
|
* this somewhat cryptic code generates the sequence
|
||
|
* n[k-1] = (n[k]+1)/2 where n[log2n]=nqx or nqy
|
||
|
*/
|
||
|
c = c>>1;
|
||
|
nx = nx<<1;
|
||
|
ny = ny<<1;
|
||
|
if(nfx <= c)
|
||
|
nx--;
|
||
|
else
|
||
|
nfx -= c;
|
||
|
if(nfy <= c)
|
||
|
ny--;
|
||
|
else
|
||
|
nfy -= c;
|
||
|
qtree_expand(infile, scratch, nx, ny, scratch);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* copy last set of 4-bit codes to bitplane bit of array a
|
||
|
*/
|
||
|
qtree_bitins(scratch, nqx, nqy, a, n, bit);
|
||
|
}
|
||
|
}
|
||
|
free(scratch);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* do one quadtree expansion step on array a[(nqx+1)/2,(nqy+1)/2]
|
||
|
* results put into b[nqx,nqy] (which may be the same as a)
|
||
|
*/
|
||
|
static
|
||
|
void
|
||
|
qtree_expand(Biobuf *infile, uchar *a, int nx, int ny, uchar *b)
|
||
|
{
|
||
|
uchar *b1;
|
||
|
|
||
|
/*
|
||
|
* first copy a to b, expanding each 4-bit value
|
||
|
*/
|
||
|
qtree_copy(a, nx, ny, b, ny);
|
||
|
|
||
|
/*
|
||
|
* now read new 4-bit values into b for each non-zero element
|
||
|
*/
|
||
|
b1 = &b[nx*ny];
|
||
|
while(b1 > b) {
|
||
|
b1--;
|
||
|
if(*b1 != 0)
|
||
|
*b1 = input_huffman(infile);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
|
||
|
* each value to 2x2 pixels
|
||
|
* a,b may be same array
|
||
|
*/
|
||
|
static
|
||
|
void
|
||
|
qtree_copy(uchar *a, int nx, int ny, uchar *b, int n)
|
||
|
{
|
||
|
int i, j, k, nx2, ny2;
|
||
|
int s00, s10;
|
||
|
|
||
|
/*
|
||
|
* first copy 4-bit values to b
|
||
|
* start at end in case a,b are same array
|
||
|
*/
|
||
|
nx2 = (nx+1)/2;
|
||
|
ny2 = (ny+1)/2;
|
||
|
k = ny2*(nx2-1) + ny2-1; /* k is index of a[i,j] */
|
||
|
for (i = nx2-1; i >= 0; i--) {
|
||
|
s00 = 2*(n*i+ny2-1); /* s00 is index of b[2*i,2*j] */
|
||
|
for (j = ny2-1; j >= 0; j--) {
|
||
|
b[s00] = a[k];
|
||
|
k -= 1;
|
||
|
s00 -= 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* now expand each 2x2 block
|
||
|
*/
|
||
|
for(i = 0; i<nx-1; i += 2) {
|
||
|
s00 = n*i; /* s00 is index of b[i,j] */
|
||
|
s10 = s00+n; /* s10 is index of b[i+1,j] */
|
||
|
for(j = 0; j<ny-1; j += 2) {
|
||
|
b[s10+1] = b[s00] & 1;
|
||
|
b[s10 ] = (b[s00]>>1) & 1;
|
||
|
b[s00+1] = (b[s00]>>2) & 1;
|
||
|
b[s00 ] = (b[s00]>>3) & 1;
|
||
|
s00 += 2;
|
||
|
s10 += 2;
|
||
|
}
|
||
|
if(j < ny) {
|
||
|
/*
|
||
|
* row size is odd, do last element in row
|
||
|
* s00+1, s10+1 are off edge
|
||
|
*/
|
||
|
b[s10 ] = (b[s00]>>1) & 1;
|
||
|
b[s00 ] = (b[s00]>>3) & 1;
|
||
|
}
|
||
|
}
|
||
|
if(i < nx) {
|
||
|
/*
|
||
|
* column size is odd, do last row
|
||
|
* s10, s10+1 are off edge
|
||
|
*/
|
||
|
s00 = n*i;
|
||
|
for (j = 0; j<ny-1; j += 2) {
|
||
|
b[s00+1] = (b[s00]>>2) & 1;
|
||
|
b[s00 ] = (b[s00]>>3) & 1;
|
||
|
s00 += 2;
|
||
|
}
|
||
|
if(j < ny) {
|
||
|
/*
|
||
|
* both row and column size are odd, do corner element
|
||
|
* s00+1, s10, s10+1 are off edge
|
||
|
*/
|
||
|
b[s00 ] = (b[s00]>>3) & 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
|
||
|
* each value to 2x2 pixels and inserting into bitplane BIT of B.
|
||
|
* A,B may NOT be same array (it wouldn't make sense to be inserting
|
||
|
* bits into the same array anyway.)
|
||
|
*/
|
||
|
static
|
||
|
void
|
||
|
qtree_bitins(uchar *a, int nx, int ny, Pix *b, int n, int bit)
|
||
|
{
|
||
|
int i, j;
|
||
|
Pix *s00, *s10;
|
||
|
Pix px;
|
||
|
|
||
|
/*
|
||
|
* expand each 2x2 block
|
||
|
*/
|
||
|
for(i=0; i<nx-1; i+=2) {
|
||
|
s00 = &b[n*i]; /* s00 is index of b[i,j] */
|
||
|
s10 = s00+n; /* s10 is index of b[i+1,j] */
|
||
|
for(j=0; j<ny-1; j+=2) {
|
||
|
px = *a++;
|
||
|
s10[1] |= ( px & 1) << bit;
|
||
|
s10[0] |= ((px>>1) & 1) << bit;
|
||
|
s00[1] |= ((px>>2) & 1) << bit;
|
||
|
s00[0] |= ((px>>3) & 1) << bit;
|
||
|
s00 += 2;
|
||
|
s10 += 2;
|
||
|
}
|
||
|
if(j < ny) {
|
||
|
/*
|
||
|
* row size is odd, do last element in row
|
||
|
* s00+1, s10+1 are off edge
|
||
|
*/
|
||
|
px = *a++;
|
||
|
s10[0] |= ((px>>1) & 1) << bit;
|
||
|
s00[0] |= ((px>>3) & 1) << bit;
|
||
|
}
|
||
|
}
|
||
|
if(i < nx) {
|
||
|
/*
|
||
|
* column size is odd, do last row
|
||
|
* s10, s10+1 are off edge
|
||
|
*/
|
||
|
s00 = &b[n*i];
|
||
|
for(j=0; j<ny-1; j+=2) {
|
||
|
px = *a++;
|
||
|
s00[1] |= ((px>>2) & 1) << bit;
|
||
|
s00[0] |= ((px>>3) & 1) << bit;
|
||
|
s00 += 2;
|
||
|
}
|
||
|
if(j < ny) {
|
||
|
/*
|
||
|
* both row and column size are odd, do corner element
|
||
|
* s00+1, s10, s10+1 are off edge
|
||
|
*/
|
||
|
s00[0] |= ((*a>>3) & 1) << bit;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
void
|
||
|
read_bdirect(Biobuf *infile, Pix *a, int n, int nqx, int nqy, uchar *scratch, int bit)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
/*
|
||
|
* read bit image packed 4 pixels/nybble
|
||
|
*/
|
||
|
for(i = 0; i < ((nqx+1)/2) * ((nqy+1)/2); i++) {
|
||
|
scratch[i] = input_nybble(infile);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* insert in bitplane BIT of image A
|
||
|
*/
|
||
|
qtree_bitins(scratch, nqx, nqy, a, n, bit);
|
||
|
}
|