采用pdf.js的代码实现jbig2的解析编码

This commit is contained in:
Donal 2020-09-10 15:24:59 +08:00
parent 3b77d648b5
commit bd83513e5f
13 changed files with 7228 additions and 24 deletions

View File

@ -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",

View File

@ -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) => {

View 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

File diff suppressed because it is too large Load Diff

312
src/utils/compatibility.js Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

81
src/utils/jbig2_stream.js Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

972
src/utils/util.js Normal file
View 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
View File

@ -0,0 +1,3 @@
module.exports = {
lintOnSave: false
}