Skip to content

Commit

Permalink
Decompress FlatDecode images in using DecompressStream stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
calixteman committed May 24, 2024
1 parent 18a7bd6 commit 4878ce4
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 20 deletions.
12 changes: 12 additions & 0 deletions src/core/base_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ class BaseStream {
unreachable("Abstract method `getBytes` called");
}

async getImageData(_ignoreColorSpace) {
unreachable("Abstract method `getImageData` called");
}

get isAsync() {
return false;
}

get canDecodeImageFromBuffer() {
return false;
}

peekByte() {
const peekedByte = this.getByte();
if (peekedByte !== -1) {
Expand Down
18 changes: 18 additions & 0 deletions src/core/decode_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ class DecodeStream extends BaseStream {
return this.buffer.subarray(pos, end);
}

async getImageData(ignoreColorSpace = false) {
if (!this.canDecodeImageFromBuffer) {
return this.getBytes(0, ignoreColorSpace);
}
if (!this.stream.isAsync) {
return this.decodeImage(null, ignoreColorSpace);
}
let data;
try {
data = await this.stream.asyncGetBytes();
} catch {
this.reset();
return this.decodeImage(null, ignoreColorSpace);
}

return this.decodeImage(data, ignoreColorSpace);
}

reset() {
this.pos = 0;
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3405,7 +3405,7 @@ class PartialEvaluator {
});
}
break;
case OPS.beginMarkedContentProps:
/*case OPS.beginMarkedContentProps:
flushTextContentItem();
if (includeMarkedContent) {
markedContentData.level++;
Expand All @@ -3422,7 +3422,7 @@ class PartialEvaluator {
tag: args[0] instanceof Name ? args[0].name : null,
});
}
break;
break;*/
case OPS.endMarkedContent:
flushTextContentItem();
if (includeMarkedContent) {
Expand Down
32 changes: 32 additions & 0 deletions src/core/flate_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,38 @@ class FlateStream extends DecodeStream {
this.codeBuf = 0;
}

get isAsync() {
return true;
}

async asyncGetBytes() {
const ds = new DecompressionStream("deflate");
const writer = ds.writable.getWriter();
this.stream.str.reset();
const bytes = this.stream.str.getBytes();
writer.write(bytes);
writer.close();

const chunks = [];
let totalLength = 0;
const reader = ds.readable.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) {
break;
}
chunks.push(value);
totalLength += value.byteLength;
}
reader.releaseLock();
const data = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
data.set(new Uint8Array(chunk), offset);
offset += chunk.byteLength;
}
}

