Skip to content

Commit 699abbd

Browse files
committed
Removing huffman tables; decoding context refactoring
1 parent 2e5414c commit 699abbd

File tree

1 file changed

+81
-105
lines changed

1 file changed

+81
-105
lines changed

src/jbig2.js

Lines changed: 81 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,50 @@ var Jbig2Image = (function Jbig2ImageClosure() {
168168
return ArithmeticDecoder;
169169
})();
170170

171+
// Utility data structures
172+
function ContextCache() {}
173+
174+
ContextCache.prototype = {
175+
getContexts: function(id) {
176+
if (id in this)
177+
return this[id];
178+
return (this[id] = []);
179+
}
180+
};
181+
182+
function DecodingContext(data, start, end) {
183+
this.data = data;
184+
this.start = start;
185+
this.end = end;
186+
}
187+
188+
DecodingContext.prototype = {
189+
get decoder() {
190+
var decoder = new ArithmeticDecoder(this.data, this.start, this.end);
191+
Object.defineProperty(this, 'decoder', {
192+
value: decoder,
193+
writable: false,
194+
configurable: true,
195+
enumerable: true
196+
});
197+
return decoder;
198+
},
199+
get contextCache() {
200+
var cache = new ContextCache();
201+
Object.defineProperty(this, 'contextCache', {
202+
value: cache,
203+
writable: false,
204+
configurable: true,
205+
enumerable: true
206+
});
207+
return cache;
208+
}
209+
};
210+
171211
// Annex A. Arithmetic Integer Decoding Procedure
172212
// A.2 Procedure for decoding values
173213
function decodeInteger(contextCache, procedure, decoder) {
174-
var contexts;
175-
if (procedure in contextCache)
176-
contexts = contextCache[procedure];
177-
else
178-
contextCache[procedure] = contexts = [];
214+
var contexts = contextCache.getContexts(procedure);
179215

180216
var prev = 1;
181217
var state = 1, v = 0, s;
@@ -232,13 +268,10 @@ var Jbig2Image = (function Jbig2ImageClosure() {
232268
v += offset;
233269
return !s ? v : v > 0 ? -v : null;
234270
}
271+
235272
// A.3 The IAID decoding procedure
236273
function decodeIAID(contextCache, decoder, codeLength) {
237-
var contexts;
238-
if ('IAID' in contextCache)
239-
contexts = contextCache['IAID'];
240-
else
241-
contextCache['IAID'] = contexts = [];
274+
var contexts = contextCache.getContexts('IAID');
242275

243276
var prev = 1;
244277
for (var i = 0; i < codeLength; i++) {
@@ -254,41 +287,6 @@ var Jbig2Image = (function Jbig2ImageClosure() {
254287
return prev - Math.pow(2, codeLength);
255288
}
256289

257-
// Annex B. Huffman Table Decoding Procedure
258-
// B.5 Standard Huffman tables
259-
function TableB1(reader) {
260-
if (!reader.readBit())
261-
return reader.readBits(4); // 0 + VAL
262-
if (!reader.readBit())
263-
return reader.readBits(8) + 16; // 10 + (VAL - 16)
264-
if (!reader.readBit())
265-
return reader.readBits(16) + 272; // 110 + (VAL - 272)
266-
if (!reader.readBit())
267-
return reader.readBits(32) + 65808; // 1110 + (VAL - 65808)
268-
}
269-
270-
function TableB2(reader) {
271-
if (!reader.readBit())
272-
return 0; // 0
273-
if (!reader.readBit())
274-
return 1; // 10
275-
if (!reader.readBit())
276-
return 2; // 110
277-
if (!reader.readBit())
278-
return reader.readBits(3) + 3; // 1110 + (VAL - 3)
279-
if (!reader.readBit())
280-
return reader.readBits(6) + 11; // 11110 + (VAL - 11)
281-
if (!reader.readBit())
282-
return reader.readBits(32) + 75; // 111110 + (VAL - 75)
283-
return null; // OOB
284-
}
285-
286-
function TableB3(reader) {}
287-
288-
function TableB4(reader) {}
289-
290-
function TableB5(reader) {}
291-
292290
// 7.3 Segment types
293291
var SegmentTypes = [
294292
'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null,
@@ -374,7 +372,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
374372

375373
// 6.2 Generic Region Decoding Procedure
376374
function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
377-
data, start, end) {
375+
decodingContext) {
378376
if (mmr)
379377
throw 'MMR encoding is not supported';
380378

@@ -390,23 +388,14 @@ var Jbig2Image = (function Jbig2ImageClosure() {
390388

391389
var pseudoPixelContext = ReusedContexts[templateIndex];
392390
var bitmap = [];
393-
var decoder, contexts, cx;
394-
if (data instanceof ArithmeticDecoder) {
395-
decoder = data;
396-
var contextCache = start;
397-
if ('GB' in contextCache)
398-
contexts = contextCache['GB'];
399-
else
400-
contextCache['GB'] = contexts = [];
401-
} else {
402-
decoder = new ArithmeticDecoder(data, start, end);
403-
contexts = [];
404-
}
391+
392+
var decoder = decodingContext.decoder;
393+
var contexts = decodingContext.contextCache.getContexts('GB');
405394

406395
var ltp = 0;
407396
for (var i = 0; i < height; i++) {
408397
if (prediction) {
409-
cx = contexts[pseudoPixelContext];
398+
var cx = contexts[pseudoPixelContext];
410399
if (!cx)
411400
contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
412401
var sltp = decoder.readBit(cx);
@@ -431,7 +420,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
431420
else
432421
contextLabel = (contextLabel << 1) | bitmap[i0][j0];
433422
}
434-
cx = contexts[contextLabel];
423+
var cx = contexts[contextLabel];
435424
if (!cx)
436425
contexts[contextLabel] = cx = {index: 0, mps: 0};
437426
var pixel = decoder.readBit(cx);
@@ -444,7 +433,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
444433
// 6.3.2 Generic Refinement Region Decoding Procedure
445434
function decodeRefinement(width, height, templateIndex, referenceBitmap,
446435
offsetX, offsetY, prediction, at,
447-
data, start, end) {
436+
decodingContext) {
448437
var codingTemplate = RefinementTemplates[templateIndex].coding;
449438
if (templateIndex == 0)
450439
codingTemplate = codingTemplate.concat([at[0]]);
@@ -470,23 +459,14 @@ var Jbig2Image = (function Jbig2ImageClosure() {
470459

471460
var pseudoPixelContext = RefinementReusedContexts[templateIndex];
472461
var bitmap = [];
473-
var decoder, contexts, cx;
474-
if (data instanceof ArithmeticDecoder) {
475-
decoder = data;
476-
var contextCache = start;
477-
if ('GR' in contextCache)
478-
contexts = contextCache['GR'];
479-
else
480-
contextCache['GR'] = contexts = [];
481-
} else {
482-
decoder = new ArithmeticDecoder(data, start, end);
483-
contexts = [];
484-
}
462+
463+
var decoder = decodingContext.decoder;
464+
var contexts = decodingContext.contextCache.getContexts('GR');
485465

486466
var ltp = 0;
487467
for (var i = 0; i < height; i++) {
488468
if (prediction) {
489-
cx = contexts[pseudoPixelContext];
469+
var cx = contexts[pseudoPixelContext];
490470
if (!cx)
491471
contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
492472
var sltp = decoder.readBit(cx);
@@ -514,7 +494,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
514494
else
515495
contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
516496
}
517-
cx = contexts[contextLabel];
497+
var cx = contexts[contextLabel];
518498
if (!cx)
519499
contexts[contextLabel] = cx = {index: 0, mps: 0};
520500
var pixel = decoder.readBit(cx);
@@ -530,15 +510,17 @@ var Jbig2Image = (function Jbig2ImageClosure() {
530510
numberOfNewSymbols, numberOfExportedSymbols,
531511
huffmanTables, templateIndex, at,
532512
refinementTemplateIndex, refinementAt,
533-
data, start, end) {
513+
decodingContext) {
534514
if (huffman)
535515
throw 'huffman is not supported';
536516

537517
var newSymbols = [];
538518
var currentHeight = 0;
539-
var contextCache = {};
540519
var symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
541-
var decoder = new ArithmeticDecoder(data, start, end);
520+
521+
var decoder = decodingContext.decoder;
522+
var contextCache = decodingContext.contextCache;
523+
542524
while (newSymbols.length < numberOfNewSymbols) {
543525
var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6
544526
currentHeight += deltaHeight;
@@ -563,11 +545,11 @@ var Jbig2Image = (function Jbig2ImageClosure() {
563545
newSymbols[symbolId - symbols.length];
564546
bitmap = decodeRefinement(currentWidth, currentHeight,
565547
refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
566-
decoder, contextCache);
548+
decodingContext);
567549
} else {
568550
// 6.5.8.1 Direct-coded symbol bitmap
569551
bitmap = decodeBitmap(false, currentWidth, currentHeight,
570-
templateIndex, false, null, at, decoder, contextCache);
552+
templateIndex, false, null, at, decodingContext);
571553
}
572554
newSymbols.push(bitmap);
573555
}
@@ -594,7 +576,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
594576
transposed, dsOffset, referenceCorner,
595577
combinationOperator, huffmanTables,
596578
refinementTemplateIndex, refinementAt,
597-
data, start, end) {
579+
decodingContext) {
598580
if (huffman)
599581
throw 'huffman is not supported';
600582

@@ -609,8 +591,8 @@ var Jbig2Image = (function Jbig2ImageClosure() {
609591
bitmap.push(row);
610592
}
611593

612-
var contextCache = {};
613-
var decoder = new ArithmeticDecoder(data, start, end);
594+
var decoder = decodingContext.decoder;
595+
var contextCache = decodingContext.contextCache;
614596

615597
if (transposed)
616598
throw 'transposed!=0 is not supported';
@@ -647,7 +629,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
647629
symbolBitmap = decodeRefinement(symbolWidth, symbolHeight,
648630
refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx,
649631
(rdh >> 1) + rdy, false, refinementAt,
650-
decoder, contextCache);
632+
decodingContext);
651633
}
652634
var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
653635
var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
@@ -1007,64 +989,58 @@ var Jbig2Image = (function Jbig2ImageClosure() {
1007989
function SimpleSegmentVisitor_ImmediateGenericRegion(region, data,
1008990
start, end) {
1009991
var regionInfo = region.info;
992+
var decodingContext = new DecodingContext(data, start, end);
1010993
var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height,
1011994
region.template, region.prediction, null,
1012-
region.at, data, start, end);
995+
region.at, decodingContext);
1013996
this.drawBitmap(regionInfo, bitmap);
1014997
},
1015998
SymbolDictionary:
1016999
function SimpleSegmentVisitor_SymbolDictionary(dictionary, currentSegment,
10171000
referredSegments,
10181001
data, start, end) {
1019-
var symbols = this.symbols;
10201002
var huffmanTables;
1021-
if (dictionary.huffman) {
1022-
huffmanTables = {};
1023-
huffmanTables.DeltaHeights = dictionary.huffmanDHSelector == 0 ?
1024-
TableB4 : dictionary.huffmanDHSelector == 1 ? TableB5 :
1025-
this.userTable;
1026-
huffmanTables.DeltaWidths = dictionary.huffmanDHSelector == 0 ?
1027-
TableB2 : dictionary.huffmanDHSelector == 2 ? TableB3 :
1028-
this.userTable;
1029-
huffmanTables.BitmapSize = dictionary.huffmanBitmapSizeSelector == 0 ?
1030-
TableB1 : this.userTable;
1031-
huffmanTables.AggregationInstances =
1032-
dictionary.aggregationInstancesSelector == 0 ? TableB1 :
1033-
this.userTable;
1034-
}
1003+
if (dictionary.huffman)
1004+
throw 'huffman is not supported';
1005+
10351006
// Combines exported symbols from all referred segments
1007+
var symbols = this.symbols;
1008+
if (!symbols)
1009+
this.symbols = symbols = {};
1010+
10361011
var inputSymbols = [];
10371012
for (var i = 0; i < referredSegments.length; i++)
10381013
inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
10391014

1040-
if (!symbols)
1041-
this.symbols = symbols = {};
1015+
var decodingContext = new DecodingContext(data, start, end);
10421016
symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman,
10431017
dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols,
10441018
dictionary.numberOfExportedSymbols, huffmanTables,
10451019
dictionary.template, dictionary.at,
10461020
dictionary.refinementTemplate, dictionary.refinementAt,
1047-
data, start, end);
1021+
decodingContext);
10481022
},
10491023
ImmediateTextRegion:
10501024
function SimpleSegmentVisitor_ImmediateTextRegion(region,
10511025
referredSegments,
10521026
data, start, end) {
10531027
var regionInfo = region.info;
1054-
var symbols = this.symbols;
10551028
var huffmanTables;
1029+
10561030
// Combines exported symbols from all referred segments
1031+
var symbols = this.symbols;
10571032
var inputSymbols = [];
10581033
for (var i = 0; i < referredSegments.length; i++)
10591034
inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
10601035
var symbolCodeLength = log2(inputSymbols.length);
10611036

1037+
var decodingContext = new DecodingContext(data, start, end);
10621038
var bitmap = decodeTextRegion(region.huffman, region.refinement,
10631039
regionInfo.width, regionInfo.height, region.defaultPixelValue,
10641040
region.numberOfSymbolInstances, region.stripSize, inputSymbols,
10651041
symbolCodeLength, region.transposed, region.dsOffset,
10661042
region.referenceCorner, region.combinationOperator, huffmanTables,
1067-
region.refinementTemplate, region.refinementAt, data, start, end);
1043+
region.refinementTemplate, region.refinementAt, decodingContext);
10681044
this.drawBitmap(regionInfo, bitmap);
10691045
}
10701046
};

0 commit comments

Comments
 (0)