Skip to content

Commit aa877e1

Browse files
committed
Implements refinement
1 parent e09eb52 commit aa877e1

File tree

1 file changed

+154
-16
lines changed

1 file changed

+154
-16
lines changed

src/jbig2.js

Lines changed: 154 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -319,13 +319,31 @@ var Jbig2Image = (function Jbig2ImageClosure() {
319319
{x: 1, y: -1}, {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}]
320320
];
321321

322+
var RefinementTemplates = [
323+
{
324+
coding: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
325+
reference: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}, {x: 0, y: 0},
326+
{x: 1, y: 0}, {x: -1, y: 1}, {x: 0, y: 1}, {x: 1, y: 1}]
327+
},
328+
{
329+
coding: [{x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
330+
reference: [{x: 0, y: -1}, {x: -1, y: 0}, {x: 0, y: 0}, {x: 1, y: 0},
331+
{x: 0, y: 1}, {x: 1, y: 1}]
332+
}
333+
];
334+
322335
var ReusedContexts = [
323336
0x1CD3, // '00111001101' (template) + '0011' (at),
324337
0x079A, // '001111001101' + '0',
325338
0x00E3, // '001110001' + '1',
326339
0x018B // '011000101' + '1'
327340
];
328341

342+
var RefinementReusedContexts = [
343+
0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
344+
0x0008 // '0000' + '001000'
345+
];
346+
329347
function log2(x) {
330348
var n = 1, i = 0;
331349
while (x > n) {
@@ -353,7 +371,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
353371
return (data[start] << 24) >> 24;
354372
}
355373

356-
// 6.2
374+
// 6.2 Generic Region Decoding Procedure
357375
function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
358376
data, start, end) {
359377
if (mmr)
@@ -368,7 +386,8 @@ var Jbig2Image = (function Jbig2ImageClosure() {
368386
templateX[k] = template[k].x;
369387
templateY[k] = template[k].y;
370388
}
371-
var pseudoPixelContext = ReusedContexts[template];
389+
390+
var pseudoPixelContext = ReusedContexts[templateIndex];
372391
var bitmap = [];
373392
var decoder, contexts, cx;
374393
if (data instanceof ArithmeticDecoder) {
@@ -382,6 +401,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
382401
decoder = new ArithmeticDecoder(data, start, end);
383402
contexts = [];
384403
}
404+
385405
var ltp = 0;
386406
for (var i = 0; i < height; i++) {
387407
if (prediction) {
@@ -420,6 +440,90 @@ var Jbig2Image = (function Jbig2ImageClosure() {
420440
return bitmap;
421441
}
422442

443+
// 6.3.2 Generic Refinement Region Decoding Procedure
444+
function decodeRefinement(width, height, templateIndex, referenceBitmap,
445+
offsetX, offsetY, prediction, at,
446+
data, start, end) {
447+
var codingTemplate = RefinementTemplates[templateIndex].coding;
448+
if (templateIndex == 0)
449+
codingTemplate = codingTemplate.concat([at[0]]);
450+
var codingTemplateLength = codingTemplate.length;
451+
var codingTemplateX = new Int32Array(codingTemplateLength);
452+
var codingTemplateY = new Int32Array(codingTemplateLength);
453+
for (var k = 0; k < codingTemplateLength; k++) {
454+
codingTemplateX[k] = codingTemplate[k].x;
455+
codingTemplateY[k] = codingTemplate[k].y;
456+
}
457+
var referenceTemplate = RefinementTemplates[templateIndex].reference;
458+
if (templateIndex == 0)
459+
referenceTemplate = referenceTemplate.concat([at[1]]);
460+
var referenceTemplateLength = referenceTemplate.length;
461+
var referenceTemplateX = new Int32Array(referenceTemplateLength);
462+
var referenceTemplateY = new Int32Array(referenceTemplateLength);
463+
for (var k = 0; k < referenceTemplateLength; k++) {
464+
referenceTemplateX[k] = referenceTemplate[k].x;
465+
referenceTemplateY[k] = referenceTemplate[k].y;
466+
}
467+
var referenceWidth = referenceBitmap[0].length;
468+
var referenceHeight = referenceBitmap.length;
469+
470+
var pseudoPixelContext = RefinementReusedContexts[templateIndex];
471+
var bitmap = [];
472+
var decoder, contexts, cx;
473+
if (data instanceof ArithmeticDecoder) {
474+
decoder = data;
475+
var contextCache = start;
476+
if ('GR' in contextCache)
477+
contexts = contextCache['GR'];
478+
else
479+
contextCache['GR'] = contexts = [];
480+
} else {
481+
decoder = new ArithmeticDecoder(data, start, end);
482+
contexts = [];
483+
}
484+
485+
var ltp = 0;
486+
for (var i = 0; i < height; i++) {
487+
if (prediction) {
488+
cx = contexts[pseudoPixelContext];
489+
if (!cx)
490+
contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
491+
var sltp = decoder.readBit(cx);
492+
ltp ^= sltp;
493+
}
494+
var row = new Uint8Array(width);
495+
bitmap.push(row);
496+
for (var j = 0; j < width; j++) {
497+
if (ltp)
498+
throw 'prediction is not supported';
499+
500+
var contextLabel = 0;
501+
for (var k = 0; k < codingTemplateLength; k++) {
502+
var i0 = i + codingTemplateY[k], j0 = j + codingTemplateX[k];
503+
if (i0 < 0 || j0 < 0 || j0 >= width)
504+
contextLabel <<= 1; // out of bound pixel
505+
else
506+
contextLabel = (contextLabel << 1) | bitmap[i0][j0];
507+
}
508+
for (var k = 0; k < referenceTemplateLength; k++) {
509+
var i0 = i + referenceTemplateY[k] + offsetY;
510+
var j0 = j + referenceTemplateX[k] + offsetX;
511+
if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth)
512+
contextLabel <<= 1; // out of bound pixel
513+
else
514+
contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
515+
}
516+
cx = contexts[contextLabel];
517+
if (!cx)
518+
contexts[contextLabel] = cx = {index: 0, mps: 0};
519+
var pixel = decoder.readBit(cx);
520+
row[j] = pixel;
521+
}
522+
}
523+
524+
return bitmap;
525+
}
526+
423527
// 6.5.5 Decoding the symbol dictionary
424528
function decodeSymbolDictionary(huffman, refinement, symbols,
425529
numberOfNewSymbols, numberOfExportedSymbols,
@@ -428,12 +532,11 @@ var Jbig2Image = (function Jbig2ImageClosure() {
428532
data, start, end) {
429533
if (huffman)
430534
throw 'huffman is not supported';
431-
if (refinement)
432-
throw 'refinement is not supported';
433535

434536
var newSymbols = [];
435537
var currentHeight = 0;
436538
var contextCache = {};
539+
var symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
437540
var decoder = new ArithmeticDecoder(data, start, end);
438541
while (newSymbols.length < numberOfNewSymbols) {
439542
var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6
@@ -446,9 +549,25 @@ var Jbig2Image = (function Jbig2ImageClosure() {
446549
break; // OOB
447550
currentWidth += deltaWidth;
448551
totalWidth += currentWidth;
449-
// 6.5.8.1 Direct-coded symbol bitmap
450-
var bitmap = decodeBitmap(false, currentWidth, currentHeight,
451-
templateIndex, false, null, at, decoder, contextCache);
552+
var bitmap;
553+
if (refinement) {
554+
// 6.5.8.2 Refinement/aggregate-coded symbol bitmap
555+
var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
556+
if (numberOfInstances > 1)
557+
throw 'number of instances > 1 is not supported';
558+
var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
559+
var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
560+
var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
561+
var symbol = symbolId < symbols.length ? symbols[symbolId] :
562+
newSymbols[symbolId - symbols.length];
563+
bitmap = decodeRefinement(currentWidth, currentHeight,
564+
refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
565+
decoder, contextCache);
566+
} else {
567+
// 6.5.8.1 Direct-coded symbol bitmap
568+
bitmap = decodeBitmap(false, currentWidth, currentHeight,
569+
templateIndex, false, null, at, decoder, contextCache);
570+
}
452571
newSymbols.push(bitmap);
453572
}
454573
}
@@ -473,12 +592,10 @@ var Jbig2Image = (function Jbig2ImageClosure() {
473592
stripSize, inputSymbols, symbolCodeLength,
474593
transposed, dsOffset, referenceCorner,
475594
combinationOperator, huffmanTables,
476-
refinementTemplate, refinementAt,
595+
refinementTemplateIndex, refinementAt,
477596
data, start, end) {
478597
if (huffman)
479598
throw 'huffman is not supported';
480-
if (refinement)
481-
throw 'refinement is not supported';
482599

483600
// Prepare bitmap
484601
var bitmap = [];
@@ -496,7 +613,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
496613

497614
if (transposed)
498615
throw 'transposed!=0 is not supported';
499-
if (combinationOperator != 0)
616+
if (combinationOperator != 0 && combinationOperator != 2)
500617
throw 'combinationOperator==' + combinationOperator + ' is not supported';
501618

502619
var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
@@ -512,20 +629,41 @@ var Jbig2Image = (function Jbig2ImageClosure() {
512629
do {
513630
var currentT = stripSize == 1 ? 0 :
514631
decodeInteger(contextCache, 'IAIT', decoder); // 6.4.9
515-
var t = stripT + currentT;
632+
var t = stripSize * stripT + currentT;
516633
var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
517-
634+
var applyRefinement = refinement &&
635+
decodeInteger(contextCache, 'IARI', decoder);
518636
var symbolBitmap = inputSymbols[symbolId];
519637
var symbolWidth = symbolBitmap[0].length;
520638
var symbolHeight = symbolBitmap.length;
639+
if (applyRefinement) {
640+
var rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1
641+
var rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2
642+
var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
643+
var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
644+
symbolWidth += rdw;
645+
symbolHeight += rdh;
646+
symbolBitmap = decodeRefinement(symbolWidth, symbolHeight,
647+
refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx,
648+
(rdh >> 1) + rdy, false, refinementAt,
649+
decoder, contextCache);
650+
}
521651
var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
522652
var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
523653
for (var t2 = 0; t2 < symbolHeight; t2++) {
524654
var row = bitmap[offsetT + t2];
525655
if (!row) continue;
526656
var symbolRow = symbolBitmap[t2];
527-
for (var s2 = 0; s2 < symbolWidth; s2++)
528-
row[offsetS + s2] |= symbolRow[s2];
657+
switch (combinationOperator) {
658+
case 0: // OR
659+
for (var s2 = 0; s2 < symbolWidth; s2++)
660+
row[offsetS + s2] |= symbolRow[s2];
661+
break;
662+
case 2: // XOR
663+
for (var s2 = 0; s2 < symbolWidth; s2++)
664+
row[offsetS + s2] ^= symbolRow[s2];
665+
break;
666+
}
529667
}
530668

531669
currentS += symbolWidth - 1;
@@ -722,7 +860,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
722860
});
723861
position += 2;
724862
}
725-
dictionary.refinementAt = at;
863+
textRegion.refinementAt = at;
726864
}
727865
textRegion.numberOfSymbolInstances = readUint32(data, position);
728866
position += 4;

0 commit comments

Comments
 (0)