upgrade to xpdf 3.00.
[swftools.git] / pdf2swf / xpdf / JPXStream.cc
blobdefa7d2adb08e051fa7614c38c454a6905c2009d
1 //========================================================================
2 //
3 // JPXStream.cc
4 //
5 // Copyright 2002-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
15 #include "gmem.h"
16 #include "Error.h"
17 #include "JArithmeticDecoder.h"
18 #include "JPXStream.h"
20 //~ to do:
21 // - precincts
22 // - ROI
23 // - progression order changes
24 // - packed packet headers
25 // - support for palettes, channel maps, etc.
26 // - make sure all needed JP2/JPX subboxes are parsed (readBoxes)
27 // - can we assume that QCC segments must come after the QCD segment?
28 // - skip EPH markers (readTilePartData)
29 // - handle tilePartToEOC in readTilePartData
30 // - deal with multiple codeword segments (readTilePartData,
31 // readCodeBlockData)
32 // - progression orders 2, 3, and 4
33 // - in coefficient decoding (readCodeBlockData):
34 // - termination pattern: terminate after every coding pass
35 // - error resilience segmentation symbol
36 // - selective arithmetic coding bypass
37 // - vertically causal context formation
38 // - coeffs longer than 31 bits (should just ignore the extra bits?)
39 // - handle boxes larger than 2^32 bytes
40 // - the fixed-point arithmetic won't handle 16-bit pixels
42 //------------------------------------------------------------------------
44 // number of contexts for the arithmetic decoder
45 #define jpxNContexts 19
47 #define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup
48 #define jpxContextSign 9 // 9 - 13: sign
49 #define jpxContextMagRef 14 // 14 -16: magnitude refinement
50 #define jpxContextRunLength 17 // cleanup: run length
51 #define jpxContextUniform 18 // cleanup: first signif coeff
53 //------------------------------------------------------------------------
55 #define jpxPassSigProp 0
56 #define jpxPassMagRef 1
57 #define jpxPassCleanup 2
59 //------------------------------------------------------------------------
61 // arithmetic decoder context for the significance propagation and
62 // cleanup passes:
63 // [horiz][vert][diag][subband]
64 // where subband = 0 for HL
65 // = 1 for LH and LL
66 // = 2 for HH
67 static Guint sigPropContext[3][3][5][3] = {
68 {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0
69 { 1, 1, 3 }, // horiz=0, vert=0, diag=1
70 { 2, 2, 6 }, // horiz=0, vert=0, diag=2
71 { 2, 2, 8 }, // horiz=0, vert=0, diag=3
72 { 2, 2, 8 }}, // horiz=0, vert=0, diag=4
73 {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0
74 { 6, 3, 4 }, // horiz=0, vert=1, diag=1
75 { 6, 3, 7 }, // horiz=0, vert=1, diag=2
76 { 6, 3, 8 }, // horiz=0, vert=1, diag=3
77 { 6, 3, 8 }}, // horiz=0, vert=1, diag=4
78 {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0
79 { 8, 4, 5 }, // horiz=0, vert=2, diag=1
80 { 8, 4, 7 }, // horiz=0, vert=2, diag=2
81 { 8, 4, 8 }, // horiz=0, vert=2, diag=3
82 { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4
83 {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0
84 { 3, 6, 4 }, // horiz=1, vert=0, diag=1
85 { 3, 6, 7 }, // horiz=1, vert=0, diag=2
86 { 3, 6, 8 }, // horiz=1, vert=0, diag=3
87 { 3, 6, 8 }}, // horiz=1, vert=0, diag=4
88 {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0
89 { 7, 7, 5 }, // horiz=1, vert=1, diag=1
90 { 7, 7, 7 }, // horiz=1, vert=1, diag=2
91 { 7, 7, 8 }, // horiz=1, vert=1, diag=3
92 { 7, 7, 8 }}, // horiz=1, vert=1, diag=4
93 {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0
94 { 8, 7, 5 }, // horiz=1, vert=2, diag=1
95 { 8, 7, 7 }, // horiz=1, vert=2, diag=2
96 { 8, 7, 8 }, // horiz=1, vert=2, diag=3
97 { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4
98 {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0
99 { 4, 8, 5 }, // horiz=2, vert=0, diag=1
100 { 4, 8, 7 }, // horiz=2, vert=0, diag=2
101 { 4, 8, 8 }, // horiz=2, vert=0, diag=3
102 { 4, 8, 8 }}, // horiz=2, vert=0, diag=4
103 {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0
104 { 7, 8, 5 }, // horiz=2, vert=1, diag=1
105 { 7, 8, 7 }, // horiz=2, vert=1, diag=2
106 { 7, 8, 8 }, // horiz=2, vert=1, diag=3
107 { 7, 8, 8 }}, // horiz=2, vert=1, diag=4
108 {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0
109 { 8, 8, 5 }, // horiz=2, vert=2, diag=1
110 { 8, 8, 7 }, // horiz=2, vert=2, diag=2
111 { 8, 8, 8 }, // horiz=2, vert=2, diag=3
112 { 8, 8, 8 }}} // horiz=2, vert=2, diag=4
115 // arithmetic decoder context and xor bit for the sign bit in the
116 // significance propagation pass:
117 // [horiz][vert][k]
118 // where horiz/vert are offset by 2 (i.e., range is -2 .. 2)
119 // and k = 0 for the context
120 // = 1 for the xor bit
121 static Guint signContext[5][5][2] = {
122 {{ 13, 1 }, // horiz=-2, vert=-2
123 { 13, 1 }, // horiz=-2, vert=-1
124 { 12, 1 }, // horiz=-2, vert= 0
125 { 11, 1 }, // horiz=-2, vert=+1
126 { 11, 1 }}, // horiz=-2, vert=+2
127 {{ 13, 1 }, // horiz=-1, vert=-2
128 { 13, 1 }, // horiz=-1, vert=-1
129 { 12, 1 }, // horiz=-1, vert= 0
130 { 11, 1 }, // horiz=-1, vert=+1
131 { 11, 1 }}, // horiz=-1, vert=+2
132 {{ 10, 1 }, // horiz= 0, vert=-2
133 { 10, 1 }, // horiz= 0, vert=-1
134 { 9, 0 }, // horiz= 0, vert= 0
135 { 10, 0 }, // horiz= 0, vert=+1
136 { 10, 0 }}, // horiz= 0, vert=+2
137 {{ 11, 0 }, // horiz=+1, vert=-2
138 { 11, 0 }, // horiz=+1, vert=-1
139 { 12, 0 }, // horiz=+1, vert= 0
140 { 13, 0 }, // horiz=+1, vert=+1
141 { 13, 0 }}, // horiz=+1, vert=+2
142 {{ 11, 0 }, // horiz=+2, vert=-2
143 { 11, 0 }, // horiz=+2, vert=-1
144 { 12, 0 }, // horiz=+2, vert= 0
145 { 13, 0 }, // horiz=+2, vert=+1
146 { 13, 0 }}, // horiz=+2, vert=+2
149 //------------------------------------------------------------------------
151 // constants used in the IDWT
152 #define idwtAlpha -1.586134342059924
153 #define idwtBeta -0.052980118572961
154 #define idwtGamma 0.882911075530934
155 #define idwtDelta 0.443506852043971
156 #define idwtKappa 1.230174104914001
157 #define idwtIKappa (1.0 / idwtKappa)
159 // number of bits to the right of the decimal point for the fixed
160 // point arithmetic used in the IDWT
161 #define fracBits 16
163 //------------------------------------------------------------------------
165 // floor(x / y)
166 #define jpxFloorDiv(x, y) ((x) / (y))
168 // floor(x / 2^y)
169 #define jpxFloorDivPow2(x, y) ((x) >> (y))
171 // ceil(x / y)
172 #define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y))
174 // ceil(x / 2^y)
175 #define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y))
177 //------------------------------------------------------------------------
179 JPXStream::JPXStream(Stream *strA):
180 FilterStream(strA)
182 nComps = 0;
183 bpc = NULL;
184 width = height = 0;
185 haveCS = gFalse;
186 havePalette = gFalse;
187 haveCompMap = gFalse;
188 haveChannelDefn = gFalse;
190 img.tiles = NULL;
191 bitBuf = 0;
192 bitBufLen = 0;
193 bitBufSkip = gFalse;
194 byteCount = 0;
197 JPXStream::~JPXStream() {
198 JPXTile *tile;
199 JPXTileComp *tileComp;
200 JPXResLevel *resLevel;
201 JPXPrecinct *precinct;
202 JPXSubband *subband;
203 JPXCodeBlock *cb;
204 Guint comp, i, k, r, pre, sb;
206 gfree(bpc);
207 if (havePalette) {
208 gfree(palette.bpc);
209 gfree(palette.c);
211 if (haveCompMap) {
212 gfree(compMap.comp);
213 gfree(compMap.type);
214 gfree(compMap.pComp);
216 if (haveChannelDefn) {
217 gfree(channelDefn.idx);
218 gfree(channelDefn.type);
219 gfree(channelDefn.assoc);
222 if (img.tiles) {
223 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
224 tile = &img.tiles[i];
225 if (tile->tileComps) {
226 for (comp = 0; comp < img.nComps; ++comp) {
227 tileComp = &tile->tileComps[comp];
228 gfree(tileComp->quantSteps);
229 gfree(tileComp->data);
230 gfree(tileComp->buf);
231 if (tileComp->resLevels) {
232 for (r = 0; r <= tileComp->nDecompLevels; ++r) {
233 resLevel = &tileComp->resLevels[r];
234 if (resLevel->precincts) {
235 for (pre = 0; pre < 1; ++pre) {
236 precinct = &resLevel->precincts[pre];
237 if (precinct->subbands) {
238 for (sb = 0; sb < (r == 0 ? 1 : 3); ++sb) {
239 subband = &precinct->subbands[sb];
240 gfree(subband->inclusion);
241 gfree(subband->zeroBitPlane);
242 if (subband->cbs) {
243 for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
244 cb = &subband->cbs[k];
245 gfree(cb->coeffs);
246 if (cb->stats) {
247 delete cb->stats;
250 gfree(subband->cbs);
253 gfree(precinct->subbands);
256 gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts);
259 gfree(img.tiles[i].tileComps[comp].resLevels);
262 gfree(img.tiles[i].tileComps);
265 gfree(img.tiles);
267 delete str;
270 void JPXStream::reset() {
271 str->reset();
272 if (readBoxes()) {
273 curY = img.yOffset;
274 } else {
275 // readBoxes reported an error, so we go immediately to EOF
276 curY = img.ySize;
278 curX = img.xOffset;
279 curComp = 0;
280 readBufLen = 0;
283 int JPXStream::getChar() {
284 int c;
286 if (readBufLen < 8) {
287 fillReadBuf();
289 if (readBufLen == 8) {
290 c = readBuf & 0xff;
291 readBufLen = 0;
292 } else if (readBufLen > 8) {
293 c = (readBuf >> (readBufLen - 8)) & 0xff;
294 readBufLen -= 8;
295 } else if (readBufLen == 0) {
296 c = EOF;
297 } else {
298 c = (readBuf << (8 - readBufLen)) & 0xff;
299 readBufLen = 0;
301 return c;
304 int JPXStream::lookChar() {
305 int c;
307 if (readBufLen < 8) {
308 fillReadBuf();
310 if (readBufLen == 8) {
311 c = readBuf & 0xff;
312 } else if (readBufLen > 8) {
313 c = (readBuf >> (readBufLen - 8)) & 0xff;
314 } else if (readBufLen == 0) {
315 c = EOF;
316 } else {
317 c = (readBuf << (8 - readBufLen)) & 0xff;
319 return c;
322 void JPXStream::fillReadBuf() {
323 JPXTileComp *tileComp;
324 Guint tileIdx, tx, ty;
325 int pix, pixBits;
327 do {
328 if (curY >= img.ySize) {
329 return;
331 tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles
332 + (curX - img.xTileOffset) / img.xTileSize;
333 #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
334 tileComp = &img.tiles[tileIdx].tileComps[curComp];
335 #else
336 tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp];
337 #endif
338 tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep);
339 ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep);
340 pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx];
341 pixBits = tileComp->prec;
342 #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
343 if (++curComp == img.nComps) {
344 #else
345 if (havePalette) {
346 if (pix >= 0 && pix < palette.nEntries) {
347 pix = palette.c[pix * palette.nComps + curComp];
348 } else {
349 pix =
350 pixBits = palette.bpc[curComp];
352 if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) {
353 #endif
354 curComp = 0;
355 if (++curX == img.xSize) {
356 curX = img.xOffset;
357 ++curY;
360 if (pixBits == 8) {
361 readBuf = (readBuf << 8) | (pix & 0xff);
362 } else {
363 readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1));
365 readBufLen += pixBits;
366 } while (readBufLen < 8);
369 GString *JPXStream::getPSFilter(int psLevel, char *indent) {
370 return NULL;
373 GBool JPXStream::isBinary(GBool last) {
374 return str->isBinary(gTrue);
377 GBool JPXStream::readBoxes() {
378 Guint boxType, boxLen, dataLen;
379 Guint bpc1, compression, unknownColorspace, ipr;
380 Guint i, j;
382 haveImgHdr = gFalse;
384 // check for a naked JPEG 2000 codestream (without the JP2/JPX
385 // wrapper) -- this appears to be a violation of the PDF spec, but
386 // Acrobat allows it
387 if (str->lookChar() == 0xff) {
388 error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
389 readCodestream(0);
390 nComps = img.nComps;
391 bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
392 for (i = 0; i < nComps; ++i) {
393 bpc[i] = img.tiles[0].tileComps[i].prec;
395 width = img.xSize - img.xOffset;
396 height = img.ySize - img.yOffset;
397 return gTrue;
400 while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
401 switch (boxType) {
402 case 0x6a703268: // JP2 header
403 // this is a grouping box ('superbox') which has no real
404 // contents and doesn't appear to be used consistently, i.e.,
405 // some things which should be subboxes of the JP2 header box
406 // show up outside of it - so we simply ignore the JP2 header
407 // box
408 break;
409 case 0x69686472: // image header
410 if (!readULong(&height) ||
411 !readULong(&width) ||
412 !readUWord(&nComps) ||
413 !readUByte(&bpc1) ||
414 !readUByte(&compression) ||
415 !readUByte(&unknownColorspace) ||
416 !readUByte(&ipr)) {
417 error(getPos(), "Unexpected EOF in JPX stream");
418 return gFalse;
420 if (compression != 7) {
421 error(getPos(), "Unknown compression type in JPX stream");
422 return gFalse;
424 bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
425 for (i = 0; i < nComps; ++i) {
426 bpc[i] = bpc1;
428 haveImgHdr = gTrue;
429 break;
430 case 0x62706363: // bits per component
431 if (!haveImgHdr) {
432 error(getPos(), "Found bits per component box before image header box in JPX stream");
433 return gFalse;
435 if (dataLen != nComps) {
436 error(getPos(), "Invalid bits per component box in JPX stream");
437 return gFalse;
439 for (i = 0; i < nComps; ++i) {
440 if (!readUByte(&bpc[i])) {
441 error(getPos(), "Unexpected EOF in JPX stream");
442 return gFalse;
445 break;
446 case 0x636F6C72: // color specification
447 if (!readColorSpecBox(dataLen)) {
448 return gFalse;
450 break;
451 case 0x70636c72: // palette
452 if (!readUWord(&palette.nEntries) ||
453 !readUByte(&palette.nComps)) {
454 error(getPos(), "Unexpected EOF in JPX stream");
455 return gFalse;
457 palette.bpc = (Guint *)gmalloc(palette.nComps * sizeof(Guint));
458 palette.c =
459 (int *)gmalloc(palette.nEntries * palette.nComps * sizeof(int));
460 for (i = 0; i < palette.nComps; ++i) {
461 if (!readUByte(&palette.bpc[i])) {
462 error(getPos(), "Unexpected EOF in JPX stream");
463 return gFalse;
465 ++palette.bpc[i];
467 for (i = 0; i < palette.nEntries; ++i) {
468 for (j = 0; j < palette.nComps; ++j) {
469 if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3,
470 (palette.bpc[j] & 0x80) ? gTrue : gFalse,
471 &palette.c[i * palette.nComps + j])) {
472 error(getPos(), "Unexpected EOF in JPX stream");
473 return gFalse;
477 havePalette = gTrue;
478 break;
479 case 0x636d6170: // component mapping
480 compMap.nChannels = dataLen / 4;
481 compMap.comp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
482 compMap.type = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
483 compMap.pComp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
484 for (i = 0; i < compMap.nChannels; ++i) {
485 if (!readUWord(&compMap.comp[i]) ||
486 !readUByte(&compMap.type[i]) ||
487 !readUByte(&compMap.pComp[i])) {
488 error(getPos(), "Unexpected EOF in JPX stream");
489 return gFalse;
492 haveCompMap = gTrue;
493 break;
494 case 0x63646566: // channel definition
495 if (!readUWord(&channelDefn.nChannels)) {
496 error(getPos(), "Unexpected EOF in JPX stream");
497 return gFalse;
499 channelDefn.idx =
500 (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
501 channelDefn.type =
502 (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
503 channelDefn.assoc =
504 (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
505 for (i = 0; i < channelDefn.nChannels; ++i) {
506 if (!readUWord(&channelDefn.idx[i]) ||
507 !readUWord(&channelDefn.type[i]) ||
508 !readUWord(&channelDefn.assoc[i])) {
509 error(getPos(), "Unexpected EOF in JPX stream");
510 return gFalse;
513 haveChannelDefn = gTrue;
514 break;
515 case 0x6A703263: // contiguous codestream
516 if (!bpc) {
517 error(getPos(), "JPX stream is missing the image header box");
518 return gFalse;
520 if (!haveCS) {
521 error(getPos(), "JPX stream has no supported color spec");
522 return gFalse;
524 if (!readCodestream(dataLen)) {
525 return gFalse;
527 break;
528 default:
529 for (i = 0; i < dataLen; ++i) {
530 if (str->getChar() == EOF) {
531 error(getPos(), "Unexpected EOF in JPX stream");
532 return gFalse;
535 break;
538 return gTrue;
541 GBool JPXStream::readColorSpecBox(Guint dataLen) {
542 JPXColorSpec newCS;
543 Guint csApprox, csEnum;
544 Guint i;
545 GBool ok;
547 ok = gFalse;
548 if (!readUByte(&newCS.meth) ||
549 !readByte(&newCS.prec) ||
550 !readUByte(&csApprox)) {
551 goto err;
553 switch (newCS.meth) {
554 case 1: // enumerated colorspace
555 if (!readULong(&csEnum)) {
556 goto err;
558 newCS.enumerated.type = (JPXColorSpaceType)csEnum;
559 switch (newCS.enumerated.type) {
560 case jpxCSBiLevel:
561 ok = gTrue;
562 break;
563 case jpxCSYCbCr1:
564 ok = gTrue;
565 break;
566 case jpxCSYCbCr2:
567 ok = gTrue;
568 break;
569 case jpxCSYCBCr3:
570 ok = gTrue;
571 break;
572 case jpxCSPhotoYCC:
573 ok = gTrue;
574 break;
575 case jpxCSCMY:
576 ok = gTrue;
577 break;
578 case jpxCSCMYK:
579 ok = gTrue;
580 break;
581 case jpxCSYCCK:
582 ok = gTrue;
583 break;
584 case jpxCSCIELab:
585 if (dataLen == 3 + 7*4) {
586 if (!readULong(&newCS.enumerated.cieLab.rl) ||
587 !readULong(&newCS.enumerated.cieLab.ol) ||
588 !readULong(&newCS.enumerated.cieLab.ra) ||
589 !readULong(&newCS.enumerated.cieLab.oa) ||
590 !readULong(&newCS.enumerated.cieLab.rb) ||
591 !readULong(&newCS.enumerated.cieLab.ob) ||
592 !readULong(&newCS.enumerated.cieLab.il)) {
593 goto err;
595 } else if (dataLen == 3) {
596 //~ this assumes the 8-bit case
597 newCS.enumerated.cieLab.rl = 100;
598 newCS.enumerated.cieLab.ol = 0;
599 newCS.enumerated.cieLab.ra = 255;
600 newCS.enumerated.cieLab.oa = 128;
601 newCS.enumerated.cieLab.rb = 255;
602 newCS.enumerated.cieLab.ob = 96;
603 newCS.enumerated.cieLab.il = 0x00443530;
604 } else {
605 goto err;
607 ok = gTrue;
608 break;
609 case jpxCSsRGB:
610 ok = gTrue;
611 break;
612 case jpxCSGrayscale:
613 ok = gTrue;
614 break;
615 case jpxCSBiLevel2:
616 ok = gTrue;
617 break;
618 case jpxCSCIEJab:
619 // not allowed in PDF
620 goto err;
621 case jpxCSCISesRGB:
622 ok = gTrue;
623 break;
624 case jpxCSROMMRGB:
625 ok = gTrue;
626 break;
627 case jpxCSsRGBYCbCr:
628 ok = gTrue;
629 break;
630 case jpxCSYPbPr1125:
631 ok = gTrue;
632 break;
633 case jpxCSYPbPr1250:
634 ok = gTrue;
635 break;
636 default:
637 goto err;
639 break;
640 case 2: // restricted ICC profile
641 case 3: // any ICC profile (JPX)
642 case 4: // vendor color (JPX)
643 for (i = 0; i < dataLen - 3; ++i) {
644 if (str->getChar() == EOF) {
645 goto err;
648 break;
651 if (ok && (!haveCS || newCS.prec > cs.prec)) {
652 cs = newCS;
653 haveCS = gTrue;
656 return gTrue;
658 err:
659 error(getPos(), "Error in JPX color spec");
660 return gFalse;
663 GBool JPXStream::readCodestream(Guint len) {
664 JPXTile *tile;
665 JPXTileComp *tileComp;
666 int segType;
667 GBool haveSIZ, haveCOD, haveQCD, haveSOT;
668 Guint precinctSize, style;
669 Guint segLen, capabilities, comp, i, j, r;
671 //----- main header
672 haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
673 do {
674 if (!readMarkerHdr(&segType, &segLen)) {
675 error(getPos(), "Error in JPX codestream");
676 return gFalse;
678 switch (segType) {
679 case 0x4f: // SOC - start of codestream
680 // marker only
681 break;
682 case 0x51: // SIZ - image and tile size
683 if (!readUWord(&capabilities) ||
684 !readULong(&img.xSize) ||
685 !readULong(&img.ySize) ||
686 !readULong(&img.xOffset) ||
687 !readULong(&img.yOffset) ||
688 !readULong(&img.xTileSize) ||
689 !readULong(&img.yTileSize) ||
690 !readULong(&img.xTileOffset) ||
691 !readULong(&img.yTileOffset) ||
692 !readUWord(&img.nComps)) {
693 error(getPos(), "Error in JPX SIZ marker segment");
694 return gFalse;
696 if (haveImgHdr && img.nComps != nComps) {
697 error(getPos(), "Different number of components in JPX SIZ marker segment");
698 return gFalse;
700 img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1)
701 / img.xTileSize;
702 img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
703 / img.yTileSize;
704 img.tiles = (JPXTile *)gmalloc(img.nXTiles * img.nYTiles *
705 sizeof(JPXTile));
706 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
707 img.tiles[i].tileComps = (JPXTileComp *)gmalloc(img.nComps *
708 sizeof(JPXTileComp));
709 for (comp = 0; comp < img.nComps; ++comp) {
710 img.tiles[i].tileComps[comp].quantSteps = NULL;
711 img.tiles[i].tileComps[comp].data = NULL;
712 img.tiles[i].tileComps[comp].buf = NULL;
713 img.tiles[i].tileComps[comp].resLevels = NULL;
716 for (comp = 0; comp < img.nComps; ++comp) {
717 if (!readUByte(&img.tiles[0].tileComps[comp].prec) ||
718 !readUByte(&img.tiles[0].tileComps[comp].hSep) ||
719 !readUByte(&img.tiles[0].tileComps[comp].vSep)) {
720 error(getPos(), "Error in JPX SIZ marker segment");
721 return gFalse;
723 img.tiles[0].tileComps[comp].sgned =
724 (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse;
725 img.tiles[0].tileComps[comp].prec =
726 (img.tiles[0].tileComps[comp].prec & 0x7f) + 1;
727 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
728 img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp];
731 haveSIZ = gTrue;
732 break;
733 case 0x52: // COD - coding style default
734 if (!readUByte(&img.tiles[0].tileComps[0].style) ||
735 !readUByte(&img.tiles[0].progOrder) ||
736 !readUWord(&img.tiles[0].nLayers) ||
737 !readUByte(&img.tiles[0].multiComp) ||
738 !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) ||
739 !readUByte(&img.tiles[0].tileComps[0].codeBlockW) ||
740 !readUByte(&img.tiles[0].tileComps[0].codeBlockH) ||
741 !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) ||
742 !readUByte(&img.tiles[0].tileComps[0].transform)) {
743 error(getPos(), "Error in JPX COD marker segment");
744 return gFalse;
746 img.tiles[0].tileComps[0].codeBlockW += 2;
747 img.tiles[0].tileComps[0].codeBlockH += 2;
748 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
749 if (i != 0) {
750 img.tiles[i].progOrder = img.tiles[0].progOrder;
751 img.tiles[i].nLayers = img.tiles[0].nLayers;
752 img.tiles[i].multiComp = img.tiles[0].multiComp;
754 for (comp = 0; comp < img.nComps; ++comp) {
755 if (!(i == 0 && comp == 0)) {
756 img.tiles[i].tileComps[comp].style =
757 img.tiles[0].tileComps[0].style;
758 img.tiles[i].tileComps[comp].nDecompLevels =
759 img.tiles[0].tileComps[0].nDecompLevels;
760 img.tiles[i].tileComps[comp].codeBlockW =
761 img.tiles[0].tileComps[0].codeBlockW;
762 img.tiles[i].tileComps[comp].codeBlockH =
763 img.tiles[0].tileComps[0].codeBlockH;
764 img.tiles[i].tileComps[comp].codeBlockStyle =
765 img.tiles[0].tileComps[0].codeBlockStyle;
766 img.tiles[i].tileComps[comp].transform =
767 img.tiles[0].tileComps[0].transform;
769 img.tiles[i].tileComps[comp].resLevels =
770 (JPXResLevel *)gmalloc(
771 (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
772 sizeof(JPXResLevel));
773 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
774 img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
778 for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) {
779 if (img.tiles[0].tileComps[0].style & 0x01) {
780 if (!readUByte(&precinctSize)) {
781 error(getPos(), "Error in JPX COD marker segment");
782 return gFalse;
784 img.tiles[0].tileComps[0].resLevels[r].precinctWidth =
785 precinctSize & 0x0f;
786 img.tiles[0].tileComps[0].resLevels[r].precinctHeight =
787 (precinctSize >> 4) & 0x0f;
788 } else {
789 img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15;
790 img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15;
793 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
794 for (comp = 0; comp < img.nComps; ++comp) {
795 if (!(i == 0 && comp == 0)) {
796 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
797 img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
798 img.tiles[0].tileComps[0].resLevels[r].precinctWidth;
799 img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
800 img.tiles[0].tileComps[0].resLevels[r].precinctHeight;
805 haveCOD = gTrue;
806 break;
807 case 0x53: // COC - coding style component
808 if (!haveCOD) {
809 error(getPos(), "JPX COC marker segment before COD segment");
810 return gFalse;
812 if ((img.nComps > 256 && !readUWord(&comp)) ||
813 (img.nComps <= 256 && !readUByte(&comp)) ||
814 comp >= img.nComps ||
815 !readUByte(&style) ||
816 !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) ||
817 !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) ||
818 !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) ||
819 !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) ||
820 !readUByte(&img.tiles[0].tileComps[comp].transform)) {
821 error(getPos(), "Error in JPX COC marker segment");
822 return gFalse;
824 img.tiles[0].tileComps[comp].style =
825 (img.tiles[0].tileComps[comp].style & ~1) | (style & 1);
826 img.tiles[0].tileComps[comp].codeBlockW += 2;
827 img.tiles[0].tileComps[comp].codeBlockH += 2;
828 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
829 if (i != 0) {
830 img.tiles[i].tileComps[comp].style =
831 img.tiles[0].tileComps[comp].style;
832 img.tiles[i].tileComps[comp].nDecompLevels =
833 img.tiles[0].tileComps[comp].nDecompLevels;
834 img.tiles[i].tileComps[comp].codeBlockW =
835 img.tiles[0].tileComps[comp].codeBlockW;
836 img.tiles[i].tileComps[comp].codeBlockH =
837 img.tiles[0].tileComps[comp].codeBlockH;
838 img.tiles[i].tileComps[comp].codeBlockStyle =
839 img.tiles[0].tileComps[comp].codeBlockStyle;
840 img.tiles[i].tileComps[comp].transform =
841 img.tiles[0].tileComps[comp].transform;
843 img.tiles[i].tileComps[comp].resLevels =
844 (JPXResLevel *)grealloc(
845 img.tiles[i].tileComps[comp].resLevels,
846 (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
847 sizeof(JPXResLevel));
848 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
849 img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
852 for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) {
853 if (img.tiles[0].tileComps[comp].style & 0x01) {
854 if (!readUByte(&precinctSize)) {
855 error(getPos(), "Error in JPX COD marker segment");
856 return gFalse;
858 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth =
859 precinctSize & 0x0f;
860 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight =
861 (precinctSize >> 4) & 0x0f;
862 } else {
863 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15;
864 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15;
867 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
868 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
869 img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
870 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth;
871 img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
872 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight;
875 break;
876 case 0x5c: // QCD - quantization default
877 if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) {
878 error(getPos(), "Error in JPX QCD marker segment");
879 return gFalse;
881 if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
882 img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
883 img.tiles[0].tileComps[0].quantSteps =
884 (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
885 img.tiles[0].tileComps[0].nQuantSteps *
886 sizeof(Guint));
887 for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
888 if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
889 error(getPos(), "Error in JPX QCD marker segment");
890 return gFalse;
893 } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
894 img.tiles[0].tileComps[0].nQuantSteps = 1;
895 img.tiles[0].tileComps[0].quantSteps =
896 (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
897 img.tiles[0].tileComps[0].nQuantSteps *
898 sizeof(Guint));
899 if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
900 error(getPos(), "Error in JPX QCD marker segment");
901 return gFalse;
903 } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
904 img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
905 img.tiles[0].tileComps[0].quantSteps =
906 (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
907 img.tiles[0].tileComps[0].nQuantSteps *
908 sizeof(Guint));
909 for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
910 if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
911 error(getPos(), "Error in JPX QCD marker segment");
912 return gFalse;
915 } else {
916 error(getPos(), "Error in JPX QCD marker segment");
917 return gFalse;
919 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
920 for (comp = 0; comp < img.nComps; ++comp) {
921 if (!(i == 0 && comp == 0)) {
922 img.tiles[i].tileComps[comp].quantStyle =
923 img.tiles[0].tileComps[0].quantStyle;
924 img.tiles[i].tileComps[comp].nQuantSteps =
925 img.tiles[0].tileComps[0].nQuantSteps;
926 img.tiles[i].tileComps[comp].quantSteps =
927 (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
928 img.tiles[0].tileComps[0].nQuantSteps *
929 sizeof(Guint));
930 for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
931 img.tiles[i].tileComps[comp].quantSteps[j] =
932 img.tiles[0].tileComps[0].quantSteps[j];
937 haveQCD = gTrue;
938 break;
939 case 0x5d: // QCC - quantization component
940 if (!haveQCD) {
941 error(getPos(), "JPX QCC marker segment before QCD segment");
942 return gFalse;
944 if ((img.nComps > 256 && !readUWord(&comp)) ||
945 (img.nComps <= 256 && !readUByte(&comp)) ||
946 comp >= img.nComps ||
947 !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) {
948 error(getPos(), "Error in JPX QCC marker segment");
949 return gFalse;
951 if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) {
952 img.tiles[0].tileComps[comp].nQuantSteps =
953 segLen - (img.nComps > 256 ? 5 : 4);
954 img.tiles[0].tileComps[comp].quantSteps =
955 (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
956 img.tiles[0].tileComps[comp].nQuantSteps *
957 sizeof(Guint));
958 for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
959 if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
960 error(getPos(), "Error in JPX QCC marker segment");
961 return gFalse;
964 } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
965 img.tiles[0].tileComps[comp].nQuantSteps = 1;
966 img.tiles[0].tileComps[comp].quantSteps =
967 (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
968 img.tiles[0].tileComps[comp].nQuantSteps *
969 sizeof(Guint));
970 if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
971 error(getPos(), "Error in JPX QCC marker segment");
972 return gFalse;
974 } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) {
975 img.tiles[0].tileComps[comp].nQuantSteps =
976 (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
977 img.tiles[0].tileComps[comp].quantSteps =
978 (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
979 img.tiles[0].tileComps[comp].nQuantSteps *
980 sizeof(Guint));
981 for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
982 if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
983 error(getPos(), "Error in JPX QCD marker segment");
984 return gFalse;
987 } else {
988 error(getPos(), "Error in JPX QCC marker segment");
989 return gFalse;
991 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
992 img.tiles[i].tileComps[comp].quantStyle =
993 img.tiles[0].tileComps[comp].quantStyle;
994 img.tiles[i].tileComps[comp].nQuantSteps =
995 img.tiles[0].tileComps[comp].nQuantSteps;
996 img.tiles[i].tileComps[comp].quantSteps =
997 (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
998 img.tiles[0].tileComps[comp].nQuantSteps *
999 sizeof(Guint));
1000 for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
1001 img.tiles[i].tileComps[comp].quantSteps[j] =
1002 img.tiles[0].tileComps[comp].quantSteps[j];
1005 break;
1006 case 0x5e: // RGN - region of interest
1007 #if 1 //~ ROI is unimplemented
1008 fprintf(stderr, "RGN\n");
1009 for (i = 0; i < segLen - 2; ++i) {
1010 if (str->getChar() == EOF) {
1011 error(getPos(), "Error in JPX PPM marker segment");
1012 return gFalse;
1015 #else
1016 if ((img.nComps > 256 && !readUWord(&comp)) ||
1017 (img.nComps <= 256 && !readUByte(&comp)) ||
1018 comp >= img.nComps ||
1019 !readUByte(&compInfo[comp].defROI.style) ||
1020 !readUByte(&compInfo[comp].defROI.shift)) {
1021 error(getPos(), "Error in JPX RGN marker segment");
1022 return gFalse;
1024 #endif
1025 break;
1026 case 0x5f: // POC - progression order change
1027 #if 1 //~ progression order changes are unimplemented
1028 fprintf(stderr, "POC\n");
1029 for (i = 0; i < segLen - 2; ++i) {
1030 if (str->getChar() == EOF) {
1031 error(getPos(), "Error in JPX PPM marker segment");
1032 return gFalse;
1035 #else
1036 nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
1037 progs = (JPXProgOrder *)gmalloc(nProgs * sizeof(JPXProgOrder));
1038 for (i = 0; i < nProgs; ++i) {
1039 if (!readUByte(&progs[i].startRes) ||
1040 !(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
1041 !(img.nComps <= 256 && readUByte(&progs[i].startComp)) ||
1042 !readUWord(&progs[i].endLayer) ||
1043 !readUByte(&progs[i].endRes) ||
1044 !(img.nComps > 256 && readUWord(&progs[i].endComp)) ||
1045 !(img.nComps <= 256 && readUByte(&progs[i].endComp)) ||
1046 !readUByte(&progs[i].progOrder)) {
1047 error(getPos(), "Error in JPX POC marker segment");
1048 return gFalse;
1051 #endif
1052 break;
1053 case 0x60: // PPM - packed packet headers, main header
1054 #if 1 //~ packed packet headers are unimplemented
1055 fprintf(stderr, "PPM\n");
1056 for (i = 0; i < segLen - 2; ++i) {
1057 if (str->getChar() == EOF) {
1058 error(getPos(), "Error in JPX PPM marker segment");
1059 return gFalse;
1062 #endif
1063 break;
1064 case 0x55: // TLM - tile-part lengths
1065 // skipped
1066 for (i = 0; i < segLen - 2; ++i) {
1067 if (str->getChar() == EOF) {
1068 error(getPos(), "Error in JPX TLM marker segment");
1069 return gFalse;
1072 break;
1073 case 0x57: // PLM - packet length, main header
1074 // skipped
1075 for (i = 0; i < segLen - 2; ++i) {
1076 if (str->getChar() == EOF) {
1077 error(getPos(), "Error in JPX PLM marker segment");
1078 return gFalse;
1081 break;
1082 case 0x63: // CRG - component registration
1083 // skipped
1084 for (i = 0; i < segLen - 2; ++i) {
1085 if (str->getChar() == EOF) {
1086 error(getPos(), "Error in JPX CRG marker segment");
1087 return gFalse;
1090 break;
1091 case 0x64: // COM - comment
1092 // skipped
1093 for (i = 0; i < segLen - 2; ++i) {
1094 if (str->getChar() == EOF) {
1095 error(getPos(), "Error in JPX COM marker segment");
1096 return gFalse;
1099 break;
1100 case 0x90: // SOT - start of tile
1101 haveSOT = gTrue;
1102 break;
1103 default:
1104 error(getPos(), "Unknown marker segment %02x in JPX stream", segType);
1105 for (i = 0; i < segLen - 2; ++i) {
1106 if (str->getChar() == EOF) {
1107 break;
1110 break;
1112 } while (!haveSOT);
1114 if (!haveSIZ) {
1115 error(getPos(), "Missing SIZ marker segment in JPX stream");
1116 return gFalse;
1118 if (!haveCOD) {
1119 error(getPos(), "Missing COD marker segment in JPX stream");
1120 return gFalse;
1122 if (!haveQCD) {
1123 error(getPos(), "Missing QCD marker segment in JPX stream");
1124 return gFalse;
1127 //----- read the tile-parts
1128 while (1) {
1129 if (!readTilePart()) {
1130 return gFalse;
1132 if (!readMarkerHdr(&segType, &segLen)) {
1133 error(getPos(), "Error in JPX codestream");
1134 return gFalse;
1136 if (segType != 0x90) { // SOT - start of tile
1137 break;
1141 if (segType != 0xd9) { // EOC - end of codestream
1142 error(getPos(), "Missing EOC marker in JPX codestream");
1143 return gFalse;
1146 //----- finish decoding the image
1147 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1148 tile = &img.tiles[i];
1149 for (comp = 0; comp < img.nComps; ++comp) {
1150 tileComp = &tile->tileComps[comp];
1151 inverseTransform(tileComp);
1153 if (!inverseMultiCompAndDC(tile)) {
1154 return gFalse;
1158 //~ can free memory below tileComps here, and also tileComp.buf
1160 return gTrue;
1163 GBool JPXStream::readTilePart() {
1164 JPXTile *tile;
1165 JPXTileComp *tileComp;
1166 JPXResLevel *resLevel;
1167 JPXPrecinct *precinct;
1168 JPXSubband *subband;
1169 JPXCodeBlock *cb;
1170 GBool haveSOD;
1171 Guint tileIdx, tilePartLen, tilePartIdx, nTileParts;
1172 GBool tilePartToEOC;
1173 Guint precinctSize, style;
1174 Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen;
1175 Guint i, j, k, cbX, cbY, r, pre, sb, cbi;
1176 int segType, level;
1178 // process the SOT marker segment
1179 if (!readUWord(&tileIdx) ||
1180 !readULong(&tilePartLen) ||
1181 !readUByte(&tilePartIdx) ||
1182 !readUByte(&nTileParts)) {
1183 error(getPos(), "Error in JPX SOT marker segment");
1184 return gFalse;
1187 if (tileIdx >= img.nXTiles * img.nYTiles) {
1188 error(getPos(), "Weird tile index in JPX stream");
1189 return gFalse;
1192 tilePartToEOC = tilePartLen == 0;
1193 tilePartLen -= 12; // subtract size of SOT segment
1195 haveSOD = gFalse;
1196 do {
1197 if (!readMarkerHdr(&segType, &segLen)) {
1198 error(getPos(), "Error in JPX tile-part codestream");
1199 return gFalse;
1201 tilePartLen -= 2 + segLen;
1202 switch (segType) {
1203 case 0x52: // COD - coding style default
1204 if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) ||
1205 !readUByte(&img.tiles[tileIdx].progOrder) ||
1206 !readUWord(&img.tiles[tileIdx].nLayers) ||
1207 !readUByte(&img.tiles[tileIdx].multiComp) ||
1208 !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) ||
1209 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) ||
1210 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) ||
1211 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) ||
1212 !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) {
1213 error(getPos(), "Error in JPX COD marker segment");
1214 return gFalse;
1216 img.tiles[tileIdx].tileComps[0].codeBlockW += 2;
1217 img.tiles[tileIdx].tileComps[0].codeBlockH += 2;
1218 for (comp = 0; comp < img.nComps; ++comp) {
1219 if (comp != 0) {
1220 img.tiles[tileIdx].tileComps[comp].style =
1221 img.tiles[tileIdx].tileComps[0].style;
1222 img.tiles[tileIdx].tileComps[comp].nDecompLevels =
1223 img.tiles[tileIdx].tileComps[0].nDecompLevels;
1224 img.tiles[tileIdx].tileComps[comp].codeBlockW =
1225 img.tiles[tileIdx].tileComps[0].codeBlockW;
1226 img.tiles[tileIdx].tileComps[comp].codeBlockH =
1227 img.tiles[tileIdx].tileComps[0].codeBlockH;
1228 img.tiles[tileIdx].tileComps[comp].codeBlockStyle =
1229 img.tiles[tileIdx].tileComps[0].codeBlockStyle;
1230 img.tiles[tileIdx].tileComps[comp].transform =
1231 img.tiles[tileIdx].tileComps[0].transform;
1233 img.tiles[tileIdx].tileComps[comp].resLevels =
1234 (JPXResLevel *)grealloc(
1235 img.tiles[tileIdx].tileComps[comp].resLevels,
1236 (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
1237 sizeof(JPXResLevel));
1238 for (r = 0;
1239 r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
1240 ++r) {
1241 img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
1244 for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) {
1245 if (img.tiles[tileIdx].tileComps[0].style & 0x01) {
1246 if (!readUByte(&precinctSize)) {
1247 error(getPos(), "Error in JPX COD marker segment");
1248 return gFalse;
1250 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth =
1251 precinctSize & 0x0f;
1252 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight =
1253 (precinctSize >> 4) & 0x0f;
1254 } else {
1255 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15;
1256 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15;
1259 for (comp = 1; comp < img.nComps; ++comp) {
1260 for (r = 0;
1261 r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
1262 ++r) {
1263 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
1264 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth;
1265 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
1266 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight;
1269 break;
1270 case 0x53: // COC - coding style component
1271 if ((img.nComps > 256 && !readUWord(&comp)) ||
1272 (img.nComps <= 256 && !readUByte(&comp)) ||
1273 comp >= img.nComps ||
1274 !readUByte(&style) ||
1275 !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) ||
1276 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) ||
1277 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) ||
1278 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) ||
1279 !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) {
1280 error(getPos(), "Error in JPX COC marker segment");
1281 return gFalse;
1283 img.tiles[tileIdx].tileComps[comp].style =
1284 (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1);
1285 img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
1286 img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
1287 img.tiles[tileIdx].tileComps[comp].resLevels =
1288 (JPXResLevel *)grealloc(
1289 img.tiles[tileIdx].tileComps[comp].resLevels,
1290 (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
1291 sizeof(JPXResLevel));
1292 for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
1293 img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
1295 for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
1296 if (img.tiles[tileIdx].tileComps[comp].style & 0x01) {
1297 if (!readUByte(&precinctSize)) {
1298 error(getPos(), "Error in JPX COD marker segment");
1299 return gFalse;
1301 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
1302 precinctSize & 0x0f;
1303 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
1304 (precinctSize >> 4) & 0x0f;
1305 } else {
1306 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15;
1307 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15;
1310 break;
1311 case 0x5c: // QCD - quantization default
1312 if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) {
1313 error(getPos(), "Error in JPX QCD marker segment");
1314 return gFalse;
1316 if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) {
1317 img.tiles[tileIdx].tileComps[0].nQuantSteps =
1318 segLen - 3;
1319 img.tiles[tileIdx].tileComps[0].quantSteps =
1320 (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
1321 img.tiles[tileIdx].tileComps[0].nQuantSteps *
1322 sizeof(Guint));
1323 for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
1324 if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
1325 error(getPos(), "Error in JPX QCD marker segment");
1326 return gFalse;
1329 } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
1330 img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
1331 img.tiles[tileIdx].tileComps[0].quantSteps =
1332 (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
1333 img.tiles[tileIdx].tileComps[0].nQuantSteps *
1334 sizeof(Guint));
1335 if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
1336 error(getPos(), "Error in JPX QCD marker segment");
1337 return gFalse;
1339 } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
1340 img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
1341 img.tiles[tileIdx].tileComps[0].quantSteps =
1342 (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
1343 img.tiles[tileIdx].tileComps[0].nQuantSteps *
1344 sizeof(Guint));
1345 for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
1346 if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
1347 error(getPos(), "Error in JPX QCD marker segment");
1348 return gFalse;
1351 } else {
1352 error(getPos(), "Error in JPX QCD marker segment");
1353 return gFalse;
1355 for (comp = 1; comp < img.nComps; ++comp) {
1356 img.tiles[tileIdx].tileComps[comp].quantStyle =
1357 img.tiles[tileIdx].tileComps[0].quantStyle;
1358 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1359 img.tiles[tileIdx].tileComps[0].nQuantSteps;
1360 img.tiles[tileIdx].tileComps[comp].quantSteps =
1361 (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
1362 img.tiles[tileIdx].tileComps[0].nQuantSteps *
1363 sizeof(Guint));
1364 for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
1365 img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
1366 img.tiles[tileIdx].tileComps[0].quantSteps[j];
1369 break;
1370 case 0x5d: // QCC - quantization component
1371 if ((img.nComps > 256 && !readUWord(&comp)) ||
1372 (img.nComps <= 256 && !readUByte(&comp)) ||
1373 comp >= img.nComps ||
1374 !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) {
1375 error(getPos(), "Error in JPX QCC marker segment");
1376 return gFalse;
1378 if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) {
1379 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1380 segLen - (img.nComps > 256 ? 5 : 4);
1381 img.tiles[tileIdx].tileComps[comp].quantSteps =
1382 (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
1383 img.tiles[tileIdx].tileComps[comp].nQuantSteps *
1384 sizeof(Guint));
1385 for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
1386 if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
1387 error(getPos(), "Error in JPX QCC marker segment");
1388 return gFalse;
1391 } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
1392 == 0x01) {
1393 img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
1394 img.tiles[tileIdx].tileComps[comp].quantSteps =
1395 (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
1396 img.tiles[tileIdx].tileComps[comp].nQuantSteps *
1397 sizeof(Guint));
1398 if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
1399 error(getPos(), "Error in JPX QCC marker segment");
1400 return gFalse;
1402 } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
1403 == 0x02) {
1404 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1405 (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
1406 img.tiles[tileIdx].tileComps[comp].quantSteps =
1407 (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
1408 img.tiles[tileIdx].tileComps[comp].nQuantSteps *
1409 sizeof(Guint));
1410 for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
1411 if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
1412 error(getPos(), "Error in JPX QCD marker segment");
1413 return gFalse;
1416 } else {
1417 error(getPos(), "Error in JPX QCC marker segment");
1418 return gFalse;
1420 break;
1421 case 0x5e: // RGN - region of interest
1422 #if 1 //~ ROI is unimplemented
1423 fprintf(stderr, "RGN\n");
1424 for (i = 0; i < segLen - 2; ++i) {
1425 if (str->getChar() == EOF) {
1426 error(getPos(), "Error in JPX PPM marker segment");
1427 return gFalse;
1430 #else
1431 if ((img.nComps > 256 && !readUWord(&comp)) ||
1432 (img.nComps <= 256 && !readUByte(&comp)) ||
1433 comp >= img.nComps ||
1434 !readUByte(&compInfo[comp].roi.style) ||
1435 !readUByte(&compInfo[comp].roi.shift)) {
1436 error(getPos(), "Error in JPX RGN marker segment");
1437 return gFalse;
1439 #endif
1440 break;
1441 case 0x5f: // POC - progression order change
1442 #if 1 //~ progression order changes are unimplemented
1443 fprintf(stderr, "POC\n");
1444 for (i = 0; i < segLen - 2; ++i) {
1445 if (str->getChar() == EOF) {
1446 error(getPos(), "Error in JPX PPM marker segment");
1447 return gFalse;
1450 #else
1451 nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
1452 tileProgs = (JPXProgOrder *)gmalloc(nTileProgs * sizeof(JPXProgOrder));
1453 for (i = 0; i < nTileProgs; ++i) {
1454 if (!readUByte(&tileProgs[i].startRes) ||
1455 !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
1456 !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) ||
1457 !readUWord(&tileProgs[i].endLayer) ||
1458 !readUByte(&tileProgs[i].endRes) ||
1459 !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) ||
1460 !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) ||
1461 !readUByte(&tileProgs[i].progOrder)) {
1462 error(getPos(), "Error in JPX POC marker segment");
1463 return gFalse;
1466 #endif
1467 break;
1468 case 0x61: // PPT - packed packet headers, tile-part hdr
1469 #if 1 //~ packed packet headers are unimplemented
1470 fprintf(stderr, "PPT\n");
1471 for (i = 0; i < segLen - 2; ++i) {
1472 if (str->getChar() == EOF) {
1473 error(getPos(), "Error in JPX PPT marker segment");
1474 return gFalse;
1477 #endif
1478 case 0x58: // PLT - packet length, tile-part header
1479 // skipped
1480 for (i = 0; i < segLen - 2; ++i) {
1481 if (str->getChar() == EOF) {
1482 error(getPos(), "Error in JPX PLT marker segment");
1483 return gFalse;
1486 break;
1487 case 0x64: // COM - comment
1488 // skipped
1489 for (i = 0; i < segLen - 2; ++i) {
1490 if (str->getChar() == EOF) {
1491 error(getPos(), "Error in JPX COM marker segment");
1492 return gFalse;
1495 break;
1496 case 0x93: // SOD - start of data
1497 haveSOD = gTrue;
1498 break;
1499 default:
1500 error(getPos(), "Unknown marker segment %02x in JPX tile-part stream",
1501 segType);
1502 for (i = 0; i < segLen - 2; ++i) {
1503 if (str->getChar() == EOF) {
1504 break;
1507 break;
1509 } while (!haveSOD);
1511 //----- initialize the tile, precincts, and code-blocks
1512 if (tilePartIdx == 0) {
1513 tile = &img.tiles[tileIdx];
1514 i = tileIdx / img.nXTiles;
1515 j = tileIdx % img.nXTiles;
1516 if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) {
1517 tile->x0 = img.xOffset;
1519 if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) {
1520 tile->y0 = img.yOffset;
1522 if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) {
1523 tile->x1 = img.xSize;
1525 if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) {
1526 tile->y1 = img.ySize;
1528 tile->comp = 0;
1529 tile->res = 0;
1530 tile->precinct = 0;
1531 tile->layer = 0;
1532 tile->maxNDecompLevels = 0;
1533 for (comp = 0; comp < img.nComps; ++comp) {
1534 tileComp = &tile->tileComps[comp];
1535 if (tileComp->nDecompLevels > tile->maxNDecompLevels) {
1536 tile->maxNDecompLevels = tileComp->nDecompLevels;
1538 tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep);
1539 tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->hSep);
1540 tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep);
1541 tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep);
1542 tileComp->cbW = 1 << tileComp->codeBlockW;
1543 tileComp->cbH = 1 << tileComp->codeBlockH;
1544 tileComp->data = (int *)gmalloc((tileComp->x1 - tileComp->x0) *
1545 (tileComp->y1 - tileComp->y0) *
1546 sizeof(int));
1547 if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
1548 n = tileComp->x1 - tileComp->x0;
1549 } else {
1550 n = tileComp->y1 - tileComp->y0;
1552 tileComp->buf = (int *)gmalloc((n + 8) * sizeof(int));
1553 for (r = 0; r <= tileComp->nDecompLevels; ++r) {
1554 resLevel = &tileComp->resLevels[r];
1555 k = r == 0 ? tileComp->nDecompLevels
1556 : tileComp->nDecompLevels - r + 1;
1557 resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k);
1558 resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k);
1559 resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k);
1560 resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k);
1561 if (r == 0) {
1562 resLevel->bx0[0] = resLevel->x0;
1563 resLevel->by0[0] = resLevel->y0;
1564 resLevel->bx1[0] = resLevel->x1;
1565 resLevel->by1[0] = resLevel->y1;
1566 } else {
1567 resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
1568 resLevel->by0[0] = resLevel->y0;
1569 resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
1570 resLevel->by1[0] = resLevel->y1;
1571 resLevel->bx0[1] = resLevel->x0;
1572 resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
1573 resLevel->bx1[1] = resLevel->x1;
1574 resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
1575 resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
1576 resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
1577 resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
1578 resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
1580 resLevel->precincts = (JPXPrecinct *)gmalloc(1 * sizeof(JPXPrecinct));
1581 for (pre = 0; pre < 1; ++pre) {
1582 precinct = &resLevel->precincts[pre];
1583 precinct->x0 = resLevel->x0;
1584 precinct->y0 = resLevel->y0;
1585 precinct->x1 = resLevel->x1;
1586 precinct->y1 = resLevel->y1;
1587 nSBs = r == 0 ? 1 : 3;
1588 precinct->subbands =
1589 (JPXSubband *)gmalloc(nSBs * sizeof(JPXSubband));
1590 for (sb = 0; sb < nSBs; ++sb) {
1591 subband = &precinct->subbands[sb];
1592 subband->x0 = resLevel->bx0[sb];
1593 subband->y0 = resLevel->by0[sb];
1594 subband->x1 = resLevel->bx1[sb];
1595 subband->y1 = resLevel->by1[sb];
1596 subband->nXCBs = jpxCeilDivPow2(subband->x1,
1597 tileComp->codeBlockW)
1598 - jpxFloorDivPow2(subband->x0,
1599 tileComp->codeBlockW);
1600 subband->nYCBs = jpxCeilDivPow2(subband->y1,
1601 tileComp->codeBlockH)
1602 - jpxFloorDivPow2(subband->y0,
1603 tileComp->codeBlockH);
1604 n = subband->nXCBs > subband->nYCBs ? subband->nXCBs
1605 : subband->nYCBs;
1606 for (subband->maxTTLevel = 0, --n;
1608 ++subband->maxTTLevel, n >>= 1) ;
1609 n = 0;
1610 for (level = subband->maxTTLevel; level >= 0; --level) {
1611 nx = jpxCeilDivPow2(subband->nXCBs, level);
1612 ny = jpxCeilDivPow2(subband->nYCBs, level);
1613 n += nx * ny;
1615 subband->inclusion =
1616 (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
1617 subband->zeroBitPlane =
1618 (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
1619 for (k = 0; k < n; ++k) {
1620 subband->inclusion[k].finished = gFalse;
1621 subband->inclusion[k].val = 0;
1622 subband->zeroBitPlane[k].finished = gFalse;
1623 subband->zeroBitPlane[k].val = 0;
1625 subband->cbs = (JPXCodeBlock *)gmalloc(subband->nXCBs *
1626 subband->nYCBs *
1627 sizeof(JPXCodeBlock));
1628 sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
1629 sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
1630 cb = subband->cbs;
1631 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
1632 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
1633 cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW;
1634 cb->x1 = cb->x0 + tileComp->cbW;
1635 if (subband->x0 > cb->x0) {
1636 cb->x0 = subband->x0;
1638 if (subband->x1 < cb->x1) {
1639 cb->x1 = subband->x1;
1641 cb->y0 = (sby0 + cbY) << tileComp->codeBlockH;
1642 cb->y1 = cb->y0 + tileComp->cbH;
1643 if (subband->y0 > cb->y0) {
1644 cb->y0 = subband->y0;
1646 if (subband->y1 < cb->y1) {
1647 cb->y1 = subband->y1;
1649 cb->seen = gFalse;
1650 cb->lBlock = 3;
1651 cb->nextPass = jpxPassCleanup;
1652 cb->nZeroBitPlanes = 0;
1653 cb->coeffs =
1654 (JPXCoeff *)gmalloc((1 << (tileComp->codeBlockW
1655 + tileComp->codeBlockH))
1656 * sizeof(JPXCoeff));
1657 for (cbi = 0;
1658 cbi < (Guint)(1 << (tileComp->codeBlockW
1659 + tileComp->codeBlockH));
1660 ++cbi) {
1661 cb->coeffs[cbi].flags = 0;
1662 cb->coeffs[cbi].len = 0;
1663 cb->coeffs[cbi].mag = 0;
1665 cb->stats = new JArithmeticDecoderStats(jpxNContexts);
1666 cb->stats->setEntry(jpxContextSigProp, 4, 0);
1667 cb->stats->setEntry(jpxContextRunLength, 3, 0);
1668 cb->stats->setEntry(jpxContextUniform, 46, 0);
1669 ++cb;
1678 return readTilePartData(tileIdx, tilePartLen, tilePartToEOC);
1681 GBool JPXStream::readTilePartData(Guint tileIdx,
1682 Guint tilePartLen, GBool tilePartToEOC) {
1683 JPXTile *tile;
1684 JPXTileComp *tileComp;
1685 JPXResLevel *resLevel;
1686 JPXPrecinct *precinct;
1687 JPXSubband *subband;
1688 JPXCodeBlock *cb;
1689 Guint ttVal;
1690 Guint bits, cbX, cbY, nx, ny, i, j, n, sb;
1691 int level;
1693 tile = &img.tiles[tileIdx];
1695 // read all packets from this tile-part
1696 while (1) {
1697 if (tilePartToEOC) {
1698 //~ peek for an EOC marker
1699 } else if (tilePartLen == 0) {
1700 break;
1703 tileComp = &tile->tileComps[tile->comp];
1704 resLevel = &tileComp->resLevels[tile->res];
1705 precinct = &resLevel->precincts[tile->precinct];
1707 //----- packet header
1709 // zero-length flag
1710 if (!readBits(1, &bits)) {
1711 goto err;
1713 if (!bits) {
1714 // packet is empty -- clear all code-block inclusion flags
1715 for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
1716 subband = &precinct->subbands[sb];
1717 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
1718 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
1719 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
1720 cb->included = gFalse;
1724 } else {
1726 for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
1727 subband = &precinct->subbands[sb];
1728 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
1729 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
1730 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
1732 // skip code-blocks with no coefficients
1733 if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) {
1734 cb->included = gFalse;
1735 continue;
1738 // code-block inclusion
1739 if (cb->seen) {
1740 if (!readBits(1, &cb->included)) {
1741 goto err;
1743 } else {
1744 ttVal = 0;
1745 i = 0;
1746 for (level = subband->maxTTLevel; level >= 0; --level) {
1747 nx = jpxCeilDivPow2(subband->nXCBs, level);
1748 ny = jpxCeilDivPow2(subband->nYCBs, level);
1749 j = i + (cbY >> level) * nx + (cbX >> level);
1750 if (!subband->inclusion[j].finished &&
1751 !subband->inclusion[j].val) {
1752 subband->inclusion[j].val = ttVal;
1753 } else {
1754 ttVal = subband->inclusion[j].val;
1756 while (!subband->inclusion[j].finished &&
1757 ttVal <= tile->layer) {
1758 if (!readBits(1, &bits)) {
1759 goto err;
1761 if (bits == 1) {
1762 subband->inclusion[j].finished = gTrue;
1763 } else {
1764 ++ttVal;
1767 subband->inclusion[j].val = ttVal;
1768 if (ttVal > tile->layer) {
1769 break;
1771 i += nx * ny;
1773 cb->included = level < 0;
1776 if (cb->included) {
1778 // zero bit-plane count
1779 if (!cb->seen) {
1780 ttVal = 0;
1781 i = 0;
1782 for (level = subband->maxTTLevel; level >= 0; --level) {
1783 nx = jpxCeilDivPow2(subband->nXCBs, level);
1784 ny = jpxCeilDivPow2(subband->nYCBs, level);
1785 j = i + (cbY >> level) * nx + (cbX >> level);
1786 if (!subband->zeroBitPlane[j].finished &&
1787 !subband->zeroBitPlane[j].val) {
1788 subband->zeroBitPlane[j].val = ttVal;
1789 } else {
1790 ttVal = subband->zeroBitPlane[j].val;
1792 while (!subband->zeroBitPlane[j].finished) {
1793 if (!readBits(1, &bits)) {
1794 goto err;
1796 if (bits == 1) {
1797 subband->zeroBitPlane[j].finished = gTrue;
1798 } else {
1799 ++ttVal;
1802 subband->zeroBitPlane[j].val = ttVal;
1803 i += nx * ny;
1805 cb->nZeroBitPlanes = ttVal;
1808 // number of coding passes
1809 if (!readBits(1, &bits)) {
1810 goto err;
1812 if (bits == 0) {
1813 cb->nCodingPasses = 1;
1814 } else {
1815 if (!readBits(1, &bits)) {
1816 goto err;
1818 if (bits == 0) {
1819 cb->nCodingPasses = 2;
1820 } else {
1821 if (!readBits(2, &bits)) {
1822 goto err;
1824 if (bits < 3) {
1825 cb->nCodingPasses = 3 + bits;
1826 } else {
1827 if (!readBits(5, &bits)) {
1828 goto err;
1830 if (bits < 31) {
1831 cb->nCodingPasses = 6 + bits;
1832 } else {
1833 if (!readBits(7, &bits)) {
1834 goto err;
1836 cb->nCodingPasses = 37 + bits;
1842 // update Lblock
1843 while (1) {
1844 if (!readBits(1, &bits)) {
1845 goto err;
1847 if (!bits) {
1848 break;
1850 ++cb->lBlock;
1853 // length of compressed data
1854 //~ deal with multiple codeword segments
1855 for (n = cb->lBlock, i = cb->nCodingPasses >> 1;
1857 ++n, i >>= 1) ;
1858 if (!readBits(n, &cb->dataLen)) {
1859 goto err;
1866 tilePartLen -= byteCount;
1867 clearBitBuf();
1869 //----- packet data
1871 for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
1872 subband = &precinct->subbands[sb];
1873 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
1874 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
1875 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
1876 if (cb->included) {
1877 if (!readCodeBlockData(tileComp, resLevel, precinct, subband,
1878 tile->res, sb, cb)) {
1879 return gFalse;
1881 tilePartLen -= cb->dataLen;
1882 cb->seen = gTrue;
1888 //----- next packet
1890 switch (tile->progOrder) {
1891 case 0: // layer, resolution level, component, precinct
1892 if (++tile->comp == img.nComps) {
1893 tile->comp = 0;
1894 if (++tile->res == tile->maxNDecompLevels + 1) {
1895 tile->res = 0;
1896 if (++tile->layer == tile->nLayers) {
1897 tile->layer = 0;
1901 break;
1902 case 1: // resolution level, layer, component, precinct
1903 if (++tile->comp == img.nComps) {
1904 tile->comp = 0;
1905 if (++tile->layer == tile->nLayers) {
1906 tile->layer = 0;
1907 if (++tile->res == tile->maxNDecompLevels + 1) {
1908 tile->res = 0;
1912 break;
1913 case 2: // resolution level, precinct, component, layer
1914 //~ this isn't correct -- see B.12.1.3
1915 if (++tile->layer == tile->nLayers) {
1916 tile->layer = 0;
1917 if (++tile->comp == img.nComps) {
1918 tile->comp = 0;
1919 if (++tile->res == tile->maxNDecompLevels + 1) {
1920 tile->res = 0;
1924 break;
1925 case 3: // precinct, component, resolution level, layer
1926 //~ this isn't correct -- see B.12.1.4
1927 if (++tile->layer == tile->nLayers) {
1928 tile->layer = 0;
1929 if (++tile->res == tile->maxNDecompLevels + 1) {
1930 tile->res = 0;
1931 if (++tile->comp == img.nComps) {
1932 tile->comp = 0;
1936 break;
1937 case 4: // component, precinct, resolution level, layer
1938 //~ this isn't correct -- see B.12.1.5
1939 if (++tile->layer == tile->nLayers) {
1940 tile->layer = 0;
1941 if (++tile->res == tile->maxNDecompLevels + 1) {
1942 tile->res = 0;
1943 if (++tile->comp == img.nComps) {
1944 tile->comp = 0;
1948 break;
1952 return gTrue;
1954 err:
1955 error(getPos(), "Error in JPX stream");
1956 return gFalse;
1959 GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
1960 JPXResLevel *resLevel,
1961 JPXPrecinct *precinct,
1962 JPXSubband *subband,
1963 Guint res, Guint sb,
1964 JPXCodeBlock *cb) {
1965 JPXCoeff *coeff0, *coeff1, *coeff;
1966 JArithmeticDecoder *arithDecoder;
1967 Guint horiz, vert, diag, all, cx, xorBit;
1968 int horizSign, vertSign;
1969 Guint i, x, y0, y1, y2;
1971 arithDecoder = new JArithmeticDecoder();
1972 arithDecoder->setStream(str, cb->dataLen);
1973 arithDecoder->start();
1975 for (i = 0; i < cb->nCodingPasses; ++i) {
1976 switch (cb->nextPass) {
1978 //----- significance propagation pass
1979 case jpxPassSigProp:
1980 for (y0 = cb->y0, coeff0 = cb->coeffs;
1981 y0 < cb->y1;
1982 y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
1983 for (x = cb->x0, coeff1 = coeff0;
1984 x < cb->x1;
1985 ++x, ++coeff1) {
1986 for (y1 = 0, coeff = coeff1;
1987 y1 < 4 && y0+y1 < cb->y1;
1988 ++y1, coeff += tileComp->cbW) {
1989 if (!(coeff->flags & jpxCoeffSignificant)) {
1990 horiz = vert = diag = 0;
1991 horizSign = vertSign = 2;
1992 if (x > cb->x0) {
1993 if (coeff[-1].flags & jpxCoeffSignificant) {
1994 ++horiz;
1995 horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
1997 if (y0+y1 > cb->y0) {
1998 diag += (coeff[-tileComp->cbW - 1].flags
1999 >> jpxCoeffSignificantB) & 1;
2001 if (y0+y1 < cb->y1 - 1) {
2002 diag += (coeff[tileComp->cbW - 1].flags
2003 >> jpxCoeffSignificantB) & 1;
2006 if (x < cb->x1 - 1) {
2007 if (coeff[1].flags & jpxCoeffSignificant) {
2008 ++horiz;
2009 horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
2011 if (y0+y1 > cb->y0) {
2012 diag += (coeff[-tileComp->cbW + 1].flags
2013 >> jpxCoeffSignificantB) & 1;
2015 if (y0+y1 < cb->y1 - 1) {
2016 diag += (coeff[tileComp->cbW + 1].flags
2017 >> jpxCoeffSignificantB) & 1;
2020 if (y0+y1 > cb->y0) {
2021 if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
2022 ++vert;
2023 vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
2024 ? -1 : 1;
2027 if (y0+y1 < cb->y1 - 1) {
2028 if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) {
2029 ++vert;
2030 vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign)
2031 ? -1 : 1;
2034 cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
2035 if (cx != 0) {
2036 if (arithDecoder->decodeBit(cx, cb->stats)) {
2037 coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
2038 coeff->mag = (coeff->mag << 1) | 1;
2039 cx = signContext[horizSign][vertSign][0];
2040 xorBit = signContext[horizSign][vertSign][1];
2041 if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2042 coeff->flags |= jpxCoeffSign;
2045 ++coeff->len;
2046 coeff->flags |= jpxCoeffTouched;
2052 ++cb->nextPass;
2053 break;
2055 //----- magnitude refinement pass
2056 case jpxPassMagRef:
2057 for (y0 = cb->y0, coeff0 = cb->coeffs;
2058 y0 < cb->y1;
2059 y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
2060 for (x = cb->x0, coeff1 = coeff0;
2061 x < cb->x1;
2062 ++x, ++coeff1) {
2063 for (y1 = 0, coeff = coeff1;
2064 y1 < 4 && y0+y1 < cb->y1;
2065 ++y1, coeff += tileComp->cbW) {
2066 if ((coeff->flags & jpxCoeffSignificant) &&
2067 !(coeff->flags & jpxCoeffTouched)) {
2068 if (coeff->flags & jpxCoeffFirstMagRef) {
2069 all = 0;
2070 if (x > cb->x0) {
2071 all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1;
2072 if (y0+y1 > cb->y0) {
2073 all += (coeff[-tileComp->cbW - 1].flags
2074 >> jpxCoeffSignificantB) & 1;
2076 if (y0+y1 < cb->y1 - 1) {
2077 all += (coeff[tileComp->cbW - 1].flags
2078 >> jpxCoeffSignificantB) & 1;
2081 if (x < cb->x1 - 1) {
2082 all += (coeff[1].flags >> jpxCoeffSignificantB) & 1;
2083 if (y0+y1 > cb->y0) {
2084 all += (coeff[-tileComp->cbW + 1].flags
2085 >> jpxCoeffSignificantB) & 1;
2087 if (y0+y1 < cb->y1 - 1) {
2088 all += (coeff[tileComp->cbW + 1].flags
2089 >> jpxCoeffSignificantB) & 1;
2092 if (y0+y1 > cb->y0) {
2093 all += (coeff[-tileComp->cbW].flags
2094 >> jpxCoeffSignificantB) & 1;
2096 if (y0+y1 < cb->y1 - 1) {
2097 all += (coeff[tileComp->cbW].flags
2098 >> jpxCoeffSignificantB) & 1;
2100 cx = all ? 15 : 14;
2101 } else {
2102 cx = 16;
2104 coeff->mag = (coeff->mag << 1) |
2105 arithDecoder->decodeBit(cx, cb->stats);
2106 ++coeff->len;
2107 coeff->flags |= jpxCoeffTouched;
2108 coeff->flags &= ~jpxCoeffFirstMagRef;
2113 ++cb->nextPass;
2114 break;
2116 //----- cleanup pass
2117 case jpxPassCleanup:
2118 for (y0 = cb->y0, coeff0 = cb->coeffs;
2119 y0 < cb->y1;
2120 y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
2121 for (x = cb->x0, coeff1 = coeff0;
2122 x < cb->x1;
2123 ++x, ++coeff1) {
2124 y1 = 0;
2125 if (y0 + 3 < cb->y1 &&
2126 !(coeff1->flags & jpxCoeffTouched) &&
2127 !(coeff1[tileComp->cbW].flags & jpxCoeffTouched) &&
2128 !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) &&
2129 !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) &&
2130 (x == cb->x0 || y0 == cb->y0 ||
2131 !(coeff1[-tileComp->cbW - 1].flags
2132 & jpxCoeffSignificant)) &&
2133 (y0 == cb->y0 ||
2134 !(coeff1[-tileComp->cbW].flags & jpxCoeffSignificant)) &&
2135 (x == cb->x1 - 1 || y0 == cb->y0 ||
2136 !(coeff1[-tileComp->cbW + 1].flags & jpxCoeffSignificant)) &&
2137 (x == cb->x0 ||
2138 (!(coeff1[-1].flags & jpxCoeffSignificant) &&
2139 !(coeff1[tileComp->cbW - 1].flags
2140 & jpxCoeffSignificant) &&
2141 !(coeff1[2 * tileComp->cbW - 1].flags
2142 & jpxCoeffSignificant) &&
2143 !(coeff1[3 * tileComp->cbW - 1].flags
2144 & jpxCoeffSignificant))) &&
2145 (x == cb->x1 - 1 ||
2146 (!(coeff1[1].flags & jpxCoeffSignificant) &&
2147 !(coeff1[tileComp->cbW + 1].flags
2148 & jpxCoeffSignificant) &&
2149 !(coeff1[2 * tileComp->cbW + 1].flags
2150 & jpxCoeffSignificant) &&
2151 !(coeff1[3 * tileComp->cbW + 1].flags
2152 & jpxCoeffSignificant))) &&
2153 (x == cb->x0 || y0+4 == cb->y1 ||
2154 !(coeff1[4 * tileComp->cbW - 1].flags & jpxCoeffSignificant)) &&
2155 (y0+4 == cb->y1 ||
2156 !(coeff1[4 * tileComp->cbW].flags & jpxCoeffSignificant)) &&
2157 (x == cb->x1 - 1 || y0+4 == cb->y1 ||
2158 !(coeff1[4 * tileComp->cbW + 1].flags
2159 & jpxCoeffSignificant))) {
2160 if (arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
2161 y1 = arithDecoder->decodeBit(jpxContextUniform, cb->stats);
2162 y1 = (y1 << 1) |
2163 arithDecoder->decodeBit(jpxContextUniform, cb->stats);
2164 for (y2 = 0, coeff = coeff1;
2165 y2 < y1;
2166 ++y2, coeff += tileComp->cbW) {
2167 ++coeff->len;
2169 coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
2170 coeff->mag = (coeff->mag << 1) | 1;
2171 ++coeff->len;
2172 cx = signContext[2][2][0];
2173 xorBit = signContext[2][2][1];
2174 if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2175 coeff->flags |= jpxCoeffSign;
2177 ++y1;
2178 } else {
2179 for (y1 = 0, coeff = coeff1;
2180 y1 < 4;
2181 ++y1, coeff += tileComp->cbW) {
2182 ++coeff->len;
2184 y1 = 4;
2187 for (coeff = &coeff1[y1 << tileComp->codeBlockW];
2188 y1 < 4 && y0 + y1 < cb->y1;
2189 ++y1, coeff += tileComp->cbW) {
2190 if (!(coeff->flags & jpxCoeffTouched)) {
2191 horiz = vert = diag = 0;
2192 horizSign = vertSign = 2;
2193 if (x > cb->x0) {
2194 if (coeff[-1].flags & jpxCoeffSignificant) {
2195 ++horiz;
2196 horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
2198 if (y0+y1 > cb->y0) {
2199 diag += (coeff[-tileComp->cbW - 1].flags
2200 >> jpxCoeffSignificantB) & 1;
2202 if (y0+y1 < cb->y1 - 1) {
2203 diag += (coeff[tileComp->cbW - 1].flags
2204 >> jpxCoeffSignificantB) & 1;
2207 if (x < cb->x1 - 1) {
2208 if (coeff[1].flags & jpxCoeffSignificant) {
2209 ++horiz;
2210 horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
2212 if (y0+y1 > cb->y0) {
2213 diag += (coeff[-tileComp->cbW + 1].flags
2214 >> jpxCoeffSignificantB) & 1;
2216 if (y0+y1 < cb->y1 - 1) {
2217 diag += (coeff[tileComp->cbW + 1].flags
2218 >> jpxCoeffSignificantB) & 1;
2221 if (y0+y1 > cb->y0) {
2222 if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
2223 ++vert;
2224 vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
2225 ? -1 : 1;
2228 if (y0+y1 < cb->y1 - 1) {
2229 if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) {
2230 ++vert;
2231 vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign)
2232 ? -1 : 1;
2235 cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
2236 if (arithDecoder->decodeBit(cx, cb->stats)) {
2237 coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
2238 coeff->mag = (coeff->mag << 1) | 1;
2239 cx = signContext[horizSign][vertSign][0];
2240 xorBit = signContext[horizSign][vertSign][1];
2241 if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2242 coeff->flags |= jpxCoeffSign;
2245 ++coeff->len;
2246 } else {
2247 coeff->flags &= ~jpxCoeffTouched;
2252 cb->nextPass = jpxPassSigProp;
2253 break;
2257 delete arithDecoder;
2258 return gTrue;
2261 // Inverse quantization, and wavelet transform (IDWT). This also does
2262 // the initial shift to convert to fixed point format.
2263 void JPXStream::inverseTransform(JPXTileComp *tileComp) {
2264 JPXResLevel *resLevel;
2265 JPXPrecinct *precinct;
2266 JPXSubband *subband;
2267 JPXCodeBlock *cb;
2268 JPXCoeff *coeff0, *coeff;
2269 Guint qStyle, guard, eps, shift, shift2;
2270 double mu;
2271 int val;
2272 int *dataPtr;
2273 Guint nx0, ny0, nx1, ny1;
2274 Guint r, cbX, cbY, x, y;
2276 //----- (NL)LL subband (resolution level 0)
2278 resLevel = &tileComp->resLevels[0];
2279 precinct = &resLevel->precincts[0];
2280 subband = &precinct->subbands[0];
2282 // i-quant parameters
2283 qStyle = tileComp->quantStyle & 0x1f;
2284 guard = (tileComp->quantStyle >> 5) & 7;
2285 if (qStyle == 0) {
2286 eps = (tileComp->quantSteps[0] >> 3) & 0x1f;
2287 shift = guard + eps - 1;
2288 mu = 0; // make gcc happy
2289 } else {
2290 shift = guard - 1 + tileComp->prec;
2291 mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0;
2293 if (tileComp->transform == 0) {
2294 shift += fracBits;
2297 // copy (NL)LL into the upper-left corner of the data array, doing
2298 // the fixed point adjustment and dequantization along the way
2299 cb = subband->cbs;
2300 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2301 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2302 for (y = cb->y0, coeff0 = cb->coeffs;
2303 y < cb->y1;
2304 ++y, coeff0 += tileComp->cbW) {
2305 dataPtr = &tileComp->data[(y - subband->y0)
2306 * (tileComp->x1 - tileComp->x0)
2307 + (cb->x0 - subband->x0)];
2308 for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) {
2309 val = (int)coeff->mag;
2310 if (val != 0) {
2311 shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
2312 if (shift2 > 0) {
2313 val = (val << shift2) + (1 << (shift2 - 1));
2314 } else {
2315 val >>= -shift2;
2317 if (qStyle == 0) {
2318 if (tileComp->transform == 0) {
2319 val &= -1 << fracBits;
2321 } else {
2322 val = (int)((double)val * mu);
2324 if (coeff->flags & jpxCoeffSign) {
2325 val = -val;
2328 *dataPtr++ = val;
2331 ++cb;
2335 //----- IDWT for each level
2337 for (r = 1; r <= tileComp->nDecompLevels; ++r) {
2338 resLevel = &tileComp->resLevels[r];
2340 // (n)LL is already in the upper-left corner of the
2341 // tile-component data array -- interleave with (n)HL/LH/HH
2342 // and inverse transform to get (n-1)LL, which will be stored
2343 // in the upper-left corner of the tile-component data array
2344 if (r == tileComp->nDecompLevels) {
2345 nx0 = tileComp->x0;
2346 ny0 = tileComp->y0;
2347 nx1 = tileComp->x1;
2348 ny1 = tileComp->y1;
2349 } else {
2350 nx0 = tileComp->resLevels[r+1].x0;
2351 ny0 = tileComp->resLevels[r+1].y0;
2352 nx1 = tileComp->resLevels[r+1].x1;
2353 ny1 = tileComp->resLevels[r+1].y1;
2355 inverseTransformLevel(tileComp, r, resLevel, nx0, ny0, nx1, ny1);
2359 // Do one level of the inverse transform:
2360 // - take (n)LL from the tile-component data array
2361 // - take (n)HL/LH/HH from <resLevel>
2362 // - leave the resulting (n-1)LL in the tile-component data array
2363 void JPXStream::inverseTransformLevel(JPXTileComp *tileComp,
2364 Guint r, JPXResLevel *resLevel,
2365 Guint nx0, Guint ny0,
2366 Guint nx1, Guint ny1) {
2367 JPXPrecinct *precinct;
2368 JPXSubband *subband;
2369 JPXCodeBlock *cb;
2370 JPXCoeff *coeff0, *coeff;
2371 Guint qStyle, guard, eps, shift, shift2, t;
2372 double mu;
2373 int val;
2374 int *dataPtr;
2375 Guint xo, yo;
2376 Guint x, y, sb, cbX, cbY;
2377 int xx, yy;
2379 //----- interleave
2381 // spread out LL
2382 for (yy = resLevel->y1 - 1; yy >= (int)resLevel->y0; --yy) {
2383 for (xx = resLevel->x1 - 1; xx >= (int)resLevel->x0; --xx) {
2384 tileComp->data[(2 * yy - ny0) * (tileComp->x1 - tileComp->x0)
2385 + (2 * xx - nx0)] =
2386 tileComp->data[(yy - resLevel->y0) * (tileComp->x1 - tileComp->x0)
2387 + (xx - resLevel->x0)];
2391 // i-quant parameters
2392 qStyle = tileComp->quantStyle & 0x1f;
2393 guard = (tileComp->quantStyle >> 5) & 7;
2395 // interleave HL/LH/HH
2396 precinct = &resLevel->precincts[0];
2397 for (sb = 0; sb < 3; ++sb) {
2399 // i-quant parameters
2400 if (qStyle == 0) {
2401 eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f;
2402 shift = guard + eps - 1;
2403 mu = 0; // make gcc happy
2404 } else {
2405 shift = guard + tileComp->prec;
2406 if (sb == 2) {
2407 ++shift;
2409 t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)];
2410 mu = (double)(0x800 + (t & 0x7ff)) / 2048.0;
2412 if (tileComp->transform == 0) {
2413 shift += fracBits;
2416 // copy the subband coefficients into the data array, doing the
2417 // fixed point adjustment and dequantization along the way
2418 xo = (sb & 1) ? 0 : 1;
2419 yo = (sb > 0) ? 1 : 0;
2420 subband = &precinct->subbands[sb];
2421 cb = subband->cbs;
2422 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2423 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2424 for (y = cb->y0, coeff0 = cb->coeffs;
2425 y < cb->y1;
2426 ++y, coeff0 += tileComp->cbW) {
2427 dataPtr = &tileComp->data[(2 * y + yo - ny0)
2428 * (tileComp->x1 - tileComp->x0)
2429 + (2 * cb->x0 + xo - nx0)];
2430 for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) {
2431 val = (int)coeff->mag;
2432 if (val != 0) {
2433 shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
2434 if (shift2 > 0) {
2435 val = (val << shift2) + (1 << (shift2 - 1));
2436 } else {
2437 val >>= -shift2;
2439 if (qStyle == 0) {
2440 if (tileComp->transform == 0) {
2441 val &= -1 << fracBits;
2443 } else {
2444 val = (int)((double)val * mu);
2446 if (coeff->flags & jpxCoeffSign) {
2447 val = -val;
2450 *dataPtr = val;
2451 dataPtr += 2;
2454 ++cb;
2459 //----- horizontal (row) transforms
2460 dataPtr = tileComp->data;
2461 for (y = 0; y < ny1 - ny0; ++y) {
2462 inverseTransform1D(tileComp, dataPtr, 1, nx0, nx1);
2463 dataPtr += tileComp->x1 - tileComp->x0;
2466 //----- vertical (column) transforms
2467 dataPtr = tileComp->data;
2468 for (x = 0; x < nx1 - nx0; ++x) {
2469 inverseTransform1D(tileComp, dataPtr,
2470 tileComp->x1 - tileComp->x0, ny0, ny1);
2471 ++dataPtr;
2475 void JPXStream::inverseTransform1D(JPXTileComp *tileComp,
2476 int *data, Guint stride,
2477 Guint i0, Guint i1) {
2478 int *buf;
2479 Guint offset, end, i;
2481 //----- special case for length = 1
2482 if (i1 - i0 == 1) {
2483 if (i0 & 1) {
2484 *data >>= 1;
2487 } else {
2489 // choose an offset: this makes even buf[] indexes correspond to
2490 // odd values of i, and vice versa
2491 offset = 3 + (i0 & 1);
2492 end = offset + i1 - i0;
2494 //----- gather
2495 buf = tileComp->buf;
2496 for (i = 0; i < i1 - i0; ++i) {
2497 buf[offset + i] = data[i * stride];
2500 //----- extend right
2501 buf[end] = buf[end - 2];
2502 if (i1 - i0 == 2) {
2503 buf[end+1] = buf[offset + 1];
2504 buf[end+2] = buf[offset];
2505 buf[end+3] = buf[offset + 1];
2506 } else {
2507 buf[end+1] = buf[end - 3];
2508 if (i1 - i0 == 3) {
2509 buf[end+2] = buf[offset + 1];
2510 buf[end+3] = buf[offset + 2];
2511 } else {
2512 buf[end+2] = buf[end - 4];
2513 if (i1 - i0 == 4) {
2514 buf[end+3] = buf[offset + 1];
2515 } else {
2516 buf[end+3] = buf[end - 5];
2521 //----- extend left
2522 buf[offset - 1] = buf[offset + 1];
2523 buf[offset - 2] = buf[offset + 2];
2524 buf[offset - 3] = buf[offset + 3];
2525 if (offset == 4) {
2526 buf[0] = buf[offset + 4];
2529 //----- 9-7 irreversible filter
2531 if (tileComp->transform == 0) {
2532 // step 1 (even)
2533 for (i = 1; i <= end + 2; i += 2) {
2534 buf[i] = (int)(idwtKappa * buf[i]);
2536 // step 2 (odd)
2537 for (i = 0; i <= end + 3; i += 2) {
2538 buf[i] = (int)(idwtIKappa * buf[i]);
2540 // step 3 (even)
2541 for (i = 1; i <= end + 2; i += 2) {
2542 buf[i] = (int)(buf[i] - idwtDelta * (buf[i-1] + buf[i+1]));
2544 // step 4 (odd)
2545 for (i = 2; i <= end + 1; i += 2) {
2546 buf[i] = (int)(buf[i] - idwtGamma * (buf[i-1] + buf[i+1]));
2548 // step 5 (even)
2549 for (i = 3; i <= end; i += 2) {
2550 buf[i] = (int)(buf[i] - idwtBeta * (buf[i-1] + buf[i+1]));
2552 // step 6 (odd)
2553 for (i = 4; i <= end - 1; i += 2) {
2554 buf[i] = (int)(buf[i] - idwtAlpha * (buf[i-1] + buf[i+1]));
2557 //----- 5-3 reversible filter
2559 } else {
2560 // step 1 (even)
2561 for (i = 3; i <= end; i += 2) {
2562 buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2;
2564 // step 2 (odd)
2565 for (i = 4; i < end; i += 2) {
2566 buf[i] += (buf[i-1] + buf[i+1]) >> 1;
2570 //----- scatter
2571 for (i = 0; i < i1 - i0; ++i) {
2572 data[i * stride] = buf[offset + i];
2577 // Inverse multi-component transform and DC level shift. This also
2578 // converts fixed point samples back to integers.
2579 GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
2580 JPXTileComp *tileComp;
2581 int coeff, d0, d1, d2, minVal, maxVal, zeroVal;
2582 int *dataPtr;
2583 Guint j, comp, x, y;
2585 //----- inverse multi-component transform
2587 if (tile->multiComp == 1) {
2588 if (img.nComps < 3 ||
2589 tile->tileComps[0].hSep != tile->tileComps[1].hSep ||
2590 tile->tileComps[0].vSep != tile->tileComps[1].vSep ||
2591 tile->tileComps[1].hSep != tile->tileComps[2].hSep ||
2592 tile->tileComps[1].vSep != tile->tileComps[2].vSep) {
2593 return gFalse;
2596 // inverse irreversible multiple component transform
2597 if (tile->tileComps[0].transform == 0) {
2598 j = 0;
2599 for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
2600 for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
2601 d0 = tile->tileComps[0].data[j];
2602 d1 = tile->tileComps[1].data[j];
2603 d2 = tile->tileComps[2].data[j];
2604 tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5);
2605 tile->tileComps[1].data[j] =
2606 (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5);
2607 tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5);
2608 ++j;
2612 // inverse reversible multiple component transform
2613 } else {
2614 j = 0;
2615 for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
2616 for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
2617 d0 = tile->tileComps[0].data[j];
2618 d1 = tile->tileComps[1].data[j];
2619 d2 = tile->tileComps[2].data[j];
2620 tile->tileComps[0].data[j] = d0 - ((d2 + d1) >> 2);
2621 tile->tileComps[1].data[j] = d2 - d1;
2622 tile->tileComps[2].data[j] = d0 - d1;
2623 ++j;
2629 //----- DC level shift
2630 for (comp = 0; comp < img.nComps; ++comp) {
2631 tileComp = &tile->tileComps[comp];
2633 // signed: clip
2634 if (tileComp->sgned) {
2635 minVal = -(1 << (tileComp->prec - 1));
2636 maxVal = (1 << (tileComp->prec - 1)) - 1;
2637 dataPtr = tileComp->data;
2638 for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
2639 for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
2640 coeff = *dataPtr;
2641 if (tileComp->transform == 0) {
2642 coeff >>= fracBits;
2644 if (coeff < minVal) {
2645 coeff = minVal;
2646 } else if (coeff > maxVal) {
2647 coeff = maxVal;
2649 *dataPtr++ = coeff;
2653 // unsigned: inverse DC level shift and clip
2654 } else {
2655 maxVal = (1 << tileComp->prec) - 1;
2656 zeroVal = 1 << (tileComp->prec - 1);
2657 dataPtr = tileComp->data;
2658 for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
2659 for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
2660 coeff = *dataPtr;
2661 if (tileComp->transform == 0) {
2662 coeff >>= fracBits;
2664 coeff += zeroVal;
2665 if (coeff < 0) {
2666 coeff = 0;
2667 } else if (coeff > maxVal) {
2668 coeff = maxVal;
2670 *dataPtr++ = coeff;
2676 return gTrue;
2679 GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) {
2680 Guint len, lenH;
2682 if (!readULong(&len) ||
2683 !readULong(boxType)) {
2684 return gFalse;
2686 if (len == 1) {
2687 if (!readULong(&lenH) || !readULong(&len)) {
2688 return gFalse;
2690 if (lenH) {
2691 error(getPos(), "JPX stream contains a box larger than 2^32 bytes");
2692 return gFalse;
2694 *boxLen = len;
2695 *dataLen = len - 16;
2696 } else if (len == 0) {
2697 *boxLen = 0;
2698 *dataLen = 0;
2699 } else {
2700 *boxLen = len;
2701 *dataLen = len - 8;
2703 return gTrue;
2706 int JPXStream::readMarkerHdr(int *segType, Guint *segLen) {
2707 int c;
2709 do {
2710 do {
2711 if ((c = str->getChar()) == EOF) {
2712 return gFalse;
2714 } while (c != 0xff);
2715 do {
2716 if ((c = str->getChar()) == EOF) {
2717 return gFalse;
2719 } while (c == 0xff);
2720 } while (c == 0x00);
2721 *segType = c;
2722 if ((c >= 0x30 && c <= 0x3f) ||
2723 c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) {
2724 *segLen = 0;
2725 return gTrue;
2727 return readUWord(segLen);
2730 GBool JPXStream::readUByte(Guint *x) {
2731 int c0;
2733 if ((c0 = str->getChar()) == EOF) {
2734 return gFalse;
2736 *x = (Guint)c0;
2737 return gTrue;
2740 GBool JPXStream::readByte(int *x) {
2741 int c0;
2743 if ((c0 = str->getChar()) == EOF) {
2744 return gFalse;
2746 *x = c0;
2747 if (c0 & 0x80) {
2748 *x |= -1 - 0xff;
2750 return gTrue;
2753 GBool JPXStream::readUWord(Guint *x) {
2754 int c0, c1;
2756 if ((c0 = str->getChar()) == EOF ||
2757 (c1 = str->getChar()) == EOF) {
2758 return gFalse;
2760 *x = (Guint)((c0 << 8) | c1);
2761 return gTrue;
2764 GBool JPXStream::readULong(Guint *x) {
2765 int c0, c1, c2, c3;
2767 if ((c0 = str->getChar()) == EOF ||
2768 (c1 = str->getChar()) == EOF ||
2769 (c2 = str->getChar()) == EOF ||
2770 (c3 = str->getChar()) == EOF) {
2771 return gFalse;
2773 *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
2774 return gTrue;
2777 GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) {
2778 int y, c, i;
2780 y = 0;
2781 for (i = 0; i < nBytes; ++i) {
2782 if ((c = str->getChar()) == EOF) {
2783 return gFalse;
2785 y = (y << 8) + c;
2787 if (signd) {
2788 if (y & (1 << (8 * nBytes - 1))) {
2789 y |= -1 << (8 * nBytes);
2792 *x = y;
2793 return gTrue;
2796 GBool JPXStream::readBits(int nBits, Guint *x) {
2797 int c;
2799 while (bitBufLen < nBits) {
2800 if ((c = str->getChar()) == EOF) {
2801 return gFalse;
2803 ++byteCount;
2804 if (bitBufSkip) {
2805 bitBuf = (bitBuf << 7) | (c & 0x7f);
2806 bitBufLen += 7;
2807 } else {
2808 bitBuf = (bitBuf << 8) | (c & 0xff);
2809 bitBufLen += 8;
2811 bitBufSkip = c == 0xff;
2813 *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1);
2814 bitBufLen -= nBits;
2815 return gTrue;
2818 void JPXStream::clearBitBuf() {
2819 bitBufLen = 0;
2820 bitBufSkip = gFalse;
2821 byteCount = 0;