beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / JPXStream.cc
blob1476e6a0cfea95b8d5afe507d17e5f56dd80989c
1 //========================================================================
2 //
3 // JPXStream.cc
4 //
5 // Copyright 2002-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2008, 2012 Albert Astals Cid <aacid@kde.org>
17 // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
18 // Copyright (C) 2012 Even Rouault <even.rouault@mines-paris.org>
20 // To see a description of the changes please see the Changelog file that
21 // came with your tarball or type make ChangeLog if you are building from git
23 //========================================================================
25 #include <config.h>
27 #ifdef USE_GCC_PRAGMAS
28 #pragma implementation
29 #endif
31 #include <limits.h>
32 #include "gmem.h"
33 #include "Error.h"
34 #include "JArithmeticDecoder.h"
35 #include "JPXStream.h"
37 //~ to do:
38 // - precincts
39 // - ROI
40 // - progression order changes
41 // - packed packet headers
42 // - support for palettes, channel maps, etc.
43 // - make sure all needed JP2/JPX subboxes are parsed (readBoxes)
44 // - can we assume that QCC segments must come after the QCD segment?
45 // - handle tilePartToEOC in readTilePartData
46 // - progression orders 2, 3, and 4
47 // - in coefficient decoding (readCodeBlockData):
48 // - selective arithmetic coding bypass
49 // (this also affects reading the cb->dataLen array)
50 // - coeffs longer than 31 bits (should just ignore the extra bits?)
51 // - handle boxes larger than 2^32 bytes
52 // - the fixed-point arithmetic won't handle 16-bit pixels
54 //------------------------------------------------------------------------
56 // number of contexts for the arithmetic decoder
57 #define jpxNContexts 19
59 #define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup
60 #define jpxContextSign 9 // 9 - 13: sign
61 #define jpxContextMagRef 14 // 14 -16: magnitude refinement
62 #define jpxContextRunLength 17 // cleanup: run length
63 #define jpxContextUniform 18 // cleanup: first signif coeff
65 //------------------------------------------------------------------------
67 #define jpxPassSigProp 0
68 #define jpxPassMagRef 1
69 #define jpxPassCleanup 2
71 //------------------------------------------------------------------------
73 // arithmetic decoder context for the significance propagation and
74 // cleanup passes:
75 // [horiz][vert][diag][subband]
76 // where subband = 0 for HL
77 // = 1 for LH and LL
78 // = 2 for HH
79 static const Guint sigPropContext[3][3][5][3] = {
80 {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0
81 { 1, 1, 3 }, // horiz=0, vert=0, diag=1
82 { 2, 2, 6 }, // horiz=0, vert=0, diag=2
83 { 2, 2, 8 }, // horiz=0, vert=0, diag=3
84 { 2, 2, 8 }}, // horiz=0, vert=0, diag=4
85 {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0
86 { 6, 3, 4 }, // horiz=0, vert=1, diag=1
87 { 6, 3, 7 }, // horiz=0, vert=1, diag=2
88 { 6, 3, 8 }, // horiz=0, vert=1, diag=3
89 { 6, 3, 8 }}, // horiz=0, vert=1, diag=4
90 {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0
91 { 8, 4, 5 }, // horiz=0, vert=2, diag=1
92 { 8, 4, 7 }, // horiz=0, vert=2, diag=2
93 { 8, 4, 8 }, // horiz=0, vert=2, diag=3
94 { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4
95 {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0
96 { 3, 6, 4 }, // horiz=1, vert=0, diag=1
97 { 3, 6, 7 }, // horiz=1, vert=0, diag=2
98 { 3, 6, 8 }, // horiz=1, vert=0, diag=3
99 { 3, 6, 8 }}, // horiz=1, vert=0, diag=4
100 {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0
101 { 7, 7, 5 }, // horiz=1, vert=1, diag=1
102 { 7, 7, 7 }, // horiz=1, vert=1, diag=2
103 { 7, 7, 8 }, // horiz=1, vert=1, diag=3
104 { 7, 7, 8 }}, // horiz=1, vert=1, diag=4
105 {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0
106 { 8, 7, 5 }, // horiz=1, vert=2, diag=1
107 { 8, 7, 7 }, // horiz=1, vert=2, diag=2
108 { 8, 7, 8 }, // horiz=1, vert=2, diag=3
109 { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4
110 {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0
111 { 4, 8, 5 }, // horiz=2, vert=0, diag=1
112 { 4, 8, 7 }, // horiz=2, vert=0, diag=2
113 { 4, 8, 8 }, // horiz=2, vert=0, diag=3
114 { 4, 8, 8 }}, // horiz=2, vert=0, diag=4
115 {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0
116 { 7, 8, 5 }, // horiz=2, vert=1, diag=1
117 { 7, 8, 7 }, // horiz=2, vert=1, diag=2
118 { 7, 8, 8 }, // horiz=2, vert=1, diag=3
119 { 7, 8, 8 }}, // horiz=2, vert=1, diag=4
120 {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0
121 { 8, 8, 5 }, // horiz=2, vert=2, diag=1
122 { 8, 8, 7 }, // horiz=2, vert=2, diag=2
123 { 8, 8, 8 }, // horiz=2, vert=2, diag=3
124 { 8, 8, 8 }}} // horiz=2, vert=2, diag=4
127 // arithmetic decoder context and xor bit for the sign bit in the
128 // significance propagation pass:
129 // [horiz][vert][k]
130 // where horiz/vert are offset by 2 (i.e., range is -2 .. 2)
131 // and k = 0 for the context
132 // = 1 for the xor bit
133 static const Guint signContext[5][5][2] = {
134 {{ 13, 1 }, // horiz=-2, vert=-2
135 { 13, 1 }, // horiz=-2, vert=-1
136 { 12, 1 }, // horiz=-2, vert= 0
137 { 11, 1 }, // horiz=-2, vert=+1
138 { 11, 1 }}, // horiz=-2, vert=+2
139 {{ 13, 1 }, // horiz=-1, vert=-2
140 { 13, 1 }, // horiz=-1, vert=-1
141 { 12, 1 }, // horiz=-1, vert= 0
142 { 11, 1 }, // horiz=-1, vert=+1
143 { 11, 1 }}, // horiz=-1, vert=+2
144 {{ 10, 1 }, // horiz= 0, vert=-2
145 { 10, 1 }, // horiz= 0, vert=-1
146 { 9, 0 }, // horiz= 0, vert= 0
147 { 10, 0 }, // horiz= 0, vert=+1
148 { 10, 0 }}, // horiz= 0, vert=+2
149 {{ 11, 0 }, // horiz=+1, vert=-2
150 { 11, 0 }, // horiz=+1, vert=-1
151 { 12, 0 }, // horiz=+1, vert= 0
152 { 13, 0 }, // horiz=+1, vert=+1
153 { 13, 0 }}, // horiz=+1, vert=+2
154 {{ 11, 0 }, // horiz=+2, vert=-2
155 { 11, 0 }, // horiz=+2, vert=-1
156 { 12, 0 }, // horiz=+2, vert= 0
157 { 13, 0 }, // horiz=+2, vert=+1
158 { 13, 0 }}, // horiz=+2, vert=+2
161 //------------------------------------------------------------------------
163 // constants used in the IDWT
164 #define idwtAlpha -1.586134342059924
165 #define idwtBeta -0.052980118572961
166 #define idwtGamma 0.882911075530934
167 #define idwtDelta 0.443506852043971
168 #define idwtKappa 1.230174104914001
169 #define idwtIKappa (1.0 / idwtKappa)
171 // number of bits to the right of the decimal point for the fixed
172 // point arithmetic used in the IDWT
173 #define fracBits 16
175 //------------------------------------------------------------------------
177 // floor(x / y)
178 #define jpxFloorDiv(x, y) ((x) / (y))
180 // floor(x / 2^y)
181 #define jpxFloorDivPow2(x, y) ((x) >> (y))
183 // ceil(x / y)
184 #define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y))
186 // ceil(x / 2^y)
187 #define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y))
189 //------------------------------------------------------------------------
191 #if 1 //----- disable coverage tracking
193 #define cover(idx)
195 #else //----- enable coverage tracking
197 class JPXCover {
198 public:
200 JPXCover(int sizeA);
201 ~JPXCover();
202 void incr(int idx);
204 private:
206 int size, used;
207 int *data;
210 JPXCover::JPXCover(int sizeA) {
211 size = sizeA;
212 used = -1;
213 data = (int *)gmallocn(size, sizeof(int));
214 memset(data, 0, size * sizeof(int));
217 JPXCover::~JPXCover() {
218 int i;
220 printf("JPX coverage:\n");
221 for (i = 0; i <= used; ++i) {
222 printf(" %4d: %8d\n", i, data[i]);
224 gfree(data);
227 void JPXCover::incr(int idx) {
228 if (idx < size) {
229 ++data[idx];
230 if (idx > used) {
231 used = idx;
236 JPXCover jpxCover(150);
238 #define cover(idx) jpxCover.incr(idx)
240 #endif //----- coverage tracking
242 //------------------------------------------------------------------------
244 JPXStream::JPXStream(Stream *strA):
245 FilterStream(strA)
247 bufStr = new BufStream(str, 2);
249 nComps = 0;
250 bpc = NULL;
251 width = height = 0;
252 haveCS = gFalse;
253 havePalette = gFalse;
254 haveCompMap = gFalse;
255 haveChannelDefn = gFalse;
257 img.tiles = NULL;
258 bitBuf = 0;
259 bitBufLen = 0;
260 bitBufSkip = gFalse;
261 byteCount = 0;
263 curX = curY = 0;
264 curComp = 0;
265 readBufLen = 0;
268 JPXStream::~JPXStream() {
269 close();
270 delete bufStr;
273 void JPXStream::reset() {
274 bufStr->reset();
275 if (readBoxes()) {
276 curY = img.yOffset;
277 } else {
278 // readBoxes reported an error, so we go immediately to EOF
279 curY = img.ySize;
281 curX = img.xOffset;
282 curComp = 0;
283 readBufLen = 0;
286 void JPXStream::close() {
287 JPXTile *tile;
288 JPXTileComp *tileComp;
289 JPXResLevel *resLevel;
290 JPXPrecinct *precinct;
291 JPXSubband *subband;
292 JPXCodeBlock *cb;
293 Guint comp, i, k, r, pre, sb;
295 gfree(bpc);
296 bpc = NULL;
297 if (havePalette) {
298 gfree(palette.bpc);
299 gfree(palette.c);
300 havePalette = gFalse;
302 if (haveCompMap) {
303 gfree(compMap.comp);
304 gfree(compMap.type);
305 gfree(compMap.pComp);
306 haveCompMap = gFalse;
308 if (haveChannelDefn) {
309 gfree(channelDefn.idx);
310 gfree(channelDefn.type);
311 gfree(channelDefn.assoc);
312 haveChannelDefn = gFalse;
315 if (img.tiles) {
316 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
317 tile = &img.tiles[i];
318 if (tile->tileComps) {
319 for (comp = 0; comp < img.nComps; ++comp) {
320 tileComp = &tile->tileComps[comp];
321 gfree(tileComp->quantSteps);
322 gfree(tileComp->data);
323 gfree(tileComp->buf);
324 if (tileComp->resLevels) {
325 for (r = 0; r <= tileComp->nDecompLevels; ++r) {
326 resLevel = &tileComp->resLevels[r];
327 if (resLevel->precincts) {
328 for (pre = 0; pre < 1; ++pre) {
329 precinct = &resLevel->precincts[pre];
330 if (precinct->subbands) {
331 for (sb = 0; sb < (Guint)(r == 0 ? 1 : 3); ++sb) {
332 subband = &precinct->subbands[sb];
333 gfree(subband->inclusion);
334 gfree(subband->zeroBitPlane);
335 if (subband->cbs) {
336 for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
337 cb = &subband->cbs[k];
338 gfree(cb->dataLen);
339 gfree(cb->touched);
340 if (cb->arithDecoder) {
341 delete cb->arithDecoder;
343 if (cb->stats) {
344 delete cb->stats;
347 gfree(subband->cbs);
350 gfree(precinct->subbands);
353 gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts);
356 gfree(img.tiles[i].tileComps[comp].resLevels);
359 gfree(img.tiles[i].tileComps);
362 gfree(img.tiles);
363 img.tiles = NULL;
365 bufStr->close();
368 int JPXStream::getChar() {
369 int c;
371 if (readBufLen < 8) {
372 fillReadBuf();
374 if (readBufLen == 8) {
375 c = readBuf & 0xff;
376 readBufLen = 0;
377 } else if (readBufLen > 8) {
378 c = (readBuf >> (readBufLen - 8)) & 0xff;
379 readBufLen -= 8;
380 } else if (readBufLen == 0) {
381 c = EOF;
382 } else {
383 c = (readBuf << (8 - readBufLen)) & 0xff;
384 readBufLen = 0;
386 return c;
389 int JPXStream::lookChar() {
390 int c;
392 if (readBufLen < 8) {
393 fillReadBuf();
395 if (readBufLen == 8) {
396 c = readBuf & 0xff;
397 } else if (readBufLen > 8) {
398 c = (readBuf >> (readBufLen - 8)) & 0xff;
399 } else if (readBufLen == 0) {
400 c = EOF;
401 } else {
402 c = (readBuf << (8 - readBufLen)) & 0xff;
404 return c;
407 void JPXStream::fillReadBuf() {
408 JPXTileComp *tileComp;
409 Guint tileIdx, tx, ty;
410 int pix, pixBits;
412 do {
413 if (curY >= img.ySize) {
414 return;
416 tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles
417 + (curX - img.xTileOffset) / img.xTileSize;
418 #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
419 if (img.tiles == NULL || tileIdx >= img.nXTiles * img.nYTiles || img.tiles[tileIdx].tileComps == NULL) {
420 error(errSyntaxError, getPos(), "Unexpected tileIdx in fillReadBuf in JPX stream");
421 return;
423 tileComp = &img.tiles[tileIdx].tileComps[curComp];
424 #else
425 tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp];
426 #endif
427 tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep);
428 ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep);
429 if (unlikely(ty >= (tileComp->y1 - tileComp->y0))) {
430 error(errSyntaxError, getPos(), "Unexpected ty in fillReadBuf in JPX stream");
431 return;
433 if (unlikely(tx >= (tileComp->x1 - tileComp->x0))) {
434 error(errSyntaxError, getPos(), "Unexpected tx in fillReadBuf in JPX stream");
435 return;
437 pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx];
438 pixBits = tileComp->prec;
439 #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
440 if (++curComp == img.nComps) {
441 #else
442 if (havePalette) {
443 if (pix >= 0 && pix < palette.nEntries) {
444 pix = palette.c[pix * palette.nComps + curComp];
445 } else {
446 pix = 0;
448 pixBits = palette.bpc[curComp];
450 if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) {
451 #endif
452 curComp = 0;
453 if (++curX == img.xSize) {
454 curX = img.xOffset;
455 ++curY;
456 if (pixBits < 8) {
457 pix <<= 8 - pixBits;
458 pixBits = 8;
462 if (pixBits == 8) {
463 readBuf = (readBuf << 8) | (pix & 0xff);
464 } else {
465 readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1));
467 readBufLen += pixBits;
468 } while (readBufLen < 8);
471 GooString *JPXStream::getPSFilter(int psLevel, const char *indent) {
472 return NULL;
475 GBool JPXStream::isBinary(GBool last) {
476 return str->isBinary(gTrue);
479 void JPXStream::getImageParams(int *bitsPerComponent,
480 StreamColorSpaceMode *csMode) {
481 Guint boxType, boxLen, dataLen, csEnum;
482 Guint bpc1, dummy, i;
483 int csMeth, csPrec, csPrec1, dummy2;
484 StreamColorSpaceMode csMode1;
485 GBool haveBPC, haveCSMode;
487 csPrec = 0; // make gcc happy
488 haveBPC = haveCSMode = gFalse;
489 bufStr->reset();
490 if (bufStr->lookChar() == 0xff) {
491 getImageParams2(bitsPerComponent, csMode);
492 } else {
493 while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
494 if (boxType == 0x6a703268) { // JP2 header
495 cover(0);
496 // skip the superbox
497 } else if (boxType == 0x69686472) { // image header
498 cover(1);
499 if (readULong(&dummy) &&
500 readULong(&dummy) &&
501 readUWord(&dummy) &&
502 readUByte(&bpc1) &&
503 readUByte(&dummy) &&
504 readUByte(&dummy) &&
505 readUByte(&dummy)) {
506 *bitsPerComponent = bpc1 + 1;
507 haveBPC = gTrue;
509 } else if (boxType == 0x636F6C72) { // color specification
510 cover(2);
511 if (readByte(&csMeth) &&
512 readByte(&csPrec1) &&
513 readByte(&dummy2)) {
514 if (csMeth == 1) {
515 if (readULong(&csEnum)) {
516 csMode1 = streamCSNone;
517 if (csEnum == jpxCSBiLevel ||
518 csEnum == jpxCSGrayscale) {
519 csMode1 = streamCSDeviceGray;
520 } else if (csEnum == jpxCSCMYK) {
521 csMode1 = streamCSDeviceCMYK;
522 } else if (csEnum == jpxCSsRGB ||
523 csEnum == jpxCSCISesRGB ||
524 csEnum == jpxCSROMMRGB) {
525 csMode1 = streamCSDeviceRGB;
527 if (csMode1 != streamCSNone &&
528 (!haveCSMode || csPrec1 > csPrec)) {
529 *csMode = csMode1;
530 csPrec = csPrec1;
531 haveCSMode = gTrue;
533 if( dataLen >= 7 ) {
534 for (i = 0; i < dataLen - 7; ++i) {
535 if (bufStr->getChar() == EOF)
536 break;
540 } else {
541 if( dataLen >= 3 ) {
542 for (i = 0; i < dataLen - 3; ++i) {
543 if (bufStr->getChar() == EOF)
544 break;
549 } else if (boxType == 0x6A703263) { // codestream
550 cover(3);
551 if (!(haveBPC && haveCSMode)) {
552 getImageParams2(bitsPerComponent, csMode);
554 break;
555 } else {
556 cover(4);
557 for (i = 0; i < dataLen; ++i) {
558 if (unlikely(bufStr->getChar() == EOF)) {
559 error(errSyntaxError, getPos(), "Unexpected EOF in getImageParams in JPX stream");
560 break;
566 bufStr->close();
569 // Get image parameters from the codestream.
570 void JPXStream::getImageParams2(int *bitsPerComponent,
571 StreamColorSpaceMode *csMode) {
572 int segType;
573 Guint segLen, nComps1, bpc1, dummy, i;
575 while (readMarkerHdr(&segType, &segLen)) {
576 if (segType == 0x51) { // SIZ - image and tile size
577 cover(5);
578 if (readUWord(&dummy) &&
579 readULong(&dummy) &&
580 readULong(&dummy) &&
581 readULong(&dummy) &&
582 readULong(&dummy) &&
583 readULong(&dummy) &&
584 readULong(&dummy) &&
585 readULong(&dummy) &&
586 readULong(&dummy) &&
587 readUWord(&nComps1) &&
588 readUByte(&bpc1)) {
589 *bitsPerComponent = (bpc1 & 0x7f) + 1;
590 // if there's no color space info, take a guess
591 if (nComps1 == 1) {
592 *csMode = streamCSDeviceGray;
593 } else if (nComps1 == 3) {
594 *csMode = streamCSDeviceRGB;
595 } else if (nComps1 == 4) {
596 *csMode = streamCSDeviceCMYK;
599 break;
600 } else {
601 cover(6);
602 if (segLen > 2) {
603 for (i = 0; i < segLen - 2; ++i) {
604 bufStr->getChar();
611 GBool JPXStream::readBoxes() {
612 Guint boxType, boxLen, dataLen;
613 Guint bpc1, compression, unknownColorspace, ipr;
614 Guint i, j;
616 haveImgHdr = gFalse;
618 // initialize in case there is a parse error
619 img.xSize = img.ySize = 0;
620 img.xOffset = img.yOffset = 0;
621 img.xTileSize = img.yTileSize = 0;
622 img.xTileOffset = img.yTileOffset = 0;
623 img.nComps = 0;
625 // check for a naked JPEG 2000 codestream (without the JP2/JPX
626 // wrapper) -- this appears to be a violation of the PDF spec, but
627 // Acrobat allows it
628 if (bufStr->lookChar() == 0xff) {
629 cover(7);
630 error(errSyntaxWarning, getPos(),
631 "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
632 if (!readCodestream(0)) {
633 return gFalse;
635 nComps = img.nComps;
636 bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
637 for (i = 0; i < nComps; ++i) {
638 bpc[i] = img.tiles[0].tileComps[i].prec;
640 width = img.xSize - img.xOffset;
641 height = img.ySize - img.yOffset;
642 return gTrue;
645 while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
646 switch (boxType) {
647 case 0x6a703268: // JP2 header
648 // this is a grouping box ('superbox') which has no real
649 // contents and doesn't appear to be used consistently, i.e.,
650 // some things which should be subboxes of the JP2 header box
651 // show up outside of it - so we simply ignore the JP2 header
652 // box
653 cover(8);
654 break;
655 case 0x69686472: // image header
656 cover(9);
657 if (!readULong(&height) ||
658 !readULong(&width) ||
659 !readUWord(&nComps) ||
660 !readUByte(&bpc1) ||
661 !readUByte(&compression) ||
662 !readUByte(&unknownColorspace) ||
663 !readUByte(&ipr)) {
664 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
665 return gFalse;
667 if (compression != 7) {
668 error(errSyntaxError, getPos(),
669 "Unknown compression type in JPX stream");
670 return gFalse;
672 bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
673 for (i = 0; i < nComps; ++i) {
674 bpc[i] = bpc1;
676 haveImgHdr = gTrue;
677 break;
678 case 0x62706363: // bits per component
679 cover(10);
680 if (!haveImgHdr) {
681 error(errSyntaxError, getPos(),
682 "Found bits per component box before image header box in JPX stream");
683 return gFalse;
685 if (dataLen != nComps) {
686 error(errSyntaxError, getPos(),
687 "Invalid bits per component box in JPX stream");
688 return gFalse;
690 for (i = 0; i < nComps; ++i) {
691 if (!readUByte(&bpc[i])) {
692 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
693 return gFalse;
696 break;
697 case 0x636F6C72: // color specification
698 cover(11);
699 if (!readColorSpecBox(dataLen)) {
700 return gFalse;
702 break;
703 case 0x70636c72: // palette
704 cover(12);
705 if (!readUWord(&palette.nEntries) ||
706 !readUByte(&palette.nComps)) {
707 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
708 return gFalse;
710 palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint));
711 palette.c =
712 (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int));
713 for (i = 0; i < palette.nComps; ++i) {
714 if (!readUByte(&palette.bpc[i])) {
715 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
716 return gFalse;
718 ++palette.bpc[i];
720 for (i = 0; i < palette.nEntries; ++i) {
721 for (j = 0; j < palette.nComps; ++j) {
722 if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3,
723 (palette.bpc[j] & 0x80) ? gTrue : gFalse,
724 &palette.c[i * palette.nComps + j])) {
725 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
726 return gFalse;
730 havePalette = gTrue;
731 break;
732 case 0x636d6170: // component mapping
733 cover(13);
734 compMap.nChannels = dataLen / 4;
735 compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
736 compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
737 compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
738 for (i = 0; i < compMap.nChannels; ++i) {
739 if (!readUWord(&compMap.comp[i]) ||
740 !readUByte(&compMap.type[i]) ||
741 !readUByte(&compMap.pComp[i])) {
742 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
743 return gFalse;
746 haveCompMap = gTrue;
747 break;
748 case 0x63646566: // channel definition
749 cover(14);
750 if (!readUWord(&channelDefn.nChannels)) {
751 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
752 return gFalse;
754 channelDefn.idx =
755 (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
756 channelDefn.type =
757 (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
758 channelDefn.assoc =
759 (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
760 for (i = 0; i < channelDefn.nChannels; ++i) {
761 if (!readUWord(&channelDefn.idx[i]) ||
762 !readUWord(&channelDefn.type[i]) ||
763 !readUWord(&channelDefn.assoc[i])) {
764 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
765 return gFalse;
768 haveChannelDefn = gTrue;
769 break;
770 case 0x6A703263: // contiguous codestream
771 cover(15);
772 if (!bpc) {
773 error(errSyntaxError, getPos(),
774 "JPX stream is missing the image header box");
776 if (!haveCS) {
777 error(errSyntaxError, getPos(),
778 "JPX stream has no supported color spec");
780 if (!readCodestream(dataLen)) {
781 return gFalse;
783 break;
784 default:
785 cover(16);
786 for (i = 0; i < dataLen; ++i) {
787 if (bufStr->getChar() == EOF) {
788 error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
789 return gFalse;
792 break;
795 return gTrue;
798 GBool JPXStream::readColorSpecBox(Guint dataLen) {
799 JPXColorSpec newCS;
800 Guint csApprox, csEnum;
801 Guint i;
802 GBool ok;
804 ok = gFalse;
805 if (!readUByte(&newCS.meth) ||
806 !readByte(&newCS.prec) ||
807 !readUByte(&csApprox)) {
808 goto err;
810 switch (newCS.meth) {
811 case 1: // enumerated colorspace
812 cover(17);
813 if (!readULong(&csEnum)) {
814 goto err;
816 newCS.enumerated.type = (JPXColorSpaceType)csEnum;
817 switch (newCS.enumerated.type) {
818 case jpxCSBiLevel:
819 ok = gTrue;
820 break;
821 case jpxCSYCbCr1:
822 ok = gTrue;
823 break;
824 case jpxCSYCbCr2:
825 ok = gTrue;
826 break;
827 case jpxCSYCBCr3:
828 ok = gTrue;
829 break;
830 case jpxCSPhotoYCC:
831 ok = gTrue;
832 break;
833 case jpxCSCMY:
834 ok = gTrue;
835 break;
836 case jpxCSCMYK:
837 ok = gTrue;
838 break;
839 case jpxCSYCCK:
840 ok = gTrue;
841 break;
842 case jpxCSCIELab:
843 if (dataLen == 7 + 7*4) {
844 if (!readULong(&newCS.enumerated.cieLab.rl) ||
845 !readULong(&newCS.enumerated.cieLab.ol) ||
846 !readULong(&newCS.enumerated.cieLab.ra) ||
847 !readULong(&newCS.enumerated.cieLab.oa) ||
848 !readULong(&newCS.enumerated.cieLab.rb) ||
849 !readULong(&newCS.enumerated.cieLab.ob) ||
850 !readULong(&newCS.enumerated.cieLab.il)) {
851 goto err;
853 } else if (dataLen == 7) {
854 //~ this assumes the 8-bit case
855 cover(92);
856 newCS.enumerated.cieLab.rl = 100;
857 newCS.enumerated.cieLab.ol = 0;
858 newCS.enumerated.cieLab.ra = 255;
859 newCS.enumerated.cieLab.oa = 128;
860 newCS.enumerated.cieLab.rb = 255;
861 newCS.enumerated.cieLab.ob = 96;
862 newCS.enumerated.cieLab.il = 0x00443530;
863 } else {
864 goto err;
866 ok = gTrue;
867 break;
868 case jpxCSsRGB:
869 ok = gTrue;
870 break;
871 case jpxCSGrayscale:
872 ok = gTrue;
873 break;
874 case jpxCSBiLevel2:
875 ok = gTrue;
876 break;
877 case jpxCSCIEJab:
878 // not allowed in PDF
879 goto err;
880 case jpxCSCISesRGB:
881 ok = gTrue;
882 break;
883 case jpxCSROMMRGB:
884 ok = gTrue;
885 break;
886 case jpxCSsRGBYCbCr:
887 ok = gTrue;
888 break;
889 case jpxCSYPbPr1125:
890 ok = gTrue;
891 break;
892 case jpxCSYPbPr1250:
893 ok = gTrue;
894 break;
895 default:
896 goto err;
898 break;
899 case 2: // restricted ICC profile
900 case 3: // any ICC profile (JPX)
901 case 4: // vendor color (JPX)
902 cover(18);
903 for (i = 0; i < dataLen - 3; ++i) {
904 if (bufStr->getChar() == EOF) {
905 goto err;
908 break;
911 if (ok && (!haveCS || newCS.prec > cs.prec)) {
912 cs = newCS;
913 haveCS = gTrue;
916 return gTrue;
918 err:
919 error(errSyntaxError, getPos(), "Error in JPX color spec");
920 return gFalse;
923 GBool JPXStream::readCodestream(Guint len) {
924 JPXTile *tile;
925 JPXTileComp *tileComp;
926 int segType;
927 GBool haveSIZ, haveCOD, haveQCD, haveSOT;
928 Guint precinctSize, style, nDecompLevels;
929 Guint segLen, capabilities, comp, i, j, r;
931 //----- main header
932 haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
933 do {
934 if (!readMarkerHdr(&segType, &segLen)) {
935 error(errSyntaxError, getPos(), "Error in JPX codestream");
936 return gFalse;
938 switch (segType) {
939 case 0x4f: // SOC - start of codestream
940 // marker only
941 cover(19);
942 break;
943 case 0x51: // SIZ - image and tile size
944 cover(20);
945 if (haveSIZ) {
946 error(errSyntaxError, getPos(),
947 "Duplicate SIZ marker segment in JPX stream");
948 return gFalse;
950 if (!readUWord(&capabilities) ||
951 !readULong(&img.xSize) ||
952 !readULong(&img.ySize) ||
953 !readULong(&img.xOffset) ||
954 !readULong(&img.yOffset) ||
955 !readULong(&img.xTileSize) ||
956 !readULong(&img.yTileSize) ||
957 !readULong(&img.xTileOffset) ||
958 !readULong(&img.yTileOffset) ||
959 !readUWord(&img.nComps)) {
960 error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment");
961 return gFalse;
963 if (haveImgHdr && img.nComps != nComps) {
964 error(errSyntaxError, getPos(),
965 "Different number of components in JPX SIZ marker segment");
966 return gFalse;
968 if (img.xSize == 0 || img.ySize == 0 ||
969 img.xOffset >= img.xSize || img.yOffset >= img.ySize ||
970 img.xTileSize == 0 || img.yTileSize == 0 ||
971 img.xTileOffset > img.xOffset ||
972 img.yTileOffset > img.yOffset ||
973 img.xTileSize + img.xTileOffset <= img.xOffset ||
974 img.yTileSize + img.yTileOffset <= img.yOffset) {
975 error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment");
976 return gFalse;
978 img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1)
979 / img.xTileSize;
980 img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
981 / img.yTileSize;
982 // check for overflow before allocating memory
983 if (img.nXTiles <= 0 || img.nYTiles <= 0 ||
984 img.nXTiles >= 65535 / img.nYTiles) {
985 error(errSyntaxError, getPos(),
986 "Bad tile count in JPX SIZ marker segment");
987 return gFalse;
989 img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles,
990 sizeof(JPXTile));
991 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
992 img.tiles[i].init = gFalse;
993 img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps,
994 sizeof(JPXTileComp));
995 for (comp = 0; comp < img.nComps; ++comp) {
996 img.tiles[i].tileComps[comp].quantSteps = NULL;
997 img.tiles[i].tileComps[comp].data = NULL;
998 img.tiles[i].tileComps[comp].buf = NULL;
999 img.tiles[i].tileComps[comp].resLevels = NULL;
1002 for (comp = 0; comp < img.nComps; ++comp) {
1003 if (!readUByte(&img.tiles[0].tileComps[comp].prec) ||
1004 !readUByte(&img.tiles[0].tileComps[comp].hSep) ||
1005 !readUByte(&img.tiles[0].tileComps[comp].vSep)) {
1006 error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment");
1007 return gFalse;
1009 if (img.tiles[0].tileComps[comp].hSep == 0 ||
1010 img.tiles[0].tileComps[comp].vSep == 0) {
1011 error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment");
1012 return gFalse;
1014 img.tiles[0].tileComps[comp].sgned =
1015 (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse;
1016 img.tiles[0].tileComps[comp].prec =
1017 (img.tiles[0].tileComps[comp].prec & 0x7f) + 1;
1018 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
1019 img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp];
1022 haveSIZ = gTrue;
1023 break;
1024 case 0x52: // COD - coding style default
1025 cover(21);
1026 if (!haveSIZ) {
1027 error(errSyntaxError, getPos(),
1028 "JPX COD marker segment before SIZ segment");
1029 return gFalse;
1031 if (img.tiles == NULL || img.nXTiles * img.nYTiles == 0 || img.tiles[0].tileComps == NULL) {
1032 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1033 return gFalse;
1035 if (!readUByte(&img.tiles[0].tileComps[0].style) ||
1036 !readUByte(&img.tiles[0].progOrder) ||
1037 !readUWord(&img.tiles[0].nLayers) ||
1038 !readUByte(&img.tiles[0].multiComp) ||
1039 !readUByte(&nDecompLevels) ||
1040 !readUByte(&img.tiles[0].tileComps[0].codeBlockW) ||
1041 !readUByte(&img.tiles[0].tileComps[0].codeBlockH) ||
1042 !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) ||
1043 !readUByte(&img.tiles[0].tileComps[0].transform)) {
1044 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1045 return gFalse;
1047 if (nDecompLevels > 32 ||
1048 img.tiles[0].tileComps[0].codeBlockW > 8 ||
1049 img.tiles[0].tileComps[0].codeBlockH > 8) {
1050 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1051 return gFalse;
1053 img.tiles[0].tileComps[0].nDecompLevels = nDecompLevels;
1054 img.tiles[0].tileComps[0].codeBlockW += 2;
1055 img.tiles[0].tileComps[0].codeBlockH += 2;
1056 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1057 if (i != 0) {
1058 img.tiles[i].progOrder = img.tiles[0].progOrder;
1059 img.tiles[i].nLayers = img.tiles[0].nLayers;
1060 img.tiles[i].multiComp = img.tiles[0].multiComp;
1062 for (comp = 0; comp < img.nComps; ++comp) {
1063 if (!(i == 0 && comp == 0)) {
1064 img.tiles[i].tileComps[comp].style =
1065 img.tiles[0].tileComps[0].style;
1066 img.tiles[i].tileComps[comp].nDecompLevels =
1067 img.tiles[0].tileComps[0].nDecompLevels;
1068 img.tiles[i].tileComps[comp].codeBlockW =
1069 img.tiles[0].tileComps[0].codeBlockW;
1070 img.tiles[i].tileComps[comp].codeBlockH =
1071 img.tiles[0].tileComps[0].codeBlockH;
1072 img.tiles[i].tileComps[comp].codeBlockStyle =
1073 img.tiles[0].tileComps[0].codeBlockStyle;
1074 img.tiles[i].tileComps[comp].transform =
1075 img.tiles[0].tileComps[0].transform;
1077 img.tiles[i].tileComps[comp].resLevels =
1078 (JPXResLevel *)gmallocn_checkoverflow(
1079 (img.tiles[i].tileComps[comp].nDecompLevels + 1),
1080 sizeof(JPXResLevel));
1081 if (img.tiles[i].tileComps[comp].resLevels == NULL) {
1082 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1083 return gFalse;
1085 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
1086 img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
1090 for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) {
1091 if (img.tiles[0].tileComps[0].style & 0x01) {
1092 cover(91);
1093 if (!readUByte(&precinctSize)) {
1094 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1095 return gFalse;
1097 img.tiles[0].tileComps[0].resLevels[r].precinctWidth =
1098 precinctSize & 0x0f;
1099 img.tiles[0].tileComps[0].resLevels[r].precinctHeight =
1100 (precinctSize >> 4) & 0x0f;
1101 } else {
1102 img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15;
1103 img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15;
1106 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1107 for (comp = 0; comp < img.nComps; ++comp) {
1108 if (!(i == 0 && comp == 0)) {
1109 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
1110 img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
1111 img.tiles[0].tileComps[0].resLevels[r].precinctWidth;
1112 img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
1113 img.tiles[0].tileComps[0].resLevels[r].precinctHeight;
1118 haveCOD = gTrue;
1119 break;
1120 case 0x53: // COC - coding style component
1121 cover(22);
1122 if (!haveCOD) {
1123 error(errSyntaxError, getPos(),
1124 "JPX COC marker segment before COD segment");
1125 return gFalse;
1127 if ((img.nComps > 256 && !readUWord(&comp)) ||
1128 (img.nComps <= 256 && !readUByte(&comp)) ||
1129 comp >= img.nComps ||
1130 !readUByte(&style) ||
1131 !readUByte(&nDecompLevels) ||
1132 !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) ||
1133 !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) ||
1134 !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) ||
1135 !readUByte(&img.tiles[0].tileComps[comp].transform)) {
1136 error(errSyntaxError, getPos(), "Error in JPX COC marker segment");
1137 return gFalse;
1139 if (nDecompLevels > 32 ||
1140 img.tiles[0].tileComps[comp].codeBlockW > 8 ||
1141 img.tiles[0].tileComps[comp].codeBlockH > 8) {
1142 error(errSyntaxError, getPos(), "Error in JPX COC marker segment");
1143 return gFalse;
1145 img.tiles[0].tileComps[comp].nDecompLevels = nDecompLevels;
1146 img.tiles[0].tileComps[comp].style =
1147 (img.tiles[0].tileComps[comp].style & ~1) | (style & 1);
1148 img.tiles[0].tileComps[comp].codeBlockW += 2;
1149 img.tiles[0].tileComps[comp].codeBlockH += 2;
1150 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1151 if (i != 0) {
1152 img.tiles[i].tileComps[comp].style =
1153 img.tiles[0].tileComps[comp].style;
1154 img.tiles[i].tileComps[comp].nDecompLevels =
1155 img.tiles[0].tileComps[comp].nDecompLevels;
1156 img.tiles[i].tileComps[comp].codeBlockW =
1157 img.tiles[0].tileComps[comp].codeBlockW;
1158 img.tiles[i].tileComps[comp].codeBlockH =
1159 img.tiles[0].tileComps[comp].codeBlockH;
1160 img.tiles[i].tileComps[comp].codeBlockStyle =
1161 img.tiles[0].tileComps[comp].codeBlockStyle;
1162 img.tiles[i].tileComps[comp].transform =
1163 img.tiles[0].tileComps[comp].transform;
1165 img.tiles[i].tileComps[comp].resLevels =
1166 (JPXResLevel *)greallocn(
1167 img.tiles[i].tileComps[comp].resLevels,
1168 (img.tiles[i].tileComps[comp].nDecompLevels + 1),
1169 sizeof(JPXResLevel));
1170 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
1171 img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
1174 for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) {
1175 if (img.tiles[0].tileComps[comp].style & 0x01) {
1176 if (!readUByte(&precinctSize)) {
1177 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1178 return gFalse;
1180 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth =
1181 precinctSize & 0x0f;
1182 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight =
1183 (precinctSize >> 4) & 0x0f;
1184 } else {
1185 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15;
1186 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15;
1189 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
1190 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
1191 img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
1192 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth;
1193 img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
1194 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight;
1197 break;
1198 case 0x5c: // QCD - quantization default
1199 cover(23);
1200 if (!haveSIZ) {
1201 error(errSyntaxError, getPos(),
1202 "JPX QCD marker segment before SIZ segment");
1203 return gFalse;
1205 if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) {
1206 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1207 return gFalse;
1209 if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
1210 if (segLen <= 3) {
1211 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1212 return gFalse;
1214 img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
1215 img.tiles[0].tileComps[0].quantSteps =
1216 (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
1217 img.tiles[0].tileComps[0].nQuantSteps,
1218 sizeof(Guint));
1219 for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
1220 if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
1221 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1222 return gFalse;
1225 } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
1226 img.tiles[0].tileComps[0].nQuantSteps = 1;
1227 img.tiles[0].tileComps[0].quantSteps =
1228 (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
1229 img.tiles[0].tileComps[0].nQuantSteps,
1230 sizeof(Guint));
1231 if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
1232 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1233 return gFalse;
1235 } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
1236 if (segLen < 5) {
1237 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1238 return gFalse;
1240 img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
1241 img.tiles[0].tileComps[0].quantSteps =
1242 (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
1243 img.tiles[0].tileComps[0].nQuantSteps,
1244 sizeof(Guint));
1245 for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
1246 if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
1247 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1248 return gFalse;
1251 } else {
1252 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1253 return gFalse;
1255 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1256 for (comp = 0; comp < img.nComps; ++comp) {
1257 if (!(i == 0 && comp == 0)) {
1258 img.tiles[i].tileComps[comp].quantStyle =
1259 img.tiles[0].tileComps[0].quantStyle;
1260 img.tiles[i].tileComps[comp].nQuantSteps =
1261 img.tiles[0].tileComps[0].nQuantSteps;
1262 img.tiles[i].tileComps[comp].quantSteps =
1263 (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
1264 img.tiles[0].tileComps[0].nQuantSteps,
1265 sizeof(Guint));
1266 for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
1267 img.tiles[i].tileComps[comp].quantSteps[j] =
1268 img.tiles[0].tileComps[0].quantSteps[j];
1273 haveQCD = gTrue;
1274 break;
1275 case 0x5d: // QCC - quantization component
1276 cover(24);
1277 if (!haveQCD) {
1278 error(errSyntaxError, getPos(),
1279 "JPX QCC marker segment before QCD segment");
1280 return gFalse;
1282 if ((img.nComps > 256 && !readUWord(&comp)) ||
1283 (img.nComps <= 256 && !readUByte(&comp)) ||
1284 comp >= img.nComps ||
1285 !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) {
1286 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1287 return gFalse;
1289 if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) {
1290 if (segLen <= (img.nComps > 256 ? 5U : 4U)) {
1291 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1292 return gFalse;
1294 img.tiles[0].tileComps[comp].nQuantSteps =
1295 segLen - (img.nComps > 256 ? 5 : 4);
1296 img.tiles[0].tileComps[comp].quantSteps =
1297 (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
1298 img.tiles[0].tileComps[comp].nQuantSteps,
1299 sizeof(Guint));
1300 for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
1301 if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
1302 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1303 return gFalse;
1306 } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
1307 img.tiles[0].tileComps[comp].nQuantSteps = 1;
1308 img.tiles[0].tileComps[comp].quantSteps =
1309 (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
1310 img.tiles[0].tileComps[comp].nQuantSteps,
1311 sizeof(Guint));
1312 if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
1313 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1314 return gFalse;
1316 } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) {
1317 if (segLen < (img.nComps > 256 ? 5U : 4U) + 2) {
1318 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1319 return gFalse;
1321 img.tiles[0].tileComps[comp].nQuantSteps =
1322 (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
1323 img.tiles[0].tileComps[comp].quantSteps =
1324 (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
1325 img.tiles[0].tileComps[comp].nQuantSteps,
1326 sizeof(Guint));
1327 for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
1328 if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
1329 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1330 return gFalse;
1333 } else {
1334 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1335 return gFalse;
1337 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
1338 img.tiles[i].tileComps[comp].quantStyle =
1339 img.tiles[0].tileComps[comp].quantStyle;
1340 img.tiles[i].tileComps[comp].nQuantSteps =
1341 img.tiles[0].tileComps[comp].nQuantSteps;
1342 img.tiles[i].tileComps[comp].quantSteps =
1343 (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
1344 img.tiles[0].tileComps[comp].nQuantSteps,
1345 sizeof(Guint));
1346 for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
1347 img.tiles[i].tileComps[comp].quantSteps[j] =
1348 img.tiles[0].tileComps[comp].quantSteps[j];
1351 break;
1352 case 0x5e: // RGN - region of interest
1353 cover(25);
1354 #if 1 //~ ROI is unimplemented
1355 error(errUnimplemented, -1, "got a JPX RGN segment");
1356 for (i = 0; i < segLen - 2; ++i) {
1357 if (bufStr->getChar() == EOF) {
1358 error(errSyntaxError, getPos(), "Error in JPX RGN marker segment");
1359 return gFalse;
1362 #else
1363 if ((img.nComps > 256 && !readUWord(&comp)) ||
1364 (img.nComps <= 256 && !readUByte(&comp)) ||
1365 comp >= img.nComps ||
1366 !readUByte(&compInfo[comp].defROI.style) ||
1367 !readUByte(&compInfo[comp].defROI.shift)) {
1368 error(errSyntaxError, getPos(), "Error in JPX RGN marker segment");
1369 return gFalse;
1371 #endif
1372 break;
1373 case 0x5f: // POC - progression order change
1374 cover(26);
1375 #if 1 //~ progression order changes are unimplemented
1376 error(errUnimplemented, -1, "got a JPX POC segment");
1377 for (i = 0; i < segLen - 2; ++i) {
1378 if (bufStr->getChar() == EOF) {
1379 error(errSyntaxError, getPos(), "Error in JPX POC marker segment");
1380 return gFalse;
1383 #else
1384 nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
1385 progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder));
1386 for (i = 0; i < nProgs; ++i) {
1387 if (!readUByte(&progs[i].startRes) ||
1388 !(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
1389 !(img.nComps <= 256 && readUByte(&progs[i].startComp)) ||
1390 !readUWord(&progs[i].endLayer) ||
1391 !readUByte(&progs[i].endRes) ||
1392 !(img.nComps > 256 && readUWord(&progs[i].endComp)) ||
1393 !(img.nComps <= 256 && readUByte(&progs[i].endComp)) ||
1394 !readUByte(&progs[i].progOrder)) {
1395 error(errSyntaxError, getPos(), "Error in JPX POC marker segment");
1396 return gFalse;
1399 #endif
1400 break;
1401 case 0x60: // PPM - packed packet headers, main header
1402 cover(27);
1403 #if 1 //~ packed packet headers are unimplemented
1404 error(errUnimplemented, -1, "Got a JPX PPM segment");
1405 for (i = 0; i < segLen - 2; ++i) {
1406 if (bufStr->getChar() == EOF) {
1407 error(errSyntaxError, getPos(), "Error in JPX PPM marker segment");
1408 return gFalse;
1411 #endif
1412 break;
1413 case 0x55: // TLM - tile-part lengths
1414 // skipped
1415 cover(28);
1416 for (i = 0; i < segLen - 2; ++i) {
1417 if (bufStr->getChar() == EOF) {
1418 error(errSyntaxError, getPos(), "Error in JPX TLM marker segment");
1419 return gFalse;
1422 break;
1423 case 0x57: // PLM - packet length, main header
1424 // skipped
1425 cover(29);
1426 for (i = 0; i < segLen - 2; ++i) {
1427 if (bufStr->getChar() == EOF) {
1428 error(errSyntaxError, getPos(), "Error in JPX PLM marker segment");
1429 return gFalse;
1432 break;
1433 case 0x63: // CRG - component registration
1434 // skipped
1435 cover(30);
1436 for (i = 0; i < segLen - 2; ++i) {
1437 if (bufStr->getChar() == EOF) {
1438 error(errSyntaxError, getPos(), "Error in JPX CRG marker segment");
1439 return gFalse;
1442 break;
1443 case 0x64: // COM - comment
1444 // skipped
1445 cover(31);
1446 for (i = 0; i < segLen - 2; ++i) {
1447 if (bufStr->getChar() == EOF) {
1448 error(errSyntaxError, getPos(), "Error in JPX COM marker segment");
1449 return gFalse;
1452 break;
1453 case 0x90: // SOT - start of tile
1454 cover(32);
1455 haveSOT = gTrue;
1456 break;
1457 default:
1458 cover(33);
1459 error(errSyntaxError, getPos(),
1460 "Unknown marker segment {0:02x} in JPX stream", segType);
1461 for (i = 0; i < segLen - 2; ++i) {
1462 if (bufStr->getChar() == EOF) {
1463 break;
1466 break;
1468 } while (!haveSOT);
1470 if (!haveSIZ) {
1471 error(errSyntaxError, getPos(),
1472 "Missing SIZ marker segment in JPX stream");
1473 return gFalse;
1475 if (!haveCOD) {
1476 error(errSyntaxError, getPos(),
1477 "Missing COD marker segment in JPX stream");
1478 return gFalse;
1480 if (!haveQCD) {
1481 error(errSyntaxError, getPos(),
1482 "Missing QCD marker segment in JPX stream");
1483 return gFalse;
1486 //----- read the tile-parts
1487 while (1) {
1488 if (!readTilePart()) {
1489 return gFalse;
1491 if (!readMarkerHdr(&segType, &segLen)) {
1492 error(errSyntaxError, getPos(), "Error in JPX codestream");
1493 return gFalse;
1495 if (segType != 0x90) { // SOT - start of tile
1496 break;
1500 if (segType != 0xd9) { // EOC - end of codestream
1501 error(errSyntaxError, getPos(), "Missing EOC marker in JPX codestream");
1502 return gFalse;
1505 //----- finish decoding the image
1506 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1507 tile = &img.tiles[i];
1508 if (!tile->init) {
1509 error(errSyntaxError, getPos(), "Uninitialized tile in JPX codestream");
1510 return gFalse;
1512 for (comp = 0; comp < img.nComps; ++comp) {
1513 tileComp = &tile->tileComps[comp];
1514 inverseTransform(tileComp);
1516 if (!inverseMultiCompAndDC(tile)) {
1517 return gFalse;
1521 //~ can free memory below tileComps here, and also tileComp.buf
1523 return gTrue;
1526 GBool JPXStream::readTilePart() {
1527 JPXTile *tile;
1528 JPXTileComp *tileComp;
1529 JPXResLevel *resLevel;
1530 JPXPrecinct *precinct;
1531 JPXSubband *subband;
1532 JPXCodeBlock *cb;
1533 int *sbCoeffs;
1534 GBool haveSOD;
1535 Guint tileIdx, tilePartLen, tilePartIdx, nTileParts;
1536 GBool tilePartToEOC;
1537 Guint precinctSize, style, nDecompLevels;
1538 Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen;
1539 Guint i, j, k, cbX, cbY, r, pre, sb, cbi, cbj;
1540 int segType, level;
1542 // process the SOT marker segment
1543 if (!readUWord(&tileIdx) ||
1544 !readULong(&tilePartLen) ||
1545 !readUByte(&tilePartIdx) ||
1546 !readUByte(&nTileParts)) {
1547 error(errSyntaxError, getPos(), "Error in JPX SOT marker segment");
1548 return gFalse;
1551 if (tileIdx >= img.nXTiles * img.nYTiles ||
1552 (tilePartIdx > 0 && !img.tiles[tileIdx].init)) {
1553 error(errSyntaxError, getPos(), "Weird tile index in JPX stream");
1554 return gFalse;
1557 tilePartToEOC = tilePartLen == 0;
1558 tilePartLen -= 12; // subtract size of SOT segment
1560 haveSOD = gFalse;
1561 do {
1562 if (!readMarkerHdr(&segType, &segLen)) {
1563 error(errSyntaxError, getPos(), "Error in JPX tile-part codestream");
1564 return gFalse;
1566 tilePartLen -= 2 + segLen;
1567 switch (segType) {
1568 case 0x52: // COD - coding style default
1569 cover(34);
1570 if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) ||
1571 !readUByte(&img.tiles[tileIdx].progOrder) ||
1572 !readUWord(&img.tiles[tileIdx].nLayers) ||
1573 !readUByte(&img.tiles[tileIdx].multiComp) ||
1574 !readUByte(&nDecompLevels) ||
1575 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) ||
1576 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) ||
1577 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) ||
1578 !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) {
1579 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1580 return gFalse;
1582 if (nDecompLevels > 32 ||
1583 img.tiles[tileIdx].tileComps[0].codeBlockW > 8 ||
1584 img.tiles[tileIdx].tileComps[0].codeBlockH > 8) {
1585 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1586 return gFalse;
1588 img.tiles[tileIdx].tileComps[0].nDecompLevels = nDecompLevels;
1589 img.tiles[tileIdx].tileComps[0].codeBlockW += 2;
1590 img.tiles[tileIdx].tileComps[0].codeBlockH += 2;
1591 for (comp = 0; comp < img.nComps; ++comp) {
1592 if (comp != 0) {
1593 img.tiles[tileIdx].tileComps[comp].style =
1594 img.tiles[tileIdx].tileComps[0].style;
1595 img.tiles[tileIdx].tileComps[comp].nDecompLevels =
1596 img.tiles[tileIdx].tileComps[0].nDecompLevels;
1597 img.tiles[tileIdx].tileComps[comp].codeBlockW =
1598 img.tiles[tileIdx].tileComps[0].codeBlockW;
1599 img.tiles[tileIdx].tileComps[comp].codeBlockH =
1600 img.tiles[tileIdx].tileComps[0].codeBlockH;
1601 img.tiles[tileIdx].tileComps[comp].codeBlockStyle =
1602 img.tiles[tileIdx].tileComps[0].codeBlockStyle;
1603 img.tiles[tileIdx].tileComps[comp].transform =
1604 img.tiles[tileIdx].tileComps[0].transform;
1606 img.tiles[tileIdx].tileComps[comp].resLevels =
1607 (JPXResLevel *)greallocn(
1608 img.tiles[tileIdx].tileComps[comp].resLevels,
1609 (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
1610 sizeof(JPXResLevel));
1611 for (r = 0;
1612 r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
1613 ++r) {
1614 img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
1617 for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) {
1618 if (img.tiles[tileIdx].tileComps[0].style & 0x01) {
1619 if (!readUByte(&precinctSize)) {
1620 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1621 return gFalse;
1623 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth =
1624 precinctSize & 0x0f;
1625 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight =
1626 (precinctSize >> 4) & 0x0f;
1627 } else {
1628 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15;
1629 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15;
1632 for (comp = 1; comp < img.nComps; ++comp) {
1633 for (r = 0;
1634 r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
1635 ++r) {
1636 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
1637 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth;
1638 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
1639 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight;
1642 break;
1643 case 0x53: // COC - coding style component
1644 cover(35);
1645 if ((img.nComps > 256 && !readUWord(&comp)) ||
1646 (img.nComps <= 256 && !readUByte(&comp)) ||
1647 comp >= img.nComps ||
1648 !readUByte(&style) ||
1649 !readUByte(&nDecompLevels) ||
1650 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) ||
1651 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) ||
1652 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) ||
1653 !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) {
1654 error(errSyntaxError, getPos(), "Error in JPX COC marker segment");
1655 return gFalse;
1657 if (nDecompLevels > 32 ||
1658 img.tiles[tileIdx].tileComps[comp].codeBlockW > 8 ||
1659 img.tiles[tileIdx].tileComps[comp].codeBlockH > 8) {
1660 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1661 return gFalse;
1663 img.tiles[tileIdx].tileComps[comp].nDecompLevels = nDecompLevels;
1664 img.tiles[tileIdx].tileComps[comp].style =
1665 (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1);
1666 img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
1667 img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
1668 img.tiles[tileIdx].tileComps[comp].resLevels =
1669 (JPXResLevel *)greallocn(
1670 img.tiles[tileIdx].tileComps[comp].resLevels,
1671 (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
1672 sizeof(JPXResLevel));
1673 for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
1674 img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
1676 for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
1677 if (img.tiles[tileIdx].tileComps[comp].style & 0x01) {
1678 if (!readUByte(&precinctSize)) {
1679 error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
1680 return gFalse;
1682 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
1683 precinctSize & 0x0f;
1684 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
1685 (precinctSize >> 4) & 0x0f;
1686 } else {
1687 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15;
1688 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15;
1691 break;
1692 case 0x5c: // QCD - quantization default
1693 cover(36);
1694 if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) {
1695 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1696 return gFalse;
1698 if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) {
1699 if (segLen <= 3) {
1700 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1701 return gFalse;
1703 img.tiles[tileIdx].tileComps[0].nQuantSteps = segLen - 3;
1704 img.tiles[tileIdx].tileComps[0].quantSteps =
1705 (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
1706 img.tiles[tileIdx].tileComps[0].nQuantSteps,
1707 sizeof(Guint));
1708 for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
1709 if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
1710 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1711 return gFalse;
1714 } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
1715 img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
1716 img.tiles[tileIdx].tileComps[0].quantSteps =
1717 (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
1718 img.tiles[tileIdx].tileComps[0].nQuantSteps,
1719 sizeof(Guint));
1720 if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
1721 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1722 return gFalse;
1724 } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
1725 if (segLen < 5) {
1726 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1727 return gFalse;
1729 img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
1730 img.tiles[tileIdx].tileComps[0].quantSteps =
1731 (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
1732 img.tiles[tileIdx].tileComps[0].nQuantSteps,
1733 sizeof(Guint));
1734 for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
1735 if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
1736 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1737 return gFalse;
1740 } else {
1741 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1742 return gFalse;
1744 for (comp = 1; comp < img.nComps; ++comp) {
1745 img.tiles[tileIdx].tileComps[comp].quantStyle =
1746 img.tiles[tileIdx].tileComps[0].quantStyle;
1747 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1748 img.tiles[tileIdx].tileComps[0].nQuantSteps;
1749 img.tiles[tileIdx].tileComps[comp].quantSteps =
1750 (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
1751 img.tiles[tileIdx].tileComps[0].nQuantSteps,
1752 sizeof(Guint));
1753 for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
1754 img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
1755 img.tiles[tileIdx].tileComps[0].quantSteps[j];
1758 break;
1759 case 0x5d: // QCC - quantization component
1760 cover(37);
1761 if ((img.nComps > 256 && !readUWord(&comp)) ||
1762 (img.nComps <= 256 && !readUByte(&comp)) ||
1763 comp >= img.nComps ||
1764 !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) {
1765 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1766 return gFalse;
1768 if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) {
1769 if (segLen <= (img.nComps > 256 ? 5U : 4U)) {
1770 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1771 return gFalse;
1773 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1774 segLen - (img.nComps > 256 ? 5 : 4);
1775 img.tiles[tileIdx].tileComps[comp].quantSteps =
1776 (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
1777 img.tiles[tileIdx].tileComps[comp].nQuantSteps,
1778 sizeof(Guint));
1779 for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
1780 if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
1781 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1782 return gFalse;
1785 } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
1786 == 0x01) {
1787 img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
1788 img.tiles[tileIdx].tileComps[comp].quantSteps =
1789 (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
1790 img.tiles[tileIdx].tileComps[comp].nQuantSteps,
1791 sizeof(Guint));
1792 if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
1793 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1794 return gFalse;
1796 } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
1797 == 0x02) {
1798 if (segLen < (img.nComps > 256 ? 5U : 4U) + 2) {
1799 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1800 return gFalse;
1802 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1803 (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
1804 img.tiles[tileIdx].tileComps[comp].quantSteps =
1805 (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
1806 img.tiles[tileIdx].tileComps[comp].nQuantSteps,
1807 sizeof(Guint));
1808 for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
1809 if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
1810 error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
1811 return gFalse;
1814 } else {
1815 error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
1816 return gFalse;
1818 break;
1819 case 0x5e: // RGN - region of interest
1820 cover(38);
1821 #if 1 //~ ROI is unimplemented
1822 error(errUnimplemented, -1, "Got a JPX RGN segment");
1823 for (i = 0; i < segLen - 2; ++i) {
1824 if (bufStr->getChar() == EOF) {
1825 error(errSyntaxError, getPos(), "Error in JPX RGN marker segment");
1826 return gFalse;
1829 #else
1830 if ((img.nComps > 256 && !readUWord(&comp)) ||
1831 (img.nComps <= 256 && !readUByte(&comp)) ||
1832 comp >= img.nComps ||
1833 !readUByte(&compInfo[comp].roi.style) ||
1834 !readUByte(&compInfo[comp].roi.shift)) {
1835 error(errSyntaxError, getPos(), "Error in JPX RGN marker segment");
1836 return gFalse;
1838 #endif
1839 break;
1840 case 0x5f: // POC - progression order change
1841 cover(39);
1842 #if 1 //~ progression order changes are unimplemented
1843 error(errUnimplemented, -1, "Got a JPX POC segment");
1844 for (i = 0; i < segLen - 2; ++i) {
1845 if (bufStr->getChar() == EOF) {
1846 error(errSyntaxError, getPos(), "Error in JPX POC marker segment");
1847 return gFalse;
1850 #else
1851 nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
1852 tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder));
1853 for (i = 0; i < nTileProgs; ++i) {
1854 if (!readUByte(&tileProgs[i].startRes) ||
1855 !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
1856 !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) ||
1857 !readUWord(&tileProgs[i].endLayer) ||
1858 !readUByte(&tileProgs[i].endRes) ||
1859 !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) ||
1860 !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) ||
1861 !readUByte(&tileProgs[i].progOrder)) {
1862 error(errSyntaxError, getPos(), "Error in JPX POC marker segment");
1863 return gFalse;
1866 #endif
1867 break;
1868 case 0x61: // PPT - packed packet headers, tile-part hdr
1869 cover(40);
1870 #if 1 //~ packed packet headers are unimplemented
1871 error(errUnimplemented, -1, "Got a JPX PPT segment");
1872 for (i = 0; i < segLen - 2; ++i) {
1873 if (bufStr->getChar() == EOF) {
1874 error(errSyntaxError, getPos(), "Error in JPX PPT marker segment");
1875 return gFalse;
1878 #endif
1879 case 0x58: // PLT - packet length, tile-part header
1880 // skipped
1881 cover(41);
1882 for (i = 0; i < segLen - 2; ++i) {
1883 if (bufStr->getChar() == EOF) {
1884 error(errSyntaxError, getPos(), "Error in JPX PLT marker segment");
1885 return gFalse;
1888 break;
1889 case 0x64: // COM - comment
1890 // skipped
1891 cover(42);
1892 for (i = 0; i < segLen - 2; ++i) {
1893 if (bufStr->getChar() == EOF) {
1894 error(errSyntaxError, getPos(), "Error in JPX COM marker segment");
1895 return gFalse;
1898 break;
1899 case 0x93: // SOD - start of data
1900 cover(43);
1901 haveSOD = gTrue;
1902 break;
1903 default:
1904 cover(44);
1905 error(errSyntaxError, getPos(),
1906 "Unknown marker segment {0:02x} in JPX tile-part stream",
1907 segType);
1908 for (i = 0; i < segLen - 2; ++i) {
1909 if (bufStr->getChar() == EOF) {
1910 break;
1913 break;
1915 } while (!haveSOD);
1917 //----- initialize the tile, precincts, and code-blocks
1918 if (tilePartIdx == 0) {
1919 tile = &img.tiles[tileIdx];
1920 tile->init = gTrue;
1921 i = tileIdx / img.nXTiles;
1922 j = tileIdx % img.nXTiles;
1923 if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) {
1924 tile->x0 = img.xOffset;
1926 if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) {
1927 tile->y0 = img.yOffset;
1929 if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) {
1930 tile->x1 = img.xSize;
1932 if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) {
1933 tile->y1 = img.ySize;
1935 tile->comp = 0;
1936 tile->res = 0;
1937 tile->precinct = 0;
1938 tile->layer = 0;
1939 tile->maxNDecompLevels = 0;
1940 for (comp = 0; comp < img.nComps; ++comp) {
1941 tileComp = &tile->tileComps[comp];
1942 if (tileComp->nDecompLevels > tile->maxNDecompLevels) {
1943 tile->maxNDecompLevels = tileComp->nDecompLevels;
1945 tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep);
1946 tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->vSep);
1947 tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep);
1948 tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->vSep);
1949 tileComp->w = tileComp->x1 - tileComp->x0;
1950 tileComp->cbW = 1 << tileComp->codeBlockW;
1951 tileComp->cbH = 1 << tileComp->codeBlockH;
1952 tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) *
1953 (tileComp->y1 - tileComp->y0),
1954 sizeof(int));
1955 if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
1956 n = tileComp->x1 - tileComp->x0;
1957 } else {
1958 n = tileComp->y1 - tileComp->y0;
1960 tileComp->buf = (int *)gmallocn(n + 8, sizeof(int));
1961 for (r = 0; r <= tileComp->nDecompLevels; ++r) {
1962 resLevel = &tileComp->resLevels[r];
1963 k = r == 0 ? tileComp->nDecompLevels
1964 : tileComp->nDecompLevels - r + 1;
1965 resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k);
1966 resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k);
1967 resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k);
1968 resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k);
1969 if (r == 0) {
1970 resLevel->bx0[0] = resLevel->x0;
1971 resLevel->by0[0] = resLevel->y0;
1972 resLevel->bx1[0] = resLevel->x1;
1973 resLevel->by1[0] = resLevel->y1;
1974 } else {
1975 resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
1976 resLevel->by0[0] = resLevel->y0;
1977 resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
1978 resLevel->by1[0] = resLevel->y1;
1979 resLevel->bx0[1] = resLevel->x0;
1980 resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
1981 resLevel->bx1[1] = resLevel->x1;
1982 resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
1983 resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
1984 resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
1985 resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
1986 resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
1988 resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct));
1989 for (pre = 0; pre < 1; ++pre) {
1990 precinct = &resLevel->precincts[pre];
1991 precinct->x0 = resLevel->x0;
1992 precinct->y0 = resLevel->y0;
1993 precinct->x1 = resLevel->x1;
1994 precinct->y1 = resLevel->y1;
1995 nSBs = r == 0 ? 1 : 3;
1996 precinct->subbands =
1997 (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
1998 for (sb = 0; sb < nSBs; ++sb) {
1999 subband = &precinct->subbands[sb];
2000 subband->x0 = resLevel->bx0[sb];
2001 subband->y0 = resLevel->by0[sb];
2002 subband->x1 = resLevel->bx1[sb];
2003 subband->y1 = resLevel->by1[sb];
2004 subband->nXCBs = jpxCeilDivPow2(subband->x1,
2005 tileComp->codeBlockW)
2006 - jpxFloorDivPow2(subband->x0,
2007 tileComp->codeBlockW);
2008 subband->nYCBs = jpxCeilDivPow2(subband->y1,
2009 tileComp->codeBlockH)
2010 - jpxFloorDivPow2(subband->y0,
2011 tileComp->codeBlockH);
2012 n = subband->nXCBs > subband->nYCBs ? subband->nXCBs
2013 : subband->nYCBs;
2014 for (subband->maxTTLevel = 0, --n;
2016 ++subband->maxTTLevel, n >>= 1) ;
2017 n = 0;
2018 for (level = subband->maxTTLevel; level >= 0; --level) {
2019 nx = jpxCeilDivPow2(subband->nXCBs, level);
2020 ny = jpxCeilDivPow2(subband->nYCBs, level);
2021 n += nx * ny;
2023 subband->inclusion =
2024 (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
2025 subband->zeroBitPlane =
2026 (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
2027 for (k = 0; k < n; ++k) {
2028 subband->inclusion[k].finished = gFalse;
2029 subband->inclusion[k].val = 0;
2030 subband->zeroBitPlane[k].finished = gFalse;
2031 subband->zeroBitPlane[k].val = 0;
2033 subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
2034 subband->nYCBs,
2035 sizeof(JPXCodeBlock));
2036 sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
2037 sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
2038 if (r == 0) { // (NL)LL
2039 sbCoeffs = tileComp->data;
2040 } else if (sb == 0) { // (NL-r+1)HL
2041 sbCoeffs = tileComp->data
2042 + resLevel->bx1[1] - resLevel->bx0[1];
2043 } else if (sb == 1) { // (NL-r+1)LH
2044 sbCoeffs = tileComp->data
2045 + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w;
2046 } else { // (NL-r+1)HH
2047 sbCoeffs = tileComp->data
2048 + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w
2049 + resLevel->bx1[1] - resLevel->bx0[1];
2051 cb = subband->cbs;
2052 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2053 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2054 cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW;
2055 cb->x1 = cb->x0 + tileComp->cbW;
2056 if (subband->x0 > cb->x0) {
2057 cb->x0 = subband->x0;
2059 if (subband->x1 < cb->x1) {
2060 cb->x1 = subband->x1;
2062 cb->y0 = (sby0 + cbY) << tileComp->codeBlockH;
2063 cb->y1 = cb->y0 + tileComp->cbH;
2064 if (subband->y0 > cb->y0) {
2065 cb->y0 = subband->y0;
2067 if (subband->y1 < cb->y1) {
2068 cb->y1 = subband->y1;
2070 cb->seen = gFalse;
2071 cb->lBlock = 3;
2072 cb->nextPass = jpxPassCleanup;
2073 cb->nZeroBitPlanes = 0;
2074 cb->dataLenSize = 1;
2075 cb->dataLen = (Guint *)gmalloc(sizeof(Guint));
2076 cb->coeffs = sbCoeffs
2077 + (cb->y0 - subband->y0) * tileComp->w
2078 + (cb->x0 - subband->x0);
2079 cb->touched = (char *)gmalloc(1 << (tileComp->codeBlockW
2080 + tileComp->codeBlockH));
2081 cb->len = 0;
2082 for (cbj = 0; cbj < cb->y1 - cb->y0; ++cbj) {
2083 for (cbi = 0; cbi < cb->x1 - cb->x0; ++cbi) {
2084 cb->coeffs[cbj * tileComp->w + cbi] = 0;
2087 memset(cb->touched, 0,
2088 (1 << (tileComp->codeBlockW + tileComp->codeBlockH)));
2089 cb->arithDecoder = NULL;
2090 cb->stats = NULL;
2091 ++cb;
2100 return readTilePartData(tileIdx, tilePartLen, tilePartToEOC);
2103 GBool JPXStream::readTilePartData(Guint tileIdx,
2104 Guint tilePartLen, GBool tilePartToEOC) {
2105 JPXTile *tile;
2106 JPXTileComp *tileComp;
2107 JPXResLevel *resLevel;
2108 JPXPrecinct *precinct;
2109 JPXSubband *subband;
2110 JPXCodeBlock *cb;
2111 Guint ttVal;
2112 Guint bits, cbX, cbY, nx, ny, i, j, n, sb;
2113 int level;
2115 tile = &img.tiles[tileIdx];
2117 // read all packets from this tile-part
2118 while (1) {
2119 if (tilePartToEOC) {
2120 //~ peek for an EOC marker
2121 cover(93);
2122 } else if (tilePartLen == 0) {
2123 break;
2126 tileComp = &tile->tileComps[tile->comp];
2127 resLevel = &tileComp->resLevels[tile->res];
2128 precinct = &resLevel->precincts[tile->precinct];
2130 //----- packet header
2132 // setup
2133 startBitBuf(tilePartLen);
2134 if (tileComp->style & 0x02) {
2135 skipSOP();
2138 // zero-length flag
2139 if (!readBits(1, &bits)) {
2140 goto err;
2142 if (!bits) {
2143 // packet is empty -- clear all code-block inclusion flags
2144 cover(45);
2145 for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
2146 subband = &precinct->subbands[sb];
2147 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2148 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2149 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
2150 cb->included = gFalse;
2154 } else {
2156 for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
2157 subband = &precinct->subbands[sb];
2158 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2159 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2160 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
2162 // skip code-blocks with no coefficients
2163 if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) {
2164 cover(46);
2165 cb->included = gFalse;
2166 continue;
2169 // code-block inclusion
2170 if (cb->seen) {
2171 cover(47);
2172 if (!readBits(1, &cb->included)) {
2173 goto err;
2175 } else {
2176 cover(48);
2177 ttVal = 0;
2178 i = 0;
2179 for (level = subband->maxTTLevel; level >= 0; --level) {
2180 nx = jpxCeilDivPow2(subband->nXCBs, level);
2181 ny = jpxCeilDivPow2(subband->nYCBs, level);
2182 j = i + (cbY >> level) * nx + (cbX >> level);
2183 if (!subband->inclusion[j].finished &&
2184 !subband->inclusion[j].val) {
2185 subband->inclusion[j].val = ttVal;
2186 } else {
2187 ttVal = subband->inclusion[j].val;
2189 while (!subband->inclusion[j].finished &&
2190 ttVal <= tile->layer) {
2191 if (!readBits(1, &bits)) {
2192 goto err;
2194 if (bits == 1) {
2195 subband->inclusion[j].finished = gTrue;
2196 } else {
2197 ++ttVal;
2200 subband->inclusion[j].val = ttVal;
2201 if (ttVal > tile->layer) {
2202 break;
2204 i += nx * ny;
2206 cb->included = level < 0;
2209 if (cb->included) {
2210 cover(49);
2212 // zero bit-plane count
2213 if (!cb->seen) {
2214 cover(50);
2215 ttVal = 0;
2216 i = 0;
2217 for (level = subband->maxTTLevel; level >= 0; --level) {
2218 nx = jpxCeilDivPow2(subband->nXCBs, level);
2219 ny = jpxCeilDivPow2(subband->nYCBs, level);
2220 j = i + (cbY >> level) * nx + (cbX >> level);
2221 if (!subband->zeroBitPlane[j].finished &&
2222 !subband->zeroBitPlane[j].val) {
2223 subband->zeroBitPlane[j].val = ttVal;
2224 } else {
2225 ttVal = subband->zeroBitPlane[j].val;
2227 while (!subband->zeroBitPlane[j].finished) {
2228 if (!readBits(1, &bits)) {
2229 goto err;
2231 if (bits == 1) {
2232 subband->zeroBitPlane[j].finished = gTrue;
2233 } else {
2234 ++ttVal;
2237 subband->zeroBitPlane[j].val = ttVal;
2238 i += nx * ny;
2240 cb->nZeroBitPlanes = ttVal;
2243 // number of coding passes
2244 if (!readBits(1, &bits)) {
2245 goto err;
2247 if (bits == 0) {
2248 cover(51);
2249 cb->nCodingPasses = 1;
2250 } else {
2251 if (!readBits(1, &bits)) {
2252 goto err;
2254 if (bits == 0) {
2255 cover(52);
2256 cb->nCodingPasses = 2;
2257 } else {
2258 cover(53);
2259 if (!readBits(2, &bits)) {
2260 goto err;
2262 if (bits < 3) {
2263 cover(54);
2264 cb->nCodingPasses = 3 + bits;
2265 } else {
2266 cover(55);
2267 if (!readBits(5, &bits)) {
2268 goto err;
2270 if (bits < 31) {
2271 cover(56);
2272 cb->nCodingPasses = 6 + bits;
2273 } else {
2274 cover(57);
2275 if (!readBits(7, &bits)) {
2276 goto err;
2278 cb->nCodingPasses = 37 + bits;
2284 // update Lblock
2285 while (1) {
2286 if (!readBits(1, &bits)) {
2287 goto err;
2289 if (!bits) {
2290 break;
2292 ++cb->lBlock;
2295 // one codeword segment for each of the coding passes
2296 if (tileComp->codeBlockStyle & 0x04) {
2297 if (cb->nCodingPasses > cb->dataLenSize) {
2298 cb->dataLenSize = cb->nCodingPasses;
2299 cb->dataLen = (Guint *)greallocn(cb->dataLen,
2300 cb->dataLenSize,
2301 sizeof(Guint));
2304 // read the lengths
2305 for (i = 0; i < cb->nCodingPasses; ++i) {
2306 if (!readBits(cb->lBlock, &cb->dataLen[i])) {
2307 goto err;
2311 // one codeword segment for all of the coding passes
2312 } else {
2314 // read the length
2315 for (n = cb->lBlock, i = cb->nCodingPasses >> 1;
2317 ++n, i >>= 1) ;
2318 if (!readBits(n, &cb->dataLen[0])) {
2319 goto err;
2327 if (tileComp->style & 0x04) {
2328 skipEPH();
2330 tilePartLen = finishBitBuf();
2332 //----- packet data
2334 for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
2335 subband = &precinct->subbands[sb];
2336 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2337 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2338 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
2339 if (cb->included) {
2340 if (!readCodeBlockData(tileComp, resLevel, precinct, subband,
2341 tile->res, sb, cb)) {
2342 return gFalse;
2344 if (tileComp->codeBlockStyle & 0x04) {
2345 for (i = 0; i < cb->nCodingPasses; ++i) {
2346 tilePartLen -= cb->dataLen[i];
2348 } else {
2349 tilePartLen -= cb->dataLen[0];
2351 cb->seen = gTrue;
2357 //----- next packet
2359 switch (tile->progOrder) {
2360 case 0: // layer, resolution level, component, precinct
2361 cover(58);
2362 if (++tile->comp == img.nComps) {
2363 tile->comp = 0;
2364 if (++tile->res == tile->maxNDecompLevels + 1) {
2365 tile->res = 0;
2366 if (++tile->layer == tile->nLayers) {
2367 tile->layer = 0;
2371 break;
2372 case 1: // resolution level, layer, component, precinct
2373 cover(59);
2374 if (++tile->comp == img.nComps) {
2375 tile->comp = 0;
2376 if (++tile->layer == tile->nLayers) {
2377 tile->layer = 0;
2378 if (++tile->res == tile->maxNDecompLevels + 1) {
2379 tile->res = 0;
2383 break;
2384 case 2: // resolution level, precinct, component, layer
2385 //~ this isn't correct -- see B.12.1.3
2386 cover(60);
2387 if (++tile->layer == tile->nLayers) {
2388 tile->layer = 0;
2389 if (++tile->comp == img.nComps) {
2390 tile->comp = 0;
2391 if (++tile->res == tile->maxNDecompLevels + 1) {
2392 tile->res = 0;
2395 tileComp = &tile->tileComps[tile->comp];
2396 if (tile->res >= tileComp->nDecompLevels + 1) {
2397 if (++tile->comp == img.nComps) {
2398 return gTrue;
2402 break;
2403 case 3: // precinct, component, resolution level, layer
2404 //~ this isn't correct -- see B.12.1.4
2405 cover(61);
2406 if (++tile->layer == tile->nLayers) {
2407 tile->layer = 0;
2408 if (++tile->res == tile->maxNDecompLevels + 1) {
2409 tile->res = 0;
2410 if (++tile->comp == img.nComps) {
2411 tile->comp = 0;
2415 break;
2416 case 4: // component, precinct, resolution level, layer
2417 //~ this isn't correct -- see B.12.1.5
2418 cover(62);
2419 if (++tile->layer == tile->nLayers) {
2420 tile->layer = 0;
2421 if (++tile->res == tile->maxNDecompLevels + 1) {
2422 tile->res = 0;
2423 if (++tile->comp == img.nComps) {
2424 tile->comp = 0;
2428 break;
2432 return gTrue;
2434 err:
2435 error(errSyntaxError, getPos(), "Error in JPX stream");
2436 return gFalse;
2439 GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
2440 JPXResLevel *resLevel,
2441 JPXPrecinct *precinct,
2442 JPXSubband *subband,
2443 Guint res, Guint sb,
2444 JPXCodeBlock *cb) {
2445 int *coeff0, *coeff1, *coeff;
2446 char *touched0, *touched1, *touched;
2447 Guint horiz, vert, diag, all, cx, xorBit;
2448 int horizSign, vertSign, bit;
2449 int segSym;
2450 Guint i, x, y0, y1;
2452 if (cb->arithDecoder) {
2453 cover(63);
2454 cb->arithDecoder->restart(cb->dataLen[0]);
2455 } else {
2456 cover(64);
2457 cb->arithDecoder = new JArithmeticDecoder();
2458 cb->arithDecoder->setStream(bufStr, cb->dataLen[0]);
2459 cb->arithDecoder->start();
2460 cb->stats = new JArithmeticDecoderStats(jpxNContexts);
2461 cb->stats->setEntry(jpxContextSigProp, 4, 0);
2462 cb->stats->setEntry(jpxContextRunLength, 3, 0);
2463 cb->stats->setEntry(jpxContextUniform, 46, 0);
2466 for (i = 0; i < cb->nCodingPasses; ++i) {
2467 if ((tileComp->codeBlockStyle & 0x04) && i > 0) {
2468 cb->arithDecoder->setStream(bufStr, cb->dataLen[i]);
2469 cb->arithDecoder->start();
2472 switch (cb->nextPass) {
2474 //----- significance propagation pass
2475 case jpxPassSigProp:
2476 cover(65);
2477 for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
2478 y0 < cb->y1;
2479 y0 += 4, coeff0 += 4 * tileComp->w,
2480 touched0 += 4 << tileComp->codeBlockW) {
2481 for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
2482 x < cb->x1;
2483 ++x, ++coeff1, ++touched1) {
2484 for (y1 = 0, coeff = coeff1, touched = touched1;
2485 y1 < 4 && y0+y1 < cb->y1;
2486 ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
2487 if (!*coeff) {
2488 horiz = vert = diag = 0;
2489 horizSign = vertSign = 2;
2490 if (x > cb->x0) {
2491 if (coeff[-1]) {
2492 ++horiz;
2493 horizSign += coeff[-1] < 0 ? -1 : 1;
2495 if (y0+y1 > cb->y0) {
2496 diag += coeff[-(int)tileComp->w - 1] ? 1 : 0;
2498 if (y0+y1 < cb->y1 - 1 &&
2499 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2500 diag += coeff[tileComp->w - 1] ? 1 : 0;
2503 if (x < cb->x1 - 1) {
2504 if (coeff[1]) {
2505 ++horiz;
2506 horizSign += coeff[1] < 0 ? -1 : 1;
2508 if (y0+y1 > cb->y0) {
2509 diag += coeff[-(int)tileComp->w + 1] ? 1 : 0;
2511 if (y0+y1 < cb->y1 - 1 &&
2512 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2513 diag += coeff[tileComp->w + 1] ? 1 : 0;
2516 if (y0+y1 > cb->y0) {
2517 if (coeff[-(int)tileComp->w]) {
2518 ++vert;
2519 vertSign += coeff[-(int)tileComp->w] < 0 ? -1 : 1;
2522 if (y0+y1 < cb->y1 - 1 &&
2523 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2524 if (coeff[tileComp->w]) {
2525 ++vert;
2526 vertSign += coeff[tileComp->w] < 0 ? -1 : 1;
2529 cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
2530 if (cx != 0) {
2531 if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
2532 cx = signContext[horizSign][vertSign][0];
2533 xorBit = signContext[horizSign][vertSign][1];
2534 if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2535 *coeff = -1;
2536 } else {
2537 *coeff = 1;
2540 *touched = 1;
2546 ++cb->nextPass;
2547 break;
2549 //----- magnitude refinement pass
2550 case jpxPassMagRef:
2551 cover(66);
2552 for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
2553 y0 < cb->y1;
2554 y0 += 4, coeff0 += 4 * tileComp->w,
2555 touched0 += 4 << tileComp->codeBlockW) {
2556 for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
2557 x < cb->x1;
2558 ++x, ++coeff1, ++touched1) {
2559 for (y1 = 0, coeff = coeff1, touched = touched1;
2560 y1 < 4 && y0+y1 < cb->y1;
2561 ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
2562 if (*coeff && !*touched) {
2563 if (*coeff == 1 || *coeff == -1) {
2564 all = 0;
2565 if (x > cb->x0) {
2566 all += coeff[-1] ? 1 : 0;
2567 if (y0+y1 > cb->y0) {
2568 all += coeff[-(int)tileComp->w - 1] ? 1 : 0;
2570 if (y0+y1 < cb->y1 - 1 &&
2571 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2572 all += coeff[tileComp->w - 1] ? 1 : 0;
2575 if (x < cb->x1 - 1) {
2576 all += coeff[1] ? 1 : 0;
2577 if (y0+y1 > cb->y0) {
2578 all += coeff[-(int)tileComp->w + 1] ? 1 : 0;
2580 if (y0+y1 < cb->y1 - 1 &&
2581 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2582 all += coeff[tileComp->w + 1] ? 1 : 0;
2585 if (y0+y1 > cb->y0) {
2586 all += coeff[-(int)tileComp->w] ? 1 : 0;
2588 if (y0+y1 < cb->y1 - 1 &&
2589 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2590 all += coeff[tileComp->w] ? 1 : 0;
2592 cx = all ? 15 : 14;
2593 } else {
2594 cx = 16;
2596 bit = cb->arithDecoder->decodeBit(cx, cb->stats);
2597 if (*coeff < 0) {
2598 *coeff = (*coeff << 1) - bit;
2599 } else {
2600 *coeff = (*coeff << 1) + bit;
2602 *touched = 1;
2607 ++cb->nextPass;
2608 break;
2610 //----- cleanup pass
2611 case jpxPassCleanup:
2612 cover(67);
2613 for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
2614 y0 < cb->y1;
2615 y0 += 4, coeff0 += 4 * tileComp->w,
2616 touched0 += 4 << tileComp->codeBlockW) {
2617 for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
2618 x < cb->x1;
2619 ++x, ++coeff1, ++touched1) {
2620 y1 = 0;
2621 if (y0 + 3 < cb->y1 &&
2622 !(*touched1) &&
2623 !(touched1[tileComp->cbW]) &&
2624 !(touched1[2 * tileComp->cbW]) &&
2625 !(touched1[3 * tileComp->cbW]) &&
2626 (x == cb->x0 || y0 == cb->y0 ||
2627 !coeff1[-(int)tileComp->w - 1]) &&
2628 (y0 == cb->y0 ||
2629 !coeff1[-(int)tileComp->w]) &&
2630 (x == cb->x1 - 1 || y0 == cb->y0 ||
2631 !coeff1[-(int)tileComp->w + 1]) &&
2632 (x == cb->x0 ||
2633 (!coeff1[-1] &&
2634 !coeff1[tileComp->w - 1] &&
2635 !coeff1[2 * tileComp->w - 1] &&
2636 !coeff1[3 * tileComp->w - 1])) &&
2637 (x == cb->x1 - 1 ||
2638 (!coeff1[1] &&
2639 !coeff1[tileComp->w + 1] &&
2640 !coeff1[2 * tileComp->w + 1] &&
2641 !coeff1[3 * tileComp->w + 1])) &&
2642 ((tileComp->codeBlockStyle & 0x08) ||
2643 ((x == cb->x0 || y0+4 == cb->y1 ||
2644 !coeff1[4 * tileComp->w - 1]) &&
2645 (y0+4 == cb->y1 ||
2646 !coeff1[4 * tileComp->w]) &&
2647 (x == cb->x1 - 1 || y0+4 == cb->y1 ||
2648 !coeff1[4 * tileComp->w + 1])))) {
2649 if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
2650 y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
2651 y1 = (y1 << 1) |
2652 cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
2653 coeff = &coeff1[y1 * tileComp->w];
2654 cx = signContext[2][2][0];
2655 xorBit = signContext[2][2][1];
2656 if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2657 *coeff = -1;
2658 } else {
2659 *coeff = 1;
2661 ++y1;
2662 } else {
2663 y1 = 4;
2666 for (coeff = &coeff1[y1 * tileComp->w],
2667 touched = &touched1[y1 << tileComp->codeBlockW];
2668 y1 < 4 && y0 + y1 < cb->y1;
2669 ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
2670 if (!*touched) {
2671 horiz = vert = diag = 0;
2672 horizSign = vertSign = 2;
2673 if (x > cb->x0) {
2674 if (coeff[-1]) {
2675 ++horiz;
2676 horizSign += coeff[-1] < 0 ? -1 : 1;
2678 if (y0+y1 > cb->y0) {
2679 diag += coeff[-(int)tileComp->w - 1] ? 1 : 0;
2681 if (y0+y1 < cb->y1 - 1 &&
2682 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2683 diag += coeff[tileComp->w - 1] ? 1 : 0;
2686 if (x < cb->x1 - 1) {
2687 if (coeff[1]) {
2688 ++horiz;
2689 horizSign += coeff[1] < 0 ? -1 : 1;
2691 if (y0+y1 > cb->y0) {
2692 diag += coeff[-(int)tileComp->w + 1] ? 1 : 0;
2694 if (y0+y1 < cb->y1 - 1 &&
2695 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2696 diag += coeff[tileComp->w + 1] ? 1 : 0;
2699 if (y0+y1 > cb->y0) {
2700 if (coeff[-(int)tileComp->w]) {
2701 ++vert;
2702 vertSign += coeff[-(int)tileComp->w] < 0 ? -1 : 1;
2705 if (y0+y1 < cb->y1 - 1 &&
2706 (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
2707 if (coeff[tileComp->w]) {
2708 ++vert;
2709 vertSign += coeff[tileComp->w] < 0 ? -1 : 1;
2712 cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
2713 if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
2714 cx = signContext[horizSign][vertSign][0];
2715 xorBit = signContext[horizSign][vertSign][1];
2716 if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2717 *coeff = -1;
2718 } else {
2719 *coeff = 1;
2722 } else {
2723 *touched = 0;
2728 ++cb->len;
2729 // look for a segmentation symbol
2730 if (tileComp->codeBlockStyle & 0x20) {
2731 segSym = cb->arithDecoder->decodeBit(jpxContextUniform,
2732 cb->stats) << 3;
2733 segSym |= cb->arithDecoder->decodeBit(jpxContextUniform,
2734 cb->stats) << 2;
2735 segSym |= cb->arithDecoder->decodeBit(jpxContextUniform,
2736 cb->stats) << 1;
2737 segSym |= cb->arithDecoder->decodeBit(jpxContextUniform,
2738 cb->stats);
2739 if (segSym != 0x0a) {
2740 // in theory this should be a fatal error, but it seems to
2741 // be problematic
2742 error(errSyntaxWarning, getPos(),
2743 "Missing or invalid segmentation symbol in JPX stream");
2746 cb->nextPass = jpxPassSigProp;
2747 break;
2750 if (tileComp->codeBlockStyle & 0x02) {
2751 cb->stats->reset();
2752 cb->stats->setEntry(jpxContextSigProp, 4, 0);
2753 cb->stats->setEntry(jpxContextRunLength, 3, 0);
2754 cb->stats->setEntry(jpxContextUniform, 46, 0);
2757 if (tileComp->codeBlockStyle & 0x04) {
2758 cb->arithDecoder->cleanup();
2762 cb->arithDecoder->cleanup();
2763 return gTrue;
2766 // Inverse quantization, and wavelet transform (IDWT). This also does
2767 // the initial shift to convert to fixed point format.
2768 void JPXStream::inverseTransform(JPXTileComp *tileComp) {
2769 JPXResLevel *resLevel;
2770 JPXPrecinct *precinct;
2771 JPXSubband *subband;
2772 JPXCodeBlock *cb;
2773 int *coeff0, *coeff;
2774 char *touched0, *touched;
2775 Guint qStyle, guard, eps, shift;
2776 int shift2;
2777 double mu;
2778 int val;
2779 Guint r, cbX, cbY, x, y;
2781 cover(68);
2783 //----- (NL)LL subband (resolution level 0)
2785 resLevel = &tileComp->resLevels[0];
2786 precinct = &resLevel->precincts[0];
2787 subband = &precinct->subbands[0];
2789 // i-quant parameters
2790 qStyle = tileComp->quantStyle & 0x1f;
2791 guard = (tileComp->quantStyle >> 5) & 7;
2792 if (qStyle == 0) {
2793 cover(69);
2794 eps = (tileComp->quantSteps[0] >> 3) & 0x1f;
2795 shift = guard + eps - 1;
2796 mu = 0; // make gcc happy
2797 } else {
2798 cover(70);
2799 shift = guard - 1 + tileComp->prec;
2800 mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0;
2802 if (tileComp->transform == 0) {
2803 cover(71);
2804 shift += fracBits;
2807 // do fixed point adjustment and dequantization on (NL)LL
2808 cb = subband->cbs;
2809 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2810 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2811 for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
2812 y < cb->y1;
2813 ++y, coeff0 += tileComp->w, touched0 += tileComp->cbW) {
2814 for (x = cb->x0, coeff = coeff0, touched = touched0;
2815 x < cb->x1;
2816 ++x, ++coeff, ++touched) {
2817 val = *coeff;
2818 if (val != 0) {
2819 shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched);
2820 if (shift2 > 0) {
2821 cover(94);
2822 if (val < 0) {
2823 val = (val << shift2) - (1 << (shift2 - 1));
2824 } else {
2825 val = (val << shift2) + (1 << (shift2 - 1));
2827 } else {
2828 cover(95);
2829 val >>= -shift2;
2831 if (qStyle == 0) {
2832 cover(96);
2833 if (tileComp->transform == 0) {
2834 cover(97);
2835 val &= -1 << fracBits;
2837 } else {
2838 cover(98);
2839 val = (int)((double)val * mu);
2842 *coeff = val;
2845 ++cb;
2849 //----- IDWT for each level
2851 for (r = 1; r <= tileComp->nDecompLevels; ++r) {
2852 resLevel = &tileComp->resLevels[r];
2854 // (n)LL is already in the upper-left corner of the
2855 // tile-component data array -- interleave with (n)HL/LH/HH
2856 // and inverse transform to get (n-1)LL, which will be stored
2857 // in the upper-left corner of the tile-component data array
2858 inverseTransformLevel(tileComp, r, resLevel);
2862 // Do one level of the inverse transform:
2863 // - take (n)LL, (n)HL, (n)LH, and (n)HH from the upper-left corner
2864 // of the tile-component data array
2865 // - leave the resulting (n-1)LL in the same place
2866 void JPXStream::inverseTransformLevel(JPXTileComp *tileComp,
2867 Guint r, JPXResLevel *resLevel) {
2868 JPXPrecinct *precinct;
2869 JPXSubband *subband;
2870 JPXCodeBlock *cb;
2871 int *coeff0, *coeff;
2872 char *touched0, *touched;
2873 Guint qStyle, guard, eps, shift, t;
2874 int shift2;
2875 double mu;
2876 int val;
2877 int *dataPtr, *bufPtr;
2878 Guint nx1, nx2, ny1, ny2, offset;
2879 Guint x, y, sb, cbX, cbY;
2881 //----- fixed-point adjustment and dequantization
2883 qStyle = tileComp->quantStyle & 0x1f;
2884 guard = (tileComp->quantStyle >> 5) & 7;
2885 precinct = &resLevel->precincts[0];
2886 for (sb = 0; sb < 3; ++sb) {
2888 // i-quant parameters
2889 if (qStyle == 0) {
2890 cover(100);
2891 const Guint stepIndex = 3*r - 2 + sb;
2892 if (unlikely(stepIndex >= tileComp->nQuantSteps)) {
2893 error(errSyntaxError, getPos(),
2894 "Wrong index for quantSteps in inverseTransformLevel in JPX stream");
2895 break;
2897 eps = (tileComp->quantSteps[stepIndex] >> 3) & 0x1f;
2898 shift = guard + eps - 1;
2899 mu = 0; // make gcc happy
2900 } else {
2901 cover(101);
2902 shift = guard + tileComp->prec;
2903 if (sb == 2) {
2904 cover(102);
2905 ++shift;
2907 const Guint stepIndex = qStyle == 1 ? 0 : (3*r - 2 + sb);
2908 if (unlikely(stepIndex >= tileComp->nQuantSteps)) {
2909 error(errSyntaxError, getPos(),
2910 "Wrong index for quantSteps in inverseTransformLevel in JPX stream");
2911 break;
2913 t = tileComp->quantSteps[stepIndex];
2914 mu = (double)(0x800 + (t & 0x7ff)) / 2048.0;
2916 if (tileComp->transform == 0) {
2917 cover(103);
2918 shift += fracBits;
2921 // fixed point adjustment and dequantization
2922 subband = &precinct->subbands[sb];
2923 cb = subband->cbs;
2924 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2925 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2926 for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
2927 y < cb->y1;
2928 ++y, coeff0 += tileComp->w, touched0 += tileComp->cbW) {
2929 for (x = cb->x0, coeff = coeff0, touched = touched0;
2930 x < cb->x1;
2931 ++x, ++coeff, ++touched) {
2932 val = *coeff;
2933 if (val != 0) {
2934 shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched);
2935 if (shift2 > 0) {
2936 cover(74);
2937 if (val < 0) {
2938 val = (val << shift2) - (1 << (shift2 - 1));
2939 } else {
2940 val = (val << shift2) + (1 << (shift2 - 1));
2942 } else {
2943 cover(75);
2944 val >>= -shift2;
2946 if (qStyle == 0) {
2947 cover(76);
2948 if (tileComp->transform == 0) {
2949 val &= -1 << fracBits;
2951 } else {
2952 cover(77);
2953 val = (int)((double)val * mu);
2956 *coeff = val;
2959 ++cb;
2964 //----- inverse transform
2966 // compute the subband bounds:
2967 // 0 nx1 nx2
2968 // | | |
2969 // v v v
2970 // +----+----+
2971 // | LL | HL | <- 0
2972 // +----+----+
2973 // | LH | HH | <- ny1
2974 // +----+----+
2975 // <- ny2
2976 nx1 = precinct->subbands[1].x1 - precinct->subbands[1].x0;
2977 nx2 = nx1 + precinct->subbands[0].x1 - precinct->subbands[0].x0;
2978 ny1 = precinct->subbands[0].y1 - precinct->subbands[0].y0;
2979 ny2 = ny1 + precinct->subbands[1].y1 - precinct->subbands[1].y0;
2981 // horizontal (row) transforms
2982 if (r == tileComp->nDecompLevels) {
2983 offset = 3 + (tileComp->x0 & 1);
2984 } else {
2985 offset = 3 + (tileComp->resLevels[r+1].x0 & 1);
2987 for (y = 0, dataPtr = tileComp->data; y < ny2; ++y, dataPtr += tileComp->w) {
2988 if (precinct->subbands[0].x0 == precinct->subbands[1].x0) {
2989 // fetch LL/LH
2990 for (x = 0, bufPtr = tileComp->buf + offset;
2991 x < nx1;
2992 ++x, bufPtr += 2) {
2993 *bufPtr = dataPtr[x];
2995 // fetch HL/HH
2996 for (x = nx1, bufPtr = tileComp->buf + offset + 1;
2997 x < nx2;
2998 ++x, bufPtr += 2) {
2999 *bufPtr = dataPtr[x];
3001 } else {
3002 // fetch LL/LH
3003 for (x = 0, bufPtr = tileComp->buf + offset + 1;
3004 x < nx1;
3005 ++x, bufPtr += 2) {
3006 *bufPtr = dataPtr[x];
3008 // fetch HL/HH
3009 for (x = nx1, bufPtr = tileComp->buf + offset;
3010 x < nx2;
3011 ++x, bufPtr += 2) {
3012 *bufPtr = dataPtr[x];
3015 if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
3016 x = tileComp->x1 - tileComp->x0 + 5;
3017 } else {
3018 x = tileComp->y1 - tileComp->y0 + 5;
3020 if (offset + nx2 > x || nx2 == 0) {
3021 error(errSyntaxError, getPos(),
3022 "Invalid call of inverseTransform1D in inverseTransformLevel in JPX stream");
3023 return;
3025 inverseTransform1D(tileComp, tileComp->buf, offset, nx2);
3026 for (x = 0, bufPtr = tileComp->buf + offset; x < nx2; ++x, ++bufPtr) {
3027 dataPtr[x] = *bufPtr;
3031 // vertical (column) transforms
3032 if (r == tileComp->nDecompLevels) {
3033 offset = 3 + (tileComp->y0 & 1);
3034 } else {
3035 offset = 3 + (tileComp->resLevels[r+1].y0 & 1);
3037 for (x = 0, dataPtr = tileComp->data; x < nx2; ++x, ++dataPtr) {
3038 if (precinct->subbands[1].y0 == precinct->subbands[0].y0) {
3039 // fetch LL/HL
3040 for (y = 0, bufPtr = tileComp->buf + offset;
3041 y < ny1;
3042 ++y, bufPtr += 2) {
3043 *bufPtr = dataPtr[y * tileComp->w];
3045 // fetch LH/HH
3046 for (y = ny1, bufPtr = tileComp->buf + offset + 1;
3047 y < ny2;
3048 ++y, bufPtr += 2) {
3049 *bufPtr = dataPtr[y * tileComp->w];
3051 } else {
3052 // fetch LL/HL
3053 for (y = 0, bufPtr = tileComp->buf + offset + 1;
3054 y < ny1;
3055 ++y, bufPtr += 2) {
3056 *bufPtr = dataPtr[y * tileComp->w];
3058 // fetch LH/HH
3059 for (y = ny1, bufPtr = tileComp->buf + offset;
3060 y < ny2;
3061 ++y, bufPtr += 2) {
3062 *bufPtr = dataPtr[y * tileComp->w];
3065 if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
3066 y = tileComp->x1 - tileComp->x0 + 5;
3067 } else {
3068 y = tileComp->y1 - tileComp->y0 + 5;
3070 if (offset + ny2 > y || ny2 == 0) {
3071 error(errSyntaxError, getPos(),
3072 "Invalid call of inverseTransform1D in inverseTransformLevel in JPX stream");
3073 return;
3075 inverseTransform1D(tileComp, tileComp->buf, offset, ny2);
3076 for (y = 0, bufPtr = tileComp->buf + offset; y < ny2; ++y, ++bufPtr) {
3077 dataPtr[y * tileComp->w] = *bufPtr;
3082 void JPXStream::inverseTransform1D(JPXTileComp *tileComp, int *data,
3083 Guint offset, Guint n) {
3084 Guint end, i;
3086 //----- special case for length = 1
3087 if (n == 1) {
3088 cover(79);
3089 if (offset == 4) {
3090 cover(104);
3091 *data >>= 1;
3094 } else {
3095 cover(80);
3097 end = offset + n;
3099 //----- extend right
3100 data[end] = data[end - 2];
3101 if (n == 2) {
3102 cover(81);
3103 data[end+1] = data[offset + 1];
3104 data[end+2] = data[offset];
3105 data[end+3] = data[offset + 1];
3106 } else {
3107 cover(82);
3108 data[end+1] = data[end - 3];
3109 if (n == 3) {
3110 cover(105);
3111 data[end+2] = data[offset + 1];
3112 data[end+3] = data[offset + 2];
3113 } else {
3114 cover(106);
3115 data[end+2] = data[end - 4];
3116 if (n == 4) {
3117 cover(107);
3118 data[end+3] = data[offset + 1];
3119 } else {
3120 cover(108);
3121 data[end+3] = data[end - 5];
3126 //----- extend left
3127 data[offset - 1] = data[offset + 1];
3128 data[offset - 2] = data[offset + 2];
3129 data[offset - 3] = data[offset + 3];
3130 if (offset == 4) {
3131 cover(83);
3132 data[0] = data[offset + 4];
3135 //----- 9-7 irreversible filter
3137 if (tileComp->transform == 0) {
3138 cover(84);
3139 // step 1 (even)
3140 for (i = 1; i <= end + 2; i += 2) {
3141 data[i] = (int)(idwtKappa * data[i]);
3143 // step 2 (odd)
3144 for (i = 0; i <= end + 3; i += 2) {
3145 data[i] = (int)(idwtIKappa * data[i]);
3147 // step 3 (even)
3148 for (i = 1; i <= end + 2; i += 2) {
3149 data[i] = (int)(data[i] - idwtDelta * (data[i-1] + data[i+1]));
3151 // step 4 (odd)
3152 for (i = 2; i <= end + 1; i += 2) {
3153 data[i] = (int)(data[i] - idwtGamma * (data[i-1] + data[i+1]));
3155 // step 5 (even)
3156 for (i = 3; i <= end; i += 2) {
3157 data[i] = (int)(data[i] - idwtBeta * (data[i-1] + data[i+1]));
3159 // step 6 (odd)
3160 for (i = 4; i <= end - 1; i += 2) {
3161 data[i] = (int)(data[i] - idwtAlpha * (data[i-1] + data[i+1]));
3164 //----- 5-3 reversible filter
3166 } else {
3167 cover(85);
3168 // step 1 (even)
3169 for (i = 3; i <= end; i += 2) {
3170 data[i] -= (data[i-1] + data[i+1] + 2) >> 2;
3172 // step 2 (odd)
3173 for (i = 4; i < end; i += 2) {
3174 data[i] += (data[i-1] + data[i+1]) >> 1;
3180 // Inverse multi-component transform and DC level shift. This also
3181 // converts fixed point samples back to integers.
3182 GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
3183 JPXTileComp *tileComp;
3184 int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal;
3185 int *dataPtr;
3186 Guint j, comp, x, y;
3188 //----- inverse multi-component transform
3190 if (tile->multiComp == 1) {
3191 cover(86);
3192 if (img.nComps < 3 ||
3193 tile->tileComps[0].hSep != tile->tileComps[1].hSep ||
3194 tile->tileComps[0].vSep != tile->tileComps[1].vSep ||
3195 tile->tileComps[1].hSep != tile->tileComps[2].hSep ||
3196 tile->tileComps[1].vSep != tile->tileComps[2].vSep) {
3197 return gFalse;
3200 // inverse irreversible multiple component transform
3201 if (tile->tileComps[0].transform == 0) {
3202 cover(87);
3203 j = 0;
3204 for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
3205 for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
3206 d0 = tile->tileComps[0].data[j];
3207 d1 = tile->tileComps[1].data[j];
3208 d2 = tile->tileComps[2].data[j];
3209 tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5);
3210 tile->tileComps[1].data[j] =
3211 (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5);
3212 tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5);
3213 ++j;
3217 // inverse reversible multiple component transform
3218 } else {
3219 cover(88);
3220 j = 0;
3221 for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
3222 for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
3223 d0 = tile->tileComps[0].data[j];
3224 d1 = tile->tileComps[1].data[j];
3225 d2 = tile->tileComps[2].data[j];
3226 tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2);
3227 tile->tileComps[0].data[j] = d2 + t;
3228 tile->tileComps[2].data[j] = d1 + t;
3229 ++j;
3235 //----- DC level shift
3236 for (comp = 0; comp < img.nComps; ++comp) {
3237 tileComp = &tile->tileComps[comp];
3239 // signed: clip
3240 if (tileComp->sgned) {
3241 cover(89);
3242 minVal = -(1 << (tileComp->prec - 1));
3243 maxVal = (1 << (tileComp->prec - 1)) - 1;
3244 dataPtr = tileComp->data;
3245 for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
3246 for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
3247 coeff = *dataPtr;
3248 if (tileComp->transform == 0) {
3249 cover(109);
3250 coeff >>= fracBits;
3252 if (coeff < minVal) {
3253 cover(110);
3254 coeff = minVal;
3255 } else if (coeff > maxVal) {
3256 cover(111);
3257 coeff = maxVal;
3259 *dataPtr++ = coeff;
3263 // unsigned: inverse DC level shift and clip
3264 } else {
3265 cover(90);
3266 maxVal = (1 << tileComp->prec) - 1;
3267 zeroVal = 1 << (tileComp->prec - 1);
3268 dataPtr = tileComp->data;
3269 for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
3270 for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
3271 coeff = *dataPtr;
3272 if (tileComp->transform == 0) {
3273 cover(112);
3274 coeff >>= fracBits;
3276 coeff += zeroVal;
3277 if (coeff < 0) {
3278 cover(113);
3279 coeff = 0;
3280 } else if (coeff > maxVal) {
3281 cover(114);
3282 coeff = maxVal;
3284 *dataPtr++ = coeff;
3290 return gTrue;
3293 GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) {
3294 Guint len, lenH;
3296 if (!readULong(&len) ||
3297 !readULong(boxType)) {
3298 return gFalse;
3300 if (len == 1) {
3301 if (!readULong(&lenH) || !readULong(&len)) {
3302 return gFalse;
3304 if (lenH) {
3305 error(errSyntaxError, getPos(),
3306 "JPX stream contains a box larger than 2^32 bytes");
3307 return gFalse;
3309 *boxLen = len;
3310 *dataLen = len - 16;
3311 } else if (len == 0) {
3312 *boxLen = 0;
3313 *dataLen = 0;
3314 } else {
3315 *boxLen = len;
3316 *dataLen = len - 8;
3318 return gTrue;
3321 int JPXStream::readMarkerHdr(int *segType, Guint *segLen) {
3322 int c;
3324 do {
3325 do {
3326 if ((c = bufStr->getChar()) == EOF) {
3327 return gFalse;
3329 } while (c != 0xff);
3330 do {
3331 if ((c = bufStr->getChar()) == EOF) {
3332 return gFalse;
3334 } while (c == 0xff);
3335 } while (c == 0x00);
3336 *segType = c;
3337 if ((c >= 0x30 && c <= 0x3f) ||
3338 c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) {
3339 *segLen = 0;
3340 return gTrue;
3342 return readUWord(segLen);
3345 GBool JPXStream::readUByte(Guint *x) {
3346 int c0;
3348 if ((c0 = bufStr->getChar()) == EOF) {
3349 return gFalse;
3351 *x = (Guint)c0;
3352 return gTrue;
3355 GBool JPXStream::readByte(int *x) {
3356 int c0;
3358 if ((c0 = bufStr->getChar()) == EOF) {
3359 return gFalse;
3361 *x = c0;
3362 if (c0 & 0x80) {
3363 *x |= -1 - 0xff;
3365 return gTrue;
3368 GBool JPXStream::readUWord(Guint *x) {
3369 int c0, c1;
3371 if ((c0 = bufStr->getChar()) == EOF ||
3372 (c1 = bufStr->getChar()) == EOF) {
3373 return gFalse;
3375 *x = (Guint)((c0 << 8) | c1);
3376 return gTrue;
3379 GBool JPXStream::readULong(Guint *x) {
3380 int c0, c1, c2, c3;
3382 if ((c0 = bufStr->getChar()) == EOF ||
3383 (c1 = bufStr->getChar()) == EOF ||
3384 (c2 = bufStr->getChar()) == EOF ||
3385 (c3 = bufStr->getChar()) == EOF) {
3386 return gFalse;
3388 *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
3389 return gTrue;
3392 GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) {
3393 int y, c, i;
3395 y = 0;
3396 for (i = 0; i < nBytes; ++i) {
3397 if ((c = bufStr->getChar()) == EOF) {
3398 return gFalse;
3400 y = (y << 8) + c;
3402 if (signd) {
3403 if (y & (1 << (8 * nBytes - 1))) {
3404 y |= -1 << (8 * nBytes);
3407 *x = y;
3408 return gTrue;
3411 void JPXStream::startBitBuf(Guint byteCountA) {
3412 bitBufLen = 0;
3413 bitBufSkip = gFalse;
3414 byteCount = byteCountA;
3417 GBool JPXStream::readBits(int nBits, Guint *x) {
3418 int c;
3420 while (bitBufLen < nBits) {
3421 if (byteCount == 0 || (c = bufStr->getChar()) == EOF) {
3422 return gFalse;
3424 --byteCount;
3425 if (bitBufSkip) {
3426 bitBuf = (bitBuf << 7) | (c & 0x7f);
3427 bitBufLen += 7;
3428 } else {
3429 bitBuf = (bitBuf << 8) | (c & 0xff);
3430 bitBufLen += 8;
3432 bitBufSkip = c == 0xff;
3434 *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1);
3435 bitBufLen -= nBits;
3436 return gTrue;
3439 void JPXStream::skipSOP() {
3440 int i;
3442 // SOP occurs at the start of the packet header, so we don't need to
3443 // worry about bit-stuff prior to it
3444 if (byteCount >= 6 &&
3445 bufStr->lookChar(0) == 0xff &&
3446 bufStr->lookChar(1) == 0x91) {
3447 for (i = 0; i < 6; ++i) {
3448 bufStr->getChar();
3450 byteCount -= 6;
3451 bitBufLen = 0;
3452 bitBufSkip = gFalse;
3456 void JPXStream::skipEPH() {
3457 int i, k;
3459 k = bitBufSkip ? 1 : 0;
3460 if (byteCount >= (Guint)(k + 2) &&
3461 bufStr->lookChar(k) == 0xff &&
3462 bufStr->lookChar(k + 1) == 0x92) {
3463 for (i = 0; i < k + 2; ++i) {
3464 bufStr->getChar();
3466 byteCount -= k + 2;
3467 bitBufLen = 0;
3468 bitBufSkip = gFalse;
3472 Guint JPXStream::finishBitBuf() {
3473 if (bitBufSkip) {
3474 bufStr->getChar();
3475 --byteCount;
3477 return byteCount;