getBits(bits) {
const str = this.str;
let codeSize = this.codeSize;
Expand Down
29 changes: 17 additions & 12 deletions src/core/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ class PDFImage {
return output;
}

fillOpacity(rgbaBuf, width, height, actualHeight, image) {
async fillOpacity(rgbaBuf, width, height, actualHeight, image) {
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(
rgbaBuf instanceof Uint8ClampedArray,
Expand All @@ -580,7 +580,7 @@ class PDFImage {
sw = smask.width;
sh = smask.height;
alphaBuf = new Uint8ClampedArray(sw * sh);
smask.fillGrayBuffer(alphaBuf);
await smask.fillGrayBuffer(alphaBuf);
if (sw !== width || sh !== height) {
alphaBuf = resizeImageMask(alphaBuf, smask.bpc, sw, sh, width, height);
}
Expand All @@ -590,7 +590,7 @@ class PDFImage {
sh = mask.height;
alphaBuf = new Uint8ClampedArray(sw * sh);
mask.numComps = 1;
mask.fillGrayBuffer(alphaBuf);
await mask.fillGrayBuffer(alphaBuf);

// Need to invert values in rgbaBuf
for (i = 0, ii = sw * sh; i < ii; ++i) {
Expand Down Expand Up @@ -716,7 +716,7 @@ class PDFImage {
drawWidth === originalWidth &&
drawHeight === originalHeight
) {
const data = this.getImageBytes(originalHeight * rowBytes, {});
const data = await this.getImageBytes(originalHeight * rowBytes, {});
if (isOffscreenCanvasSupported) {
if (mustBeResized) {
return ImageResizer.createImage(
Expand Down Expand Up @@ -774,7 +774,7 @@ class PDFImage {
}

if (isHandled) {
const rgba = this.getImageBytes(imageLength, {
const rgba = await this.getImageBytes(imageLength, {
drawWidth,
drawHeight,
forceRGBA: true,
Expand All @@ -794,7 +794,7 @@ class PDFImage {
case "DeviceRGB":
case "DeviceCMYK":
imgData.kind = ImageKind.RGB_24BPP;
imgData.data = this.getImageBytes(imageLength, {
imgData.data = await this.getImageBytes(imageLength, {
drawWidth,
drawHeight,
forceRGB: true,
Expand All @@ -809,7 +809,7 @@ class PDFImage {
}
}

const imgArray = this.getImageBytes(originalHeight * rowBytes, {
const imgArray = await this.getImageBytes(originalHeight * rowBytes, {
internal: true,
});
// imgArray can be incomplete (e.g. after CCITT fax encoding).
Expand Down Expand Up @@ -852,7 +852,7 @@ class PDFImage {
maybeUndoPreblend = true;

// Color key masking (opacity) must be performed before decoding.
this.fillOpacity(data, drawWidth, drawHeight, actualHeight, comps);
await this.fillOpacity(data, drawWidth, drawHeight, actualHeight, comps);
}

if (this.needsDecode) {
Expand Down Expand Up @@ -893,7 +893,7 @@ class PDFImage {
return imgData;
}

fillGrayBuffer(buffer) {
async fillGrayBuffer(buffer) {
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(
buffer instanceof Uint8ClampedArray,
Expand All @@ -913,7 +913,9 @@ class PDFImage {

// rows start at byte boundary
const rowBytes = (width * numComps * bpc + 7) >> 3;
const imgArray = this.getImageBytes(height * rowBytes, { internal: true });
const imgArray = await this.getImageBytes(height * rowBytes, {
internal: true,
});

const comps = this.getComponents(imgArray);
let i, length;
Expand Down Expand Up @@ -975,7 +977,7 @@ class PDFImage {
};
}

getImageBytes(
async getImageBytes(
length,
{
drawWidth,
Expand All @@ -990,7 +992,10 @@ class PDFImage {
this.image.drawHeight = drawHeight || this.height;
this.image.forceRGBA = !!forceRGBA;
this.image.forceRGB = !!forceRGB;
const imageBytes = this.image.getBytes(length, this.ignoreColorSpace);
const imageBytes = await this.image.getImageData(
length,
this.ignoreColorSpace
);

// If imageBytes came from a DecodeStream, we're safe to transfer it
// (and thus detach its underlying buffer) because it will constitute
Expand Down
17 changes: 15 additions & 2 deletions src/core/jbig2_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,15 @@ class Jbig2Stream extends DecodeStream {
}

readBlock() {
return this.decodeImage();
}

decodeImage(bytes) {
if (this.eof) {
return;
return this.buffer;
}
if (!bytes) {
bytes = this.bytes;
}
const jbig2Image = new Jbig2Image();

Expand All @@ -57,7 +64,7 @@ class Jbig2Stream extends DecodeStream {
chunks.push({ data: globals, start: 0, end: globals.length });
}
}
chunks.push({ data: this.bytes, start: 0, end: this.bytes.length });
chunks.push({ data: bytes, start: 0, end: bytes.length });
const data = jbig2Image.parseChunks(chunks);
const dataLength = data.length;

Expand All @@ -68,6 +75,12 @@ class Jbig2Stream extends DecodeStream {
this.buffer = data;
this.bufferLength = dataLength;
this.eof = true;

return this.buffer;
}

get canDecodeImageFromBuffer() {
return true;
}
}

Expand Down
17 changes: 15 additions & 2 deletions src/core/jpeg_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,15 @@ class JpegStream extends DecodeStream {
}

readBlock() {
return this.decodeImage();
}

decodeImage(bytes) {
if (this.eof) {
return;
return this.buffer;
}
if (!bytes) {
bytes = this.bytes;
}
const jpegOptions = {
decodeTransform: undefined,
Expand Down Expand Up @@ -89,7 +96,7 @@ class JpegStream extends DecodeStream {
}
const jpegImage = new JpegImage(jpegOptions);

jpegImage.parse(this.bytes);
jpegImage.parse(bytes);
const data = jpegImage.getData({
width: this.drawWidth,
height: this.drawHeight,
Expand All @@ -100,6 +107,12 @@ class JpegStream extends DecodeStream {
this.buffer = data;
this.bufferLength = data.length;
this.eof = true;

return this.buffer;
}

get canDecodeImageFromBuffer() {
return true;
}
}

Expand Down
16 changes: 14 additions & 2 deletions src/core/jpx_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,25 @@ class JpxStream extends DecodeStream {
}

readBlock(ignoreColorSpace) {
return this.decodeImage(null, ignoreColorSpace);
}

decodeImage(bytes, ignoreColorSpace) {
if (this.eof) {
return;
return this.buffer;
}
if (!bytes) {
bytes = this.bytes;

Check warning

Code scanning / CodeQL

Useless assignment to local variable Warning

The value assigned to bytes here is unused.
}

this.buffer = JpxImage.decode(this.bytes, ignoreColorSpace);
this.bufferLength = this.buffer.length;
this.eof = true;

return this.buffer;
}

get canDecodeImageFromBuffer() {
return true;
}
}

Expand Down

0 comments on commit 4878ce4

Please sign in to comment.