diff --git a/examples/forge-functionality/api_examples.js b/examples/forge-functionality/api_examples.js index fcbee6094..955c0205b 100644 --- a/examples/forge-functionality/api_examples.js +++ b/examples/forge-functionality/api_examples.js @@ -24,8 +24,9 @@ const loadingTask = getDocument({ try { const pdfDocument = await loadingTask.promise; console.log("# PDF document loaded."); - const table = await pdfDocument.getStreamAsString("/Page2/Contents/0/Data"); - console.log(table); + const page = await pdfDocument.getPage(1); + const opList = await page.getOperatorList(); + console.log(opList); } catch (e) { console.error(e); } diff --git a/examples/forge-functionality/fetch_primitives.js b/examples/forge-functionality/fetch_primitives.js index 4d2d32e0d..78e751894 100644 --- a/examples/forge-functionality/fetch_primitives.js +++ b/examples/forge-functionality/fetch_primitives.js @@ -1,9 +1,13 @@ +import { EvaluatorPreprocessor } from "../../src/core/evaluator.js"; import { getImageAsBlob, getPrim, + getPrimitive, getPrimTree, getStreamAsString, } from "../../src/core/obj_walker.js"; +import { Lexer, Parser } from "../../src/core/parser.js"; +import { EOF } from "../../src/core/primitives.js"; import fs from "fs"; import { PDFDocument } from "../../src/core/document.js"; import { Stream } from "../../src/core/stream.js"; @@ -32,12 +36,58 @@ fs.readFile(filePath, (err, data) => { } }); +function bytesToString(bytes) { + let string = ""; + for (let i = 0; i < bytes.length; i++) { + string += String.fromCharCode(bytes[i]); + } + return string; +} + async function parse(doc) { + const path = "/Page2/Contents/2"; + let [stream] = await getPrimitive(path, doc); + const lexer = new Lexer(stream); + const parser = new Parser({ lexer, xref: doc.xref, trackRanges: true }); + const objs = []; + let [obj, start, end] = parser.getObjWithRange(); + while (obj !== EOF) { + if (obj.cmd) { + objs.push([obj.cmd, start, end]); + } else { + objs.push([obj, start, end]); + } + [obj, start, end] = parser.getObjWithRange(); + } + [stream] = await getPrimitive(path, doc); + const bytes = stream.getBytes(); + const classes = new Set(); + for (const o of objs) { + console.log(o[0].constructor.name); + classes.add(o[0].constructor.name); + const lexemmeBytes = bytes.slice(o[1], o[2]); + console.log(bytesToString(lexemmeBytes)); + } + console.log("unique classes", classes); + [stream] = await getPrimitive(path, doc); + const preprocessor = new EvaluatorPreprocessor(stream, doc.xref); + const operation = {}; + operation.args = null; + while (preprocessor.read(operation)) { + const args = operation.args; + const fn = operation.fn; + const range = operation.range; + const op = bytesToString(bytes.slice(range[0], range[1])); + console.log(args, fn); + console.log(`${range[0]}------------------------------------`); + console.log(op); + console.log(`${range[1]}------------------------------------`); + } // console.time("xref"); // let table = await retrieveXref(doc); // console.timeEnd("xref"); // console.time("get prim"); - // const prim = await getPrim("/Page2/Resources/XObject/Im0/Length", doc); + // const prim = await getPrim("/Trailer/Root/Names/Dests/Names/1", doc); // console.timeEnd("get prim"); // console.log(prim); // const request = { @@ -55,20 +105,40 @@ async function parse(doc) { // const tree = await getPrimTree([request], doc); // console.timeEnd("get tree"); // logTree(tree); - console.time("string"); - const string = await getStreamAsString("/Page2/Contents/0/Data", doc); - console.timeEnd("string"); - console.log(string); - // const handler = { send: undefined }; + // console.time("string"); + // const string = await getStreamAsString("/Page2/Contents/0/Data", doc); + // console.timeEnd("string"); + // console.log(string); // console.time("image"); // // const image = await getStreamAsImage("/Page2/Contents/2/Data", doc); - // const image = await getImageAsBlob( + // const blob = await getImageAsBlob( // "/Page2/Resources/XObject/Im0/Data", - // doc, - // handler + // doc // ); // console.timeEnd("image"); - // console.log(image); + // console.log(blob); + // saveBlobToFile(blob, "image.png"); +} + +async function saveBlobToFile(blob, imagePath) { + const buffer = await blobToBuffer(blob); + + fs.writeFile(imagePath, buffer, err => { + if (err) { + console.error("Error saving file:", err); + } else { + console.log("File saved successfully!"); + } + }); +} + +function blobToBuffer(blob) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onloadend = () => resolve(Buffer.from(reader.result)); + reader.onerror = reject; + reader.readAsArrayBuffer(blob); + }); } function logTree(tree) { diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 2f9e6897e..08737beb5 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -177,11 +177,17 @@ function normalizeBlendMode(value, parsingArray = false) { return "source-over"; } -function addLocallyCachedImageOps(opList, data) { +function addLocallyCachedImageOps(opList, data, range) { if (data.objId) { opList.addDependency(data.objId); } - opList.addImageOps(data.fn, data.args, data.optionalContent, data.hasMask); + opList.addImageOps( + data.fn, + data.args, + range, + data.optionalContent, + data.hasMask + ); if (data.fn === OPS.paintImageMaskXObject && data.args[0]?.count > 0) { data.args[0].count++; @@ -455,7 +461,8 @@ class PartialEvaluator { operatorList, task, initialState, - localColorSpaceCache + localColorSpaceCache, + range = null ) { const dict = xobj.dict; const matrix = lookupMatrix(dict.getArray("Matrix"), null); @@ -469,7 +476,11 @@ class PartialEvaluator { ); } if (optionalContent !== undefined) { - operatorList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]); + operatorList.addOp( + OPS.beginMarkedContentProps, + ["OC", optionalContent], + range + ); } const group = dict.get("Group"); if (group) { @@ -511,14 +522,14 @@ class PartialEvaluator { smask.backdrop = colorSpace.getRgb(smask.backdrop, 0); } - operatorList.addOp(OPS.beginGroup, [groupOptions]); + operatorList.addOp(OPS.beginGroup, [groupOptions], range); } // If it's a group, a new canvas will be created that is the size of the // bounding box and translated to the correct position so we don't need to // apply the bounding box to it. const args = group ? [matrix, null] : [matrix, bbox]; - operatorList.addOp(OPS.paintFormXObjectBegin, args); + operatorList.addOp(OPS.paintFormXObjectBegin, args, range); await this.getOperatorList({ stream: xobj, @@ -527,14 +538,14 @@ class PartialEvaluator { operatorList, initialState, }); - operatorList.addOp(OPS.paintFormXObjectEnd, []); + operatorList.addOp(OPS.paintFormXObjectEnd, [], range); if (group) { - operatorList.addOp(OPS.endGroup, [groupOptions]); + operatorList.addOp(OPS.endGroup, [groupOptions], range); } if (optionalContent !== undefined) { - operatorList.addOp(OPS.endMarkedContent, []); + operatorList.addOp(OPS.endMarkedContent, [], range); } } @@ -569,6 +580,7 @@ class PartialEvaluator { cacheKey, localImageCache, localColorSpaceCache, + range, }) { const dict = image.dict; const imageRef = dict.objId; @@ -627,6 +639,7 @@ class PartialEvaluator { operatorList.addImageOps( OPS.paintImageMaskXObject, args, + range, optionalContent ); @@ -899,7 +912,8 @@ class PartialEvaluator { operatorList, task, stateManager, - localColorSpaceCache + localColorSpaceCache, + range ) { const smaskContent = smask.get("G"); const smaskOptions = { @@ -929,7 +943,8 @@ class PartialEvaluator { operatorList, task, stateManager.state.clone(), - localColorSpaceCache + localColorSpaceCache, + range ); } @@ -1013,7 +1028,7 @@ class PartialEvaluator { // Add the dependencies to the parent operator list so they are // resolved before the sub operator list is executed synchronously. operatorList.addDependencies(tilingOpList.dependencies); - operatorList.addOp(fn, tilingPatternIR); + operatorList.addOp(fn, tilingPatternIR, range); if (patternDict.objId) { localTilingPatternCache.set(/* name = */ null, patternDict.objId, { @@ -1124,6 +1139,7 @@ class PartialEvaluator { stateManager, localGStateCache, localColorSpaceCache, + range, }) { const gStateRef = gState.objId; let isSimpleGState = true; @@ -1180,7 +1196,8 @@ class PartialEvaluator { operatorList, task, stateManager, - localColorSpaceCache + localColorSpaceCache, + range ) ); gStateObj.push([key, true]); @@ -1218,7 +1235,7 @@ class PartialEvaluator { await promise; if (gStateObj.length > 0) { - operatorList.addOp(OPS.setGState, [gStateObj]); + operatorList.addOp(OPS.setGState, [gStateObj], range); } if (isSimpleGState) { @@ -1387,7 +1404,7 @@ class PartialEvaluator { return promise; } - buildPath(operatorList, fn, args, parsingText = false) { + buildPath(operatorList, fn, args, parsingText = false, range = null) { const lastIndex = operatorList.length - 1; if (!args) { args = []; @@ -1405,7 +1422,7 @@ class PartialEvaluator { // *extremely* rare that shouldn't really matter much in practice. if (parsingText) { warn(`Encountered path operator "${fn}" inside of a text object.`); - operatorList.addOp(OPS.save, null); + operatorList.addOp(OPS.save, null, range); } let minMax; @@ -1428,10 +1445,10 @@ class PartialEvaluator { minMax = [Infinity, Infinity, -Infinity, -Infinity]; break; } - operatorList.addOp(OPS.constructPath, [[fn], args, minMax]); + operatorList.addOp(OPS.constructPath, [[fn], args, minMax], range); if (parsingText) { - operatorList.addOp(OPS.restore, null); + operatorList.addOp(OPS.restore, null, range); } } else { const opArgs = operatorList.argsArray[lastIndex]; @@ -1439,6 +1456,9 @@ class PartialEvaluator { opArgs[1].push(...args); const minMax = opArgs[2]; + const opRange = operatorList.rangeArray[lastIndex]; + opRange[1] = range[1]; + // Compute min/max in the worker instead of the main thread. // If the current matrix (when drawing) is a scaling one // then min/max can be easily computed in using those values. @@ -1543,7 +1563,8 @@ class PartialEvaluator { task, localColorSpaceCache, localTilingPatternCache, - localShadingPatternCache + localShadingPatternCache, + range ) { // compile tiling patterns const patternName = args.pop(); @@ -1562,7 +1583,7 @@ class PartialEvaluator { localTilingPattern.dict, color ); - operatorList.addOp(fn, tilingPatternIR); + operatorList.addOp(fn, tilingPatternIR, range); return undefined; } catch { // Handle any errors during normal TilingPattern parsing. @@ -1596,7 +1617,7 @@ class PartialEvaluator { }); if (objId) { const matrix = lookupMatrix(dict.getArray("Matrix"), null); - operatorList.addOp(fn, ["Shading", objId, matrix]); + operatorList.addOp(fn, ["Shading", objId, matrix], range); } return undefined; } @@ -1771,6 +1792,7 @@ class PartialEvaluator { } let args = operation.args; let fn = operation.fn; + const range = operation.range; switch (fn | 0) { case OPS.paintXObject: @@ -1781,7 +1803,7 @@ class PartialEvaluator { if (isValidName) { const localImage = localImageCache.getByName(name); if (localImage) { - addLocallyCachedImageOps(operatorList, localImage); + addLocallyCachedImageOps(operatorList, localImage, range); args = null; continue; } @@ -1859,6 +1881,7 @@ class PartialEvaluator { cacheKey: name, localImageCache, localColorSpaceCache, + range, }) .then(resolveXObject, rejectXObject); return; @@ -1900,7 +1923,11 @@ class PartialEvaluator { ) .then(function (loadedName) { operatorList.addDependency(loadedName); - operatorList.addOp(OPS.setFont, [loadedName, fontSize]); + operatorList.addOp( + OPS.setFont, + [loadedName, fontSize], + range + ); }) ); return; @@ -1929,6 +1956,7 @@ class PartialEvaluator { cacheKey, localImageCache, localColorSpaceCache, + range, }) ); return; @@ -1961,7 +1989,7 @@ class PartialEvaluator { self.ensureStateFont(stateManager.state); continue; } - operatorList.addOp(OPS.nextLine); + operatorList.addOp(OPS.nextLine, null, range); args[0] = self.handleText(args[0], stateManager.state); fn = OPS.showText; break; @@ -1970,9 +1998,9 @@ class PartialEvaluator { self.ensureStateFont(stateManager.state); continue; } - operatorList.addOp(OPS.nextLine); - operatorList.addOp(OPS.setWordSpacing, [args.shift()]); - operatorList.addOp(OPS.setCharSpacing, [args.shift()]); + operatorList.addOp(OPS.nextLine, null, range); + operatorList.addOp(OPS.setWordSpacing, [args.shift()], range); + operatorList.addOp(OPS.setCharSpacing, [args.shift()], range); args[0] = self.handleText(args[0], stateManager.state); fn = OPS.showText; break; @@ -2092,7 +2120,8 @@ class PartialEvaluator { task, localColorSpaceCache, localTilingPatternCache, - localShadingPatternCache + localShadingPatternCache, + range ) ); return; @@ -2124,7 +2153,8 @@ class PartialEvaluator { task, localColorSpaceCache, localTilingPatternCache, - localShadingPatternCache + localShadingPatternCache, + range ) ); return; @@ -2175,7 +2205,7 @@ class PartialEvaluator { const localGStateObj = localGStateCache.getByName(name); if (localGStateObj) { if (localGStateObj.length > 0) { - operatorList.addOp(OPS.setGState, [localGStateObj]); + operatorList.addOp(OPS.setGState, [localGStateObj], range); } args = null; continue; @@ -2211,6 +2241,7 @@ class PartialEvaluator { stateManager, localGStateCache, localColorSpaceCache, + range, }) .then(resolveGState, rejectGState); }).catch(function (reason) { @@ -2232,7 +2263,7 @@ class PartialEvaluator { case OPS.curveTo3: case OPS.closePath: case OPS.rectangle: - self.buildPath(operatorList, fn, args, parsingText); + self.buildPath(operatorList, fn, args, parsingText, range); continue; case OPS.markPoint: case OPS.markPointProps: @@ -2248,7 +2279,11 @@ class PartialEvaluator { case OPS.beginMarkedContentProps: if (!(args[0] instanceof Name)) { warn(`Expected name for beginMarkedContentProps arg0=${args[0]}`); - operatorList.addOp(OPS.beginMarkedContentProps, ["OC", null]); + operatorList.addOp( + OPS.beginMarkedContentProps, + ["OC", null], + range + ); continue; } if (args[0].name === "OC") { @@ -2256,10 +2291,11 @@ class PartialEvaluator { self .parseMarkedContentProps(args[1], resources) .then(data => { - operatorList.addOp(OPS.beginMarkedContentProps, [ - "OC", - data, - ]); + operatorList.addOp( + OPS.beginMarkedContentProps, + ["OC", data], + range + ); }) .catch(reason => { if (reason instanceof AbortException) { @@ -2269,10 +2305,11 @@ class PartialEvaluator { warn( `getOperatorList - ignoring beginMarkedContentProps: "${reason}".` ); - operatorList.addOp(OPS.beginMarkedContentProps, [ - "OC", - null, - ]); + operatorList.addOp( + OPS.beginMarkedContentProps, + ["OC", null], + range + ); return; } throw reason; @@ -2305,7 +2342,7 @@ class PartialEvaluator { } } } - operatorList.addOp(fn, args); + operatorList.addOp(fn, args, range); } if (stop) { next(deferred); @@ -5101,6 +5138,7 @@ class EvaluatorPreprocessor { // avoiding allocations where possible is worthwhile. // read(operation) { + const start = this.parser.getPosition(); let args = operation.args; while (true) { const obj = this.parser.getObj(); @@ -5177,6 +5215,8 @@ class EvaluatorPreprocessor { operation.fn = fn; operation.args = args; + const end = this.parser.getPosition(); + operation.range = [start, end]; return true; } if (obj === EOF) { diff --git a/src/core/obj_walker.js b/src/core/obj_walker.js index 2e7dcf0c5..d990f1db9 100644 --- a/src/core/obj_walker.js +++ b/src/core/obj_walker.js @@ -47,8 +47,7 @@ async function getImageAsBlob(path, doc) { pdfFunctionFactory, localColorSpaceCache: new LocalColorSpaceCache(), }); - const imageData = await pdfImage.createImageData(true, false); - return new Blob([imageData.data], { type: "image/png" }); + return pdfImage.createImageData(true, false); } async function getPrimitive(path, doc) { @@ -254,6 +253,8 @@ function toType(prim) { return ["String", "-"]; } else if (isRef(prim)) { return ["Reference", "-"]; + } else if (prim === null) { + return ["Null", "-"]; } throw new Error("Unknown prim"); } @@ -305,6 +306,8 @@ function primToString(prim) { return prim; } else if (isRef(prim)) { return "XRef(" + prim.num + ", " + prim.gen + ")"; + } else if (prim === null) { + return "Null"; } throw new Error("Unknown prim"); } @@ -376,5 +379,6 @@ export { getPrimTree, getStreamAsString, PrimitiveModel, + toType, TreeViewModel, }; diff --git a/src/core/operator_list.js b/src/core/operator_list.js index 1212e6e93..a33ea02c0 100644 --- a/src/core/operator_list.js +++ b/src/core/operator_list.js @@ -477,9 +477,10 @@ class NullOptimizer { _optimize() {} - push(fn, args) { + push(fn, args, range) { this.queue.fnArray.push(fn); this.queue.argsArray.push(args); + this.queue.rangeArray.push(range); this._optimize(); } @@ -589,6 +590,7 @@ class OperatorList { this._streamSink = streamSink; this.fnArray = []; this.argsArray = []; + this.rangeArray = []; this.optimizer = streamSink && !(intent & RenderingIntentFlag.OPLIST) ? new QueueOptimizer(this) @@ -620,8 +622,8 @@ class OperatorList { return this._totalLength + this.length; } - addOp(fn, args) { - this.optimizer.push(fn, args); + addOp(fn, args, range = null) { + this.optimizer.push(fn, args, range); this.weight++; if (this._streamSink) { if (this.weight >= OperatorList.CHUNK_SIZE) { @@ -636,7 +638,7 @@ class OperatorList { } } - addImageOps(fn, args, optionalContent, hasMask = false) { + addImageOps(fn, args, range, optionalContent, hasMask = false) { if (hasMask) { this.addOp(OPS.save); this.addOp(OPS.setGState, [[["SMask", false]]]); @@ -645,7 +647,7 @@ class OperatorList { this.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]); } - this.addOp(fn, args); + this.addOp(fn, args, range); if (optionalContent !== undefined) { this.addOp(OPS.endMarkedContent, []); @@ -678,7 +680,7 @@ class OperatorList { this.dependencies.add(dependency); } for (let i = 0, ii = opList.length; i < ii; i++) { - this.addOp(opList.fnArray[i], opList.argsArray[i]); + this.addOp(opList.fnArray[i], opList.argsArray[i], opList.rangeArray[i]); } } @@ -686,6 +688,7 @@ class OperatorList { return { fnArray: this.fnArray, argsArray: this.argsArray, + rangeArray: this.rangeArray, length: this.length, }; } @@ -717,6 +720,7 @@ class OperatorList { { fnArray: this.fnArray, argsArray: this.argsArray, + rangeArray: this.rangeArray, lastChunk, separateAnnots, length, @@ -728,6 +732,7 @@ class OperatorList { this.dependencies.clear(); this.fnArray.length = 0; this.argsArray.length = 0; + this.rangeArray.length = 0; this.weight = 0; this.optimizer.reset(); } diff --git a/src/core/parser.js b/src/core/parser.js index 50ea563db..8db773a96 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -59,26 +59,51 @@ function getInlineImageCacheKey(bytes) { } class Parser { - constructor({ lexer, xref, allowStreams = false, recoveryMode = false }) { + constructor({ + lexer, + xref, + allowStreams = false, + recoveryMode = false, + trackRanges = true, + }) { this.lexer = lexer; this.xref = xref; this.allowStreams = allowStreams; this.recoveryMode = recoveryMode; - + this.withRange = trackRanges; this.imageCache = Object.create(null); this._imageId = 0; this.refill(); } refill() { - this.buf1 = this.lexer.getObj(); - this.buf2 = this.lexer.getObj(); + if (this.withRange) { + const [buf1, start1, end1] = this.lexer.getObjWithRange(); + const [buf2, start2, end2] = this.lexer.getObjWithRange(); + this.buf1 = buf1; + this.range1 = [start1, end1]; + this.buf2 = buf2; + this.range2 = [start2, end2]; + } else { + this.buf1 = this.lexer.getObj(); + this.buf2 = this.lexer.getObj(); + } } shift() { if (this.buf2 instanceof Cmd && this.buf2.cmd === "ID") { this.buf1 = this.buf2; this.buf2 = null; + if (this.withRange) { + this.range1 = this.range2; + this.range2 = null; + } + } else if (this.withRange) { + this.buf1 = this.buf2; + this.range1 = this.range2; + const [buf2, start2, end2] = this.lexer.getObjWithRange(); + this.buf2 = buf2; + this.range2 = [start2, end2]; } else { this.buf1 = this.buf2; this.buf2 = this.lexer.getObj(); @@ -99,6 +124,17 @@ class Parser { } } + getPosition() { + return this.range1 ? this.range1[0] : 0; + } + + getObjWithRange(cipherTransform = null) { + const start = this.range1[0]; + const obj = this.getObj(cipherTransform); + const end = this.range1[0]; + return [obj, start, end]; + } + getObj(cipherTransform = null) { const buf1 = this.buf1; this.shift(); @@ -1204,6 +1240,14 @@ class Lexer { return strBuf.join(""); } + getObjWithRange() { + // at the start of getObj() the stream has stepped beyond currentChar by one + const start = this.stream.pos - 1; + const obj = this.getObj(); + const end = this.stream.pos; + return [obj, start, end]; + } + getObj() { // Skip whitespace and comments. let comment = false; diff --git a/src/core/retrieve_xref.js b/src/core/retrieve_xref.js index 59ef2ef14..681b15272 100644 --- a/src/core/retrieve_xref.js +++ b/src/core/retrieve_xref.js @@ -1,8 +1,8 @@ -import {Dict, Ref} from "./primitives.js"; -import {BaseStream} from "./base_stream.js"; +import { Ref } from "./primitives.js"; +import { toType } from "./obj_walker.js"; async function retrieveXref(doc) { - let result = new XRefTable(doc.xref.entries.length); + const result = new XRefTable(doc.xref.entries.length); for (let i = 0; i < doc.xref.entries.length; i++) { result.entries.push(to_model(i, doc.xref.entries[i], doc.xref)); } @@ -13,13 +13,8 @@ function to_model(i, entry, xref) { if (entry.free) { return new XRefEntry("Free", i, entry.gen, entry.offset); } - const fetched = xref.fetch(new Ref(i, entry.gen)); - let type = "Unknown"; - if (fetched instanceof Dict) { - type = "Dictionary"; - } else if (fetched instanceof BaseStream) { - type = "Stream"; - } + const fetched = xref.fetch(Ref.get(i, entry.gen)); + const [type] = toType(fetched); return new XRefEntry(type, i, entry.gen, entry.offset); } @@ -39,4 +34,4 @@ class XRefEntry { } } -export { XRefEntry, XRefTable, retrieveXref }; +export { retrieveXref, XRefEntry, XRefTable }; diff --git a/src/core/worker.js b/src/core/worker.js index 3f28b56f5..925f648cc 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -503,7 +503,7 @@ class WorkerMessageHandler { return getPrimTree(request, pdfManager.pdfDocument); }); - handler.on("GetImageAsBlob", function (path) { + handler.on("GetImageData", function (path) { return getImageAsBlob(path, pdfManager.pdfDocument); }); diff --git a/src/display/api.js b/src/display/api.js index 3695da3e4..b84a02434 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -1133,11 +1133,11 @@ class PDFDocumentProxy { } /** - * @returns {Promise} A promise that is resolved to a blob representing - * the image as png. + * @returns {Promise} A promise that is resolved to ImageData. + * Throws an Error if the path does not lead to an image! */ - getImageByPath(path) { - return this._transport.getImageAsBlob(path); + getImageDataByPath(path) { + return this._transport.getImageDataByPath(path); } /** @@ -1705,6 +1705,7 @@ class PDFPageProxy { intentState.operatorList = { fnArray: [], argsArray: [], + rangeArray: [], lastChunk: false, separateAnnots: null, }; @@ -1882,6 +1883,11 @@ class PDFPageProxy { for (let i = 0, ii = operatorListChunk.length; i < ii; i++) { intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]); intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]); + if (intentState.operatorList.rangeArray) { + intentState.operatorList.rangeArray.push( + operatorListChunk.rangeArray[i] + ); + } } intentState.operatorList.lastChunk = operatorListChunk.lastChunk; intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots; @@ -2956,8 +2962,8 @@ class WorkerTransport { return this.messageHandler.sendWithPromise("GetPrimTree", request); } - getImageAsBlob(path) { - return this.messageHandler.sendWithPromise("GetImageAsBlob", path); + getImageDataByPath(path) { + return this.messageHandler.sendWithPromise("GetImageData", path); } getStreamAsString(path) {