mirror of
https://github.com/zen-browser/pdf.js.git
synced 2025-07-08 17:30:09 +02:00
Add (basic) support for transfer functions to Images (issue 6931, bug 1149713)
This is *similar* to the existing transfer function support for SMasks, but extended to simple image data. Please note that the extra amount of data now being sent to the worker-thread, for affected /ExtGState entries, is limited to *at most* 4 `Uint8Array`s each with a length of 256 elements. Refer to https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G9.1658137 for additional details.
This commit is contained in:
parent
9d3e046a4f
commit
1058f16605
5 changed files with 143 additions and 6 deletions
|
@ -416,6 +416,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
|
|||
this.lineWidth = 1;
|
||||
this.activeSMask = null;
|
||||
this.resumeSMaskCtx = null; // nonclonable field (see the save method below)
|
||||
this.transferMaps = null;
|
||||
}
|
||||
|
||||
CanvasExtraState.prototype = {
|
||||
|
@ -484,7 +485,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
this._cachedGetSinglePixelWidth = null;
|
||||
}
|
||||
|
||||
function putBinaryImageData(ctx, imgData) {
|
||||
function putBinaryImageData(ctx, imgData, transferMaps = null) {
|
||||
if (typeof ImageData !== "undefined" && imgData instanceof ImageData) {
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
return;
|
||||
|
@ -514,6 +515,24 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
var dest = chunkImgData.data;
|
||||
var i, j, thisChunkHeight, elemsInThisChunk;
|
||||
|
||||
let transferMapRed, transferMapGreen, transferMapBlue, transferMapGray;
|
||||
if (transferMaps) {
|
||||
switch (transferMaps.length) {
|
||||
case 1:
|
||||
transferMapRed = transferMaps[0];
|
||||
transferMapGreen = transferMaps[0];
|
||||
transferMapBlue = transferMaps[0];
|
||||
transferMapGray = transferMaps[0];
|
||||
break;
|
||||
case 4:
|
||||
transferMapRed = transferMaps[0];
|
||||
transferMapGreen = transferMaps[1];
|
||||
transferMapBlue = transferMaps[2];
|
||||
transferMapGray = transferMaps[3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// There are multiple forms in which the pixel data can be passed, and
|
||||
// imgData.kind tells us which one this is.
|
||||
if (imgData.kind === ImageKind.GRAYSCALE_1BPP) {
|
||||
|
@ -524,13 +543,20 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
var fullSrcDiff = (width + 7) >> 3;
|
||||
var white = 0xffffffff;
|
||||
var black = IsLittleEndianCached.value ? 0xff000000 : 0x000000ff;
|
||||
|
||||
if (transferMapGray) {
|
||||
if (transferMapGray[0] === 0xff && transferMapGray[0xff] === 0) {
|
||||
[white, black] = [black, white];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < totalChunks; i++) {
|
||||
thisChunkHeight =
|
||||
i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
|
||||
destPos = 0;
|
||||
for (j = 0; j < thisChunkHeight; j++) {
|
||||
var srcDiff = srcLength - srcPos;
|
||||
var k = 0;
|
||||
let k = 0;
|
||||
var kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7;
|
||||
var kEndUnrolled = kEnd & ~7;
|
||||
var mask = 0;
|
||||
|
@ -565,6 +591,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
}
|
||||
} else if (imgData.kind === ImageKind.RGBA_32BPP) {
|
||||
// RGBA, 32-bits per pixel.
|
||||
const hasTransferMaps = !!(
|
||||
transferMapRed ||
|
||||
transferMapGreen ||
|
||||
transferMapBlue
|
||||
);
|
||||
|
||||
j = 0;
|
||||
elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;
|
||||
|
@ -572,16 +603,51 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
|
||||
srcPos += elemsInThisChunk;
|
||||
|
||||
if (hasTransferMaps) {
|
||||
for (let k = 0; k < elemsInThisChunk; k += 4) {
|
||||
if (transferMapRed) {
|
||||
dest[k + 0] = transferMapRed[dest[k + 0]];
|
||||
}
|
||||
if (transferMapGreen) {
|
||||
dest[k + 1] = transferMapGreen[dest[k + 1]];
|
||||
}
|
||||
if (transferMapBlue) {
|
||||
dest[k + 2] = transferMapBlue[dest[k + 2]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.putImageData(chunkImgData, 0, j);
|
||||
j += FULL_CHUNK_HEIGHT;
|
||||
}
|
||||
if (i < totalChunks) {
|
||||
elemsInThisChunk = width * partialChunkHeight * 4;
|
||||
dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
|
||||
|
||||
if (hasTransferMaps) {
|
||||
for (let k = 0; k < elemsInThisChunk; k += 4) {
|
||||
if (transferMapRed) {
|
||||
dest[k + 0] = transferMapRed[dest[k + 0]];
|
||||
}
|
||||
if (transferMapGreen) {
|
||||
dest[k + 1] = transferMapGreen[dest[k + 1]];
|
||||
}
|
||||
if (transferMapBlue) {
|
||||
dest[k + 2] = transferMapBlue[dest[k + 2]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.putImageData(chunkImgData, 0, j);
|
||||
}
|
||||
} else if (imgData.kind === ImageKind.RGB_24BPP) {
|
||||
// RGB, 24-bits per pixel.
|
||||
const hasTransferMaps = !!(
|
||||
transferMapRed ||
|
||||
transferMapGreen ||
|
||||
transferMapBlue
|
||||
);
|
||||
|
||||
thisChunkHeight = FULL_CHUNK_HEIGHT;
|
||||
elemsInThisChunk = width * thisChunkHeight;
|
||||
for (i = 0; i < totalChunks; i++) {
|
||||
|
@ -597,6 +663,21 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
dest[destPos++] = src[srcPos++];
|
||||
dest[destPos++] = 255;
|
||||
}
|
||||
|
||||
if (hasTransferMaps) {
|
||||
for (let k = 0; k < destPos; k += 4) {
|
||||
if (transferMapRed) {
|
||||
dest[k + 0] = transferMapRed[dest[k + 0]];
|
||||
}
|
||||
if (transferMapGreen) {
|
||||
dest[k + 1] = transferMapGreen[dest[k + 1]];
|
||||
}
|
||||
if (transferMapBlue) {
|
||||
dest[k + 2] = transferMapBlue[dest[k + 2]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
|
||||
}
|
||||
} else {
|
||||
|
@ -1040,6 +1121,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
}
|
||||
this.tempSMask = null;
|
||||
break;
|
||||
case "TR":
|
||||
this.current.transferMaps = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2362,7 +2445,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
} else {
|
||||
tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
|
||||
var tmpCtx = tmpCanvas.context;
|
||||
putBinaryImageData(tmpCtx, imgData);
|
||||
putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
|
||||
imgToPaint = tmpCanvas.canvas;
|
||||
}
|
||||
|
||||
|
@ -2447,7 +2530,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
|
||||
var tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h);
|
||||
var tmpCtx = tmpCanvas.context;
|
||||
putBinaryImageData(tmpCtx, imgData);
|
||||
putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
|
||||
|
||||
for (var i = 0, ii = map.length; i < ii; i++) {
|
||||
var entry = map[i];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue