1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier #include "sky.h"
5219b2ee8SDavid du Colombier
6219b2ee8SDavid du Colombier static void qtree_expand(Biobuf*, uchar*, int, int, uchar*);
7219b2ee8SDavid du Colombier static void qtree_copy(uchar*, int, int, uchar*, int);
8219b2ee8SDavid du Colombier static void qtree_bitins(uchar*, int, int, Pix*, int, int);
9219b2ee8SDavid du Colombier static void read_bdirect(Biobuf*, Pix*, int, int, int, uchar*, int);
10219b2ee8SDavid du Colombier
11219b2ee8SDavid du Colombier void
qtree_decode(Biobuf * infile,Pix * a,int n,int nqx,int nqy,int nbitplanes)12219b2ee8SDavid du Colombier qtree_decode(Biobuf *infile, Pix *a, int n, int nqx, int nqy, int nbitplanes)
13219b2ee8SDavid du Colombier {
14219b2ee8SDavid du Colombier int log2n, k, bit, b, nqmax;
15219b2ee8SDavid du Colombier int nx,ny,nfx,nfy,c;
16219b2ee8SDavid du Colombier int nqx2, nqy2;
17219b2ee8SDavid du Colombier unsigned char *scratch;
18219b2ee8SDavid du Colombier
19219b2ee8SDavid du Colombier /*
20219b2ee8SDavid du Colombier * log2n is log2 of max(nqx,nqy) rounded up to next power of 2
21219b2ee8SDavid du Colombier */
22219b2ee8SDavid du Colombier nqmax = nqy;
23219b2ee8SDavid du Colombier if(nqx > nqmax)
24219b2ee8SDavid du Colombier nqmax = nqx;
25219b2ee8SDavid du Colombier log2n = log(nqmax)/LN2+0.5;
26219b2ee8SDavid du Colombier if (nqmax > (1<<log2n))
27219b2ee8SDavid du Colombier log2n++;
28219b2ee8SDavid du Colombier
29219b2ee8SDavid du Colombier /*
30219b2ee8SDavid du Colombier * allocate scratch array for working space
31219b2ee8SDavid du Colombier */
32219b2ee8SDavid du Colombier nqx2 = (nqx+1)/2;
33219b2ee8SDavid du Colombier nqy2 = (nqy+1)/2;
34219b2ee8SDavid du Colombier scratch = (uchar*)malloc(nqx2*nqy2);
35*59cc4ca5SDavid du Colombier if(scratch == nil) {
36219b2ee8SDavid du Colombier fprint(2, "qtree_decode: insufficient memory\n");
37219b2ee8SDavid du Colombier exits("memory");
38219b2ee8SDavid du Colombier }
39219b2ee8SDavid du Colombier
40219b2ee8SDavid du Colombier /*
41219b2ee8SDavid du Colombier * now decode each bit plane, starting at the top
42219b2ee8SDavid du Colombier * A is assumed to be initialized to zero
43219b2ee8SDavid du Colombier */
44219b2ee8SDavid du Colombier for(bit = nbitplanes-1; bit >= 0; bit--) {
45219b2ee8SDavid du Colombier /*
46219b2ee8SDavid du Colombier * Was bitplane was quadtree-coded or written directly?
47219b2ee8SDavid du Colombier */
48219b2ee8SDavid du Colombier b = input_nybble(infile);
49219b2ee8SDavid du Colombier if(b == 0) {
50219b2ee8SDavid du Colombier /*
51219b2ee8SDavid du Colombier * bit map was written directly
52219b2ee8SDavid du Colombier */
53219b2ee8SDavid du Colombier read_bdirect(infile, a, n, nqx, nqy, scratch, bit);
54219b2ee8SDavid du Colombier } else
55219b2ee8SDavid du Colombier if(b != 0xf) {
56219b2ee8SDavid du Colombier fprint(2, "qtree_decode: bad format code %x\n",b);
57219b2ee8SDavid du Colombier exits("format");
58219b2ee8SDavid du Colombier } else {
59219b2ee8SDavid du Colombier /*
60219b2ee8SDavid du Colombier * bitmap was quadtree-coded, do log2n expansions
61219b2ee8SDavid du Colombier * read first code
62219b2ee8SDavid du Colombier */
63219b2ee8SDavid du Colombier
64219b2ee8SDavid du Colombier scratch[0] = input_huffman(infile);
65219b2ee8SDavid du Colombier
66219b2ee8SDavid du Colombier /*
67219b2ee8SDavid du Colombier * do log2n expansions, reading codes from file as necessary
68219b2ee8SDavid du Colombier */
69219b2ee8SDavid du Colombier nx = 1;
70219b2ee8SDavid du Colombier ny = 1;
71219b2ee8SDavid du Colombier nfx = nqx;
72219b2ee8SDavid du Colombier nfy = nqy;
73219b2ee8SDavid du Colombier c = 1<<log2n;
74219b2ee8SDavid du Colombier for(k = 1; k<log2n; k++) {
75219b2ee8SDavid du Colombier /*
76219b2ee8SDavid du Colombier * this somewhat cryptic code generates the sequence
77219b2ee8SDavid du Colombier * n[k-1] = (n[k]+1)/2 where n[log2n]=nqx or nqy
78219b2ee8SDavid du Colombier */
79219b2ee8SDavid du Colombier c = c>>1;
80219b2ee8SDavid du Colombier nx = nx<<1;
81219b2ee8SDavid du Colombier ny = ny<<1;
82219b2ee8SDavid du Colombier if(nfx <= c)
83219b2ee8SDavid du Colombier nx--;
84219b2ee8SDavid du Colombier else
85219b2ee8SDavid du Colombier nfx -= c;
86219b2ee8SDavid du Colombier if(nfy <= c)
87219b2ee8SDavid du Colombier ny--;
88219b2ee8SDavid du Colombier else
89219b2ee8SDavid du Colombier nfy -= c;
90219b2ee8SDavid du Colombier qtree_expand(infile, scratch, nx, ny, scratch);
91219b2ee8SDavid du Colombier }
92219b2ee8SDavid du Colombier
93219b2ee8SDavid du Colombier /*
94219b2ee8SDavid du Colombier * copy last set of 4-bit codes to bitplane bit of array a
95219b2ee8SDavid du Colombier */
96219b2ee8SDavid du Colombier qtree_bitins(scratch, nqx, nqy, a, n, bit);
97219b2ee8SDavid du Colombier }
98219b2ee8SDavid du Colombier }
99219b2ee8SDavid du Colombier free(scratch);
100219b2ee8SDavid du Colombier }
101219b2ee8SDavid du Colombier
102219b2ee8SDavid du Colombier /*
103219b2ee8SDavid du Colombier * do one quadtree expansion step on array a[(nqx+1)/2,(nqy+1)/2]
104219b2ee8SDavid du Colombier * results put into b[nqx,nqy] (which may be the same as a)
105219b2ee8SDavid du Colombier */
106219b2ee8SDavid du Colombier static
107219b2ee8SDavid du Colombier void
qtree_expand(Biobuf * infile,uchar * a,int nx,int ny,uchar * b)108219b2ee8SDavid du Colombier qtree_expand(Biobuf *infile, uchar *a, int nx, int ny, uchar *b)
109219b2ee8SDavid du Colombier {
110219b2ee8SDavid du Colombier uchar *b1;
111219b2ee8SDavid du Colombier
112219b2ee8SDavid du Colombier /*
113219b2ee8SDavid du Colombier * first copy a to b, expanding each 4-bit value
114219b2ee8SDavid du Colombier */
115219b2ee8SDavid du Colombier qtree_copy(a, nx, ny, b, ny);
116219b2ee8SDavid du Colombier
117219b2ee8SDavid du Colombier /*
118219b2ee8SDavid du Colombier * now read new 4-bit values into b for each non-zero element
119219b2ee8SDavid du Colombier */
120219b2ee8SDavid du Colombier b1 = &b[nx*ny];
121219b2ee8SDavid du Colombier while(b1 > b) {
122219b2ee8SDavid du Colombier b1--;
123219b2ee8SDavid du Colombier if(*b1 != 0)
124219b2ee8SDavid du Colombier *b1 = input_huffman(infile);
125219b2ee8SDavid du Colombier }
126219b2ee8SDavid du Colombier }
127219b2ee8SDavid du Colombier
128219b2ee8SDavid du Colombier /*
129219b2ee8SDavid du Colombier * copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
130219b2ee8SDavid du Colombier * each value to 2x2 pixels
131219b2ee8SDavid du Colombier * a,b may be same array
132219b2ee8SDavid du Colombier */
133219b2ee8SDavid du Colombier static
134219b2ee8SDavid du Colombier void
qtree_copy(uchar * a,int nx,int ny,uchar * b,int n)135219b2ee8SDavid du Colombier qtree_copy(uchar *a, int nx, int ny, uchar *b, int n)
136219b2ee8SDavid du Colombier {
137219b2ee8SDavid du Colombier int i, j, k, nx2, ny2;
138219b2ee8SDavid du Colombier int s00, s10;
139219b2ee8SDavid du Colombier
140219b2ee8SDavid du Colombier /*
141219b2ee8SDavid du Colombier * first copy 4-bit values to b
142219b2ee8SDavid du Colombier * start at end in case a,b are same array
143219b2ee8SDavid du Colombier */
144219b2ee8SDavid du Colombier nx2 = (nx+1)/2;
145219b2ee8SDavid du Colombier ny2 = (ny+1)/2;
146219b2ee8SDavid du Colombier k = ny2*(nx2-1) + ny2-1; /* k is index of a[i,j] */
147219b2ee8SDavid du Colombier for (i = nx2-1; i >= 0; i--) {
148219b2ee8SDavid du Colombier s00 = 2*(n*i+ny2-1); /* s00 is index of b[2*i,2*j] */
149219b2ee8SDavid du Colombier for (j = ny2-1; j >= 0; j--) {
150219b2ee8SDavid du Colombier b[s00] = a[k];
151219b2ee8SDavid du Colombier k -= 1;
152219b2ee8SDavid du Colombier s00 -= 2;
153219b2ee8SDavid du Colombier }
154219b2ee8SDavid du Colombier }
155219b2ee8SDavid du Colombier
156219b2ee8SDavid du Colombier /*
157219b2ee8SDavid du Colombier * now expand each 2x2 block
158219b2ee8SDavid du Colombier */
159219b2ee8SDavid du Colombier for(i = 0; i<nx-1; i += 2) {
160219b2ee8SDavid du Colombier s00 = n*i; /* s00 is index of b[i,j] */
161219b2ee8SDavid du Colombier s10 = s00+n; /* s10 is index of b[i+1,j] */
162219b2ee8SDavid du Colombier for(j = 0; j<ny-1; j += 2) {
163219b2ee8SDavid du Colombier b[s10+1] = b[s00] & 1;
164219b2ee8SDavid du Colombier b[s10 ] = (b[s00]>>1) & 1;
165219b2ee8SDavid du Colombier b[s00+1] = (b[s00]>>2) & 1;
166219b2ee8SDavid du Colombier b[s00 ] = (b[s00]>>3) & 1;
167219b2ee8SDavid du Colombier s00 += 2;
168219b2ee8SDavid du Colombier s10 += 2;
169219b2ee8SDavid du Colombier }
170219b2ee8SDavid du Colombier if(j < ny) {
171219b2ee8SDavid du Colombier /*
172219b2ee8SDavid du Colombier * row size is odd, do last element in row
173219b2ee8SDavid du Colombier * s00+1, s10+1 are off edge
174219b2ee8SDavid du Colombier */
175219b2ee8SDavid du Colombier b[s10 ] = (b[s00]>>1) & 1;
176219b2ee8SDavid du Colombier b[s00 ] = (b[s00]>>3) & 1;
177219b2ee8SDavid du Colombier }
178219b2ee8SDavid du Colombier }
179219b2ee8SDavid du Colombier if(i < nx) {
180219b2ee8SDavid du Colombier /*
181219b2ee8SDavid du Colombier * column size is odd, do last row
182219b2ee8SDavid du Colombier * s10, s10+1 are off edge
183219b2ee8SDavid du Colombier */
184219b2ee8SDavid du Colombier s00 = n*i;
185219b2ee8SDavid du Colombier for (j = 0; j<ny-1; j += 2) {
186219b2ee8SDavid du Colombier b[s00+1] = (b[s00]>>2) & 1;
187219b2ee8SDavid du Colombier b[s00 ] = (b[s00]>>3) & 1;
188219b2ee8SDavid du Colombier s00 += 2;
189219b2ee8SDavid du Colombier }
190219b2ee8SDavid du Colombier if(j < ny) {
191219b2ee8SDavid du Colombier /*
192219b2ee8SDavid du Colombier * both row and column size are odd, do corner element
193219b2ee8SDavid du Colombier * s00+1, s10, s10+1 are off edge
194219b2ee8SDavid du Colombier */
195219b2ee8SDavid du Colombier b[s00 ] = (b[s00]>>3) & 1;
196219b2ee8SDavid du Colombier }
197219b2ee8SDavid du Colombier }
198219b2ee8SDavid du Colombier }
199219b2ee8SDavid du Colombier
200219b2ee8SDavid du Colombier /*
201219b2ee8SDavid du Colombier * Copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
202219b2ee8SDavid du Colombier * each value to 2x2 pixels and inserting into bitplane BIT of B.
203219b2ee8SDavid du Colombier * A,B may NOT be same array (it wouldn't make sense to be inserting
204219b2ee8SDavid du Colombier * bits into the same array anyway.)
205219b2ee8SDavid du Colombier */
206219b2ee8SDavid du Colombier static
207219b2ee8SDavid du Colombier void
qtree_bitins(uchar * a,int nx,int ny,Pix * b,int n,int bit)208219b2ee8SDavid du Colombier qtree_bitins(uchar *a, int nx, int ny, Pix *b, int n, int bit)
209219b2ee8SDavid du Colombier {
210219b2ee8SDavid du Colombier int i, j;
211219b2ee8SDavid du Colombier Pix *s00, *s10;
212219b2ee8SDavid du Colombier Pix px;
213219b2ee8SDavid du Colombier
214219b2ee8SDavid du Colombier /*
215219b2ee8SDavid du Colombier * expand each 2x2 block
216219b2ee8SDavid du Colombier */
217219b2ee8SDavid du Colombier for(i=0; i<nx-1; i+=2) {
218219b2ee8SDavid du Colombier s00 = &b[n*i]; /* s00 is index of b[i,j] */
219219b2ee8SDavid du Colombier s10 = s00+n; /* s10 is index of b[i+1,j] */
220219b2ee8SDavid du Colombier for(j=0; j<ny-1; j+=2) {
221219b2ee8SDavid du Colombier px = *a++;
222219b2ee8SDavid du Colombier s10[1] |= ( px & 1) << bit;
223219b2ee8SDavid du Colombier s10[0] |= ((px>>1) & 1) << bit;
224219b2ee8SDavid du Colombier s00[1] |= ((px>>2) & 1) << bit;
225219b2ee8SDavid du Colombier s00[0] |= ((px>>3) & 1) << bit;
226219b2ee8SDavid du Colombier s00 += 2;
227219b2ee8SDavid du Colombier s10 += 2;
228219b2ee8SDavid du Colombier }
229219b2ee8SDavid du Colombier if(j < ny) {
230219b2ee8SDavid du Colombier /*
231219b2ee8SDavid du Colombier * row size is odd, do last element in row
232219b2ee8SDavid du Colombier * s00+1, s10+1 are off edge
233219b2ee8SDavid du Colombier */
234219b2ee8SDavid du Colombier px = *a++;
235219b2ee8SDavid du Colombier s10[0] |= ((px>>1) & 1) << bit;
236219b2ee8SDavid du Colombier s00[0] |= ((px>>3) & 1) << bit;
237219b2ee8SDavid du Colombier }
238219b2ee8SDavid du Colombier }
239219b2ee8SDavid du Colombier if(i < nx) {
240219b2ee8SDavid du Colombier /*
241219b2ee8SDavid du Colombier * column size is odd, do last row
242219b2ee8SDavid du Colombier * s10, s10+1 are off edge
243219b2ee8SDavid du Colombier */
244219b2ee8SDavid du Colombier s00 = &b[n*i];
245219b2ee8SDavid du Colombier for(j=0; j<ny-1; j+=2) {
246219b2ee8SDavid du Colombier px = *a++;
247219b2ee8SDavid du Colombier s00[1] |= ((px>>2) & 1) << bit;
248219b2ee8SDavid du Colombier s00[0] |= ((px>>3) & 1) << bit;
249219b2ee8SDavid du Colombier s00 += 2;
250219b2ee8SDavid du Colombier }
251219b2ee8SDavid du Colombier if(j < ny) {
252219b2ee8SDavid du Colombier /*
253219b2ee8SDavid du Colombier * both row and column size are odd, do corner element
254219b2ee8SDavid du Colombier * s00+1, s10, s10+1 are off edge
255219b2ee8SDavid du Colombier */
256219b2ee8SDavid du Colombier s00[0] |= ((*a>>3) & 1) << bit;
257219b2ee8SDavid du Colombier }
258219b2ee8SDavid du Colombier }
259219b2ee8SDavid du Colombier }
260219b2ee8SDavid du Colombier
261219b2ee8SDavid du Colombier static
262219b2ee8SDavid du Colombier void
read_bdirect(Biobuf * infile,Pix * a,int n,int nqx,int nqy,uchar * scratch,int bit)263219b2ee8SDavid du Colombier read_bdirect(Biobuf *infile, Pix *a, int n, int nqx, int nqy, uchar *scratch, int bit)
264219b2ee8SDavid du Colombier {
265219b2ee8SDavid du Colombier int i;
266219b2ee8SDavid du Colombier
267219b2ee8SDavid du Colombier /*
268219b2ee8SDavid du Colombier * read bit image packed 4 pixels/nybble
269219b2ee8SDavid du Colombier */
270219b2ee8SDavid du Colombier for(i = 0; i < ((nqx+1)/2) * ((nqy+1)/2); i++) {
271219b2ee8SDavid du Colombier scratch[i] = input_nybble(infile);
272219b2ee8SDavid du Colombier }
273219b2ee8SDavid du Colombier
274219b2ee8SDavid du Colombier /*
275219b2ee8SDavid du Colombier * insert in bitplane BIT of image A
276219b2ee8SDavid du Colombier */
277219b2ee8SDavid du Colombier qtree_bitins(scratch, nqx, nqy, a, n, bit);
278219b2ee8SDavid du Colombier }
279