|
|
|
@ -111,7 +111,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
@@ -111,7 +111,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
|
|
|
|
|
var SegmentTypes = [ |
|
|
|
|
'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null, |
|
|
|
|
'ImmediateTextRegion', 'ImmediateLosslessTextRegion', null, null, null, |
|
|
|
|
null, null, null, null, null, 'patternDictionary', null, null, null, |
|
|
|
|
null, null, null, null, null, 'PatternDictionary', null, null, null, |
|
|
|
|
'IntermediateHalftoneRegion', null, 'ImmediateHalftoneRegion', |
|
|
|
|
'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null, |
|
|
|
|
null, null, null, null, null, 'IntermediateGenericRegion', null, |
|
|
|
@ -619,6 +619,148 @@ var Jbig2Image = (function Jbig2ImageClosure() {
@@ -619,6 +619,148 @@ var Jbig2Image = (function Jbig2ImageClosure() {
|
|
|
|
|
return bitmap; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function decodePatternDictionary(mmr, patternWidth, patternHeight, |
|
|
|
|
maxPatternIndex, template, decodingContext) { |
|
|
|
|
let at = []; |
|
|
|
|
at.push({ |
|
|
|
|
x: -patternWidth, |
|
|
|
|
y: 0, |
|
|
|
|
}); |
|
|
|
|
if (template === 0) { |
|
|
|
|
at.push({ |
|
|
|
|
x: -3, |
|
|
|
|
y: -1, |
|
|
|
|
}); |
|
|
|
|
at.push({ |
|
|
|
|
x: 2, |
|
|
|
|
y: -2, |
|
|
|
|
}); |
|
|
|
|
at.push({ |
|
|
|
|
x: -2, |
|
|
|
|
y: -2, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
let collectiveWidth = (maxPatternIndex + 1) * patternWidth; |
|
|
|
|
let collectiveBitmap = decodeBitmap(mmr, collectiveWidth, patternHeight, |
|
|
|
|
template, false, null, at, |
|
|
|
|
decodingContext); |
|
|
|
|
// Divide collective bitmap into patterns.
|
|
|
|
|
let patterns = [], i = 0, patternBitmap, xMin, xMax, y; |
|
|
|
|
while (i <= maxPatternIndex) { |
|
|
|
|
patternBitmap = []; |
|
|
|
|
xMin = patternWidth * i; |
|
|
|
|
xMax = xMin + patternWidth; |
|
|
|
|
for (y = 0; y < patternHeight; y++) { |
|
|
|
|
patternBitmap.push(collectiveBitmap[y].subarray(xMin, xMax)); |
|
|
|
|
} |
|
|
|
|
patterns.push(patternBitmap); |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
return patterns; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function decodeHalftoneRegion(mmr, patterns, template, regionWidth, |
|
|
|
|
regionHeight, defaultPixelValue, enableSkip, |
|
|
|
|
combinationOperator, gridWidth, gridHeight, |
|
|
|
|
gridOffsetX, gridOffsetY, gridVectorX, |
|
|
|
|
gridVectorY, decodingContext) { |
|
|
|
|
let skip = null; |
|
|
|
|
if (enableSkip) { |
|
|
|
|
throw new Jbig2Error('skip is not supported'); |
|
|
|
|
} |
|
|
|
|
if (combinationOperator !== 0) { |
|
|
|
|
throw new Jbig2Error('operator ' + combinationOperator + |
|
|
|
|
' is not supported in halftone region'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Prepare bitmap.
|
|
|
|
|
let regionBitmap = []; |
|
|
|
|
let i, j, row; |
|
|
|
|
for (i = 0; i < regionHeight; i++) { |
|
|
|
|
row = new Uint8Array(regionWidth); |
|
|
|
|
if (defaultPixelValue) { |
|
|
|
|
for (j = 0; j < regionWidth; j++) { |
|
|
|
|
row[j] = defaultPixelValue; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
regionBitmap.push(row); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let numberOfPatterns = patterns.length; |
|
|
|
|
let pattern0 = patterns[0]; |
|
|
|
|
let patternWidth = pattern0[0].length, patternHeight = pattern0.length; |
|
|
|
|
let bitsPerValue = log2(numberOfPatterns); |
|
|
|
|
let at = []; |
|
|
|
|
at.push({ |
|
|
|
|
x: (template <= 1) ? 3 : 2, |
|
|
|
|
y: -1, |
|
|
|
|
}); |
|
|
|
|
if (template === 0) { |
|
|
|
|
at.push({ |
|
|
|
|
x: -3, |
|
|
|
|
y: -1, |
|
|
|
|
}); |
|
|
|
|
at.push({ |
|
|
|
|
x: 2, |
|
|
|
|
y: -2, |
|
|
|
|
}); |
|
|
|
|
at.push({ |
|
|
|
|
x: -2, |
|
|
|
|
y: -2, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
// Annex C. Gray-scale Image Decoding Procedure.
|
|
|
|
|
let grayScaleBitPlanes = []; |
|
|
|
|
for (i = bitsPerValue - 1; i >= 0; i--) { |
|
|
|
|
grayScaleBitPlanes[i] = decodeBitmap(mmr, gridWidth, gridHeight, |
|
|
|
|
template, false, skip, at, |
|
|
|
|
decodingContext); |
|
|
|
|
} |
|
|
|
|
// 6.6.5.2 Rendering the patterns.
|
|
|
|
|
let mg, ng, bit, patternIndex, patternBitmap, x, y, patternRow, regionRow; |
|
|
|
|
for (mg = 0; mg < gridHeight; mg++) { |
|
|
|
|
for (ng = 0; ng < gridWidth; ng++) { |
|
|
|
|
bit = 0; |
|
|
|
|
patternIndex = 0; |
|
|
|
|
for (j = bitsPerValue - 1; j >= 0; j--) { |
|
|
|
|
bit = grayScaleBitPlanes[j][mg][ng] ^ bit; // Gray decoding
|
|
|
|
|
patternIndex |= bit << j; |
|
|
|
|
} |
|
|
|
|
patternBitmap = patterns[patternIndex]; |
|
|
|
|
x = (gridOffsetX + mg * gridVectorY + ng * gridVectorX) >> 8; |
|
|
|
|
y = (gridOffsetY + mg * gridVectorX - ng * gridVectorY) >> 8; |
|
|
|
|
// Draw patternBitmap at (x, y).
|
|
|
|
|
if (x >= 0 && x + patternWidth <= regionWidth && y >= 0 && |
|
|
|
|
y + patternHeight <= regionHeight) { |
|
|
|
|
for (i = 0; i < patternHeight; i++) { |
|
|
|
|
regionRow = regionBitmap[y + i]; |
|
|
|
|
patternRow = patternBitmap[i]; |
|
|
|
|
for (j = 0; j < patternWidth; j++) { |
|
|
|
|
regionRow[x + j] |= patternRow[j]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
let regionX, regionY; |
|
|
|
|
for (i = 0; i < patternHeight; i++) { |
|
|
|
|
regionY = y + i; |
|
|
|
|
if (regionY < 0 || regionY >= regionHeight) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
regionRow = regionBitmap[regionY]; |
|
|
|
|
patternRow = patternBitmap[i]; |
|
|
|
|
for (j = 0; j < patternWidth; j++) { |
|
|
|
|
regionX = x + j; |
|
|
|
|
if (regionX >= 0 && regionX < regionWidth) { |
|
|
|
|
regionRow[regionX] |= patternRow[j]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return regionBitmap; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function readSegmentHeader(data, start) { |
|
|
|
|
var segmentHeader = {}; |
|
|
|
|
segmentHeader.number = readUint32(data, start); |
|
|
|
@ -850,6 +992,44 @@ var Jbig2Image = (function Jbig2ImageClosure() {
@@ -850,6 +992,44 @@ var Jbig2Image = (function Jbig2ImageClosure() {
|
|
|
|
|
} |
|
|
|
|
args = [textRegion, header.referredTo, data, position, end]; |
|
|
|
|
break; |
|
|
|
|
case 16: // PatternDictionary
|
|
|
|
|
// 7.4.4. Pattern dictionary segment syntax
|
|
|
|
|
let patternDictionary = {}; |
|
|
|
|
let patternDictionaryFlags = data[position++]; |
|
|
|
|
patternDictionary.mmr = !!(patternDictionaryFlags & 1); |
|
|
|
|
patternDictionary.template = (patternDictionaryFlags >> 1) & 3; |
|
|
|
|
patternDictionary.patternWidth = data[position++]; |
|
|
|
|
patternDictionary.patternHeight = data[position++]; |
|
|
|
|
patternDictionary.maxPatternIndex = readUint32(data, position); |
|
|
|
|
position += 4; |
|
|
|
|
args = [patternDictionary, header.number, data, position, end]; |
|
|
|
|
break; |
|
|
|
|
case 22: // ImmediateHalftoneRegion
|
|
|
|
|
case 23: // ImmediateLosslessHalftoneRegion
|
|
|
|
|
// 7.4.5 Halftone region segment syntax
|
|
|
|
|
let halftoneRegion = {}; |
|
|
|
|
halftoneRegion.info = readRegionSegmentInformation(data, position); |
|
|
|
|
position += RegionSegmentInformationFieldLength; |
|
|
|
|
let halftoneRegionFlags = data[position++]; |
|
|
|
|
halftoneRegion.mmr = !!(halftoneRegionFlags & 1); |
|
|
|
|
halftoneRegion.template = (halftoneRegionFlags >> 1) & 3; |
|
|
|
|
halftoneRegion.enableSkip = !!(halftoneRegionFlags & 8); |
|
|
|
|
halftoneRegion.combinationOperator = (halftoneRegionFlags >> 4) & 7; |
|
|
|
|
halftoneRegion.defaultPixelValue = (halftoneRegionFlags >> 7) & 1; |
|
|
|
|
halftoneRegion.gridWidth = readUint32(data, position); |
|
|
|
|
position += 4; |
|
|
|
|
halftoneRegion.gridHeight = readUint32(data, position); |
|
|
|
|
position += 4; |
|
|
|
|
halftoneRegion.gridOffsetX = readUint32(data, position) & 0xFFFFFFFF; |
|
|
|
|
position += 4; |
|
|
|
|
halftoneRegion.gridOffsetY = readUint32(data, position) & 0xFFFFFFFF; |
|
|
|
|
position += 4; |
|
|
|
|
halftoneRegion.gridVectorX = readUint16(data, position); |
|
|
|
|
position += 2; |
|
|
|
|
halftoneRegion.gridVectorY = readUint16(data, position); |
|
|
|
|
position += 2; |
|
|
|
|
args = [halftoneRegion, header.referredTo, data, position, end]; |
|
|
|
|
break; |
|
|
|
|
case 38: // ImmediateGenericRegion
|
|
|
|
|
case 39: // ImmediateLosslessGenericRegion
|
|
|
|
|
var genericRegion = {}; |
|
|
|
@ -1086,6 +1266,32 @@ var Jbig2Image = (function Jbig2ImageClosure() {
@@ -1086,6 +1266,32 @@ var Jbig2Image = (function Jbig2ImageClosure() {
|
|
|
|
|
function SimpleSegmentVisitor_onImmediateLosslessTextRegion() { |
|
|
|
|
this.onImmediateTextRegion.apply(this, arguments); |
|
|
|
|
}, |
|
|
|
|
onPatternDictionary(dictionary, currentSegment, data, start, end) { |
|
|
|
|
let patterns = this.patterns; |
|
|
|
|
if (!patterns) { |
|
|
|
|
this.patterns = patterns = {}; |
|
|
|
|
} |
|
|
|
|
let decodingContext = new DecodingContext(data, start, end); |
|
|
|
|
patterns[currentSegment] = decodePatternDictionary(dictionary.mmr, |
|
|
|
|
dictionary.patternWidth, dictionary.patternHeight, |
|
|
|
|
dictionary.maxPatternIndex, dictionary.template, decodingContext); |
|
|
|
|
}, |
|
|
|
|
onImmediateHalftoneRegion(region, referredSegments, data, start, end) { |
|
|
|
|
// HalftoneRegion refers to exactly one PatternDictionary.
|
|
|
|
|
let patterns = this.patterns[referredSegments[0]]; |
|
|
|
|
let regionInfo = region.info; |
|
|
|
|
let decodingContext = new DecodingContext(data, start, end); |
|
|
|
|
let bitmap = decodeHalftoneRegion(region.mmr, patterns, |
|
|
|
|
region.template, regionInfo.width, regionInfo.height, |
|
|
|
|
region.defaultPixelValue, region.enableSkip, region.combinationOperator, |
|
|
|
|
region.gridWidth, region.gridHeight, region.gridOffsetX, |
|
|
|
|
region.gridOffsetY, region.gridVectorX, region.gridVectorY, |
|
|
|
|
decodingContext); |
|
|
|
|
this.drawBitmap(regionInfo, bitmap); |
|
|
|
|
}, |
|
|
|
|
onImmediateLosslessHalftoneRegion() { |
|
|
|
|
this.onImmediateHalftoneRegion.apply(this, arguments); |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function Jbig2Image() {} |
|
|
|
|