util.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  1. /* Copyright 2012 Mozilla Foundation
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. /* eslint no-var: error */
  16. import "./compatibility.js";
  17. const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
  18. const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
  19. // Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
  20. const PermissionFlag = {
  21. PRINT: 0x04,
  22. MODIFY_CONTENTS: 0x08,
  23. COPY: 0x10,
  24. MODIFY_ANNOTATIONS: 0x20,
  25. FILL_INTERACTIVE_FORMS: 0x100,
  26. COPY_FOR_ACCESSIBILITY: 0x200,
  27. ASSEMBLE: 0x400,
  28. PRINT_HIGH_QUALITY: 0x800,
  29. };
  30. const TextRenderingMode = {
  31. FILL: 0,
  32. STROKE: 1,
  33. FILL_STROKE: 2,
  34. INVISIBLE: 3,
  35. FILL_ADD_TO_PATH: 4,
  36. STROKE_ADD_TO_PATH: 5,
  37. FILL_STROKE_ADD_TO_PATH: 6,
  38. ADD_TO_PATH: 7,
  39. FILL_STROKE_MASK: 3,
  40. ADD_TO_PATH_FLAG: 4,
  41. };
  42. const ImageKind = {
  43. GRAYSCALE_1BPP: 1,
  44. RGB_24BPP: 2,
  45. RGBA_32BPP: 3,
  46. };
  47. const AnnotationType = {
  48. TEXT: 1,
  49. LINK: 2,
  50. FREETEXT: 3,
  51. LINE: 4,
  52. SQUARE: 5,
  53. CIRCLE: 6,
  54. POLYGON: 7,
  55. POLYLINE: 8,
  56. HIGHLIGHT: 9,
  57. UNDERLINE: 10,
  58. SQUIGGLY: 11,
  59. STRIKEOUT: 12,
  60. STAMP: 13,
  61. CARET: 14,
  62. INK: 15,
  63. POPUP: 16,
  64. FILEATTACHMENT: 17,
  65. SOUND: 18,
  66. MOVIE: 19,
  67. WIDGET: 20,
  68. SCREEN: 21,
  69. PRINTERMARK: 22,
  70. TRAPNET: 23,
  71. WATERMARK: 24,
  72. THREED: 25,
  73. REDACT: 26,
  74. };
  75. const AnnotationStateModelType = {
  76. MARKED: "Marked",
  77. REVIEW: "Review",
  78. };
  79. const AnnotationMarkedState = {
  80. MARKED: "Marked",
  81. UNMARKED: "Unmarked",
  82. };
  83. const AnnotationReviewState = {
  84. ACCEPTED: "Accepted",
  85. REJECTED: "Rejected",
  86. CANCELLED: "Cancelled",
  87. COMPLETED: "Completed",
  88. NONE: "None",
  89. };
  90. const AnnotationReplyType = {
  91. GROUP: "Group",
  92. REPLY: "R",
  93. };
  94. const AnnotationFlag = {
  95. INVISIBLE: 0x01,
  96. HIDDEN: 0x02,
  97. PRINT: 0x04,
  98. NOZOOM: 0x08,
  99. NOROTATE: 0x10,
  100. NOVIEW: 0x20,
  101. READONLY: 0x40,
  102. LOCKED: 0x80,
  103. TOGGLENOVIEW: 0x100,
  104. LOCKEDCONTENTS: 0x200,
  105. };
  106. const AnnotationFieldFlag = {
  107. READONLY: 0x0000001,
  108. REQUIRED: 0x0000002,
  109. NOEXPORT: 0x0000004,
  110. MULTILINE: 0x0001000,
  111. PASSWORD: 0x0002000,
  112. NOTOGGLETOOFF: 0x0004000,
  113. RADIO: 0x0008000,
  114. PUSHBUTTON: 0x0010000,
  115. COMBO: 0x0020000,
  116. EDIT: 0x0040000,
  117. SORT: 0x0080000,
  118. FILESELECT: 0x0100000,
  119. MULTISELECT: 0x0200000,
  120. DONOTSPELLCHECK: 0x0400000,
  121. DONOTSCROLL: 0x0800000,
  122. COMB: 0x1000000,
  123. RICHTEXT: 0x2000000,
  124. RADIOSINUNISON: 0x2000000,
  125. COMMITONSELCHANGE: 0x4000000,
  126. };
  127. const AnnotationBorderStyleType = {
  128. SOLID: 1,
  129. DASHED: 2,
  130. BEVELED: 3,
  131. INSET: 4,
  132. UNDERLINE: 5,
  133. };
  134. const StreamType = {
  135. UNKNOWN: "UNKNOWN",
  136. FLATE: "FLATE",
  137. LZW: "LZW",
  138. DCT: "DCT",
  139. JPX: "JPX",
  140. JBIG: "JBIG",
  141. A85: "A85",
  142. AHX: "AHX",
  143. CCF: "CCF",
  144. RLX: "RLX", // PDF short name is 'RL', but telemetry requires three chars.
  145. };
  146. const FontType = {
  147. UNKNOWN: "UNKNOWN",
  148. TYPE1: "TYPE1",
  149. TYPE1C: "TYPE1C",
  150. CIDFONTTYPE0: "CIDFONTTYPE0",
  151. CIDFONTTYPE0C: "CIDFONTTYPE0C",
  152. TRUETYPE: "TRUETYPE",
  153. CIDFONTTYPE2: "CIDFONTTYPE2",
  154. TYPE3: "TYPE3",
  155. OPENTYPE: "OPENTYPE",
  156. TYPE0: "TYPE0",
  157. MMTYPE1: "MMTYPE1",
  158. };
  159. const VerbosityLevel = {
  160. ERRORS: 0,
  161. WARNINGS: 1,
  162. INFOS: 5,
  163. };
  164. const CMapCompressionType = {
  165. NONE: 0,
  166. BINARY: 1,
  167. STREAM: 2,
  168. };
  169. // All the possible operations for an operator list.
  170. const OPS = {
  171. // Intentionally start from 1 so it is easy to spot bad operators that will be
  172. // 0's.
  173. dependency: 1,
  174. setLineWidth: 2,
  175. setLineCap: 3,
  176. setLineJoin: 4,
  177. setMiterLimit: 5,
  178. setDash: 6,
  179. setRenderingIntent: 7,
  180. setFlatness: 8,
  181. setGState: 9,
  182. save: 10,
  183. restore: 11,
  184. transform: 12,
  185. moveTo: 13,
  186. lineTo: 14,
  187. curveTo: 15,
  188. curveTo2: 16,
  189. curveTo3: 17,
  190. closePath: 18,
  191. rectangle: 19,
  192. stroke: 20,
  193. closeStroke: 21,
  194. fill: 22,
  195. eoFill: 23,
  196. fillStroke: 24,
  197. eoFillStroke: 25,
  198. closeFillStroke: 26,
  199. closeEOFillStroke: 27,
  200. endPath: 28,
  201. clip: 29,
  202. eoClip: 30,
  203. beginText: 31,
  204. endText: 32,
  205. setCharSpacing: 33,
  206. setWordSpacing: 34,
  207. setHScale: 35,
  208. setLeading: 36,
  209. setFont: 37,
  210. setTextRenderingMode: 38,
  211. setTextRise: 39,
  212. moveText: 40,
  213. setLeadingMoveText: 41,
  214. setTextMatrix: 42,
  215. nextLine: 43,
  216. showText: 44,
  217. showSpacedText: 45,
  218. nextLineShowText: 46,
  219. nextLineSetSpacingShowText: 47,
  220. setCharWidth: 48,
  221. setCharWidthAndBounds: 49,
  222. setStrokeColorSpace: 50,
  223. setFillColorSpace: 51,
  224. setStrokeColor: 52,
  225. setStrokeColorN: 53,
  226. setFillColor: 54,
  227. setFillColorN: 55,
  228. setStrokeGray: 56,
  229. setFillGray: 57,
  230. setStrokeRGBColor: 58,
  231. setFillRGBColor: 59,
  232. setStrokeCMYKColor: 60,
  233. setFillCMYKColor: 61,
  234. shadingFill: 62,
  235. beginInlineImage: 63,
  236. beginImageData: 64,
  237. endInlineImage: 65,
  238. paintXObject: 66,
  239. markPoint: 67,
  240. markPointProps: 68,
  241. beginMarkedContent: 69,
  242. beginMarkedContentProps: 70,
  243. endMarkedContent: 71,
  244. beginCompat: 72,
  245. endCompat: 73,
  246. paintFormXObjectBegin: 74,
  247. paintFormXObjectEnd: 75,
  248. beginGroup: 76,
  249. endGroup: 77,
  250. beginAnnotations: 78,
  251. endAnnotations: 79,
  252. beginAnnotation: 80,
  253. endAnnotation: 81,
  254. paintJpegXObject: 82,
  255. paintImageMaskXObject: 83,
  256. paintImageMaskXObjectGroup: 84,
  257. paintImageXObject: 85,
  258. paintInlineImageXObject: 86,
  259. paintInlineImageXObjectGroup: 87,
  260. paintImageXObjectRepeat: 88,
  261. paintImageMaskXObjectRepeat: 89,
  262. paintSolidColorImageMask: 90,
  263. constructPath: 91,
  264. };
  265. const UNSUPPORTED_FEATURES = {
  266. /** @deprecated unused */
  267. unknown: "unknown",
  268. forms: "forms",
  269. javaScript: "javaScript",
  270. smask: "smask",
  271. shadingPattern: "shadingPattern",
  272. /** @deprecated unused */
  273. font: "font",
  274. errorTilingPattern: "errorTilingPattern",
  275. errorExtGState: "errorExtGState",
  276. errorXObject: "errorXObject",
  277. errorFontLoadType3: "errorFontLoadType3",
  278. errorFontState: "errorFontState",
  279. errorFontMissing: "errorFontMissing",
  280. errorFontTranslate: "errorFontTranslate",
  281. errorColorSpace: "errorColorSpace",
  282. errorOperatorList: "errorOperatorList",
  283. errorFontToUnicode: "errorFontToUnicode",
  284. errorFontLoadNative: "errorFontLoadNative",
  285. errorFontGetPath: "errorFontGetPath",
  286. errorMarkedContent: "errorMarkedContent",
  287. };
  288. const PasswordResponses = {
  289. NEED_PASSWORD: 1,
  290. INCORRECT_PASSWORD: 2,
  291. };
  292. let verbosity = VerbosityLevel.WARNINGS;
  293. function setVerbosityLevel(level) {
  294. if (Number.isInteger(level)) {
  295. verbosity = level;
  296. }
  297. }
  298. function getVerbosityLevel() {
  299. return verbosity;
  300. }
  301. // A notice for devs. These are good for things that are helpful to devs, such
  302. // as warning that Workers were disabled, which is important to devs but not
  303. // end users.
  304. function info(msg) {
  305. if (verbosity >= VerbosityLevel.INFOS) {
  306. console.log(`Info: ${msg}`);
  307. }
  308. }
  309. // Non-fatal warnings.
  310. function warn(msg) {
  311. if (verbosity >= VerbosityLevel.WARNINGS) {
  312. console.log(`Warning: ${msg}`);
  313. }
  314. }
  315. function unreachable(msg) {
  316. throw new Error(msg);
  317. }
  318. function assert(cond, msg) {
  319. if (!cond) {
  320. unreachable(msg);
  321. }
  322. }
  323. // Checks if URLs have the same origin. For non-HTTP based URLs, returns false.
  324. function isSameOrigin(baseUrl, otherUrl) {
  325. let base;
  326. try {
  327. base = new URL(baseUrl);
  328. if (!base.origin || base.origin === "null") {
  329. return false; // non-HTTP url
  330. }
  331. } catch (e) {
  332. return false;
  333. }
  334. const other = new URL(otherUrl, base);
  335. return base.origin === other.origin;
  336. }
  337. // Checks if URLs use one of the allowed protocols, e.g. to avoid XSS.
  338. function _isValidProtocol(url) {
  339. if (!url) {
  340. return false;
  341. }
  342. switch (url.protocol) {
  343. case "http:":
  344. case "https:":
  345. case "ftp:":
  346. case "mailto:":
  347. case "tel:":
  348. return true;
  349. default:
  350. return false;
  351. }
  352. }
  353. /**
  354. * Attempts to create a valid absolute URL.
  355. *
  356. * @param {URL|string} url - An absolute, or relative, URL.
  357. * @param {URL|string} baseUrl - An absolute URL.
  358. * @returns Either a valid {URL}, or `null` otherwise.
  359. */
  360. function createValidAbsoluteUrl(url, baseUrl) {
  361. if (!url) {
  362. return null;
  363. }
  364. try {
  365. const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url);
  366. if (_isValidProtocol(absoluteUrl)) {
  367. return absoluteUrl;
  368. }
  369. } catch (ex) {
  370. /* `new URL()` will throw on incorrect data. */
  371. }
  372. return null;
  373. }
  374. function shadow(obj, prop, value) {
  375. Object.defineProperty(obj, prop, {
  376. value,
  377. enumerable: true,
  378. configurable: true,
  379. writable: false,
  380. });
  381. return value;
  382. }
  383. /**
  384. * @type {any}
  385. */
  386. const BaseException = (function BaseExceptionClosure() {
  387. // eslint-disable-next-line no-shadow
  388. function BaseException(message) {
  389. if (this.constructor === BaseException) {
  390. unreachable("Cannot initialize BaseException.");
  391. }
  392. this.message = message;
  393. this.name = this.constructor.name;
  394. }
  395. BaseException.prototype = new Error();
  396. BaseException.constructor = BaseException;
  397. return BaseException;
  398. })();
  399. class PasswordException extends BaseException {
  400. constructor(msg, code) {
  401. super(msg);
  402. this.code = code;
  403. }
  404. }
  405. class UnknownErrorException extends BaseException {
  406. constructor(msg, details) {
  407. super(msg);
  408. this.details = details;
  409. }
  410. }
  411. class InvalidPDFException extends BaseException {}
  412. class MissingPDFException extends BaseException {}
  413. class UnexpectedResponseException extends BaseException {
  414. constructor(msg, status) {
  415. super(msg);
  416. this.status = status;
  417. }
  418. }
  419. /**
  420. * Error caused during parsing PDF data.
  421. */
  422. class FormatError extends BaseException {}
  423. /**
  424. * Error used to indicate task cancellation.
  425. */
  426. class AbortException extends BaseException {}
  427. const NullCharactersRegExp = /\x00/g;
  428. /**
  429. * @param {string} str
  430. */
  431. function removeNullCharacters(str) {
  432. if (typeof str !== "string") {
  433. warn("The argument for removeNullCharacters must be a string.");
  434. return str;
  435. }
  436. return str.replace(NullCharactersRegExp, "");
  437. }
  438. function bytesToString(bytes) {
  439. assert(
  440. bytes !== null && typeof bytes === "object" && bytes.length !== undefined,
  441. "Invalid argument for bytesToString"
  442. );
  443. const length = bytes.length;
  444. const MAX_ARGUMENT_COUNT = 8192;
  445. if (length < MAX_ARGUMENT_COUNT) {
  446. return String.fromCharCode.apply(null, bytes);
  447. }
  448. const strBuf = [];
  449. for (let i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
  450. const chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
  451. const chunk = bytes.subarray(i, chunkEnd);
  452. strBuf.push(String.fromCharCode.apply(null, chunk));
  453. }
  454. return strBuf.join("");
  455. }
  456. function stringToBytes(str) {
  457. assert(typeof str === "string", "Invalid argument for stringToBytes");
  458. const length = str.length;
  459. const bytes = new Uint8Array(length);
  460. for (let i = 0; i < length; ++i) {
  461. bytes[i] = str.charCodeAt(i) & 0xff;
  462. }
  463. return bytes;
  464. }
  465. /**
  466. * Gets length of the array (Array, Uint8Array, or string) in bytes.
  467. * @param {Array<any>|Uint8Array|string} arr
  468. * @returns {number}
  469. */
  470. function arrayByteLength(arr) {
  471. if (arr.length !== undefined) {
  472. return arr.length;
  473. }
  474. assert(arr.byteLength !== undefined, "arrayByteLength - invalid argument.");
  475. return arr.byteLength;
  476. }
  477. /**
  478. * Combines array items (arrays) into single Uint8Array object.
  479. * @param {Array<Array<any>|Uint8Array|string>} arr - the array of the arrays
  480. * (Array, Uint8Array, or string).
  481. * @returns {Uint8Array}
  482. */
  483. function arraysToBytes(arr) {
  484. const length = arr.length;
  485. // Shortcut: if first and only item is Uint8Array, return it.
  486. if (length === 1 && arr[0] instanceof Uint8Array) {
  487. return arr[0];
  488. }
  489. let resultLength = 0;
  490. for (let i = 0; i < length; i++) {
  491. resultLength += arrayByteLength(arr[i]);
  492. }
  493. let pos = 0;
  494. const data = new Uint8Array(resultLength);
  495. for (let i = 0; i < length; i++) {
  496. let item = arr[i];
  497. if (!(item instanceof Uint8Array)) {
  498. if (typeof item === "string") {
  499. item = stringToBytes(item);
  500. } else {
  501. item = new Uint8Array(item);
  502. }
  503. }
  504. const itemLength = item.byteLength;
  505. data.set(item, pos);
  506. pos += itemLength;
  507. }
  508. return data;
  509. }
  510. function string32(value) {
  511. return String.fromCharCode(
  512. (value >> 24) & 0xff,
  513. (value >> 16) & 0xff,
  514. (value >> 8) & 0xff,
  515. value & 0xff
  516. );
  517. }
  518. // Checks the endianness of the platform.
  519. function isLittleEndian() {
  520. const buffer8 = new Uint8Array(4);
  521. buffer8[0] = 1;
  522. const view32 = new Uint32Array(buffer8.buffer, 0, 1);
  523. return view32[0] === 1;
  524. }
  525. const IsLittleEndianCached = {
  526. get value() {
  527. return shadow(this, "value", isLittleEndian());
  528. },
  529. };
  530. // Checks if it's possible to eval JS expressions.
  531. function isEvalSupported() {
  532. try {
  533. new Function(""); // eslint-disable-line no-new, no-new-func
  534. return true;
  535. } catch (e) {
  536. return false;
  537. }
  538. }
  539. const IsEvalSupportedCached = {
  540. get value() {
  541. return shadow(this, "value", isEvalSupported());
  542. },
  543. };
  544. const rgbBuf = ["rgb(", 0, ",", 0, ",", 0, ")"];
  545. class Util {
  546. // makeCssRgb() can be called thousands of times. Using ´rgbBuf` avoids
  547. // creating many intermediate strings.
  548. static makeCssRgb(r, g, b) {
  549. rgbBuf[1] = r;
  550. rgbBuf[3] = g;
  551. rgbBuf[5] = b;
  552. return rgbBuf.join("");
  553. }
  554. // Concatenates two transformation matrices together and returns the result.
  555. static transform(m1, m2) {
  556. return [
  557. m1[0] * m2[0] + m1[2] * m2[1],
  558. m1[1] * m2[0] + m1[3] * m2[1],
  559. m1[0] * m2[2] + m1[2] * m2[3],
  560. m1[1] * m2[2] + m1[3] * m2[3],
  561. m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
  562. m1[1] * m2[4] + m1[3] * m2[5] + m1[5],
  563. ];
  564. }
  565. // For 2d affine transforms
  566. static applyTransform(p, m) {
  567. const xt = p[0] * m[0] + p[1] * m[2] + m[4];
  568. const yt = p[0] * m[1] + p[1] * m[3] + m[5];
  569. return [xt, yt];
  570. }
  571. static applyInverseTransform(p, m) {
  572. const d = m[0] * m[3] - m[1] * m[2];
  573. const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
  574. const yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
  575. return [xt, yt];
  576. }
  577. // Applies the transform to the rectangle and finds the minimum axially
  578. // aligned bounding box.
  579. static getAxialAlignedBoundingBox(r, m) {
  580. const p1 = Util.applyTransform(r, m);
  581. const p2 = Util.applyTransform(r.slice(2, 4), m);
  582. const p3 = Util.applyTransform([r[0], r[3]], m);
  583. const p4 = Util.applyTransform([r[2], r[1]], m);
  584. return [
  585. Math.min(p1[0], p2[0], p3[0], p4[0]),
  586. Math.min(p1[1], p2[1], p3[1], p4[1]),
  587. Math.max(p1[0], p2[0], p3[0], p4[0]),
  588. Math.max(p1[1], p2[1], p3[1], p4[1]),
  589. ];
  590. }
  591. static inverseTransform(m) {
  592. const d = m[0] * m[3] - m[1] * m[2];
  593. return [
  594. m[3] / d,
  595. -m[1] / d,
  596. -m[2] / d,
  597. m[0] / d,
  598. (m[2] * m[5] - m[4] * m[3]) / d,
  599. (m[4] * m[1] - m[5] * m[0]) / d,
  600. ];
  601. }
  602. // Apply a generic 3d matrix M on a 3-vector v:
  603. // | a b c | | X |
  604. // | d e f | x | Y |
  605. // | g h i | | Z |
  606. // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
  607. // with v as [X,Y,Z]
  608. static apply3dTransform(m, v) {
  609. return [
  610. m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
  611. m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
  612. m[6] * v[0] + m[7] * v[1] + m[8] * v[2],
  613. ];
  614. }
  615. // This calculation uses Singular Value Decomposition.
  616. // The SVD can be represented with formula A = USV. We are interested in the
  617. // matrix S here because it represents the scale values.
  618. static singularValueDecompose2dScale(m) {
  619. const transpose = [m[0], m[2], m[1], m[3]];
  620. // Multiply matrix m with its transpose.
  621. const a = m[0] * transpose[0] + m[1] * transpose[2];
  622. const b = m[0] * transpose[1] + m[1] * transpose[3];
  623. const c = m[2] * transpose[0] + m[3] * transpose[2];
  624. const d = m[2] * transpose[1] + m[3] * transpose[3];
  625. // Solve the second degree polynomial to get roots.
  626. const first = (a + d) / 2;
  627. const second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
  628. const sx = first + second || 1;
  629. const sy = first - second || 1;
  630. // Scale values are the square roots of the eigenvalues.
  631. return [Math.sqrt(sx), Math.sqrt(sy)];
  632. }
  633. // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
  634. // For coordinate systems whose origin lies in the bottom-left, this
  635. // means normalization to (BL,TR) ordering. For systems with origin in the
  636. // top-left, this means (TL,BR) ordering.
  637. static normalizeRect(rect) {
  638. const r = rect.slice(0); // clone rect
  639. if (rect[0] > rect[2]) {
  640. r[0] = rect[2];
  641. r[2] = rect[0];
  642. }
  643. if (rect[1] > rect[3]) {
  644. r[1] = rect[3];
  645. r[3] = rect[1];
  646. }
  647. return r;
  648. }
  649. // Returns a rectangle [x1, y1, x2, y2] corresponding to the
  650. // intersection of rect1 and rect2. If no intersection, returns 'false'
  651. // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
  652. static intersect(rect1, rect2) {
  653. function compare(a, b) {
  654. return a - b;
  655. }
  656. // Order points along the axes
  657. const orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare);
  658. const orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare);
  659. const result = [];
  660. rect1 = Util.normalizeRect(rect1);
  661. rect2 = Util.normalizeRect(rect2);
  662. // X: first and second points belong to different rectangles?
  663. if (
  664. (orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
  665. (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])
  666. ) {
  667. // Intersection must be between second and third points
  668. result[0] = orderedX[1];
  669. result[2] = orderedX[2];
  670. } else {
  671. return null;
  672. }
  673. // Y: first and second points belong to different rectangles?
  674. if (
  675. (orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
  676. (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])
  677. ) {
  678. // Intersection must be between second and third points
  679. result[1] = orderedY[1];
  680. result[3] = orderedY[2];
  681. } else {
  682. return null;
  683. }
  684. return result;
  685. }
  686. }
  687. // prettier-ignore
  688. const PDFStringTranslateTable = [
  689. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  690. 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
  691. 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,
  692. 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,
  693. 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,
  694. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
  695. 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
  696. 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
  697. 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
  698. ];
  699. function stringToPDFString(str) {
  700. const length = str.length,
  701. strBuf = [];
  702. if (str[0] === "\xFE" && str[1] === "\xFF") {
  703. // UTF16BE BOM
  704. for (let i = 2; i < length; i += 2) {
  705. strBuf.push(
  706. String.fromCharCode((str.charCodeAt(i) << 8) | str.charCodeAt(i + 1))
  707. );
  708. }
  709. } else if (str[0] === "\xFF" && str[1] === "\xFE") {
  710. // UTF16LE BOM
  711. for (let i = 2; i < length; i += 2) {
  712. strBuf.push(
  713. String.fromCharCode((str.charCodeAt(i + 1) << 8) | str.charCodeAt(i))
  714. );
  715. }
  716. } else {
  717. for (let i = 0; i < length; ++i) {
  718. const code = PDFStringTranslateTable[str.charCodeAt(i)];
  719. strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
  720. }
  721. }
  722. return strBuf.join("");
  723. }
  724. function escapeString(str) {
  725. // replace "(", ")" and "\" by "\(", "\)" and "\\"
  726. // in order to write it in a PDF file.
  727. return str.replace(/([\(\)\\])/g, "\\$1");
  728. }
  729. function stringToUTF8String(str) {
  730. return decodeURIComponent(escape(str));
  731. }
  732. function utf8StringToString(str) {
  733. return unescape(encodeURIComponent(str));
  734. }
  735. function isBool(v) {
  736. return typeof v === "boolean";
  737. }
  738. function isNum(v) {
  739. return typeof v === "number";
  740. }
  741. function isString(v) {
  742. return typeof v === "string";
  743. }
  744. function isArrayBuffer(v) {
  745. return typeof v === "object" && v !== null && v.byteLength !== undefined;
  746. }
  747. function isArrayEqual(arr1, arr2) {
  748. if (arr1.length !== arr2.length) {
  749. return false;
  750. }
  751. return arr1.every(function (element, index) {
  752. return element === arr2[index];
  753. });
  754. }
  755. function getModificationDate(date = new Date(Date.now())) {
  756. const buffer = [
  757. date.getUTCFullYear().toString(),
  758. (date.getUTCMonth() + 1).toString().padStart(2, "0"),
  759. (date.getUTCDate() + 1).toString().padStart(2, "0"),
  760. date.getUTCHours().toString().padStart(2, "0"),
  761. date.getUTCMinutes().toString().padStart(2, "0"),
  762. date.getUTCSeconds().toString().padStart(2, "0"),
  763. ];
  764. return buffer.join("");
  765. }
  766. /**
  767. * Promise Capability object.
  768. *
  769. * @typedef {Object} PromiseCapability
  770. * @property {Promise<any>} promise - A Promise object.
  771. * @property {boolean} settled - If the Promise has been fulfilled/rejected.
  772. * @property {function} resolve - Fulfills the Promise.
  773. * @property {function} reject - Rejects the Promise.
  774. */
  775. /**
  776. * Creates a promise capability object.
  777. * @alias createPromiseCapability
  778. *
  779. * @returns {PromiseCapability}
  780. */
  781. function createPromiseCapability() {
  782. const capability = Object.create(null);
  783. let isSettled = false;
  784. Object.defineProperty(capability, "settled", {
  785. get() {
  786. return isSettled;
  787. },
  788. });
  789. capability.promise = new Promise(function (resolve, reject) {
  790. capability.resolve = function (data) {
  791. isSettled = true;
  792. resolve(data);
  793. };
  794. capability.reject = function (reason) {
  795. isSettled = true;
  796. reject(reason);
  797. };
  798. });
  799. return capability;
  800. }
  801. const createObjectURL = (function createObjectURLClosure() {
  802. // Blob/createObjectURL is not available, falling back to data schema.
  803. const digits =
  804. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  805. // eslint-disable-next-line no-shadow
  806. return function createObjectURL(data, contentType, forceDataSchema = false) {
  807. if (!forceDataSchema && URL.createObjectURL) {
  808. const blob = new Blob([data], { type: contentType });
  809. return URL.createObjectURL(blob);
  810. }
  811. let buffer = `data:${contentType};base64,`;
  812. for (let i = 0, ii = data.length; i < ii; i += 3) {
  813. const b1 = data[i] & 0xff;
  814. const b2 = data[i + 1] & 0xff;
  815. const b3 = data[i + 2] & 0xff;
  816. const d1 = b1 >> 2,
  817. d2 = ((b1 & 3) << 4) | (b2 >> 4);
  818. const d3 = i + 1 < ii ? ((b2 & 0xf) << 2) | (b3 >> 6) : 64;
  819. const d4 = i + 2 < ii ? b3 & 0x3f : 64;
  820. buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
  821. }
  822. return buffer;
  823. };
  824. })();
  825. export {
  826. BaseException,
  827. FONT_IDENTITY_MATRIX,
  828. IDENTITY_MATRIX,
  829. OPS,
  830. VerbosityLevel,
  831. UNSUPPORTED_FEATURES,
  832. AnnotationBorderStyleType,
  833. AnnotationFieldFlag,
  834. AnnotationFlag,
  835. AnnotationMarkedState,
  836. AnnotationReplyType,
  837. AnnotationReviewState,
  838. AnnotationStateModelType,
  839. AnnotationType,
  840. FontType,
  841. ImageKind,
  842. CMapCompressionType,
  843. AbortException,
  844. InvalidPDFException,
  845. MissingPDFException,
  846. PasswordException,
  847. PasswordResponses,
  848. PermissionFlag,
  849. StreamType,
  850. TextRenderingMode,
  851. UnexpectedResponseException,
  852. UnknownErrorException,
  853. Util,
  854. FormatError,
  855. arrayByteLength,
  856. arraysToBytes,
  857. assert,
  858. bytesToString,
  859. createPromiseCapability,
  860. createObjectURL,
  861. escapeString,
  862. getModificationDate,
  863. getVerbosityLevel,
  864. info,
  865. isArrayBuffer,
  866. isArrayEqual,
  867. isBool,
  868. isNum,
  869. isString,
  870. isSameOrigin,
  871. createValidAbsoluteUrl,
  872. IsLittleEndianCached,
  873. IsEvalSupportedCached,
  874. removeNullCharacters,
  875. setVerbosityLevel,
  876. shadow,
  877. string32,
  878. stringToBytes,
  879. stringToPDFString,
  880. stringToUTF8String,
  881. utf8StringToString,
  882. warn,
  883. unreachable,
  884. };