2
0

canvas.js 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2021 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. "use strict";
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.CanvasGraphics = void 0;
  27. var _util = require("../shared/util.js");
  28. var _pattern_helper = require("./pattern_helper.js");
  29. const MIN_FONT_SIZE = 16;
  30. const MAX_FONT_SIZE = 100;
  31. const MAX_GROUP_SIZE = 4096;
  32. const COMPILE_TYPE3_GLYPHS = true;
  33. const MAX_SIZE_TO_COMPILE = 1000;
  34. const FULL_CHUNK_HEIGHT = 16;
  35. const LINEWIDTH_SCALE_FACTOR = 1.000001;
  36. function addContextCurrentTransform(ctx) {
  37. if (ctx.mozCurrentTransform) {
  38. return;
  39. }
  40. ctx._originalSave = ctx.save;
  41. ctx._originalRestore = ctx.restore;
  42. ctx._originalRotate = ctx.rotate;
  43. ctx._originalScale = ctx.scale;
  44. ctx._originalTranslate = ctx.translate;
  45. ctx._originalTransform = ctx.transform;
  46. ctx._originalSetTransform = ctx.setTransform;
  47. ctx._originalResetTransform = ctx.resetTransform;
  48. ctx._transformMatrix = ctx._transformMatrix || [1, 0, 0, 1, 0, 0];
  49. ctx._transformStack = [];
  50. try {
  51. const desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(ctx), "lineWidth");
  52. ctx._setLineWidth = desc.set;
  53. ctx._getLineWidth = desc.get;
  54. Object.defineProperty(ctx, "lineWidth", {
  55. set: function setLineWidth(width) {
  56. this._setLineWidth(width * LINEWIDTH_SCALE_FACTOR);
  57. },
  58. get: function getLineWidth() {
  59. return this._getLineWidth();
  60. }
  61. });
  62. } catch (_) {}
  63. Object.defineProperty(ctx, "mozCurrentTransform", {
  64. get: function getCurrentTransform() {
  65. return this._transformMatrix;
  66. }
  67. });
  68. Object.defineProperty(ctx, "mozCurrentTransformInverse", {
  69. get: function getCurrentTransformInverse() {
  70. const [a, b, c, d, e, f] = this._transformMatrix;
  71. const ad_bc = a * d - b * c;
  72. const bc_ad = b * c - a * d;
  73. return [d / ad_bc, b / bc_ad, c / bc_ad, a / ad_bc, (d * e - c * f) / bc_ad, (b * e - a * f) / ad_bc];
  74. }
  75. });
  76. ctx.save = function ctxSave() {
  77. const old = this._transformMatrix;
  78. this._transformStack.push(old);
  79. this._transformMatrix = old.slice(0, 6);
  80. this._originalSave();
  81. };
  82. ctx.restore = function ctxRestore() {
  83. const prev = this._transformStack.pop();
  84. if (prev) {
  85. this._transformMatrix = prev;
  86. this._originalRestore();
  87. }
  88. };
  89. ctx.translate = function ctxTranslate(x, y) {
  90. const m = this._transformMatrix;
  91. m[4] = m[0] * x + m[2] * y + m[4];
  92. m[5] = m[1] * x + m[3] * y + m[5];
  93. this._originalTranslate(x, y);
  94. };
  95. ctx.scale = function ctxScale(x, y) {
  96. const m = this._transformMatrix;
  97. m[0] *= x;
  98. m[1] *= x;
  99. m[2] *= y;
  100. m[3] *= y;
  101. this._originalScale(x, y);
  102. };
  103. ctx.transform = function ctxTransform(a, b, c, d, e, f) {
  104. const m = this._transformMatrix;
  105. this._transformMatrix = [m[0] * a + m[2] * b, m[1] * a + m[3] * b, m[0] * c + m[2] * d, m[1] * c + m[3] * d, m[0] * e + m[2] * f + m[4], m[1] * e + m[3] * f + m[5]];
  106. ctx._originalTransform(a, b, c, d, e, f);
  107. };
  108. ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {
  109. this._transformMatrix = [a, b, c, d, e, f];
  110. ctx._originalSetTransform(a, b, c, d, e, f);
  111. };
  112. ctx.resetTransform = function ctxResetTransform() {
  113. this._transformMatrix = [1, 0, 0, 1, 0, 0];
  114. ctx._originalResetTransform();
  115. };
  116. ctx.rotate = function ctxRotate(angle) {
  117. const cosValue = Math.cos(angle);
  118. const sinValue = Math.sin(angle);
  119. const m = this._transformMatrix;
  120. this._transformMatrix = [m[0] * cosValue + m[2] * sinValue, m[1] * cosValue + m[3] * sinValue, m[0] * -sinValue + m[2] * cosValue, m[1] * -sinValue + m[3] * cosValue, m[4], m[5]];
  121. this._originalRotate(angle);
  122. };
  123. }
  124. class CachedCanvases {
  125. constructor(canvasFactory) {
  126. this.canvasFactory = canvasFactory;
  127. this.cache = Object.create(null);
  128. }
  129. getCanvas(id, width, height, trackTransform) {
  130. let canvasEntry;
  131. if (this.cache[id] !== undefined) {
  132. canvasEntry = this.cache[id];
  133. this.canvasFactory.reset(canvasEntry, width, height);
  134. canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);
  135. } else {
  136. canvasEntry = this.canvasFactory.create(width, height);
  137. this.cache[id] = canvasEntry;
  138. }
  139. if (trackTransform) {
  140. addContextCurrentTransform(canvasEntry.context);
  141. }
  142. return canvasEntry;
  143. }
  144. clear() {
  145. for (const id in this.cache) {
  146. const canvasEntry = this.cache[id];
  147. this.canvasFactory.destroy(canvasEntry);
  148. delete this.cache[id];
  149. }
  150. }
  151. }
  152. function compileType3Glyph(imgData) {
  153. const POINT_TO_PROCESS_LIMIT = 1000;
  154. const POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
  155. const width = imgData.width,
  156. height = imgData.height,
  157. width1 = width + 1;
  158. let i, ii, j, j0;
  159. const points = new Uint8Array(width1 * (height + 1));
  160. const lineSize = width + 7 & ~7,
  161. data0 = imgData.data;
  162. const data = new Uint8Array(lineSize * height);
  163. let pos = 0;
  164. for (i = 0, ii = data0.length; i < ii; i++) {
  165. const elem = data0[i];
  166. let mask = 128;
  167. while (mask > 0) {
  168. data[pos++] = elem & mask ? 0 : 255;
  169. mask >>= 1;
  170. }
  171. }
  172. let count = 0;
  173. pos = 0;
  174. if (data[pos] !== 0) {
  175. points[0] = 1;
  176. ++count;
  177. }
  178. for (j = 1; j < width; j++) {
  179. if (data[pos] !== data[pos + 1]) {
  180. points[j] = data[pos] ? 2 : 1;
  181. ++count;
  182. }
  183. pos++;
  184. }
  185. if (data[pos] !== 0) {
  186. points[j] = 2;
  187. ++count;
  188. }
  189. for (i = 1; i < height; i++) {
  190. pos = i * lineSize;
  191. j0 = i * width1;
  192. if (data[pos - lineSize] !== data[pos]) {
  193. points[j0] = data[pos] ? 1 : 8;
  194. ++count;
  195. }
  196. let sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);
  197. for (j = 1; j < width; j++) {
  198. sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) + (data[pos - lineSize + 1] ? 8 : 0);
  199. if (POINT_TYPES[sum]) {
  200. points[j0 + j] = POINT_TYPES[sum];
  201. ++count;
  202. }
  203. pos++;
  204. }
  205. if (data[pos - lineSize] !== data[pos]) {
  206. points[j0 + j] = data[pos] ? 2 : 4;
  207. ++count;
  208. }
  209. if (count > POINT_TO_PROCESS_LIMIT) {
  210. return null;
  211. }
  212. }
  213. pos = lineSize * (height - 1);
  214. j0 = i * width1;
  215. if (data[pos] !== 0) {
  216. points[j0] = 8;
  217. ++count;
  218. }
  219. for (j = 1; j < width; j++) {
  220. if (data[pos] !== data[pos + 1]) {
  221. points[j0 + j] = data[pos] ? 4 : 8;
  222. ++count;
  223. }
  224. pos++;
  225. }
  226. if (data[pos] !== 0) {
  227. points[j0 + j] = 4;
  228. ++count;
  229. }
  230. if (count > POINT_TO_PROCESS_LIMIT) {
  231. return null;
  232. }
  233. const steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);
  234. const outlines = [];
  235. for (i = 0; count && i <= height; i++) {
  236. let p = i * width1;
  237. const end = p + width;
  238. while (p < end && !points[p]) {
  239. p++;
  240. }
  241. if (p === end) {
  242. continue;
  243. }
  244. const coords = [p % width1, i];
  245. const p0 = p;
  246. let type = points[p];
  247. do {
  248. const step = steps[type];
  249. do {
  250. p += step;
  251. } while (!points[p]);
  252. const pp = points[p];
  253. if (pp !== 5 && pp !== 10) {
  254. type = pp;
  255. points[p] = 0;
  256. } else {
  257. type = pp & 0x33 * type >> 4;
  258. points[p] &= type >> 2 | type << 2;
  259. }
  260. coords.push(p % width1, p / width1 | 0);
  261. if (!points[p]) {
  262. --count;
  263. }
  264. } while (p0 !== p);
  265. outlines.push(coords);
  266. --i;
  267. }
  268. const drawOutline = function (c) {
  269. c.save();
  270. c.scale(1 / width, -1 / height);
  271. c.translate(0, -height);
  272. c.beginPath();
  273. for (let k = 0, kk = outlines.length; k < kk; k++) {
  274. const o = outlines[k];
  275. c.moveTo(o[0], o[1]);
  276. for (let l = 2, ll = o.length; l < ll; l += 2) {
  277. c.lineTo(o[l], o[l + 1]);
  278. }
  279. }
  280. c.fill();
  281. c.beginPath();
  282. c.restore();
  283. };
  284. return drawOutline;
  285. }
  286. class CanvasExtraState {
  287. constructor() {
  288. this.alphaIsShape = false;
  289. this.fontSize = 0;
  290. this.fontSizeScale = 1;
  291. this.textMatrix = _util.IDENTITY_MATRIX;
  292. this.textMatrixScale = 1;
  293. this.fontMatrix = _util.FONT_IDENTITY_MATRIX;
  294. this.leading = 0;
  295. this.x = 0;
  296. this.y = 0;
  297. this.lineX = 0;
  298. this.lineY = 0;
  299. this.charSpacing = 0;
  300. this.wordSpacing = 0;
  301. this.textHScale = 1;
  302. this.textRenderingMode = _util.TextRenderingMode.FILL;
  303. this.textRise = 0;
  304. this.fillColor = "#000000";
  305. this.strokeColor = "#000000";
  306. this.patternFill = false;
  307. this.fillAlpha = 1;
  308. this.strokeAlpha = 1;
  309. this.lineWidth = 1;
  310. this.activeSMask = null;
  311. this.resumeSMaskCtx = null;
  312. this.transferMaps = null;
  313. }
  314. clone() {
  315. return Object.create(this);
  316. }
  317. setCurrentPoint(x, y) {
  318. this.x = x;
  319. this.y = y;
  320. }
  321. }
  322. const CanvasGraphics = function CanvasGraphicsClosure() {
  323. const EXECUTION_TIME = 15;
  324. const EXECUTION_STEPS = 10;
  325. function putBinaryImageData(ctx, imgData, transferMaps = null) {
  326. if (typeof ImageData !== "undefined" && imgData instanceof ImageData) {
  327. ctx.putImageData(imgData, 0, 0);
  328. return;
  329. }
  330. const height = imgData.height,
  331. width = imgData.width;
  332. const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
  333. const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
  334. const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
  335. const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
  336. let srcPos = 0,
  337. destPos;
  338. const src = imgData.data;
  339. const dest = chunkImgData.data;
  340. let i, j, thisChunkHeight, elemsInThisChunk;
  341. let transferMapRed, transferMapGreen, transferMapBlue, transferMapGray;
  342. if (transferMaps) {
  343. switch (transferMaps.length) {
  344. case 1:
  345. transferMapRed = transferMaps[0];
  346. transferMapGreen = transferMaps[0];
  347. transferMapBlue = transferMaps[0];
  348. transferMapGray = transferMaps[0];
  349. break;
  350. case 4:
  351. transferMapRed = transferMaps[0];
  352. transferMapGreen = transferMaps[1];
  353. transferMapBlue = transferMaps[2];
  354. transferMapGray = transferMaps[3];
  355. break;
  356. }
  357. }
  358. if (imgData.kind === _util.ImageKind.GRAYSCALE_1BPP) {
  359. const srcLength = src.byteLength;
  360. const dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2);
  361. const dest32DataLength = dest32.length;
  362. const fullSrcDiff = width + 7 >> 3;
  363. let white = 0xffffffff;
  364. let black = _util.IsLittleEndianCached.value ? 0xff000000 : 0x000000ff;
  365. if (transferMapGray) {
  366. if (transferMapGray[0] === 0xff && transferMapGray[0xff] === 0) {
  367. [white, black] = [black, white];
  368. }
  369. }
  370. for (i = 0; i < totalChunks; i++) {
  371. thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
  372. destPos = 0;
  373. for (j = 0; j < thisChunkHeight; j++) {
  374. const srcDiff = srcLength - srcPos;
  375. let k = 0;
  376. const kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7;
  377. const kEndUnrolled = kEnd & ~7;
  378. let mask = 0;
  379. let srcByte = 0;
  380. for (; k < kEndUnrolled; k += 8) {
  381. srcByte = src[srcPos++];
  382. dest32[destPos++] = srcByte & 128 ? white : black;
  383. dest32[destPos++] = srcByte & 64 ? white : black;
  384. dest32[destPos++] = srcByte & 32 ? white : black;
  385. dest32[destPos++] = srcByte & 16 ? white : black;
  386. dest32[destPos++] = srcByte & 8 ? white : black;
  387. dest32[destPos++] = srcByte & 4 ? white : black;
  388. dest32[destPos++] = srcByte & 2 ? white : black;
  389. dest32[destPos++] = srcByte & 1 ? white : black;
  390. }
  391. for (; k < kEnd; k++) {
  392. if (mask === 0) {
  393. srcByte = src[srcPos++];
  394. mask = 128;
  395. }
  396. dest32[destPos++] = srcByte & mask ? white : black;
  397. mask >>= 1;
  398. }
  399. }
  400. while (destPos < dest32DataLength) {
  401. dest32[destPos++] = 0;
  402. }
  403. ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
  404. }
  405. } else if (imgData.kind === _util.ImageKind.RGBA_32BPP) {
  406. const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue);
  407. j = 0;
  408. elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;
  409. for (i = 0; i < fullChunks; i++) {
  410. dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
  411. srcPos += elemsInThisChunk;
  412. if (hasTransferMaps) {
  413. for (let k = 0; k < elemsInThisChunk; k += 4) {
  414. if (transferMapRed) {
  415. dest[k + 0] = transferMapRed[dest[k + 0]];
  416. }
  417. if (transferMapGreen) {
  418. dest[k + 1] = transferMapGreen[dest[k + 1]];
  419. }
  420. if (transferMapBlue) {
  421. dest[k + 2] = transferMapBlue[dest[k + 2]];
  422. }
  423. }
  424. }
  425. ctx.putImageData(chunkImgData, 0, j);
  426. j += FULL_CHUNK_HEIGHT;
  427. }
  428. if (i < totalChunks) {
  429. elemsInThisChunk = width * partialChunkHeight * 4;
  430. dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
  431. if (hasTransferMaps) {
  432. for (let k = 0; k < elemsInThisChunk; k += 4) {
  433. if (transferMapRed) {
  434. dest[k + 0] = transferMapRed[dest[k + 0]];
  435. }
  436. if (transferMapGreen) {
  437. dest[k + 1] = transferMapGreen[dest[k + 1]];
  438. }
  439. if (transferMapBlue) {
  440. dest[k + 2] = transferMapBlue[dest[k + 2]];
  441. }
  442. }
  443. }
  444. ctx.putImageData(chunkImgData, 0, j);
  445. }
  446. } else if (imgData.kind === _util.ImageKind.RGB_24BPP) {
  447. const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue);
  448. thisChunkHeight = FULL_CHUNK_HEIGHT;
  449. elemsInThisChunk = width * thisChunkHeight;
  450. for (i = 0; i < totalChunks; i++) {
  451. if (i >= fullChunks) {
  452. thisChunkHeight = partialChunkHeight;
  453. elemsInThisChunk = width * thisChunkHeight;
  454. }
  455. destPos = 0;
  456. for (j = elemsInThisChunk; j--;) {
  457. dest[destPos++] = src[srcPos++];
  458. dest[destPos++] = src[srcPos++];
  459. dest[destPos++] = src[srcPos++];
  460. dest[destPos++] = 255;
  461. }
  462. if (hasTransferMaps) {
  463. for (let k = 0; k < destPos; k += 4) {
  464. if (transferMapRed) {
  465. dest[k + 0] = transferMapRed[dest[k + 0]];
  466. }
  467. if (transferMapGreen) {
  468. dest[k + 1] = transferMapGreen[dest[k + 1]];
  469. }
  470. if (transferMapBlue) {
  471. dest[k + 2] = transferMapBlue[dest[k + 2]];
  472. }
  473. }
  474. }
  475. ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
  476. }
  477. } else {
  478. throw new Error(`bad image kind: ${imgData.kind}`);
  479. }
  480. }
  481. function putBinaryImageMask(ctx, imgData) {
  482. const height = imgData.height,
  483. width = imgData.width;
  484. const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
  485. const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
  486. const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
  487. const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
  488. let srcPos = 0;
  489. const src = imgData.data;
  490. const dest = chunkImgData.data;
  491. for (let i = 0; i < totalChunks; i++) {
  492. const thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
  493. let destPos = 3;
  494. for (let j = 0; j < thisChunkHeight; j++) {
  495. let elem,
  496. mask = 0;
  497. for (let k = 0; k < width; k++) {
  498. if (!mask) {
  499. elem = src[srcPos++];
  500. mask = 128;
  501. }
  502. dest[destPos] = elem & mask ? 0 : 255;
  503. destPos += 4;
  504. mask >>= 1;
  505. }
  506. }
  507. ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
  508. }
  509. }
  510. function copyCtxState(sourceCtx, destCtx) {
  511. const properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font"];
  512. for (let i = 0, ii = properties.length; i < ii; i++) {
  513. const property = properties[i];
  514. if (sourceCtx[property] !== undefined) {
  515. destCtx[property] = sourceCtx[property];
  516. }
  517. }
  518. if (sourceCtx.setLineDash !== undefined) {
  519. destCtx.setLineDash(sourceCtx.getLineDash());
  520. destCtx.lineDashOffset = sourceCtx.lineDashOffset;
  521. }
  522. }
  523. function resetCtxToDefault(ctx) {
  524. ctx.strokeStyle = "#000000";
  525. ctx.fillStyle = "#000000";
  526. ctx.fillRule = "nonzero";
  527. ctx.globalAlpha = 1;
  528. ctx.lineWidth = 1;
  529. ctx.lineCap = "butt";
  530. ctx.lineJoin = "miter";
  531. ctx.miterLimit = 10;
  532. ctx.globalCompositeOperation = "source-over";
  533. ctx.font = "10px sans-serif";
  534. if (ctx.setLineDash !== undefined) {
  535. ctx.setLineDash([]);
  536. ctx.lineDashOffset = 0;
  537. }
  538. }
  539. function composeSMaskBackdrop(bytes, r0, g0, b0) {
  540. const length = bytes.length;
  541. for (let i = 3; i < length; i += 4) {
  542. const alpha = bytes[i];
  543. if (alpha === 0) {
  544. bytes[i - 3] = r0;
  545. bytes[i - 2] = g0;
  546. bytes[i - 1] = b0;
  547. } else if (alpha < 255) {
  548. const alpha_ = 255 - alpha;
  549. bytes[i - 3] = bytes[i - 3] * alpha + r0 * alpha_ >> 8;
  550. bytes[i - 2] = bytes[i - 2] * alpha + g0 * alpha_ >> 8;
  551. bytes[i - 1] = bytes[i - 1] * alpha + b0 * alpha_ >> 8;
  552. }
  553. }
  554. }
  555. function composeSMaskAlpha(maskData, layerData, transferMap) {
  556. const length = maskData.length;
  557. const scale = 1 / 255;
  558. for (let i = 3; i < length; i += 4) {
  559. const alpha = transferMap ? transferMap[maskData[i]] : maskData[i];
  560. layerData[i] = layerData[i] * alpha * scale | 0;
  561. }
  562. }
  563. function composeSMaskLuminosity(maskData, layerData, transferMap) {
  564. const length = maskData.length;
  565. for (let i = 3; i < length; i += 4) {
  566. const y = maskData[i - 3] * 77 + maskData[i - 2] * 152 + maskData[i - 1] * 28;
  567. layerData[i] = transferMap ? layerData[i] * transferMap[y >> 8] >> 8 : layerData[i] * y >> 16;
  568. }
  569. }
  570. function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap) {
  571. const hasBackdrop = !!backdrop;
  572. const r0 = hasBackdrop ? backdrop[0] : 0;
  573. const g0 = hasBackdrop ? backdrop[1] : 0;
  574. const b0 = hasBackdrop ? backdrop[2] : 0;
  575. let composeFn;
  576. if (subtype === "Luminosity") {
  577. composeFn = composeSMaskLuminosity;
  578. } else {
  579. composeFn = composeSMaskAlpha;
  580. }
  581. const PIXELS_TO_PROCESS = 1048576;
  582. const chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
  583. for (let row = 0; row < height; row += chunkSize) {
  584. const chunkHeight = Math.min(chunkSize, height - row);
  585. const maskData = maskCtx.getImageData(0, row, width, chunkHeight);
  586. const layerData = layerCtx.getImageData(0, row, width, chunkHeight);
  587. if (hasBackdrop) {
  588. composeSMaskBackdrop(maskData.data, r0, g0, b0);
  589. }
  590. composeFn(maskData.data, layerData.data, transferMap);
  591. maskCtx.putImageData(layerData, 0, row);
  592. }
  593. }
  594. function composeSMask(ctx, smask, layerCtx) {
  595. const mask = smask.canvas;
  596. const maskCtx = smask.context;
  597. ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY, smask.offsetX, smask.offsetY);
  598. genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height, smask.subtype, smask.backdrop, smask.transferMap);
  599. ctx.drawImage(mask, 0, 0);
  600. }
  601. const LINE_CAP_STYLES = ["butt", "round", "square"];
  602. const LINE_JOIN_STYLES = ["miter", "round", "bevel"];
  603. const NORMAL_CLIP = {};
  604. const EO_CLIP = {};
  605. class CanvasGraphics {
  606. constructor(canvasCtx, commonObjs, objs, canvasFactory, imageLayer, optionalContentConfig) {
  607. this.ctx = canvasCtx;
  608. this.current = new CanvasExtraState();
  609. this.stateStack = [];
  610. this.pendingClip = null;
  611. this.pendingEOFill = false;
  612. this.res = null;
  613. this.xobjs = null;
  614. this.commonObjs = commonObjs;
  615. this.objs = objs;
  616. this.canvasFactory = canvasFactory;
  617. this.imageLayer = imageLayer;
  618. this.groupStack = [];
  619. this.processingType3 = null;
  620. this.baseTransform = null;
  621. this.baseTransformStack = [];
  622. this.groupLevel = 0;
  623. this.smaskStack = [];
  624. this.smaskCounter = 0;
  625. this.tempSMask = null;
  626. this.contentVisible = true;
  627. this.markedContentStack = [];
  628. this.optionalContentConfig = optionalContentConfig;
  629. this.cachedCanvases = new CachedCanvases(this.canvasFactory);
  630. this.cachedPatterns = new Map();
  631. if (canvasCtx) {
  632. addContextCurrentTransform(canvasCtx);
  633. }
  634. this._cachedGetSinglePixelWidth = null;
  635. }
  636. beginDrawing({
  637. transform,
  638. viewport,
  639. transparency = false,
  640. background = null
  641. }) {
  642. const width = this.ctx.canvas.width;
  643. const height = this.ctx.canvas.height;
  644. this.ctx.save();
  645. this.ctx.fillStyle = background || "rgb(255, 255, 255)";
  646. this.ctx.fillRect(0, 0, width, height);
  647. this.ctx.restore();
  648. if (transparency) {
  649. const transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height, true);
  650. this.compositeCtx = this.ctx;
  651. this.transparentCanvas = transparentCanvas.canvas;
  652. this.ctx = transparentCanvas.context;
  653. this.ctx.save();
  654. this.ctx.transform.apply(this.ctx, this.compositeCtx.mozCurrentTransform);
  655. }
  656. this.ctx.save();
  657. resetCtxToDefault(this.ctx);
  658. if (transform) {
  659. this.ctx.transform.apply(this.ctx, transform);
  660. }
  661. this.ctx.transform.apply(this.ctx, viewport.transform);
  662. this.baseTransform = this.ctx.mozCurrentTransform.slice();
  663. this._combinedScaleFactor = Math.hypot(this.baseTransform[0], this.baseTransform[2]);
  664. if (this.imageLayer) {
  665. this.imageLayer.beginLayout();
  666. }
  667. }
  668. executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) {
  669. const argsArray = operatorList.argsArray;
  670. const fnArray = operatorList.fnArray;
  671. let i = executionStartIdx || 0;
  672. const argsArrayLen = argsArray.length;
  673. if (argsArrayLen === i) {
  674. return i;
  675. }
  676. const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function";
  677. const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
  678. let steps = 0;
  679. const commonObjs = this.commonObjs;
  680. const objs = this.objs;
  681. let fnId;
  682. while (true) {
  683. if (stepper !== undefined && i === stepper.nextBreakPoint) {
  684. stepper.breakIt(i, continueCallback);
  685. return i;
  686. }
  687. fnId = fnArray[i];
  688. if (fnId !== _util.OPS.dependency) {
  689. this[fnId].apply(this, argsArray[i]);
  690. } else {
  691. for (const depObjId of argsArray[i]) {
  692. const objsPool = depObjId.startsWith("g_") ? commonObjs : objs;
  693. if (!objsPool.has(depObjId)) {
  694. objsPool.get(depObjId, continueCallback);
  695. return i;
  696. }
  697. }
  698. }
  699. i++;
  700. if (i === argsArrayLen) {
  701. return i;
  702. }
  703. if (chunkOperations && ++steps > EXECUTION_STEPS) {
  704. if (Date.now() > endTime) {
  705. continueCallback();
  706. return i;
  707. }
  708. steps = 0;
  709. }
  710. }
  711. }
  712. endDrawing() {
  713. while (this.stateStack.length || this.current.activeSMask !== null) {
  714. this.restore();
  715. }
  716. this.ctx.restore();
  717. if (this.transparentCanvas) {
  718. this.ctx = this.compositeCtx;
  719. this.ctx.save();
  720. this.ctx.setTransform(1, 0, 0, 1, 0, 0);
  721. this.ctx.drawImage(this.transparentCanvas, 0, 0);
  722. this.ctx.restore();
  723. this.transparentCanvas = null;
  724. }
  725. this.cachedCanvases.clear();
  726. this.cachedPatterns.clear();
  727. if (this.imageLayer) {
  728. this.imageLayer.endLayout();
  729. }
  730. }
  731. _scaleImage(img, inverseTransform) {
  732. const width = img.width;
  733. const height = img.height;
  734. let widthScale = Math.max(Math.hypot(inverseTransform[0], inverseTransform[1]), 1);
  735. let heightScale = Math.max(Math.hypot(inverseTransform[2], inverseTransform[3]), 1);
  736. let paintWidth = width,
  737. paintHeight = height;
  738. let tmpCanvasId = "prescale1";
  739. let tmpCanvas, tmpCtx;
  740. while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) {
  741. let newWidth = paintWidth,
  742. newHeight = paintHeight;
  743. if (widthScale > 2 && paintWidth > 1) {
  744. newWidth = Math.ceil(paintWidth / 2);
  745. widthScale /= paintWidth / newWidth;
  746. }
  747. if (heightScale > 2 && paintHeight > 1) {
  748. newHeight = Math.ceil(paintHeight / 2);
  749. heightScale /= paintHeight / newHeight;
  750. }
  751. tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
  752. tmpCtx = tmpCanvas.context;
  753. tmpCtx.clearRect(0, 0, newWidth, newHeight);
  754. tmpCtx.drawImage(img, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight);
  755. img = tmpCanvas.canvas;
  756. paintWidth = newWidth;
  757. paintHeight = newHeight;
  758. tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1";
  759. }
  760. return {
  761. img,
  762. paintWidth,
  763. paintHeight
  764. };
  765. }
  766. _createMaskCanvas(img) {
  767. const ctx = this.ctx;
  768. const width = img.width,
  769. height = img.height;
  770. const fillColor = this.current.fillColor;
  771. const isPatternFill = this.current.patternFill;
  772. const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
  773. const maskCtx = maskCanvas.context;
  774. putBinaryImageMask(maskCtx, img);
  775. const objToCanvas = ctx.mozCurrentTransform;
  776. let maskToCanvas = _util.Util.transform(objToCanvas, [1 / width, 0, 0, -1 / height, 0, 0]);
  777. maskToCanvas = _util.Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]);
  778. const cord1 = _util.Util.applyTransform([0, 0], maskToCanvas);
  779. const cord2 = _util.Util.applyTransform([width, height], maskToCanvas);
  780. const rect = _util.Util.normalizeRect([cord1[0], cord1[1], cord2[0], cord2[1]]);
  781. const drawnWidth = Math.ceil(rect[2] - rect[0]);
  782. const drawnHeight = Math.ceil(rect[3] - rect[1]);
  783. const fillCanvas = this.cachedCanvases.getCanvas("fillCanvas", drawnWidth, drawnHeight, true);
  784. const fillCtx = fillCanvas.context;
  785. const offsetX = Math.min(cord1[0], cord2[0]);
  786. const offsetY = Math.min(cord1[1], cord2[1]);
  787. fillCtx.translate(-offsetX, -offsetY);
  788. fillCtx.transform.apply(fillCtx, maskToCanvas);
  789. const scaled = this._scaleImage(maskCanvas.canvas, fillCtx.mozCurrentTransformInverse);
  790. fillCtx.drawImage(scaled.img, 0, 0, scaled.img.width, scaled.img.height, 0, 0, width, height);
  791. fillCtx.globalCompositeOperation = "source-in";
  792. const inverse = _util.Util.transform(fillCtx.mozCurrentTransformInverse, [1, 0, 0, 1, -offsetX, -offsetY]);
  793. fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, false) : fillColor;
  794. fillCtx.fillRect(0, 0, width, height);
  795. return {
  796. canvas: fillCanvas.canvas,
  797. offsetX: Math.round(offsetX),
  798. offsetY: Math.round(offsetY)
  799. };
  800. }
  801. setLineWidth(width) {
  802. this.current.lineWidth = width;
  803. this.ctx.lineWidth = width;
  804. }
  805. setLineCap(style) {
  806. this.ctx.lineCap = LINE_CAP_STYLES[style];
  807. }
  808. setLineJoin(style) {
  809. this.ctx.lineJoin = LINE_JOIN_STYLES[style];
  810. }
  811. setMiterLimit(limit) {
  812. this.ctx.miterLimit = limit;
  813. }
  814. setDash(dashArray, dashPhase) {
  815. const ctx = this.ctx;
  816. if (ctx.setLineDash !== undefined) {
  817. ctx.setLineDash(dashArray);
  818. ctx.lineDashOffset = dashPhase;
  819. }
  820. }
  821. setRenderingIntent(intent) {}
  822. setFlatness(flatness) {}
  823. setGState(states) {
  824. for (let i = 0, ii = states.length; i < ii; i++) {
  825. const state = states[i];
  826. const key = state[0];
  827. const value = state[1];
  828. switch (key) {
  829. case "LW":
  830. this.setLineWidth(value);
  831. break;
  832. case "LC":
  833. this.setLineCap(value);
  834. break;
  835. case "LJ":
  836. this.setLineJoin(value);
  837. break;
  838. case "ML":
  839. this.setMiterLimit(value);
  840. break;
  841. case "D":
  842. this.setDash(value[0], value[1]);
  843. break;
  844. case "RI":
  845. this.setRenderingIntent(value);
  846. break;
  847. case "FL":
  848. this.setFlatness(value);
  849. break;
  850. case "Font":
  851. this.setFont(value[0], value[1]);
  852. break;
  853. case "CA":
  854. this.current.strokeAlpha = state[1];
  855. break;
  856. case "ca":
  857. this.current.fillAlpha = state[1];
  858. this.ctx.globalAlpha = state[1];
  859. break;
  860. case "BM":
  861. this.ctx.globalCompositeOperation = value;
  862. break;
  863. case "SMask":
  864. if (this.current.activeSMask) {
  865. if (this.stateStack.length > 0 && this.stateStack[this.stateStack.length - 1].activeSMask === this.current.activeSMask) {
  866. this.suspendSMaskGroup();
  867. } else {
  868. this.endSMaskGroup();
  869. }
  870. }
  871. this.current.activeSMask = value ? this.tempSMask : null;
  872. if (this.current.activeSMask) {
  873. this.beginSMaskGroup();
  874. }
  875. this.tempSMask = null;
  876. break;
  877. case "TR":
  878. this.current.transferMaps = value;
  879. }
  880. }
  881. }
  882. beginSMaskGroup() {
  883. const activeSMask = this.current.activeSMask;
  884. const drawnWidth = activeSMask.canvas.width;
  885. const drawnHeight = activeSMask.canvas.height;
  886. const cacheId = "smaskGroupAt" + this.groupLevel;
  887. const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true);
  888. const currentCtx = this.ctx;
  889. const currentTransform = currentCtx.mozCurrentTransform;
  890. this.ctx.save();
  891. const groupCtx = scratchCanvas.context;
  892. groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
  893. groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
  894. groupCtx.transform.apply(groupCtx, currentTransform);
  895. activeSMask.startTransformInverse = groupCtx.mozCurrentTransformInverse;
  896. copyCtxState(currentCtx, groupCtx);
  897. this.ctx = groupCtx;
  898. this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
  899. this.groupStack.push(currentCtx);
  900. this.groupLevel++;
  901. }
  902. suspendSMaskGroup() {
  903. const groupCtx = this.ctx;
  904. this.groupLevel--;
  905. this.ctx = this.groupStack.pop();
  906. composeSMask(this.ctx, this.current.activeSMask, groupCtx);
  907. this.ctx.restore();
  908. this.ctx.save();
  909. copyCtxState(groupCtx, this.ctx);
  910. this.current.resumeSMaskCtx = groupCtx;
  911. const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
  912. this.ctx.transform.apply(this.ctx, deltaTransform);
  913. groupCtx.save();
  914. groupCtx.setTransform(1, 0, 0, 1, 0, 0);
  915. groupCtx.clearRect(0, 0, groupCtx.canvas.width, groupCtx.canvas.height);
  916. groupCtx.restore();
  917. }
  918. resumeSMaskGroup() {
  919. const groupCtx = this.current.resumeSMaskCtx;
  920. const currentCtx = this.ctx;
  921. this.ctx = groupCtx;
  922. this.groupStack.push(currentCtx);
  923. this.groupLevel++;
  924. }
  925. endSMaskGroup() {
  926. const groupCtx = this.ctx;
  927. this.groupLevel--;
  928. this.ctx = this.groupStack.pop();
  929. composeSMask(this.ctx, this.current.activeSMask, groupCtx);
  930. this.ctx.restore();
  931. copyCtxState(groupCtx, this.ctx);
  932. const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
  933. this.ctx.transform.apply(this.ctx, deltaTransform);
  934. }
  935. save() {
  936. this.ctx.save();
  937. const old = this.current;
  938. this.stateStack.push(old);
  939. this.current = old.clone();
  940. this.current.resumeSMaskCtx = null;
  941. }
  942. restore() {
  943. if (this.current.resumeSMaskCtx) {
  944. this.resumeSMaskGroup();
  945. }
  946. if (this.current.activeSMask !== null && (this.stateStack.length === 0 || this.stateStack[this.stateStack.length - 1].activeSMask !== this.current.activeSMask)) {
  947. this.endSMaskGroup();
  948. }
  949. if (this.stateStack.length !== 0) {
  950. this.current = this.stateStack.pop();
  951. this.ctx.restore();
  952. this.pendingClip = null;
  953. this._cachedGetSinglePixelWidth = null;
  954. } else {
  955. this.current.activeSMask = null;
  956. }
  957. }
  958. transform(a, b, c, d, e, f) {
  959. this.ctx.transform(a, b, c, d, e, f);
  960. this._cachedGetSinglePixelWidth = null;
  961. }
  962. constructPath(ops, args) {
  963. const ctx = this.ctx;
  964. const current = this.current;
  965. let x = current.x,
  966. y = current.y;
  967. for (let i = 0, j = 0, ii = ops.length; i < ii; i++) {
  968. switch (ops[i] | 0) {
  969. case _util.OPS.rectangle:
  970. x = args[j++];
  971. y = args[j++];
  972. const width = args[j++];
  973. const height = args[j++];
  974. const xw = x + width;
  975. const yh = y + height;
  976. ctx.moveTo(x, y);
  977. if (width === 0 || height === 0) {
  978. ctx.lineTo(xw, yh);
  979. } else {
  980. ctx.lineTo(xw, y);
  981. ctx.lineTo(xw, yh);
  982. ctx.lineTo(x, yh);
  983. }
  984. ctx.closePath();
  985. break;
  986. case _util.OPS.moveTo:
  987. x = args[j++];
  988. y = args[j++];
  989. ctx.moveTo(x, y);
  990. break;
  991. case _util.OPS.lineTo:
  992. x = args[j++];
  993. y = args[j++];
  994. ctx.lineTo(x, y);
  995. break;
  996. case _util.OPS.curveTo:
  997. x = args[j + 4];
  998. y = args[j + 5];
  999. ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
  1000. j += 6;
  1001. break;
  1002. case _util.OPS.curveTo2:
  1003. ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
  1004. x = args[j + 2];
  1005. y = args[j + 3];
  1006. j += 4;
  1007. break;
  1008. case _util.OPS.curveTo3:
  1009. x = args[j + 2];
  1010. y = args[j + 3];
  1011. ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
  1012. j += 4;
  1013. break;
  1014. case _util.OPS.closePath:
  1015. ctx.closePath();
  1016. break;
  1017. }
  1018. }
  1019. current.setCurrentPoint(x, y);
  1020. }
  1021. closePath() {
  1022. this.ctx.closePath();
  1023. }
  1024. stroke(consumePath) {
  1025. consumePath = typeof consumePath !== "undefined" ? consumePath : true;
  1026. const ctx = this.ctx;
  1027. const strokeColor = this.current.strokeColor;
  1028. ctx.globalAlpha = this.current.strokeAlpha;
  1029. if (this.contentVisible) {
  1030. if (typeof strokeColor === "object" && strokeColor?.getPattern) {
  1031. const lineWidth = this.getSinglePixelWidth();
  1032. ctx.save();
  1033. ctx.strokeStyle = strokeColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
  1034. ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
  1035. ctx.stroke();
  1036. ctx.restore();
  1037. } else {
  1038. const lineWidth = this.getSinglePixelWidth();
  1039. if (lineWidth < 0 && -lineWidth >= this.current.lineWidth) {
  1040. ctx.save();
  1041. ctx.resetTransform();
  1042. ctx.lineWidth = Math.round(this._combinedScaleFactor);
  1043. ctx.stroke();
  1044. ctx.restore();
  1045. } else {
  1046. ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
  1047. ctx.stroke();
  1048. }
  1049. }
  1050. }
  1051. if (consumePath) {
  1052. this.consumePath();
  1053. }
  1054. ctx.globalAlpha = this.current.fillAlpha;
  1055. }
  1056. closeStroke() {
  1057. this.closePath();
  1058. this.stroke();
  1059. }
  1060. fill(consumePath) {
  1061. consumePath = typeof consumePath !== "undefined" ? consumePath : true;
  1062. const ctx = this.ctx;
  1063. const fillColor = this.current.fillColor;
  1064. const isPatternFill = this.current.patternFill;
  1065. let needRestore = false;
  1066. if (isPatternFill) {
  1067. ctx.save();
  1068. ctx.fillStyle = fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
  1069. needRestore = true;
  1070. }
  1071. if (this.contentVisible) {
  1072. if (this.pendingEOFill) {
  1073. ctx.fill("evenodd");
  1074. this.pendingEOFill = false;
  1075. } else {
  1076. ctx.fill();
  1077. }
  1078. }
  1079. if (needRestore) {
  1080. ctx.restore();
  1081. }
  1082. if (consumePath) {
  1083. this.consumePath();
  1084. }
  1085. }
  1086. eoFill() {
  1087. this.pendingEOFill = true;
  1088. this.fill();
  1089. }
  1090. fillStroke() {
  1091. this.fill(false);
  1092. this.stroke(false);
  1093. this.consumePath();
  1094. }
  1095. eoFillStroke() {
  1096. this.pendingEOFill = true;
  1097. this.fillStroke();
  1098. }
  1099. closeFillStroke() {
  1100. this.closePath();
  1101. this.fillStroke();
  1102. }
  1103. closeEOFillStroke() {
  1104. this.pendingEOFill = true;
  1105. this.closePath();
  1106. this.fillStroke();
  1107. }
  1108. endPath() {
  1109. this.consumePath();
  1110. }
  1111. clip() {
  1112. this.pendingClip = NORMAL_CLIP;
  1113. }
  1114. eoClip() {
  1115. this.pendingClip = EO_CLIP;
  1116. }
  1117. beginText() {
  1118. this.current.textMatrix = _util.IDENTITY_MATRIX;
  1119. this.current.textMatrixScale = 1;
  1120. this.current.x = this.current.lineX = 0;
  1121. this.current.y = this.current.lineY = 0;
  1122. }
  1123. endText() {
  1124. const paths = this.pendingTextPaths;
  1125. const ctx = this.ctx;
  1126. if (paths === undefined) {
  1127. ctx.beginPath();
  1128. return;
  1129. }
  1130. ctx.save();
  1131. ctx.beginPath();
  1132. for (let i = 0; i < paths.length; i++) {
  1133. const path = paths[i];
  1134. ctx.setTransform.apply(ctx, path.transform);
  1135. ctx.translate(path.x, path.y);
  1136. path.addToPath(ctx, path.fontSize);
  1137. }
  1138. ctx.restore();
  1139. ctx.clip();
  1140. ctx.beginPath();
  1141. delete this.pendingTextPaths;
  1142. }
  1143. setCharSpacing(spacing) {
  1144. this.current.charSpacing = spacing;
  1145. }
  1146. setWordSpacing(spacing) {
  1147. this.current.wordSpacing = spacing;
  1148. }
  1149. setHScale(scale) {
  1150. this.current.textHScale = scale / 100;
  1151. }
  1152. setLeading(leading) {
  1153. this.current.leading = -leading;
  1154. }
  1155. setFont(fontRefName, size) {
  1156. const fontObj = this.commonObjs.get(fontRefName);
  1157. const current = this.current;
  1158. if (!fontObj) {
  1159. throw new Error(`Can't find font for ${fontRefName}`);
  1160. }
  1161. current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX;
  1162. if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) {
  1163. (0, _util.warn)("Invalid font matrix for font " + fontRefName);
  1164. }
  1165. if (size < 0) {
  1166. size = -size;
  1167. current.fontDirection = -1;
  1168. } else {
  1169. current.fontDirection = 1;
  1170. }
  1171. this.current.font = fontObj;
  1172. this.current.fontSize = size;
  1173. if (fontObj.isType3Font) {
  1174. return;
  1175. }
  1176. const name = fontObj.loadedName || "sans-serif";
  1177. let bold = "normal";
  1178. if (fontObj.black) {
  1179. bold = "900";
  1180. } else if (fontObj.bold) {
  1181. bold = "bold";
  1182. }
  1183. const italic = fontObj.italic ? "italic" : "normal";
  1184. const typeface = `"${name}", ${fontObj.fallbackName}`;
  1185. let browserFontSize = size;
  1186. if (size < MIN_FONT_SIZE) {
  1187. browserFontSize = MIN_FONT_SIZE;
  1188. } else if (size > MAX_FONT_SIZE) {
  1189. browserFontSize = MAX_FONT_SIZE;
  1190. }
  1191. this.current.fontSizeScale = size / browserFontSize;
  1192. this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`;
  1193. }
  1194. setTextRenderingMode(mode) {
  1195. this.current.textRenderingMode = mode;
  1196. }
  1197. setTextRise(rise) {
  1198. this.current.textRise = rise;
  1199. }
  1200. moveText(x, y) {
  1201. this.current.x = this.current.lineX += x;
  1202. this.current.y = this.current.lineY += y;
  1203. }
  1204. setLeadingMoveText(x, y) {
  1205. this.setLeading(-y);
  1206. this.moveText(x, y);
  1207. }
  1208. setTextMatrix(a, b, c, d, e, f) {
  1209. this.current.textMatrix = [a, b, c, d, e, f];
  1210. this.current.textMatrixScale = Math.hypot(a, b);
  1211. this.current.x = this.current.lineX = 0;
  1212. this.current.y = this.current.lineY = 0;
  1213. }
  1214. nextLine() {
  1215. this.moveText(0, this.current.leading);
  1216. }
  1217. paintChar(character, x, y, patternTransform, resetLineWidthToOne) {
  1218. const ctx = this.ctx;
  1219. const current = this.current;
  1220. const font = current.font;
  1221. const textRenderingMode = current.textRenderingMode;
  1222. const fontSize = current.fontSize / current.fontSizeScale;
  1223. const fillStrokeMode = textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
  1224. const isAddToPathSet = !!(textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG);
  1225. const patternFill = current.patternFill && !font.missingFile;
  1226. let addToPath;
  1227. if (font.disableFontFace || isAddToPathSet || patternFill) {
  1228. addToPath = font.getPathGenerator(this.commonObjs, character);
  1229. }
  1230. if (font.disableFontFace || patternFill) {
  1231. ctx.save();
  1232. ctx.translate(x, y);
  1233. ctx.beginPath();
  1234. addToPath(ctx, fontSize);
  1235. if (patternTransform) {
  1236. ctx.setTransform.apply(ctx, patternTransform);
  1237. }
  1238. if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1239. ctx.fill();
  1240. }
  1241. if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1242. if (resetLineWidthToOne) {
  1243. ctx.resetTransform();
  1244. ctx.lineWidth = Math.round(this._combinedScaleFactor);
  1245. }
  1246. ctx.stroke();
  1247. }
  1248. ctx.restore();
  1249. } else {
  1250. if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1251. ctx.fillText(character, x, y);
  1252. }
  1253. if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1254. if (resetLineWidthToOne) {
  1255. ctx.save();
  1256. ctx.moveTo(x, y);
  1257. ctx.resetTransform();
  1258. ctx.lineWidth = Math.round(this._combinedScaleFactor);
  1259. ctx.strokeText(character, 0, 0);
  1260. ctx.restore();
  1261. } else {
  1262. ctx.strokeText(character, x, y);
  1263. }
  1264. }
  1265. }
  1266. if (isAddToPathSet) {
  1267. const paths = this.pendingTextPaths || (this.pendingTextPaths = []);
  1268. paths.push({
  1269. transform: ctx.mozCurrentTransform,
  1270. x,
  1271. y,
  1272. fontSize,
  1273. addToPath
  1274. });
  1275. }
  1276. }
  1277. get isFontSubpixelAAEnabled() {
  1278. const {
  1279. context: ctx
  1280. } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10);
  1281. ctx.scale(1.5, 1);
  1282. ctx.fillText("I", 0, 10);
  1283. const data = ctx.getImageData(0, 0, 10, 10).data;
  1284. let enabled = false;
  1285. for (let i = 3; i < data.length; i += 4) {
  1286. if (data[i] > 0 && data[i] < 255) {
  1287. enabled = true;
  1288. break;
  1289. }
  1290. }
  1291. return (0, _util.shadow)(this, "isFontSubpixelAAEnabled", enabled);
  1292. }
  1293. showText(glyphs) {
  1294. const current = this.current;
  1295. const font = current.font;
  1296. if (font.isType3Font) {
  1297. return this.showType3Text(glyphs);
  1298. }
  1299. const fontSize = current.fontSize;
  1300. if (fontSize === 0) {
  1301. return undefined;
  1302. }
  1303. const ctx = this.ctx;
  1304. const fontSizeScale = current.fontSizeScale;
  1305. const charSpacing = current.charSpacing;
  1306. const wordSpacing = current.wordSpacing;
  1307. const fontDirection = current.fontDirection;
  1308. const textHScale = current.textHScale * fontDirection;
  1309. const glyphsLength = glyphs.length;
  1310. const vertical = font.vertical;
  1311. const spacingDir = vertical ? 1 : -1;
  1312. const defaultVMetrics = font.defaultVMetrics;
  1313. const widthAdvanceScale = fontSize * current.fontMatrix[0];
  1314. const simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
  1315. ctx.save();
  1316. let patternTransform;
  1317. if (current.patternFill) {
  1318. ctx.save();
  1319. const pattern = current.fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
  1320. patternTransform = ctx.mozCurrentTransform;
  1321. ctx.restore();
  1322. ctx.fillStyle = pattern;
  1323. }
  1324. ctx.transform.apply(ctx, current.textMatrix);
  1325. ctx.translate(current.x, current.y + current.textRise);
  1326. if (fontDirection > 0) {
  1327. ctx.scale(textHScale, -1);
  1328. } else {
  1329. ctx.scale(textHScale, 1);
  1330. }
  1331. let lineWidth = current.lineWidth;
  1332. let resetLineWidthToOne = false;
  1333. const scale = current.textMatrixScale;
  1334. if (scale === 0 || lineWidth === 0) {
  1335. const fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
  1336. if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1337. this._cachedGetSinglePixelWidth = null;
  1338. lineWidth = this.getSinglePixelWidth();
  1339. resetLineWidthToOne = lineWidth < 0;
  1340. }
  1341. } else {
  1342. lineWidth /= scale;
  1343. }
  1344. if (fontSizeScale !== 1.0) {
  1345. ctx.scale(fontSizeScale, fontSizeScale);
  1346. lineWidth /= fontSizeScale;
  1347. }
  1348. ctx.lineWidth = lineWidth;
  1349. let x = 0,
  1350. i;
  1351. for (i = 0; i < glyphsLength; ++i) {
  1352. const glyph = glyphs[i];
  1353. if ((0, _util.isNum)(glyph)) {
  1354. x += spacingDir * glyph * fontSize / 1000;
  1355. continue;
  1356. }
  1357. let restoreNeeded = false;
  1358. const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
  1359. const character = glyph.fontChar;
  1360. const accent = glyph.accent;
  1361. let scaledX, scaledY;
  1362. let width = glyph.width;
  1363. if (vertical) {
  1364. const vmetric = glyph.vmetric || defaultVMetrics;
  1365. const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale;
  1366. const vy = vmetric[2] * widthAdvanceScale;
  1367. width = vmetric ? -vmetric[0] : width;
  1368. scaledX = vx / fontSizeScale;
  1369. scaledY = (x + vy) / fontSizeScale;
  1370. } else {
  1371. scaledX = x / fontSizeScale;
  1372. scaledY = 0;
  1373. }
  1374. if (font.remeasure && width > 0) {
  1375. const measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale;
  1376. if (width < measuredWidth && this.isFontSubpixelAAEnabled) {
  1377. const characterScaleX = width / measuredWidth;
  1378. restoreNeeded = true;
  1379. ctx.save();
  1380. ctx.scale(characterScaleX, 1);
  1381. scaledX /= characterScaleX;
  1382. } else if (width !== measuredWidth) {
  1383. scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale;
  1384. }
  1385. }
  1386. if (this.contentVisible && (glyph.isInFont || font.missingFile)) {
  1387. if (simpleFillText && !accent) {
  1388. ctx.fillText(character, scaledX, scaledY);
  1389. } else {
  1390. this.paintChar(character, scaledX, scaledY, patternTransform, resetLineWidthToOne);
  1391. if (accent) {
  1392. const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale;
  1393. const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale;
  1394. this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternTransform, resetLineWidthToOne);
  1395. }
  1396. }
  1397. }
  1398. let charWidth;
  1399. if (vertical) {
  1400. charWidth = width * widthAdvanceScale - spacing * fontDirection;
  1401. } else {
  1402. charWidth = width * widthAdvanceScale + spacing * fontDirection;
  1403. }
  1404. x += charWidth;
  1405. if (restoreNeeded) {
  1406. ctx.restore();
  1407. }
  1408. }
  1409. if (vertical) {
  1410. current.y -= x;
  1411. } else {
  1412. current.x += x * textHScale;
  1413. }
  1414. ctx.restore();
  1415. return undefined;
  1416. }
  1417. showType3Text(glyphs) {
  1418. const ctx = this.ctx;
  1419. const current = this.current;
  1420. const font = current.font;
  1421. const fontSize = current.fontSize;
  1422. const fontDirection = current.fontDirection;
  1423. const spacingDir = font.vertical ? 1 : -1;
  1424. const charSpacing = current.charSpacing;
  1425. const wordSpacing = current.wordSpacing;
  1426. const textHScale = current.textHScale * fontDirection;
  1427. const fontMatrix = current.fontMatrix || _util.FONT_IDENTITY_MATRIX;
  1428. const glyphsLength = glyphs.length;
  1429. const isTextInvisible = current.textRenderingMode === _util.TextRenderingMode.INVISIBLE;
  1430. let i, glyph, width, spacingLength;
  1431. if (isTextInvisible || fontSize === 0) {
  1432. return;
  1433. }
  1434. this._cachedGetSinglePixelWidth = null;
  1435. ctx.save();
  1436. ctx.transform.apply(ctx, current.textMatrix);
  1437. ctx.translate(current.x, current.y);
  1438. ctx.scale(textHScale, fontDirection);
  1439. for (i = 0; i < glyphsLength; ++i) {
  1440. glyph = glyphs[i];
  1441. if ((0, _util.isNum)(glyph)) {
  1442. spacingLength = spacingDir * glyph * fontSize / 1000;
  1443. this.ctx.translate(spacingLength, 0);
  1444. current.x += spacingLength * textHScale;
  1445. continue;
  1446. }
  1447. const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
  1448. const operatorList = font.charProcOperatorList[glyph.operatorListId];
  1449. if (!operatorList) {
  1450. (0, _util.warn)(`Type3 character "${glyph.operatorListId}" is not available.`);
  1451. continue;
  1452. }
  1453. if (this.contentVisible) {
  1454. this.processingType3 = glyph;
  1455. this.save();
  1456. ctx.scale(fontSize, fontSize);
  1457. ctx.transform.apply(ctx, fontMatrix);
  1458. this.executeOperatorList(operatorList);
  1459. this.restore();
  1460. }
  1461. const transformed = _util.Util.applyTransform([glyph.width, 0], fontMatrix);
  1462. width = transformed[0] * fontSize + spacing;
  1463. ctx.translate(width, 0);
  1464. current.x += width * textHScale;
  1465. }
  1466. ctx.restore();
  1467. this.processingType3 = null;
  1468. }
  1469. setCharWidth(xWidth, yWidth) {}
  1470. setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) {
  1471. this.ctx.rect(llx, lly, urx - llx, ury - lly);
  1472. this.clip();
  1473. this.endPath();
  1474. }
  1475. getColorN_Pattern(IR) {
  1476. let pattern;
  1477. if (IR[0] === "TilingPattern") {
  1478. const color = IR[1];
  1479. const baseTransform = this.baseTransform || this.ctx.mozCurrentTransform.slice();
  1480. const canvasGraphicsFactory = {
  1481. createCanvasGraphics: ctx => {
  1482. return new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory);
  1483. }
  1484. };
  1485. pattern = new _pattern_helper.TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform);
  1486. } else {
  1487. pattern = this._getPattern(IR[1]);
  1488. }
  1489. return pattern;
  1490. }
  1491. setStrokeColorN() {
  1492. this.current.strokeColor = this.getColorN_Pattern(arguments);
  1493. }
  1494. setFillColorN() {
  1495. this.current.fillColor = this.getColorN_Pattern(arguments);
  1496. this.current.patternFill = true;
  1497. }
  1498. setStrokeRGBColor(r, g, b) {
  1499. const color = _util.Util.makeHexColor(r, g, b);
  1500. this.ctx.strokeStyle = color;
  1501. this.current.strokeColor = color;
  1502. }
  1503. setFillRGBColor(r, g, b) {
  1504. const color = _util.Util.makeHexColor(r, g, b);
  1505. this.ctx.fillStyle = color;
  1506. this.current.fillColor = color;
  1507. this.current.patternFill = false;
  1508. }
  1509. _getPattern(objId) {
  1510. if (this.cachedPatterns.has(objId)) {
  1511. return this.cachedPatterns.get(objId);
  1512. }
  1513. const pattern = (0, _pattern_helper.getShadingPattern)(this.objs.get(objId));
  1514. this.cachedPatterns.set(objId, pattern);
  1515. return pattern;
  1516. }
  1517. shadingFill(objId) {
  1518. if (!this.contentVisible) {
  1519. return;
  1520. }
  1521. const ctx = this.ctx;
  1522. this.save();
  1523. const pattern = this._getPattern(objId);
  1524. ctx.fillStyle = pattern.getPattern(ctx, this, ctx.mozCurrentTransformInverse, true);
  1525. const inv = ctx.mozCurrentTransformInverse;
  1526. if (inv) {
  1527. const canvas = ctx.canvas;
  1528. const width = canvas.width;
  1529. const height = canvas.height;
  1530. const bl = _util.Util.applyTransform([0, 0], inv);
  1531. const br = _util.Util.applyTransform([0, height], inv);
  1532. const ul = _util.Util.applyTransform([width, 0], inv);
  1533. const ur = _util.Util.applyTransform([width, height], inv);
  1534. const x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
  1535. const y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
  1536. const x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
  1537. const y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
  1538. this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
  1539. } else {
  1540. this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
  1541. }
  1542. this.restore();
  1543. }
  1544. beginInlineImage() {
  1545. (0, _util.unreachable)("Should not call beginInlineImage");
  1546. }
  1547. beginImageData() {
  1548. (0, _util.unreachable)("Should not call beginImageData");
  1549. }
  1550. paintFormXObjectBegin(matrix, bbox) {
  1551. if (!this.contentVisible) {
  1552. return;
  1553. }
  1554. this.save();
  1555. this.baseTransformStack.push(this.baseTransform);
  1556. if (Array.isArray(matrix) && matrix.length === 6) {
  1557. this.transform.apply(this, matrix);
  1558. }
  1559. this.baseTransform = this.ctx.mozCurrentTransform;
  1560. if (bbox) {
  1561. const width = bbox[2] - bbox[0];
  1562. const height = bbox[3] - bbox[1];
  1563. this.ctx.rect(bbox[0], bbox[1], width, height);
  1564. this.clip();
  1565. this.endPath();
  1566. }
  1567. }
  1568. paintFormXObjectEnd() {
  1569. if (!this.contentVisible) {
  1570. return;
  1571. }
  1572. this.restore();
  1573. this.baseTransform = this.baseTransformStack.pop();
  1574. }
  1575. beginGroup(group) {
  1576. if (!this.contentVisible) {
  1577. return;
  1578. }
  1579. this.save();
  1580. const currentCtx = this.ctx;
  1581. if (!group.isolated) {
  1582. (0, _util.info)("TODO: Support non-isolated groups.");
  1583. }
  1584. if (group.knockout) {
  1585. (0, _util.warn)("Knockout groups not supported.");
  1586. }
  1587. const currentTransform = currentCtx.mozCurrentTransform;
  1588. if (group.matrix) {
  1589. currentCtx.transform.apply(currentCtx, group.matrix);
  1590. }
  1591. if (!group.bbox) {
  1592. throw new Error("Bounding box is required.");
  1593. }
  1594. let bounds = _util.Util.getAxialAlignedBoundingBox(group.bbox, currentCtx.mozCurrentTransform);
  1595. const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height];
  1596. bounds = _util.Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
  1597. const offsetX = Math.floor(bounds[0]);
  1598. const offsetY = Math.floor(bounds[1]);
  1599. let drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
  1600. let drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
  1601. let scaleX = 1,
  1602. scaleY = 1;
  1603. if (drawnWidth > MAX_GROUP_SIZE) {
  1604. scaleX = drawnWidth / MAX_GROUP_SIZE;
  1605. drawnWidth = MAX_GROUP_SIZE;
  1606. }
  1607. if (drawnHeight > MAX_GROUP_SIZE) {
  1608. scaleY = drawnHeight / MAX_GROUP_SIZE;
  1609. drawnHeight = MAX_GROUP_SIZE;
  1610. }
  1611. let cacheId = "groupAt" + this.groupLevel;
  1612. if (group.smask) {
  1613. cacheId += "_smask_" + this.smaskCounter++ % 2;
  1614. }
  1615. const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true);
  1616. const groupCtx = scratchCanvas.context;
  1617. groupCtx.scale(1 / scaleX, 1 / scaleY);
  1618. groupCtx.translate(-offsetX, -offsetY);
  1619. groupCtx.transform.apply(groupCtx, currentTransform);
  1620. if (group.smask) {
  1621. this.smaskStack.push({
  1622. canvas: scratchCanvas.canvas,
  1623. context: groupCtx,
  1624. offsetX,
  1625. offsetY,
  1626. scaleX,
  1627. scaleY,
  1628. subtype: group.smask.subtype,
  1629. backdrop: group.smask.backdrop,
  1630. transferMap: group.smask.transferMap || null,
  1631. startTransformInverse: null
  1632. });
  1633. } else {
  1634. currentCtx.setTransform(1, 0, 0, 1, 0, 0);
  1635. currentCtx.translate(offsetX, offsetY);
  1636. currentCtx.scale(scaleX, scaleY);
  1637. }
  1638. copyCtxState(currentCtx, groupCtx);
  1639. this.ctx = groupCtx;
  1640. this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
  1641. this.groupStack.push(currentCtx);
  1642. this.groupLevel++;
  1643. this.current.activeSMask = null;
  1644. }
  1645. endGroup(group) {
  1646. if (!this.contentVisible) {
  1647. return;
  1648. }
  1649. this.groupLevel--;
  1650. const groupCtx = this.ctx;
  1651. this.ctx = this.groupStack.pop();
  1652. if (this.ctx.imageSmoothingEnabled !== undefined) {
  1653. this.ctx.imageSmoothingEnabled = false;
  1654. } else {
  1655. this.ctx.mozImageSmoothingEnabled = false;
  1656. }
  1657. if (group.smask) {
  1658. this.tempSMask = this.smaskStack.pop();
  1659. } else {
  1660. this.ctx.drawImage(groupCtx.canvas, 0, 0);
  1661. }
  1662. this.restore();
  1663. }
  1664. beginAnnotations() {
  1665. this.save();
  1666. if (this.baseTransform) {
  1667. this.ctx.setTransform.apply(this.ctx, this.baseTransform);
  1668. }
  1669. }
  1670. endAnnotations() {
  1671. this.restore();
  1672. }
  1673. beginAnnotation(id, rect, transform, matrix) {
  1674. this.save();
  1675. resetCtxToDefault(this.ctx);
  1676. this.current = new CanvasExtraState();
  1677. if (Array.isArray(rect) && rect.length === 4) {
  1678. const width = rect[2] - rect[0];
  1679. const height = rect[3] - rect[1];
  1680. this.ctx.rect(rect[0], rect[1], width, height);
  1681. this.clip();
  1682. this.endPath();
  1683. }
  1684. this.transform.apply(this, transform);
  1685. this.transform.apply(this, matrix);
  1686. }
  1687. endAnnotation() {
  1688. this.restore();
  1689. }
  1690. paintImageMaskXObject(img) {
  1691. if (!this.contentVisible) {
  1692. return;
  1693. }
  1694. const ctx = this.ctx;
  1695. const width = img.width,
  1696. height = img.height;
  1697. const glyph = this.processingType3;
  1698. if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) {
  1699. if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {
  1700. glyph.compiled = compileType3Glyph({
  1701. data: img.data,
  1702. width,
  1703. height
  1704. });
  1705. } else {
  1706. glyph.compiled = null;
  1707. }
  1708. }
  1709. if (glyph?.compiled) {
  1710. glyph.compiled(ctx);
  1711. return;
  1712. }
  1713. const mask = this._createMaskCanvas(img);
  1714. const maskCanvas = mask.canvas;
  1715. ctx.save();
  1716. ctx.setTransform(1, 0, 0, 1, 0, 0);
  1717. ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
  1718. ctx.restore();
  1719. }
  1720. paintImageMaskXObjectRepeat(imgData, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
  1721. if (!this.contentVisible) {
  1722. return;
  1723. }
  1724. const ctx = this.ctx;
  1725. ctx.save();
  1726. const currentTransform = ctx.mozCurrentTransform;
  1727. ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0);
  1728. const mask = this._createMaskCanvas(imgData);
  1729. ctx.setTransform(1, 0, 0, 1, 0, 0);
  1730. for (let i = 0, ii = positions.length; i < ii; i += 2) {
  1731. const trans = _util.Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]);
  1732. const [x, y] = _util.Util.applyTransform([0, 0], trans);
  1733. ctx.drawImage(mask.canvas, x, y);
  1734. }
  1735. ctx.restore();
  1736. }
  1737. paintImageMaskXObjectGroup(images) {
  1738. if (!this.contentVisible) {
  1739. return;
  1740. }
  1741. const ctx = this.ctx;
  1742. const fillColor = this.current.fillColor;
  1743. const isPatternFill = this.current.patternFill;
  1744. for (let i = 0, ii = images.length; i < ii; i++) {
  1745. const image = images[i];
  1746. const width = image.width,
  1747. height = image.height;
  1748. const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
  1749. const maskCtx = maskCanvas.context;
  1750. maskCtx.save();
  1751. putBinaryImageMask(maskCtx, image);
  1752. maskCtx.globalCompositeOperation = "source-in";
  1753. maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, ctx.mozCurrentTransformInverse, false) : fillColor;
  1754. maskCtx.fillRect(0, 0, width, height);
  1755. maskCtx.restore();
  1756. ctx.save();
  1757. ctx.transform.apply(ctx, image.transform);
  1758. ctx.scale(1, -1);
  1759. ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
  1760. ctx.restore();
  1761. }
  1762. }
  1763. paintImageXObject(objId) {
  1764. if (!this.contentVisible) {
  1765. return;
  1766. }
  1767. const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
  1768. if (!imgData) {
  1769. (0, _util.warn)("Dependent image isn't ready yet");
  1770. return;
  1771. }
  1772. this.paintInlineImageXObject(imgData);
  1773. }
  1774. paintImageXObjectRepeat(objId, scaleX, scaleY, positions) {
  1775. if (!this.contentVisible) {
  1776. return;
  1777. }
  1778. const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
  1779. if (!imgData) {
  1780. (0, _util.warn)("Dependent image isn't ready yet");
  1781. return;
  1782. }
  1783. const width = imgData.width;
  1784. const height = imgData.height;
  1785. const map = [];
  1786. for (let i = 0, ii = positions.length; i < ii; i += 2) {
  1787. map.push({
  1788. transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]],
  1789. x: 0,
  1790. y: 0,
  1791. w: width,
  1792. h: height
  1793. });
  1794. }
  1795. this.paintInlineImageXObjectGroup(imgData, map);
  1796. }
  1797. paintInlineImageXObject(imgData) {
  1798. if (!this.contentVisible) {
  1799. return;
  1800. }
  1801. const width = imgData.width;
  1802. const height = imgData.height;
  1803. const ctx = this.ctx;
  1804. this.save();
  1805. ctx.scale(1 / width, -1 / height);
  1806. let imgToPaint;
  1807. if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) {
  1808. imgToPaint = imgData;
  1809. } else {
  1810. const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
  1811. const tmpCtx = tmpCanvas.context;
  1812. putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
  1813. imgToPaint = tmpCanvas.canvas;
  1814. }
  1815. const scaled = this._scaleImage(imgToPaint, ctx.mozCurrentTransformInverse);
  1816. ctx.drawImage(scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height);
  1817. if (this.imageLayer) {
  1818. const position = this.getCanvasPosition(0, -height);
  1819. this.imageLayer.appendImage({
  1820. imgData,
  1821. left: position[0],
  1822. top: position[1],
  1823. width: width / ctx.mozCurrentTransformInverse[0],
  1824. height: height / ctx.mozCurrentTransformInverse[3]
  1825. });
  1826. }
  1827. this.restore();
  1828. }
  1829. paintInlineImageXObjectGroup(imgData, map) {
  1830. if (!this.contentVisible) {
  1831. return;
  1832. }
  1833. const ctx = this.ctx;
  1834. const w = imgData.width;
  1835. const h = imgData.height;
  1836. const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h);
  1837. const tmpCtx = tmpCanvas.context;
  1838. putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
  1839. for (let i = 0, ii = map.length; i < ii; i++) {
  1840. const entry = map[i];
  1841. ctx.save();
  1842. ctx.transform.apply(ctx, entry.transform);
  1843. ctx.scale(1, -1);
  1844. ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
  1845. if (this.imageLayer) {
  1846. const position = this.getCanvasPosition(entry.x, entry.y);
  1847. this.imageLayer.appendImage({
  1848. imgData,
  1849. left: position[0],
  1850. top: position[1],
  1851. width: w,
  1852. height: h
  1853. });
  1854. }
  1855. ctx.restore();
  1856. }
  1857. }
  1858. paintSolidColorImageMask() {
  1859. if (!this.contentVisible) {
  1860. return;
  1861. }
  1862. this.ctx.fillRect(0, 0, 1, 1);
  1863. }
  1864. markPoint(tag) {}
  1865. markPointProps(tag, properties) {}
  1866. beginMarkedContent(tag) {
  1867. this.markedContentStack.push({
  1868. visible: true
  1869. });
  1870. }
  1871. beginMarkedContentProps(tag, properties) {
  1872. if (tag === "OC") {
  1873. this.markedContentStack.push({
  1874. visible: this.optionalContentConfig.isVisible(properties)
  1875. });
  1876. } else {
  1877. this.markedContentStack.push({
  1878. visible: true
  1879. });
  1880. }
  1881. this.contentVisible = this.isContentVisible();
  1882. }
  1883. endMarkedContent() {
  1884. this.markedContentStack.pop();
  1885. this.contentVisible = this.isContentVisible();
  1886. }
  1887. beginCompat() {}
  1888. endCompat() {}
  1889. consumePath() {
  1890. const ctx = this.ctx;
  1891. if (this.pendingClip) {
  1892. if (this.pendingClip === EO_CLIP) {
  1893. ctx.clip("evenodd");
  1894. } else {
  1895. ctx.clip();
  1896. }
  1897. this.pendingClip = null;
  1898. }
  1899. ctx.beginPath();
  1900. }
  1901. getSinglePixelWidth() {
  1902. if (this._cachedGetSinglePixelWidth === null) {
  1903. const m = this.ctx.mozCurrentTransform;
  1904. const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]);
  1905. const sqNorm1 = m[0] ** 2 + m[2] ** 2;
  1906. const sqNorm2 = m[1] ** 2 + m[3] ** 2;
  1907. const pixelHeight = Math.sqrt(Math.max(sqNorm1, sqNorm2)) / absDet;
  1908. if (sqNorm1 !== sqNorm2 && this._combinedScaleFactor * pixelHeight > 1) {
  1909. this._cachedGetSinglePixelWidth = -(this._combinedScaleFactor * pixelHeight);
  1910. } else if (absDet > Number.EPSILON) {
  1911. this._cachedGetSinglePixelWidth = pixelHeight;
  1912. } else {
  1913. this._cachedGetSinglePixelWidth = 1;
  1914. }
  1915. }
  1916. return this._cachedGetSinglePixelWidth;
  1917. }
  1918. getCanvasPosition(x, y) {
  1919. const transform = this.ctx.mozCurrentTransform;
  1920. return [transform[0] * x + transform[2] * y + transform[4], transform[1] * x + transform[3] * y + transform[5]];
  1921. }
  1922. isContentVisible() {
  1923. for (let i = this.markedContentStack.length - 1; i >= 0; i--) {
  1924. if (!this.markedContentStack[i].visible) {
  1925. return false;
  1926. }
  1927. }
  1928. return true;
  1929. }
  1930. }
  1931. for (const op in _util.OPS) {
  1932. CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op];
  1933. }
  1934. return CanvasGraphics;
  1935. }();
  1936. exports.CanvasGraphics = CanvasGraphics;