mirror of
https://gitee.com/Donal/ofd.js.git
synced 2024-11-29 18:38:55 +08:00
采用pdf.js的代码实现jbig2的解析编码
This commit is contained in:
parent
3b77d648b5
commit
bd83513e5f
@ -16,7 +16,8 @@
|
||||
"jszip": "^3.5.0",
|
||||
"jszip-utils": "^0.1.0",
|
||||
"vue": "^2.6.11",
|
||||
"xml-js": "^1.6.11"
|
||||
"xml-js": "^1.6.11",
|
||||
"web-streams-polyfill": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
<script>
|
||||
import JsZip from 'jszip'
|
||||
import {Jbig2Image} from '../utils/jbig2'
|
||||
import {pipeline} from "../utils/pipeline"
|
||||
import { converterDpi, convertPathAbbreviatedDatatoPoint, calPathPoint, calTextPoint} from "../utils/point_cal_util"
|
||||
let parser = require('fast-xml-parser');
|
||||
@ -138,28 +139,60 @@ export default {
|
||||
drawImageObject(imageObject, pageId) {
|
||||
const boundary = this.parseStBox(imageObject['@_Boundary']);
|
||||
const resId = imageObject['@_ResourceID'];
|
||||
let div = document.createElement('div');
|
||||
div.style.width = boundary.w;
|
||||
div.style.height = boundary.h;
|
||||
let img = document.createElement('img');
|
||||
img.src = this.multiMediaResObj[resId];
|
||||
img.setAttribute('width', boundary.w);
|
||||
img.setAttribute('height', boundary.h);
|
||||
div.appendChild(img);
|
||||
var mycanvas = document.getElementById(pageId)
|
||||
var a = setInterval(() => {
|
||||
mycanvas = document.getElementById(pageId)
|
||||
if (!mycanvas) {
|
||||
return false
|
||||
} else {
|
||||
clearInterval(a)
|
||||
div.setAttribute('style', `left: ${boundary.x}px; top: ${boundary.y}px`)
|
||||
div.style.left = boundary.x;
|
||||
div.style.top = boundary.y;
|
||||
div.style.position = 'absolute';
|
||||
mycanvas.appendChild(div);
|
||||
if (this.multiMediaResObj[resId].format === 'gbig2') {
|
||||
const img = this.multiMediaResObj[resId].img;
|
||||
const width = this.multiMediaResObj[resId].width;
|
||||
const height = this.multiMediaResObj[resId].height;
|
||||
const arr = new Uint8ClampedArray(4*width*height);
|
||||
for(var i = 0; i < img.length; i++) {
|
||||
arr[4*i] = img[i];
|
||||
arr[4*i + 1] = img[i];
|
||||
arr[4*i + 2] = img[i];
|
||||
arr[4*i + 3] = 255;
|
||||
}
|
||||
}, 1)
|
||||
let imageData = new ImageData(arr, width, height);
|
||||
let canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
let context = canvas.getContext('2d');
|
||||
context.putImageData(imageData, 0, 0);
|
||||
var mycanvas = document.getElementById(pageId)
|
||||
var a = setInterval(() => {
|
||||
mycanvas = document.getElementById(pageId)
|
||||
if (!mycanvas) {
|
||||
return false
|
||||
} else {
|
||||
clearInterval(a)
|
||||
canvas.setAttribute('style', `left: ${boundary.x}px; top: ${boundary.y}px; width: ${boundary.w}px; height: ${boundary.h}px`)
|
||||
canvas.style.position = 'absolute';
|
||||
mycanvas.appendChild(canvas);
|
||||
}
|
||||
}, 1)
|
||||
} else {
|
||||
let div = document.createElement('div');
|
||||
div.style.width = boundary.w;
|
||||
div.style.height = boundary.h;
|
||||
let img = document.createElement('img');
|
||||
img.src = this.multiMediaResObj[resId].img;
|
||||
img.setAttribute('width', boundary.w);
|
||||
img.setAttribute('height', boundary.h);
|
||||
div.appendChild(img);
|
||||
var mycanvas = document.getElementById(pageId)
|
||||
var a = setInterval(() => {
|
||||
mycanvas = document.getElementById(pageId)
|
||||
if (!mycanvas) {
|
||||
return false
|
||||
} else {
|
||||
clearInterval(a)
|
||||
div.setAttribute('style', `left: ${boundary.x}px; top: ${boundary.y}px`)
|
||||
div.style.left = boundary.x;
|
||||
div.style.top = boundary.y;
|
||||
div.style.position = 'absolute';
|
||||
mycanvas.appendChild(div);
|
||||
}
|
||||
}, 1)
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
drawTextObject(textObject, pageId, defaultFillColor, defaultStrokeColor, stampAnnotBoundary) {
|
||||
@ -472,8 +505,13 @@ export default {
|
||||
file = `${this.doc}/${file}`
|
||||
}
|
||||
if (item['@_Type'].toLowerCase() === 'image') {
|
||||
const img = await this.getImageFromZip(file);
|
||||
this.multiMediaResObj[item['@_ID']] = img;
|
||||
if (item['@_Format'].toLowerCase() === 'gbig2') {
|
||||
const jbig2 = await this.getImageArrayFromZip(file);
|
||||
this.multiMediaResObj[item['@_ID']] = jbig2;
|
||||
} else {
|
||||
const img = await this.getImageFromZip(file);
|
||||
this.multiMediaResObj[item['@_ID']] = {img, 'format': 'png'};
|
||||
}
|
||||
} else {
|
||||
this.multiMediaResObj[item['@_ID']] = file;
|
||||
}
|
||||
@ -533,6 +571,19 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
async getImageArrayFromZip(name) {
|
||||
let that = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
that.zipObj.files[name].async('uint8array').then(function (bytes) {
|
||||
let jbig2 = new Jbig2Image();
|
||||
const img = jbig2.parse(bytes);
|
||||
resolve({img, width: jbig2.width, height: jbig2.height, format: 'gbig2'});
|
||||
}, function error(e) {
|
||||
reject(e);
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
async getImageFromZip(name) {
|
||||
let that = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
|
183
src/utils/arithmetic_decoder.js
Normal file
183
src/utils/arithmetic_decoder.js
Normal file
@ -0,0 +1,183 @@
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
// Table C-2
|
||||
const QeTable = [
|
||||
{ qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1 },
|
||||
{ qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0 },
|
||||
{ qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0 },
|
||||
{ qe: 0x0ac1, nmps: 4, nlps: 12, switchFlag: 0 },
|
||||
{ qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0 },
|
||||
{ qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0 },
|
||||
{ qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1 },
|
||||
{ qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0 },
|
||||
{ qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0 },
|
||||
{ qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0 },
|
||||
{ qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0 },
|
||||
{ qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0 },
|
||||
{ qe: 0x1c01, nmps: 13, nlps: 20, switchFlag: 0 },
|
||||
{ qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0 },
|
||||
{ qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1 },
|
||||
{ qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0 },
|
||||
{ qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0 },
|
||||
{ qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0 },
|
||||
{ qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0 },
|
||||
{ qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0 },
|
||||
{ qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0 },
|
||||
{ qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0 },
|
||||
{ qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0 },
|
||||
{ qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0 },
|
||||
{ qe: 0x1c01, nmps: 25, nlps: 22, switchFlag: 0 },
|
||||
{ qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0 },
|
||||
{ qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0 },
|
||||
{ qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0 },
|
||||
{ qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0 },
|
||||
{ qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0 },
|
||||
{ qe: 0x0ac1, nmps: 31, nlps: 28, switchFlag: 0 },
|
||||
{ qe: 0x09c1, nmps: 32, nlps: 29, switchFlag: 0 },
|
||||
{ qe: 0x08a1, nmps: 33, nlps: 30, switchFlag: 0 },
|
||||
{ qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0 },
|
||||
{ qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0 },
|
||||
{ qe: 0x02a1, nmps: 36, nlps: 33, switchFlag: 0 },
|
||||
{ qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0 },
|
||||
{ qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0 },
|
||||
{ qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0 },
|
||||
{ qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0 },
|
||||
{ qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0 },
|
||||
{ qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0 },
|
||||
{ qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0 },
|
||||
{ qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0 },
|
||||
{ qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0 },
|
||||
{ qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0 },
|
||||
{ qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0 },
|
||||
];
|
||||
|
||||
/**
|
||||
* This class implements the QM Coder decoding as defined in
|
||||
* JPEG 2000 Part I Final Committee Draft Version 1.0
|
||||
* Annex C.3 Arithmetic decoding procedure
|
||||
* available at http://www.jpeg.org/public/fcd15444-1.pdf
|
||||
*
|
||||
* The arithmetic decoder is used in conjunction with context models to decode
|
||||
* JPEG2000 and JBIG2 streams.
|
||||
*/
|
||||
class ArithmeticDecoder {
|
||||
// C.3.5 Initialisation of the decoder (INITDEC)
|
||||
constructor(data, start, end) {
|
||||
this.data = data;
|
||||
this.bp = start;
|
||||
this.dataEnd = end;
|
||||
|
||||
this.chigh = data[start];
|
||||
this.clow = 0;
|
||||
|
||||
this.byteIn();
|
||||
|
||||
this.chigh = ((this.chigh << 7) & 0xffff) | ((this.clow >> 9) & 0x7f);
|
||||
this.clow = (this.clow << 7) & 0xffff;
|
||||
this.ct -= 7;
|
||||
this.a = 0x8000;
|
||||
}
|
||||
|
||||
// C.3.4 Compressed data input (BYTEIN)
|
||||
byteIn() {
|
||||
const data = this.data;
|
||||
let bp = this.bp;
|
||||
|
||||
if (data[bp] === 0xff) {
|
||||
if (data[bp + 1] > 0x8f) {
|
||||
this.clow += 0xff00;
|
||||
this.ct = 8;
|
||||
} else {
|
||||
bp++;
|
||||
this.clow += data[bp] << 9;
|
||||
this.ct = 7;
|
||||
this.bp = bp;
|
||||
}
|
||||
} else {
|
||||
bp++;
|
||||
this.clow += bp < this.dataEnd ? data[bp] << 8 : 0xff00;
|
||||
this.ct = 8;
|
||||
this.bp = bp;
|
||||
}
|
||||
if (this.clow > 0xffff) {
|
||||
this.chigh += this.clow >> 16;
|
||||
this.clow &= 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
// C.3.2 Decoding a decision (DECODE)
|
||||
readBit(contexts, pos) {
|
||||
// Contexts are packed into 1 byte:
|
||||
// highest 7 bits carry cx.index, lowest bit carries cx.mps
|
||||
let cx_index = contexts[pos] >> 1,
|
||||
cx_mps = contexts[pos] & 1;
|
||||
const qeTableIcx = QeTable[cx_index];
|
||||
const qeIcx = qeTableIcx.qe;
|
||||
let d;
|
||||
let a = this.a - qeIcx;
|
||||
|
||||
if (this.chigh < qeIcx) {
|
||||
// exchangeLps
|
||||
if (a < qeIcx) {
|
||||
a = qeIcx;
|
||||
d = cx_mps;
|
||||
cx_index = qeTableIcx.nmps;
|
||||
} else {
|
||||
a = qeIcx;
|
||||
d = 1 ^ cx_mps;
|
||||
if (qeTableIcx.switchFlag === 1) {
|
||||
cx_mps = d;
|
||||
}
|
||||
cx_index = qeTableIcx.nlps;
|
||||
}
|
||||
} else {
|
||||
this.chigh -= qeIcx;
|
||||
if ((a & 0x8000) !== 0) {
|
||||
this.a = a;
|
||||
return cx_mps;
|
||||
}
|
||||
// exchangeMps
|
||||
if (a < qeIcx) {
|
||||
d = 1 ^ cx_mps;
|
||||
if (qeTableIcx.switchFlag === 1) {
|
||||
cx_mps = d;
|
||||
}
|
||||
cx_index = qeTableIcx.nlps;
|
||||
} else {
|
||||
d = cx_mps;
|
||||
cx_index = qeTableIcx.nmps;
|
||||
}
|
||||
}
|
||||
// C.3.3 renormD;
|
||||
do {
|
||||
if (this.ct === 0) {
|
||||
this.byteIn();
|
||||
}
|
||||
|
||||
a <<= 1;
|
||||
this.chigh = ((this.chigh << 1) & 0xffff) | ((this.clow >> 15) & 1);
|
||||
this.clow = (this.clow << 1) & 0xffff;
|
||||
this.ct--;
|
||||
} while ((a & 0x8000) === 0);
|
||||
this.a = a;
|
||||
|
||||
contexts[pos] = (cx_index << 1) | cx_mps;
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
export { ArithmeticDecoder };
|
1070
src/utils/ccitt.js
Normal file
1070
src/utils/ccitt.js
Normal file
File diff suppressed because it is too large
Load Diff
312
src/utils/compatibility.js
Normal file
312
src/utils/compatibility.js
Normal file
@ -0,0 +1,312 @@
|
||||
/* Copyright 2017 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { isNodeJS } from "./is_node.js";
|
||||
|
||||
// Skip compatibility checks for modern builds and if we already ran the module.
|
||||
if (
|
||||
(typeof PDFJSDev === "undefined" || !PDFJSDev.test("SKIP_BABEL")) &&
|
||||
(typeof globalThis === "undefined" || !globalThis._pdfjsCompatibilityChecked)
|
||||
) {
|
||||
// Provides support for globalThis in legacy browsers.
|
||||
// Support: IE11/Edge, Opera
|
||||
if (typeof globalThis === "undefined" || globalThis.Math !== Math) {
|
||||
// eslint-disable-next-line no-global-assign
|
||||
globalThis = require("core-js/es/global-this");
|
||||
}
|
||||
globalThis._pdfjsCompatibilityChecked = true;
|
||||
|
||||
// Support: Node.js
|
||||
(function checkNodeBtoa() {
|
||||
if (globalThis.btoa || !isNodeJS) {
|
||||
return;
|
||||
}
|
||||
globalThis.btoa = function (chars) {
|
||||
// eslint-disable-next-line no-undef
|
||||
return Buffer.from(chars, "binary").toString("base64");
|
||||
};
|
||||
})();
|
||||
|
||||
// Support: Node.js
|
||||
(function checkNodeAtob() {
|
||||
if (globalThis.atob || !isNodeJS) {
|
||||
return;
|
||||
}
|
||||
globalThis.atob = function (input) {
|
||||
// eslint-disable-next-line no-undef
|
||||
return Buffer.from(input, "base64").toString("binary");
|
||||
};
|
||||
})();
|
||||
|
||||
// Provides support for String.prototype.startsWith in legacy browsers.
|
||||
// Support: IE, Chrome<41
|
||||
(function checkStringStartsWith() {
|
||||
if (String.prototype.startsWith) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/string/starts-with.js");
|
||||
})();
|
||||
|
||||
// Provides support for String.prototype.endsWith in legacy browsers.
|
||||
// Support: IE, Chrome<41
|
||||
(function checkStringEndsWith() {
|
||||
if (String.prototype.endsWith) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/string/ends-with.js");
|
||||
})();
|
||||
|
||||
// Provides support for String.prototype.includes in legacy browsers.
|
||||
// Support: IE, Chrome<41
|
||||
(function checkStringIncludes() {
|
||||
if (String.prototype.includes) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/string/includes.js");
|
||||
})();
|
||||
|
||||
// Provides support for Array.prototype.includes in legacy browsers.
|
||||
// Support: IE, Chrome<47
|
||||
(function checkArrayIncludes() {
|
||||
if (Array.prototype.includes) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/array/includes.js");
|
||||
})();
|
||||
|
||||
// Provides support for Array.from in legacy browsers.
|
||||
// Support: IE
|
||||
(function checkArrayFrom() {
|
||||
if (Array.from) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/array/from.js");
|
||||
})();
|
||||
|
||||
// Provides support for Object.assign in legacy browsers.
|
||||
// Support: IE
|
||||
(function checkObjectAssign() {
|
||||
if (Object.assign) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/object/assign.js");
|
||||
})();
|
||||
|
||||
// Provides support for Object.fromEntries in legacy browsers.
|
||||
// Support: IE, Chrome<73
|
||||
(function checkObjectFromEntries() {
|
||||
if (Object.fromEntries) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/object/from-entries.js");
|
||||
})();
|
||||
|
||||
// Provides support for Math.log2 in legacy browsers.
|
||||
// Support: IE, Chrome<38
|
||||
(function checkMathLog2() {
|
||||
if (Math.log2) {
|
||||
return;
|
||||
}
|
||||
Math.log2 = require("core-js/es/math/log2.js");
|
||||
})();
|
||||
|
||||
// Provides support for Number.isNaN in legacy browsers.
|
||||
// Support: IE.
|
||||
(function checkNumberIsNaN() {
|
||||
if (Number.isNaN) {
|
||||
return;
|
||||
}
|
||||
Number.isNaN = require("core-js/es/number/is-nan.js");
|
||||
})();
|
||||
|
||||
// Provides support for Number.isInteger in legacy browsers.
|
||||
// Support: IE, Chrome<34
|
||||
(function checkNumberIsInteger() {
|
||||
if (Number.isInteger) {
|
||||
return;
|
||||
}
|
||||
Number.isInteger = require("core-js/es/number/is-integer.js");
|
||||
})();
|
||||
|
||||
// Provides support for TypedArray.prototype.slice in legacy browsers.
|
||||
// Support: IE
|
||||
(function checkTypedArraySlice() {
|
||||
if (Uint8Array.prototype.slice) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/typed-array/slice");
|
||||
})();
|
||||
|
||||
// Provides support for *recent* additions to the Promise specification,
|
||||
// however basic Promise support is assumed to be available natively.
|
||||
// Support: Firefox<71, Safari<13, Chrome<76
|
||||
(function checkPromise() {
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("IMAGE_DECODERS")) {
|
||||
// The current image decoders are synchronous, hence `Promise` shouldn't
|
||||
// need to be polyfilled for the IMAGE_DECODERS build target.
|
||||
return;
|
||||
}
|
||||
if (globalThis.Promise.allSettled) {
|
||||
return;
|
||||
}
|
||||
globalThis.Promise = require("core-js/es/promise/index.js");
|
||||
})();
|
||||
|
||||
// Support: IE
|
||||
(function checkURL() {
|
||||
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) {
|
||||
// Prevent "require is not a function" errors in development mode,
|
||||
// since the `URL` constructor should be available in modern browers.
|
||||
return;
|
||||
} else if (!PDFJSDev.test("GENERIC")) {
|
||||
// The `URL` constructor is assumed to be available in the extension
|
||||
// builds.
|
||||
return;
|
||||
} else if (PDFJSDev.test("IMAGE_DECODERS")) {
|
||||
// The current image decoders don't use the `URL` constructor, so it
|
||||
// doesn't need to be polyfilled for the IMAGE_DECODERS build target.
|
||||
return;
|
||||
}
|
||||
globalThis.URL = require("core-js/web/url.js");
|
||||
})();
|
||||
|
||||
// Support: IE, Node.js
|
||||
(function checkReadableStream() {
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("IMAGE_DECODERS")) {
|
||||
// The current image decoders are synchronous, hence `ReadableStream`
|
||||
// shouldn't need to be polyfilled for the IMAGE_DECODERS build target.
|
||||
return;
|
||||
}
|
||||
let isReadableStreamSupported = false;
|
||||
|
||||
if (typeof ReadableStream !== "undefined") {
|
||||
// MS Edge may say it has ReadableStream but they are not up to spec yet.
|
||||
try {
|
||||
// eslint-disable-next-line no-new
|
||||
new ReadableStream({
|
||||
start(controller) {
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
isReadableStreamSupported = true;
|
||||
} catch (e) {
|
||||
// The ReadableStream constructor cannot be used.
|
||||
}
|
||||
}
|
||||
if (isReadableStreamSupported) {
|
||||
return;
|
||||
}
|
||||
globalThis.ReadableStream = require("web-streams-polyfill/dist/ponyfill.js").ReadableStream;
|
||||
})();
|
||||
|
||||
// We want to support Map iteration, but it doesn't seem possible to easily
|
||||
// test for that specifically; hence using a similarly unsupported property.
|
||||
// Support: IE11
|
||||
(function checkMapEntries() {
|
||||
if (globalThis.Map && globalThis.Map.prototype.entries) {
|
||||
return;
|
||||
}
|
||||
globalThis.Map = require("core-js/es/map/index.js");
|
||||
})();
|
||||
|
||||
// We want to support Set iteration, but it doesn't seem possible to easily
|
||||
// test for that specifically; hence using a similarly unsupported property.
|
||||
// Support: IE11
|
||||
(function checkSetEntries() {
|
||||
if (globalThis.Set && globalThis.Set.prototype.entries) {
|
||||
return;
|
||||
}
|
||||
globalThis.Set = require("core-js/es/set/index.js");
|
||||
})();
|
||||
|
||||
// Support: IE<11, Safari<8, Chrome<36
|
||||
(function checkWeakMap() {
|
||||
if (globalThis.WeakMap) {
|
||||
return;
|
||||
}
|
||||
globalThis.WeakMap = require("core-js/es/weak-map/index.js");
|
||||
})();
|
||||
|
||||
// Support: IE11
|
||||
(function checkWeakSet() {
|
||||
if (globalThis.WeakSet) {
|
||||
return;
|
||||
}
|
||||
globalThis.WeakSet = require("core-js/es/weak-set/index.js");
|
||||
})();
|
||||
|
||||
// Provides support for String.codePointAt in legacy browsers.
|
||||
// Support: IE11.
|
||||
(function checkStringCodePointAt() {
|
||||
if (String.prototype.codePointAt) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/string/code-point-at.js");
|
||||
})();
|
||||
|
||||
// Provides support for String.fromCodePoint in legacy browsers.
|
||||
// Support: IE11.
|
||||
(function checkStringFromCodePoint() {
|
||||
if (String.fromCodePoint) {
|
||||
return;
|
||||
}
|
||||
String.fromCodePoint = require("core-js/es/string/from-code-point.js");
|
||||
})();
|
||||
|
||||
// Support: IE
|
||||
(function checkSymbol() {
|
||||
if (globalThis.Symbol) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/symbol/index.js");
|
||||
})();
|
||||
|
||||
// Provides support for String.prototype.padStart in legacy browsers.
|
||||
// Support: IE, Chrome<57
|
||||
(function checkStringPadStart() {
|
||||
if (String.prototype.padStart) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/string/pad-start.js");
|
||||
})();
|
||||
|
||||
// Provides support for String.prototype.padEnd in legacy browsers.
|
||||
// Support: IE, Chrome<57
|
||||
(function checkStringPadEnd() {
|
||||
if (String.prototype.padEnd) {
|
||||
return;
|
||||
}
|
||||
require("core-js/es/string/pad-end.js");
|
||||
})();
|
||||
|
||||
// Provides support for Object.values in legacy browsers.
|
||||
// Support: IE, Chrome<54
|
||||
(function checkObjectValues() {
|
||||
if (Object.values) {
|
||||
return;
|
||||
}
|
||||
Object.values = require("core-js/es/object/values.js");
|
||||
})();
|
||||
|
||||
// Provides support for Object.entries in legacy browsers.
|
||||
// Support: IE, Chrome<54
|
||||
(function checkObjectEntries() {
|
||||
if (Object.entries) {
|
||||
return;
|
||||
}
|
||||
Object.entries = require("core-js/es/object/entries.js");
|
||||
})();
|
||||
}
|
180
src/utils/core_utils.js
Normal file
180
src/utils/core_utils.js
Normal file
@ -0,0 +1,180 @@
|
||||
/* Copyright 2019 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import { assert, BaseException, warn } from "./util.js";
|
||||
|
||||
function getLookupTableFactory(initializer) {
|
||||
let lookup;
|
||||
return function () {
|
||||
if (initializer) {
|
||||
lookup = Object.create(null);
|
||||
initializer(lookup);
|
||||
initializer = null;
|
||||
}
|
||||
return lookup;
|
||||
};
|
||||
}
|
||||
|
||||
class MissingDataException extends BaseException {
|
||||
constructor(begin, end) {
|
||||
super(`Missing data [${begin}, ${end})`);
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
}
|
||||
}
|
||||
|
||||
class XRefEntryException extends BaseException {}
|
||||
|
||||
class XRefParseException extends BaseException {}
|
||||
|
||||
/**
|
||||
* Get the value of an inheritable property.
|
||||
*
|
||||
* If the PDF specification explicitly lists a property in a dictionary as
|
||||
* inheritable, then the value of the property may be present in the dictionary
|
||||
* itself or in one or more parents of the dictionary.
|
||||
*
|
||||
* If the key is not found in the tree, `undefined` is returned. Otherwise,
|
||||
* the value for the key is returned or, if `stopWhenFound` is `false`, a list
|
||||
* of values is returned. To avoid infinite loops, the traversal is stopped when
|
||||
* the loop limit is reached.
|
||||
*
|
||||
* @param {Dict} dict - Dictionary from where to start the traversal.
|
||||
* @param {string} key - The key of the property to find the value for.
|
||||
* @param {boolean} getArray - Whether or not the value should be fetched as an
|
||||
* array. The default value is `false`.
|
||||
* @param {boolean} stopWhenFound - Whether or not to stop the traversal when
|
||||
* the key is found. If set to `false`, we always walk up the entire parent
|
||||
* chain, for example to be able to find `\Resources` placed on multiple
|
||||
* levels of the tree. The default value is `true`.
|
||||
*/
|
||||
function getInheritableProperty({
|
||||
dict,
|
||||
key,
|
||||
getArray = false,
|
||||
stopWhenFound = true,
|
||||
}) {
|
||||
const LOOP_LIMIT = 100;
|
||||
let loopCount = 0;
|
||||
let values;
|
||||
|
||||
while (dict) {
|
||||
const value = getArray ? dict.getArray(key) : dict.get(key);
|
||||
if (value !== undefined) {
|
||||
if (stopWhenFound) {
|
||||
return value;
|
||||
}
|
||||
if (!values) {
|
||||
values = [];
|
||||
}
|
||||
values.push(value);
|
||||
}
|
||||
if (++loopCount > LOOP_LIMIT) {
|
||||
warn(`getInheritableProperty: maximum loop count exceeded for "${key}"`);
|
||||
break;
|
||||
}
|
||||
dict = dict.get("Parent");
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
const ROMAN_NUMBER_MAP = [
|
||||
"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM",
|
||||
"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC",
|
||||
"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"
|
||||
];
|
||||
|
||||
/**
|
||||
* Converts positive integers to (upper case) Roman numerals.
|
||||
* @param {number} number - The number that should be converted.
|
||||
* @param {boolean} lowerCase - Indicates if the result should be converted
|
||||
* to lower case letters. The default value is `false`.
|
||||
* @returns {string} The resulting Roman number.
|
||||
*/
|
||||
function toRomanNumerals(number, lowerCase = false) {
|
||||
assert(
|
||||
Number.isInteger(number) && number > 0,
|
||||
"The number should be a positive integer."
|
||||
);
|
||||
const romanBuf = [];
|
||||
let pos;
|
||||
// Thousands
|
||||
while (number >= 1000) {
|
||||
number -= 1000;
|
||||
romanBuf.push("M");
|
||||
}
|
||||
// Hundreds
|
||||
pos = (number / 100) | 0;
|
||||
number %= 100;
|
||||
romanBuf.push(ROMAN_NUMBER_MAP[pos]);
|
||||
// Tens
|
||||
pos = (number / 10) | 0;
|
||||
number %= 10;
|
||||
romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]);
|
||||
// Ones
|
||||
romanBuf.push(ROMAN_NUMBER_MAP[20 + number]);
|
||||
|
||||
const romanStr = romanBuf.join("");
|
||||
return lowerCase ? romanStr.toLowerCase() : romanStr;
|
||||
}
|
||||
|
||||
// Calculate the base 2 logarithm of the number `x`. This differs from the
|
||||
// native function in the sense that it returns the ceiling value and that it
|
||||
// returns 0 instead of `Infinity`/`NaN` for `x` values smaller than/equal to 0.
|
||||
function log2(x) {
|
||||
if (x <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return Math.ceil(Math.log2(x));
|
||||
}
|
||||
|
||||
function readInt8(data, offset) {
|
||||
return (data[offset] << 24) >> 24;
|
||||
}
|
||||
|
||||
function readUint16(data, offset) {
|
||||
return (data[offset] << 8) | data[offset + 1];
|
||||
}
|
||||
|
||||
function readUint32(data, offset) {
|
||||
return (
|
||||
((data[offset] << 24) |
|
||||
(data[offset + 1] << 16) |
|
||||
(data[offset + 2] << 8) |
|
||||
data[offset + 3]) >>>
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// Checks if ch is one of the following characters: SPACE, TAB, CR or LF.
|
||||
function isWhiteSpace(ch) {
|
||||
return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a;
|
||||
}
|
||||
|
||||
export {
|
||||
getLookupTableFactory,
|
||||
MissingDataException,
|
||||
XRefEntryException,
|
||||
XRefParseException,
|
||||
getInheritableProperty,
|
||||
toRomanNumerals,
|
||||
log2,
|
||||
readInt8,
|
||||
readUint16,
|
||||
readUint32,
|
||||
isWhiteSpace,
|
||||
};
|
27
src/utils/is_node.js
Normal file
27
src/utils/is_node.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* Copyright 2018 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals process */
|
||||
|
||||
// NW.js / Electron is a browser context, but copies some Node.js objects; see
|
||||
// http://docs.nwjs.io/en/latest/For%20Users/Advanced/JavaScript%20Contexts%20in%20NW.js/#access-nodejs-and-nwjs-api-in-browser-context
|
||||
// https://www.electronjs.org/docs/api/process#processversionselectron-readonly
|
||||
// https://www.electronjs.org/docs/api/process#processtype-readonly
|
||||
const isNodeJS =
|
||||
typeof process === "object" &&
|
||||
process + "" === "[object process]" &&
|
||||
!process.versions.nw &&
|
||||
!(process.versions.electron && process.type && process.type !== "browser");
|
||||
|
||||
export { isNodeJS };
|
2589
src/utils/jbig2.js
Normal file
2589
src/utils/jbig2.js
Normal file
File diff suppressed because it is too large
Load Diff
81
src/utils/jbig2_stream.js
Normal file
81
src/utils/jbig2_stream.js
Normal file
@ -0,0 +1,81 @@
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { isDict, isStream } from "./primitives.js";
|
||||
import { DecodeStream } from "./stream.js";
|
||||
import { Jbig2Image } from "./jbig2.js";
|
||||
import { shadow } from "./util.js";
|
||||
|
||||
/**
|
||||
* For JBIG2's we use a library to decode these images and
|
||||
* the stream behaves like all the other DecodeStreams.
|
||||
*/
|
||||
const Jbig2Stream = (function Jbig2StreamClosure() {
|
||||
// eslint-disable-next-line no-shadow
|
||||
function Jbig2Stream(stream, maybeLength, dict, params) {
|
||||
this.stream = stream;
|
||||
this.maybeLength = maybeLength;
|
||||
this.dict = dict;
|
||||
this.params = params;
|
||||
|
||||
DecodeStream.call(this, maybeLength);
|
||||
}
|
||||
|
||||
Jbig2Stream.prototype = Object.create(DecodeStream.prototype);
|
||||
|
||||
Object.defineProperty(Jbig2Stream.prototype, "bytes", {
|
||||
get() {
|
||||
// If `this.maybeLength` is null, we'll get the entire stream.
|
||||
return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
Jbig2Stream.prototype.ensureBuffer = function (requested) {
|
||||
// No-op, since `this.readBlock` will always parse the entire image and
|
||||
// directly insert all of its data into `this.buffer`.
|
||||
};
|
||||
|
||||
Jbig2Stream.prototype.readBlock = function () {
|
||||
if (this.eof) {
|
||||
return;
|
||||
}
|
||||
const jbig2Image = new Jbig2Image();
|
||||
|
||||
const chunks = [];
|
||||
if (isDict(this.params)) {
|
||||
const globalsStream = this.params.get("JBIG2Globals");
|
||||
if (isStream(globalsStream)) {
|
||||
const globals = globalsStream.getBytes();
|
||||
chunks.push({ data: globals, start: 0, end: globals.length });
|
||||
}
|
||||
}
|
||||
chunks.push({ data: this.bytes, start: 0, end: this.bytes.length });
|
||||
const data = jbig2Image.parseChunks(chunks);
|
||||
const dataLength = data.length;
|
||||
|
||||
// JBIG2 had black as 1 and white as 0, inverting the colors
|
||||
for (let i = 0; i < dataLength; i++) {
|
||||
data[i] ^= 0xff;
|
||||
}
|
||||
this.buffer = data;
|
||||
this.bufferLength = dataLength;
|
||||
this.eof = true;
|
||||
};
|
||||
|
||||
return Jbig2Stream;
|
||||
})();
|
||||
|
||||
export { Jbig2Stream };
|
387
src/utils/primitives.js
Normal file
387
src/utils/primitives.js
Normal file
@ -0,0 +1,387 @@
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* uses XRef */
|
||||
|
||||
import { assert, unreachable } from "./util.js";
|
||||
|
||||
var EOF = {};
|
||||
|
||||
var Name = (function NameClosure() {
|
||||
let nameCache = Object.create(null);
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
function Name(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Name.prototype = {};
|
||||
|
||||
Name.get = function Name_get(name) {
|
||||
var nameValue = nameCache[name];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return nameValue ? nameValue : (nameCache[name] = new Name(name));
|
||||
};
|
||||
|
||||
Name._clearCache = function () {
|
||||
nameCache = Object.create(null);
|
||||
};
|
||||
|
||||
return Name;
|
||||
})();
|
||||
|
||||
var Cmd = (function CmdClosure() {
|
||||
let cmdCache = Object.create(null);
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
function Cmd(cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
Cmd.prototype = {};
|
||||
|
||||
Cmd.get = function Cmd_get(cmd) {
|
||||
var cmdValue = cmdCache[cmd];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd));
|
||||
};
|
||||
|
||||
Cmd._clearCache = function () {
|
||||
cmdCache = Object.create(null);
|
||||
};
|
||||
|
||||
return Cmd;
|
||||
})();
|
||||
|
||||
var Dict = (function DictClosure() {
|
||||
var nonSerializable = function nonSerializableClosure() {
|
||||
return nonSerializable; // creating closure on some variable
|
||||
};
|
||||
|
||||
// xref is optional
|
||||
// eslint-disable-next-line no-shadow
|
||||
function Dict(xref) {
|
||||
// Map should only be used internally, use functions below to access.
|
||||
this._map = Object.create(null);
|
||||
this.xref = xref;
|
||||
this.objId = null;
|
||||
this.suppressEncryption = false;
|
||||
this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
|
||||
}
|
||||
|
||||
Dict.prototype = {
|
||||
assignXref: function Dict_assignXref(newXref) {
|
||||
this.xref = newXref;
|
||||
},
|
||||
|
||||
get size() {
|
||||
return Object.keys(this._map).length;
|
||||
},
|
||||
|
||||
// automatically dereferences Ref objects
|
||||
get(key1, key2, key3) {
|
||||
let value = this._map[key1];
|
||||
if (value === undefined && key2 !== undefined) {
|
||||
value = this._map[key2];
|
||||
if (value === undefined && key3 !== undefined) {
|
||||
value = this._map[key3];
|
||||
}
|
||||
}
|
||||
if (value instanceof Ref && this.xref) {
|
||||
return this.xref.fetch(value, this.suppressEncryption);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
// Same as get(), but returns a promise and uses fetchIfRefAsync().
|
||||
async getAsync(key1, key2, key3) {
|
||||
let value = this._map[key1];
|
||||
if (value === undefined && key2 !== undefined) {
|
||||
value = this._map[key2];
|
||||
if (value === undefined && key3 !== undefined) {
|
||||
value = this._map[key3];
|
||||
}
|
||||
}
|
||||
if (value instanceof Ref && this.xref) {
|
||||
return this.xref.fetchAsync(value, this.suppressEncryption);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
// Same as get(), but dereferences all elements if the result is an Array.
|
||||
getArray(key1, key2, key3) {
|
||||
let value = this.get(key1, key2, key3);
|
||||
if (!Array.isArray(value) || !this.xref) {
|
||||
return value;
|
||||
}
|
||||
value = value.slice(); // Ensure that we don't modify the Dict data.
|
||||
for (let i = 0, ii = value.length; i < ii; i++) {
|
||||
if (!(value[i] instanceof Ref)) {
|
||||
continue;
|
||||
}
|
||||
value[i] = this.xref.fetch(value[i], this.suppressEncryption);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
// no dereferencing
|
||||
getRaw: function Dict_getRaw(key) {
|
||||
return this._map[key];
|
||||
},
|
||||
|
||||
getKeys: function Dict_getKeys() {
|
||||
return Object.keys(this._map);
|
||||
},
|
||||
|
||||
// no dereferencing
|
||||
getRawValues: function Dict_getRawValues() {
|
||||
return Object.values(this._map);
|
||||
},
|
||||
|
||||
set: function Dict_set(key, value) {
|
||||
if (
|
||||
(typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")) &&
|
||||
value === undefined
|
||||
) {
|
||||
unreachable('Dict.set: The "value" cannot be undefined.');
|
||||
}
|
||||
this._map[key] = value;
|
||||
},
|
||||
|
||||
has: function Dict_has(key) {
|
||||
return this._map[key] !== undefined;
|
||||
},
|
||||
|
||||
forEach: function Dict_forEach(callback) {
|
||||
for (var key in this._map) {
|
||||
callback(key, this.get(key));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Dict.empty = new Dict(null);
|
||||
|
||||
Dict.merge = function ({ xref, dictArray, mergeSubDicts = false }) {
|
||||
const mergedDict = new Dict(xref);
|
||||
|
||||
if (!mergeSubDicts) {
|
||||
for (const dict of dictArray) {
|
||||
if (!(dict instanceof Dict)) {
|
||||
continue;
|
||||
}
|
||||
for (const [key, value] of Object.entries(dict._map)) {
|
||||
if (mergedDict._map[key] === undefined) {
|
||||
mergedDict._map[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mergedDict.size > 0 ? mergedDict : Dict.empty;
|
||||
}
|
||||
const properties = new Map();
|
||||
|
||||
for (const dict of dictArray) {
|
||||
if (!(dict instanceof Dict)) {
|
||||
continue;
|
||||
}
|
||||
for (const [key, value] of Object.entries(dict._map)) {
|
||||
let property = properties.get(key);
|
||||
if (property === undefined) {
|
||||
property = [];
|
||||
properties.set(key, property);
|
||||
}
|
||||
property.push(value);
|
||||
}
|
||||
}
|
||||
for (const [name, values] of properties) {
|
||||
if (values.length === 1 || !(values[0] instanceof Dict)) {
|
||||
mergedDict._map[name] = values[0];
|
||||
continue;
|
||||
}
|
||||
const subDict = new Dict(xref);
|
||||
|
||||
for (const dict of values) {
|
||||
if (!(dict instanceof Dict)) {
|
||||
continue;
|
||||
}
|
||||
for (const [key, value] of Object.entries(dict._map)) {
|
||||
if (subDict._map[key] === undefined) {
|
||||
subDict._map[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (subDict.size > 0) {
|
||||
mergedDict._map[name] = subDict;
|
||||
}
|
||||
}
|
||||
properties.clear();
|
||||
|
||||
return mergedDict.size > 0 ? mergedDict : Dict.empty;
|
||||
};
|
||||
|
||||
return Dict;
|
||||
})();
|
||||
|
||||
var Ref = (function RefClosure() {
|
||||
let refCache = Object.create(null);
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
function Ref(num, gen) {
|
||||
this.num = num;
|
||||
this.gen = gen;
|
||||
}
|
||||
|
||||
Ref.prototype = {
|
||||
toString: function Ref_toString() {
|
||||
// This function is hot, so we make the string as compact as possible.
|
||||
// |this.gen| is almost always zero, so we treat that case specially.
|
||||
if (this.gen === 0) {
|
||||
return `${this.num}R`;
|
||||
}
|
||||
return `${this.num}R${this.gen}`;
|
||||
},
|
||||
};
|
||||
|
||||
Ref.get = function (num, gen) {
|
||||
const key = gen === 0 ? `${num}R` : `${num}R${gen}`;
|
||||
const refValue = refCache[key];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return refValue ? refValue : (refCache[key] = new Ref(num, gen));
|
||||
};
|
||||
|
||||
Ref._clearCache = function () {
|
||||
refCache = Object.create(null);
|
||||
};
|
||||
|
||||
return Ref;
|
||||
})();
|
||||
|
||||
// The reference is identified by number and generation.
|
||||
// This structure stores only one instance of the reference.
|
||||
class RefSet {
|
||||
constructor() {
|
||||
this._set = new Set();
|
||||
}
|
||||
|
||||
has(ref) {
|
||||
return this._set.has(ref.toString());
|
||||
}
|
||||
|
||||
put(ref) {
|
||||
this._set.add(ref.toString());
|
||||
}
|
||||
|
||||
remove(ref) {
|
||||
this._set.delete(ref.toString());
|
||||
}
|
||||
}
|
||||
|
||||
class RefSetCache {
|
||||
constructor() {
|
||||
this._map = new Map();
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this._map.size;
|
||||
}
|
||||
|
||||
get(ref) {
|
||||
return this._map.get(ref.toString());
|
||||
}
|
||||
|
||||
has(ref) {
|
||||
return this._map.has(ref.toString());
|
||||
}
|
||||
|
||||
put(ref, obj) {
|
||||
this._map.set(ref.toString(), obj);
|
||||
}
|
||||
|
||||
putAlias(ref, aliasRef) {
|
||||
this._map.set(ref.toString(), this.get(aliasRef));
|
||||
}
|
||||
|
||||
forEach(callback) {
|
||||
for (const value of this._map.values()) {
|
||||
callback(value);
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
function isEOF(v) {
|
||||
return v === EOF;
|
||||
}
|
||||
|
||||
function isName(v, name) {
|
||||
return v instanceof Name && (name === undefined || v.name === name);
|
||||
}
|
||||
|
||||
function isCmd(v, cmd) {
|
||||
return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);
|
||||
}
|
||||
|
||||
function isDict(v, type) {
|
||||
return (
|
||||
v instanceof Dict && (type === undefined || isName(v.get("Type"), type))
|
||||
);
|
||||
}
|
||||
|
||||
function isRef(v) {
|
||||
return v instanceof Ref;
|
||||
}
|
||||
|
||||
function isRefsEqual(v1, v2) {
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
assert(
|
||||
v1 instanceof Ref && v2 instanceof Ref,
|
||||
"isRefsEqual: Both parameters should be `Ref`s."
|
||||
);
|
||||
}
|
||||
return v1.num === v2.num && v1.gen === v2.gen;
|
||||
}
|
||||
|
||||
function isStream(v) {
|
||||
return typeof v === "object" && v !== null && v.getBytes !== undefined;
|
||||
}
|
||||
|
||||
function clearPrimitiveCaches() {
|
||||
Cmd._clearCache();
|
||||
Name._clearCache();
|
||||
Ref._clearCache();
|
||||
}
|
||||
|
||||
export {
|
||||
EOF,
|
||||
clearPrimitiveCaches,
|
||||
Cmd,
|
||||
Dict,
|
||||
Name,
|
||||
Ref,
|
||||
RefSet,
|
||||
RefSetCache,
|
||||
isEOF,
|
||||
isCmd,
|
||||
isDict,
|
||||
isName,
|
||||
isRef,
|
||||
isRefsEqual,
|
||||
isStream,
|
||||
};
|
1348
src/utils/stream.js
Normal file
1348
src/utils/stream.js
Normal file
File diff suppressed because it is too large
Load Diff
972
src/utils/util.js
Normal file
972
src/utils/util.js
Normal file
@ -0,0 +1,972 @@
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint no-var: error */
|
||||
|
||||
import "./compatibility.js";
|
||||
|
||||
const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
||||
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
||||
|
||||
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
|
||||
const PermissionFlag = {
|
||||
PRINT: 0x04,
|
||||
MODIFY_CONTENTS: 0x08,
|
||||
COPY: 0x10,
|
||||
MODIFY_ANNOTATIONS: 0x20,
|
||||
FILL_INTERACTIVE_FORMS: 0x100,
|
||||
COPY_FOR_ACCESSIBILITY: 0x200,
|
||||
ASSEMBLE: 0x400,
|
||||
PRINT_HIGH_QUALITY: 0x800,
|
||||
};
|
||||
|
||||
const TextRenderingMode = {
|
||||
FILL: 0,
|
||||
STROKE: 1,
|
||||
FILL_STROKE: 2,
|
||||
INVISIBLE: 3,
|
||||
FILL_ADD_TO_PATH: 4,
|
||||
STROKE_ADD_TO_PATH: 5,
|
||||
FILL_STROKE_ADD_TO_PATH: 6,
|
||||
ADD_TO_PATH: 7,
|
||||
FILL_STROKE_MASK: 3,
|
||||
ADD_TO_PATH_FLAG: 4,
|
||||
};
|
||||
|
||||
const ImageKind = {
|
||||
GRAYSCALE_1BPP: 1,
|
||||
RGB_24BPP: 2,
|
||||
RGBA_32BPP: 3,
|
||||
};
|
||||
|
||||
const AnnotationType = {
|
||||
TEXT: 1,
|
||||
LINK: 2,
|
||||
FREETEXT: 3,
|
||||
LINE: 4,
|
||||
SQUARE: 5,
|
||||
CIRCLE: 6,
|
||||
POLYGON: 7,
|
||||
POLYLINE: 8,
|
||||
HIGHLIGHT: 9,
|
||||
UNDERLINE: 10,
|
||||
SQUIGGLY: 11,
|
||||
STRIKEOUT: 12,
|
||||
STAMP: 13,
|
||||
CARET: 14,
|
||||
INK: 15,
|
||||
POPUP: 16,
|
||||
FILEATTACHMENT: 17,
|
||||
SOUND: 18,
|
||||
MOVIE: 19,
|
||||
WIDGET: 20,
|
||||
SCREEN: 21,
|
||||
PRINTERMARK: 22,
|
||||
TRAPNET: 23,
|
||||
WATERMARK: 24,
|
||||
THREED: 25,
|
||||
REDACT: 26,
|
||||
};
|
||||
|
||||
const AnnotationStateModelType = {
|
||||
MARKED: "Marked",
|
||||
REVIEW: "Review",
|
||||
};
|
||||
|
||||
const AnnotationMarkedState = {
|
||||
MARKED: "Marked",
|
||||
UNMARKED: "Unmarked",
|
||||
};
|
||||
|
||||
const AnnotationReviewState = {
|
||||
ACCEPTED: "Accepted",
|
||||
REJECTED: "Rejected",
|
||||
CANCELLED: "Cancelled",
|
||||
COMPLETED: "Completed",
|
||||
NONE: "None",
|
||||
};
|
||||
|
||||
const AnnotationReplyType = {
|
||||
GROUP: "Group",
|
||||
REPLY: "R",
|
||||
};
|
||||
|
||||
const AnnotationFlag = {
|
||||
INVISIBLE: 0x01,
|
||||
HIDDEN: 0x02,
|
||||
PRINT: 0x04,
|
||||
NOZOOM: 0x08,
|
||||
NOROTATE: 0x10,
|
||||
NOVIEW: 0x20,
|
||||
READONLY: 0x40,
|
||||
LOCKED: 0x80,
|
||||
TOGGLENOVIEW: 0x100,
|
||||
LOCKEDCONTENTS: 0x200,
|
||||
};
|
||||
|
||||
const AnnotationFieldFlag = {
|
||||
READONLY: 0x0000001,
|
||||
REQUIRED: 0x0000002,
|
||||
NOEXPORT: 0x0000004,
|
||||
MULTILINE: 0x0001000,
|
||||
PASSWORD: 0x0002000,
|
||||
NOTOGGLETOOFF: 0x0004000,
|
||||
RADIO: 0x0008000,
|
||||
PUSHBUTTON: 0x0010000,
|
||||
COMBO: 0x0020000,
|
||||
EDIT: 0x0040000,
|
||||
SORT: 0x0080000,
|
||||
FILESELECT: 0x0100000,
|
||||
MULTISELECT: 0x0200000,
|
||||
DONOTSPELLCHECK: 0x0400000,
|
||||
DONOTSCROLL: 0x0800000,
|
||||
COMB: 0x1000000,
|
||||
RICHTEXT: 0x2000000,
|
||||
RADIOSINUNISON: 0x2000000,
|
||||
COMMITONSELCHANGE: 0x4000000,
|
||||
};
|
||||
|
||||
const AnnotationBorderStyleType = {
|
||||
SOLID: 1,
|
||||
DASHED: 2,
|
||||
BEVELED: 3,
|
||||
INSET: 4,
|
||||
UNDERLINE: 5,
|
||||
};
|
||||
|
||||
const StreamType = {
|
||||
UNKNOWN: "UNKNOWN",
|
||||
FLATE: "FLATE",
|
||||
LZW: "LZW",
|
||||
DCT: "DCT",
|
||||
JPX: "JPX",
|
||||
JBIG: "JBIG",
|
||||
A85: "A85",
|
||||
AHX: "AHX",
|
||||
CCF: "CCF",
|
||||
RLX: "RLX", // PDF short name is 'RL', but telemetry requires three chars.
|
||||
};
|
||||
|
||||
const FontType = {
|
||||
UNKNOWN: "UNKNOWN",
|
||||
TYPE1: "TYPE1",
|
||||
TYPE1C: "TYPE1C",
|
||||
CIDFONTTYPE0: "CIDFONTTYPE0",
|
||||
CIDFONTTYPE0C: "CIDFONTTYPE0C",
|
||||
TRUETYPE: "TRUETYPE",
|
||||
CIDFONTTYPE2: "CIDFONTTYPE2",
|
||||
TYPE3: "TYPE3",
|
||||
OPENTYPE: "OPENTYPE",
|
||||
TYPE0: "TYPE0",
|
||||
MMTYPE1: "MMTYPE1",
|
||||
};
|
||||
|
||||
const VerbosityLevel = {
|
||||
ERRORS: 0,
|
||||
WARNINGS: 1,
|
||||
INFOS: 5,
|
||||
};
|
||||
|
||||
const CMapCompressionType = {
|
||||
NONE: 0,
|
||||
BINARY: 1,
|
||||
STREAM: 2,
|
||||
};
|
||||
|
||||
// All the possible operations for an operator list.
|
||||
const OPS = {
|
||||
// Intentionally start from 1 so it is easy to spot bad operators that will be
|
||||
// 0's.
|
||||
dependency: 1,
|
||||
setLineWidth: 2,
|
||||
setLineCap: 3,
|
||||
setLineJoin: 4,
|
||||
setMiterLimit: 5,
|
||||
setDash: 6,
|
||||
setRenderingIntent: 7,
|
||||
setFlatness: 8,
|
||||
setGState: 9,
|
||||
save: 10,
|
||||
restore: 11,
|
||||
transform: 12,
|
||||
moveTo: 13,
|
||||
lineTo: 14,
|
||||
curveTo: 15,
|
||||
curveTo2: 16,
|
||||
curveTo3: 17,
|
||||
closePath: 18,
|
||||
rectangle: 19,
|
||||
stroke: 20,
|
||||
closeStroke: 21,
|
||||
fill: 22,
|
||||
eoFill: 23,
|
||||
fillStroke: 24,
|
||||
eoFillStroke: 25,
|
||||
closeFillStroke: 26,
|
||||
closeEOFillStroke: 27,
|
||||
endPath: 28,
|
||||
clip: 29,
|
||||
eoClip: 30,
|
||||
beginText: 31,
|
||||
endText: 32,
|
||||
setCharSpacing: 33,
|
||||
setWordSpacing: 34,
|
||||
setHScale: 35,
|
||||
setLeading: 36,
|
||||
setFont: 37,
|
||||
setTextRenderingMode: 38,
|
||||
setTextRise: 39,
|
||||
moveText: 40,
|
||||
setLeadingMoveText: 41,
|
||||
setTextMatrix: 42,
|
||||
nextLine: 43,
|
||||
showText: 44,
|
||||
showSpacedText: 45,
|
||||
nextLineShowText: 46,
|
||||
nextLineSetSpacingShowText: 47,
|
||||
setCharWidth: 48,
|
||||
setCharWidthAndBounds: 49,
|
||||
setStrokeColorSpace: 50,
|
||||
setFillColorSpace: 51,
|
||||
setStrokeColor: 52,
|
||||
setStrokeColorN: 53,
|
||||
setFillColor: 54,
|
||||
setFillColorN: 55,
|
||||
setStrokeGray: 56,
|
||||
setFillGray: 57,
|
||||
setStrokeRGBColor: 58,
|
||||
setFillRGBColor: 59,
|
||||
setStrokeCMYKColor: 60,
|
||||
setFillCMYKColor: 61,
|
||||
shadingFill: 62,
|
||||
beginInlineImage: 63,
|
||||
beginImageData: 64,
|
||||
endInlineImage: 65,
|
||||
paintXObject: 66,
|
||||
markPoint: 67,
|
||||
markPointProps: 68,
|
||||
beginMarkedContent: 69,
|
||||
beginMarkedContentProps: 70,
|
||||
endMarkedContent: 71,
|
||||
beginCompat: 72,
|
||||
endCompat: 73,
|
||||
paintFormXObjectBegin: 74,
|
||||
paintFormXObjectEnd: 75,
|
||||
beginGroup: 76,
|
||||
endGroup: 77,
|
||||
beginAnnotations: 78,
|
||||
endAnnotations: 79,
|
||||
beginAnnotation: 80,
|
||||
endAnnotation: 81,
|
||||
paintJpegXObject: 82,
|
||||
paintImageMaskXObject: 83,
|
||||
paintImageMaskXObjectGroup: 84,
|
||||
paintImageXObject: 85,
|
||||
paintInlineImageXObject: 86,
|
||||
paintInlineImageXObjectGroup: 87,
|
||||
paintImageXObjectRepeat: 88,
|
||||
paintImageMaskXObjectRepeat: 89,
|
||||
paintSolidColorImageMask: 90,
|
||||
constructPath: 91,
|
||||
};
|
||||
|
||||
const UNSUPPORTED_FEATURES = {
|
||||
/** @deprecated unused */
|
||||
unknown: "unknown",
|
||||
forms: "forms",
|
||||
javaScript: "javaScript",
|
||||
smask: "smask",
|
||||
shadingPattern: "shadingPattern",
|
||||
/** @deprecated unused */
|
||||
font: "font",
|
||||
errorTilingPattern: "errorTilingPattern",
|
||||
errorExtGState: "errorExtGState",
|
||||
errorXObject: "errorXObject",
|
||||
errorFontLoadType3: "errorFontLoadType3",
|
||||
errorFontState: "errorFontState",
|
||||
errorFontMissing: "errorFontMissing",
|
||||
errorFontTranslate: "errorFontTranslate",
|
||||
errorColorSpace: "errorColorSpace",
|
||||
errorOperatorList: "errorOperatorList",
|
||||
errorFontToUnicode: "errorFontToUnicode",
|
||||
errorFontLoadNative: "errorFontLoadNative",
|
||||
errorFontGetPath: "errorFontGetPath",
|
||||
errorMarkedContent: "errorMarkedContent",
|
||||
};
|
||||
|
||||
const PasswordResponses = {
|
||||
NEED_PASSWORD: 1,
|
||||
INCORRECT_PASSWORD: 2,
|
||||
};
|
||||
|
||||
let verbosity = VerbosityLevel.WARNINGS;
|
||||
|
||||
function setVerbosityLevel(level) {
|
||||
if (Number.isInteger(level)) {
|
||||
verbosity = level;
|
||||
}
|
||||
}
|
||||
|
||||
function getVerbosityLevel() {
|
||||
return verbosity;
|
||||
}
|
||||
|
||||
// A notice for devs. These are good for things that are helpful to devs, such
|
||||
// as warning that Workers were disabled, which is important to devs but not
|
||||
// end users.
|
||||
function info(msg) {
|
||||
if (verbosity >= VerbosityLevel.INFOS) {
|
||||
console.log(`Info: ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Non-fatal warnings.
|
||||
function warn(msg) {
|
||||
if (verbosity >= VerbosityLevel.WARNINGS) {
|
||||
console.log(`Warning: ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
function unreachable(msg) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
function assert(cond, msg) {
|
||||
if (!cond) {
|
||||
unreachable(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if URLs have the same origin. For non-HTTP based URLs, returns false.
|
||||
function isSameOrigin(baseUrl, otherUrl) {
|
||||
let base;
|
||||
try {
|
||||
base = new URL(baseUrl);
|
||||
if (!base.origin || base.origin === "null") {
|
||||
return false; // non-HTTP url
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const other = new URL(otherUrl, base);
|
||||
return base.origin === other.origin;
|
||||
}
|
||||
|
||||
// Checks if URLs use one of the allowed protocols, e.g. to avoid XSS.
|
||||
function _isValidProtocol(url) {
|
||||
if (!url) {
|
||||
return false;
|
||||
}
|
||||
switch (url.protocol) {
|
||||
case "http:":
|
||||
case "https:":
|
||||
case "ftp:":
|
||||
case "mailto:":
|
||||
case "tel:":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to create a valid absolute URL.
|
||||
*
|
||||
* @param {URL|string} url - An absolute, or relative, URL.
|
||||
* @param {URL|string} baseUrl - An absolute URL.
|
||||
* @returns Either a valid {URL}, or `null` otherwise.
|
||||
*/
|
||||
function createValidAbsoluteUrl(url, baseUrl) {
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url);
|
||||
if (_isValidProtocol(absoluteUrl)) {
|
||||
return absoluteUrl;
|
||||
}
|
||||
} catch (ex) {
|
||||
/* `new URL()` will throw on incorrect data. */
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function shadow(obj, prop, value) {
|
||||
Object.defineProperty(obj, prop, {
|
||||
value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: false,
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
const BaseException = (function BaseExceptionClosure() {
|
||||
// eslint-disable-next-line no-shadow
|
||||
function BaseException(message) {
|
||||
if (this.constructor === BaseException) {
|
||||
unreachable("Cannot initialize BaseException.");
|
||||
}
|
||||
this.message = message;
|
||||
this.name = this.constructor.name;
|
||||
}
|
||||
BaseException.prototype = new Error();
|
||||
BaseException.constructor = BaseException;
|
||||
|
||||
return BaseException;
|
||||
})();
|
||||
|
||||
class PasswordException extends BaseException {
|
||||
constructor(msg, code) {
|
||||
super(msg);
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
class UnknownErrorException extends BaseException {
|
||||
constructor(msg, details) {
|
||||
super(msg);
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
|
||||
class InvalidPDFException extends BaseException {}
|
||||
|
||||
class MissingPDFException extends BaseException {}
|
||||
|
||||
class UnexpectedResponseException extends BaseException {
|
||||
constructor(msg, status) {
|
||||
super(msg);
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error caused during parsing PDF data.
|
||||
*/
|
||||
class FormatError extends BaseException {}
|
||||
|
||||
/**
|
||||
* Error used to indicate task cancellation.
|
||||
*/
|
||||
class AbortException extends BaseException {}
|
||||
|
||||
const NullCharactersRegExp = /\x00/g;
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
*/
|
||||
function removeNullCharacters(str) {
|
||||
if (typeof str !== "string") {
|
||||
warn("The argument for removeNullCharacters must be a string.");
|
||||
return str;
|
||||
}
|
||||
return str.replace(NullCharactersRegExp, "");
|
||||
}
|
||||
|
||||
function bytesToString(bytes) {
|
||||
assert(
|
||||
bytes !== null && typeof bytes === "object" && bytes.length !== undefined,
|
||||
"Invalid argument for bytesToString"
|
||||
);
|
||||
const length = bytes.length;
|
||||
const MAX_ARGUMENT_COUNT = 8192;
|
||||
if (length < MAX_ARGUMENT_COUNT) {
|
||||
return String.fromCharCode.apply(null, bytes);
|
||||
}
|
||||
const strBuf = [];
|
||||
for (let i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
|
||||
const chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
|
||||
const chunk = bytes.subarray(i, chunkEnd);
|
||||
strBuf.push(String.fromCharCode.apply(null, chunk));
|
||||
}
|
||||
return strBuf.join("");
|
||||
}
|
||||
|
||||
function stringToBytes(str) {
|
||||
assert(typeof str === "string", "Invalid argument for stringToBytes");
|
||||
const length = str.length;
|
||||
const bytes = new Uint8Array(length);
|
||||
for (let i = 0; i < length; ++i) {
|
||||
bytes[i] = str.charCodeAt(i) & 0xff;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets length of the array (Array, Uint8Array, or string) in bytes.
|
||||
* @param {Array<any>|Uint8Array|string} arr
|
||||
* @returns {number}
|
||||
*/
|
||||
function arrayByteLength(arr) {
|
||||
if (arr.length !== undefined) {
|
||||
return arr.length;
|
||||
}
|
||||
assert(arr.byteLength !== undefined, "arrayByteLength - invalid argument.");
|
||||
return arr.byteLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines array items (arrays) into single Uint8Array object.
|
||||
* @param {Array<Array<any>|Uint8Array|string>} arr - the array of the arrays
|
||||
* (Array, Uint8Array, or string).
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
function arraysToBytes(arr) {
|
||||
const length = arr.length;
|
||||
// Shortcut: if first and only item is Uint8Array, return it.
|
||||
if (length === 1 && arr[0] instanceof Uint8Array) {
|
||||
return arr[0];
|
||||
}
|
||||
let resultLength = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
resultLength += arrayByteLength(arr[i]);
|
||||
}
|
||||
let pos = 0;
|
||||
const data = new Uint8Array(resultLength);
|
||||
for (let i = 0; i < length; i++) {
|
||||
let item = arr[i];
|
||||
if (!(item instanceof Uint8Array)) {
|
||||
if (typeof item === "string") {
|
||||
item = stringToBytes(item);
|
||||
} else {
|
||||
item = new Uint8Array(item);
|
||||
}
|
||||
}
|
||||
const itemLength = item.byteLength;
|
||||
data.set(item, pos);
|
||||
pos += itemLength;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function string32(value) {
|
||||
return String.fromCharCode(
|
||||
(value >> 24) & 0xff,
|
||||
(value >> 16) & 0xff,
|
||||
(value >> 8) & 0xff,
|
||||
value & 0xff
|
||||
);
|
||||
}
|
||||
|
||||
// Checks the endianness of the platform.
|
||||
function isLittleEndian() {
|
||||
const buffer8 = new Uint8Array(4);
|
||||
buffer8[0] = 1;
|
||||
const view32 = new Uint32Array(buffer8.buffer, 0, 1);
|
||||
return view32[0] === 1;
|
||||
}
|
||||
const IsLittleEndianCached = {
|
||||
get value() {
|
||||
return shadow(this, "value", isLittleEndian());
|
||||
},
|
||||
};
|
||||
|
||||
// Checks if it's possible to eval JS expressions.
|
||||
function isEvalSupported() {
|
||||
try {
|
||||
new Function(""); // eslint-disable-line no-new, no-new-func
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const IsEvalSupportedCached = {
|
||||
get value() {
|
||||
return shadow(this, "value", isEvalSupported());
|
||||
},
|
||||
};
|
||||
|
||||
const rgbBuf = ["rgb(", 0, ",", 0, ",", 0, ")"];
|
||||
|
||||
class Util {
|
||||
// makeCssRgb() can be called thousands of times. Using ´rgbBuf` avoids
|
||||
// creating many intermediate strings.
|
||||
static makeCssRgb(r, g, b) {
|
||||
rgbBuf[1] = r;
|
||||
rgbBuf[3] = g;
|
||||
rgbBuf[5] = b;
|
||||
return rgbBuf.join("");
|
||||
}
|
||||
|
||||
// Concatenates two transformation matrices together and returns the result.
|
||||
static transform(m1, m2) {
|
||||
return [
|
||||
m1[0] * m2[0] + m1[2] * m2[1],
|
||||
m1[1] * m2[0] + m1[3] * m2[1],
|
||||
m1[0] * m2[2] + m1[2] * m2[3],
|
||||
m1[1] * m2[2] + m1[3] * m2[3],
|
||||
m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
|
||||
m1[1] * m2[4] + m1[3] * m2[5] + m1[5],
|
||||
];
|
||||
}
|
||||
|
||||
// For 2d affine transforms
|
||||
static applyTransform(p, m) {
|
||||
const xt = p[0] * m[0] + p[1] * m[2] + m[4];
|
||||
const yt = p[0] * m[1] + p[1] * m[3] + m[5];
|
||||
return [xt, yt];
|
||||
}
|
||||
|
||||
static applyInverseTransform(p, m) {
|
||||
const d = m[0] * m[3] - m[1] * m[2];
|
||||
const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
|
||||
const yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
|
||||
return [xt, yt];
|
||||
}
|
||||
|
||||
// Applies the transform to the rectangle and finds the minimum axially
|
||||
// aligned bounding box.
|
||||
static getAxialAlignedBoundingBox(r, m) {
|
||||
const p1 = Util.applyTransform(r, m);
|
||||
const p2 = Util.applyTransform(r.slice(2, 4), m);
|
||||
const p3 = Util.applyTransform([r[0], r[3]], m);
|
||||
const p4 = Util.applyTransform([r[2], r[1]], m);
|
||||
return [
|
||||
Math.min(p1[0], p2[0], p3[0], p4[0]),
|
||||
Math.min(p1[1], p2[1], p3[1], p4[1]),
|
||||
Math.max(p1[0], p2[0], p3[0], p4[0]),
|
||||
Math.max(p1[1], p2[1], p3[1], p4[1]),
|
||||
];
|
||||
}
|
||||
|
||||
static inverseTransform(m) {
|
||||
const d = m[0] * m[3] - m[1] * m[2];
|
||||
return [
|
||||
m[3] / d,
|
||||
-m[1] / d,
|
||||
-m[2] / d,
|
||||
m[0] / d,
|
||||
(m[2] * m[5] - m[4] * m[3]) / d,
|
||||
(m[4] * m[1] - m[5] * m[0]) / d,
|
||||
];
|
||||
}
|
||||
|
||||
// Apply a generic 3d matrix M on a 3-vector v:
|
||||
// | a b c | | X |
|
||||
// | d e f | x | Y |
|
||||
// | g h i | | Z |
|
||||
// M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
|
||||
// with v as [X,Y,Z]
|
||||
static apply3dTransform(m, v) {
|
||||
return [
|
||||
m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
|
||||
m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
|
||||
m[6] * v[0] + m[7] * v[1] + m[8] * v[2],
|
||||
];
|
||||
}
|
||||
|
||||
// This calculation uses Singular Value Decomposition.
|
||||
// The SVD can be represented with formula A = USV. We are interested in the
|
||||
// matrix S here because it represents the scale values.
|
||||
static singularValueDecompose2dScale(m) {
|
||||
const transpose = [m[0], m[2], m[1], m[3]];
|
||||
|
||||
// Multiply matrix m with its transpose.
|
||||
const a = m[0] * transpose[0] + m[1] * transpose[2];
|
||||
const b = m[0] * transpose[1] + m[1] * transpose[3];
|
||||
const c = m[2] * transpose[0] + m[3] * transpose[2];
|
||||
const d = m[2] * transpose[1] + m[3] * transpose[3];
|
||||
|
||||
// Solve the second degree polynomial to get roots.
|
||||
const first = (a + d) / 2;
|
||||
const second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
|
||||
const sx = first + second || 1;
|
||||
const sy = first - second || 1;
|
||||
|
||||
// Scale values are the square roots of the eigenvalues.
|
||||
return [Math.sqrt(sx), Math.sqrt(sy)];
|
||||
}
|
||||
|
||||
// Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
|
||||
// For coordinate systems whose origin lies in the bottom-left, this
|
||||
// means normalization to (BL,TR) ordering. For systems with origin in the
|
||||
// top-left, this means (TL,BR) ordering.
|
||||
static normalizeRect(rect) {
|
||||
const r = rect.slice(0); // clone rect
|
||||
if (rect[0] > rect[2]) {
|
||||
r[0] = rect[2];
|
||||
r[2] = rect[0];
|
||||
}
|
||||
if (rect[1] > rect[3]) {
|
||||
r[1] = rect[3];
|
||||
r[3] = rect[1];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Returns a rectangle [x1, y1, x2, y2] corresponding to the
|
||||
// intersection of rect1 and rect2. If no intersection, returns 'false'
|
||||
// The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
|
||||
static intersect(rect1, rect2) {
|
||||
function compare(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Order points along the axes
|
||||
const orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare);
|
||||
const orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare);
|
||||
const result = [];
|
||||
|
||||
rect1 = Util.normalizeRect(rect1);
|
||||
rect2 = Util.normalizeRect(rect2);
|
||||
|
||||
// X: first and second points belong to different rectangles?
|
||||
if (
|
||||
(orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
|
||||
(orderedX[0] === rect2[0] && orderedX[1] === rect1[0])
|
||||
) {
|
||||
// Intersection must be between second and third points
|
||||
result[0] = orderedX[1];
|
||||
result[2] = orderedX[2];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Y: first and second points belong to different rectangles?
|
||||
if (
|
||||
(orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
|
||||
(orderedY[0] === rect2[1] && orderedY[1] === rect1[1])
|
||||
) {
|
||||
// Intersection must be between second and third points
|
||||
result[1] = orderedY[1];
|
||||
result[3] = orderedY[2];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
const PDFStringTranslateTable = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
|
||||
0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
|
||||
0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
|
||||
0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
|
||||
];
|
||||
|
||||
function stringToPDFString(str) {
|
||||
const length = str.length,
|
||||
strBuf = [];
|
||||
if (str[0] === "\xFE" && str[1] === "\xFF") {
|
||||
// UTF16BE BOM
|
||||
for (let i = 2; i < length; i += 2) {
|
||||
strBuf.push(
|
||||
String.fromCharCode((str.charCodeAt(i) << 8) | str.charCodeAt(i + 1))
|
||||
);
|
||||
}
|
||||
} else if (str[0] === "\xFF" && str[1] === "\xFE") {
|
||||
// UTF16LE BOM
|
||||
for (let i = 2; i < length; i += 2) {
|
||||
strBuf.push(
|
||||
String.fromCharCode((str.charCodeAt(i + 1) << 8) | str.charCodeAt(i))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < length; ++i) {
|
||||
const code = PDFStringTranslateTable[str.charCodeAt(i)];
|
||||
strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
|
||||
}
|
||||
}
|
||||
return strBuf.join("");
|
||||
}
|
||||
|
||||
function escapeString(str) {
|
||||
// replace "(", ")" and "\" by "\(", "\)" and "\\"
|
||||
// in order to write it in a PDF file.
|
||||
return str.replace(/([\(\)\\])/g, "\\$1");
|
||||
}
|
||||
|
||||
function stringToUTF8String(str) {
|
||||
return decodeURIComponent(escape(str));
|
||||
}
|
||||
|
||||
function utf8StringToString(str) {
|
||||
return unescape(encodeURIComponent(str));
|
||||
}
|
||||
|
||||
function isBool(v) {
|
||||
return typeof v === "boolean";
|
||||
}
|
||||
|
||||
function isNum(v) {
|
||||
return typeof v === "number";
|
||||
}
|
||||
|
||||
function isString(v) {
|
||||
return typeof v === "string";
|
||||
}
|
||||
|
||||
function isArrayBuffer(v) {
|
||||
return typeof v === "object" && v !== null && v.byteLength !== undefined;
|
||||
}
|
||||
|
||||
function isArrayEqual(arr1, arr2) {
|
||||
if (arr1.length !== arr2.length) {
|
||||
return false;
|
||||
}
|
||||
return arr1.every(function (element, index) {
|
||||
return element === arr2[index];
|
||||
});
|
||||
}
|
||||
|
||||
function getModificationDate(date = new Date(Date.now())) {
|
||||
const buffer = [
|
||||
date.getUTCFullYear().toString(),
|
||||
(date.getUTCMonth() + 1).toString().padStart(2, "0"),
|
||||
(date.getUTCDate() + 1).toString().padStart(2, "0"),
|
||||
date.getUTCHours().toString().padStart(2, "0"),
|
||||
date.getUTCMinutes().toString().padStart(2, "0"),
|
||||
date.getUTCSeconds().toString().padStart(2, "0"),
|
||||
];
|
||||
|
||||
return buffer.join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Promise Capability object.
|
||||
*
|
||||
* @typedef {Object} PromiseCapability
|
||||
* @property {Promise<any>} promise - A Promise object.
|
||||
* @property {boolean} settled - If the Promise has been fulfilled/rejected.
|
||||
* @property {function} resolve - Fulfills the Promise.
|
||||
* @property {function} reject - Rejects the Promise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a promise capability object.
|
||||
* @alias createPromiseCapability
|
||||
*
|
||||
* @returns {PromiseCapability}
|
||||
*/
|
||||
function createPromiseCapability() {
|
||||
const capability = Object.create(null);
|
||||
let isSettled = false;
|
||||
|
||||
Object.defineProperty(capability, "settled", {
|
||||
get() {
|
||||
return isSettled;
|
||||
},
|
||||
});
|
||||
capability.promise = new Promise(function (resolve, reject) {
|
||||
capability.resolve = function (data) {
|
||||
isSettled = true;
|
||||
resolve(data);
|
||||
};
|
||||
capability.reject = function (reason) {
|
||||
isSettled = true;
|
||||
reject(reason);
|
||||
};
|
||||
});
|
||||
return capability;
|
||||
}
|
||||
|
||||
const createObjectURL = (function createObjectURLClosure() {
|
||||
// Blob/createObjectURL is not available, falling back to data schema.
|
||||
const digits =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
return function createObjectURL(data, contentType, forceDataSchema = false) {
|
||||
if (!forceDataSchema && URL.createObjectURL) {
|
||||
const blob = new Blob([data], { type: contentType });
|
||||
return URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
let buffer = `data:${contentType};base64,`;
|
||||
for (let i = 0, ii = data.length; i < ii; i += 3) {
|
||||
const b1 = data[i] & 0xff;
|
||||
const b2 = data[i + 1] & 0xff;
|
||||
const b3 = data[i + 2] & 0xff;
|
||||
const d1 = b1 >> 2,
|
||||
d2 = ((b1 & 3) << 4) | (b2 >> 4);
|
||||
const d3 = i + 1 < ii ? ((b2 & 0xf) << 2) | (b3 >> 6) : 64;
|
||||
const d4 = i + 2 < ii ? b3 & 0x3f : 64;
|
||||
buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
|
||||
}
|
||||
return buffer;
|
||||
};
|
||||
})();
|
||||
|
||||
export {
|
||||
BaseException,
|
||||
FONT_IDENTITY_MATRIX,
|
||||
IDENTITY_MATRIX,
|
||||
OPS,
|
||||
VerbosityLevel,
|
||||
UNSUPPORTED_FEATURES,
|
||||
AnnotationBorderStyleType,
|
||||
AnnotationFieldFlag,
|
||||
AnnotationFlag,
|
||||
AnnotationMarkedState,
|
||||
AnnotationReplyType,
|
||||
AnnotationReviewState,
|
||||
AnnotationStateModelType,
|
||||
AnnotationType,
|
||||
FontType,
|
||||
ImageKind,
|
||||
CMapCompressionType,
|
||||
AbortException,
|
||||
InvalidPDFException,
|
||||
MissingPDFException,
|
||||
PasswordException,
|
||||
PasswordResponses,
|
||||
PermissionFlag,
|
||||
StreamType,
|
||||
TextRenderingMode,
|
||||
UnexpectedResponseException,
|
||||
UnknownErrorException,
|
||||
Util,
|
||||
FormatError,
|
||||
arrayByteLength,
|
||||
arraysToBytes,
|
||||
assert,
|
||||
bytesToString,
|
||||
createPromiseCapability,
|
||||
createObjectURL,
|
||||
escapeString,
|
||||
getModificationDate,
|
||||
getVerbosityLevel,
|
||||
info,
|
||||
isArrayBuffer,
|
||||
isArrayEqual,
|
||||
isBool,
|
||||
isNum,
|
||||
isString,
|
||||
isSameOrigin,
|
||||
createValidAbsoluteUrl,
|
||||
IsLittleEndianCached,
|
||||
IsEvalSupportedCached,
|
||||
removeNullCharacters,
|
||||
setVerbosityLevel,
|
||||
shadow,
|
||||
string32,
|
||||
stringToBytes,
|
||||
stringToPDFString,
|
||||
stringToUTF8String,
|
||||
utf8StringToString,
|
||||
warn,
|
||||
unreachable,
|
||||
};
|
3
vue.config.js
Normal file
3
vue.config.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
lintOnSave: false
|
||||
}
|
Loading…
Reference in New Issue
Block a user