canvas.js 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320
  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] = m[0] * x;
  98. m[1] = m[1] * x;
  99. m[2] = m[2] * y;
  100. m[3] = 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. if (canvasCtx) {
  631. addContextCurrentTransform(canvasCtx);
  632. }
  633. this._cachedGetSinglePixelWidth = null;
  634. }
  635. beginDrawing({
  636. transform,
  637. viewport,
  638. transparency = false,
  639. background = null
  640. }) {
  641. const width = this.ctx.canvas.width;
  642. const height = this.ctx.canvas.height;
  643. this.ctx.save();
  644. this.ctx.fillStyle = background || "rgb(255, 255, 255)";
  645. this.ctx.fillRect(0, 0, width, height);
  646. this.ctx.restore();
  647. if (transparency) {
  648. const transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height, true);
  649. this.compositeCtx = this.ctx;
  650. this.transparentCanvas = transparentCanvas.canvas;
  651. this.ctx = transparentCanvas.context;
  652. this.ctx.save();
  653. this.ctx.transform.apply(this.ctx, this.compositeCtx.mozCurrentTransform);
  654. }
  655. this.ctx.save();
  656. resetCtxToDefault(this.ctx);
  657. if (transform) {
  658. this.ctx.transform.apply(this.ctx, transform);
  659. }
  660. this.ctx.transform.apply(this.ctx, viewport.transform);
  661. this.baseTransform = this.ctx.mozCurrentTransform.slice();
  662. this._combinedScaleFactor = Math.hypot(this.baseTransform[0], this.baseTransform[2]);
  663. if (this.imageLayer) {
  664. this.imageLayer.beginLayout();
  665. }
  666. }
  667. executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) {
  668. const argsArray = operatorList.argsArray;
  669. const fnArray = operatorList.fnArray;
  670. let i = executionStartIdx || 0;
  671. const argsArrayLen = argsArray.length;
  672. if (argsArrayLen === i) {
  673. return i;
  674. }
  675. const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function";
  676. const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
  677. let steps = 0;
  678. const commonObjs = this.commonObjs;
  679. const objs = this.objs;
  680. let fnId;
  681. while (true) {
  682. if (stepper !== undefined && i === stepper.nextBreakPoint) {
  683. stepper.breakIt(i, continueCallback);
  684. return i;
  685. }
  686. fnId = fnArray[i];
  687. if (fnId !== _util.OPS.dependency) {
  688. this[fnId].apply(this, argsArray[i]);
  689. } else {
  690. for (const depObjId of argsArray[i]) {
  691. const objsPool = depObjId.startsWith("g_") ? commonObjs : objs;
  692. if (!objsPool.has(depObjId)) {
  693. objsPool.get(depObjId, continueCallback);
  694. return i;
  695. }
  696. }
  697. }
  698. i++;
  699. if (i === argsArrayLen) {
  700. return i;
  701. }
  702. if (chunkOperations && ++steps > EXECUTION_STEPS) {
  703. if (Date.now() > endTime) {
  704. continueCallback();
  705. return i;
  706. }
  707. steps = 0;
  708. }
  709. }
  710. }
  711. endDrawing() {
  712. while (this.stateStack.length || this.current.activeSMask !== null) {
  713. this.restore();
  714. }
  715. this.ctx.restore();
  716. if (this.transparentCanvas) {
  717. this.ctx = this.compositeCtx;
  718. this.ctx.save();
  719. this.ctx.setTransform(1, 0, 0, 1, 0, 0);
  720. this.ctx.drawImage(this.transparentCanvas, 0, 0);
  721. this.ctx.restore();
  722. this.transparentCanvas = null;
  723. }
  724. this.cachedCanvases.clear();
  725. if (this.imageLayer) {
  726. this.imageLayer.endLayout();
  727. }
  728. }
  729. setLineWidth(width) {
  730. this.current.lineWidth = width;
  731. this.ctx.lineWidth = width;
  732. }
  733. setLineCap(style) {
  734. this.ctx.lineCap = LINE_CAP_STYLES[style];
  735. }
  736. setLineJoin(style) {
  737. this.ctx.lineJoin = LINE_JOIN_STYLES[style];
  738. }
  739. setMiterLimit(limit) {
  740. this.ctx.miterLimit = limit;
  741. }
  742. setDash(dashArray, dashPhase) {
  743. const ctx = this.ctx;
  744. if (ctx.setLineDash !== undefined) {
  745. ctx.setLineDash(dashArray);
  746. ctx.lineDashOffset = dashPhase;
  747. }
  748. }
  749. setRenderingIntent(intent) {}
  750. setFlatness(flatness) {}
  751. setGState(states) {
  752. for (let i = 0, ii = states.length; i < ii; i++) {
  753. const state = states[i];
  754. const key = state[0];
  755. const value = state[1];
  756. switch (key) {
  757. case "LW":
  758. this.setLineWidth(value);
  759. break;
  760. case "LC":
  761. this.setLineCap(value);
  762. break;
  763. case "LJ":
  764. this.setLineJoin(value);
  765. break;
  766. case "ML":
  767. this.setMiterLimit(value);
  768. break;
  769. case "D":
  770. this.setDash(value[0], value[1]);
  771. break;
  772. case "RI":
  773. this.setRenderingIntent(value);
  774. break;
  775. case "FL":
  776. this.setFlatness(value);
  777. break;
  778. case "Font":
  779. this.setFont(value[0], value[1]);
  780. break;
  781. case "CA":
  782. this.current.strokeAlpha = state[1];
  783. break;
  784. case "ca":
  785. this.current.fillAlpha = state[1];
  786. this.ctx.globalAlpha = state[1];
  787. break;
  788. case "BM":
  789. this.ctx.globalCompositeOperation = value;
  790. break;
  791. case "SMask":
  792. if (this.current.activeSMask) {
  793. if (this.stateStack.length > 0 && this.stateStack[this.stateStack.length - 1].activeSMask === this.current.activeSMask) {
  794. this.suspendSMaskGroup();
  795. } else {
  796. this.endSMaskGroup();
  797. }
  798. }
  799. this.current.activeSMask = value ? this.tempSMask : null;
  800. if (this.current.activeSMask) {
  801. this.beginSMaskGroup();
  802. }
  803. this.tempSMask = null;
  804. break;
  805. case "TR":
  806. this.current.transferMaps = value;
  807. }
  808. }
  809. }
  810. beginSMaskGroup() {
  811. const activeSMask = this.current.activeSMask;
  812. const drawnWidth = activeSMask.canvas.width;
  813. const drawnHeight = activeSMask.canvas.height;
  814. const cacheId = "smaskGroupAt" + this.groupLevel;
  815. const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true);
  816. const currentCtx = this.ctx;
  817. const currentTransform = currentCtx.mozCurrentTransform;
  818. this.ctx.save();
  819. const groupCtx = scratchCanvas.context;
  820. groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
  821. groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
  822. groupCtx.transform.apply(groupCtx, currentTransform);
  823. activeSMask.startTransformInverse = groupCtx.mozCurrentTransformInverse;
  824. copyCtxState(currentCtx, groupCtx);
  825. this.ctx = groupCtx;
  826. this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
  827. this.groupStack.push(currentCtx);
  828. this.groupLevel++;
  829. }
  830. suspendSMaskGroup() {
  831. const groupCtx = this.ctx;
  832. this.groupLevel--;
  833. this.ctx = this.groupStack.pop();
  834. composeSMask(this.ctx, this.current.activeSMask, groupCtx);
  835. this.ctx.restore();
  836. this.ctx.save();
  837. copyCtxState(groupCtx, this.ctx);
  838. this.current.resumeSMaskCtx = groupCtx;
  839. const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
  840. this.ctx.transform.apply(this.ctx, deltaTransform);
  841. groupCtx.save();
  842. groupCtx.setTransform(1, 0, 0, 1, 0, 0);
  843. groupCtx.clearRect(0, 0, groupCtx.canvas.width, groupCtx.canvas.height);
  844. groupCtx.restore();
  845. }
  846. resumeSMaskGroup() {
  847. const groupCtx = this.current.resumeSMaskCtx;
  848. const currentCtx = this.ctx;
  849. this.ctx = groupCtx;
  850. this.groupStack.push(currentCtx);
  851. this.groupLevel++;
  852. }
  853. endSMaskGroup() {
  854. const groupCtx = this.ctx;
  855. this.groupLevel--;
  856. this.ctx = this.groupStack.pop();
  857. composeSMask(this.ctx, this.current.activeSMask, groupCtx);
  858. this.ctx.restore();
  859. copyCtxState(groupCtx, this.ctx);
  860. const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
  861. this.ctx.transform.apply(this.ctx, deltaTransform);
  862. }
  863. save() {
  864. this.ctx.save();
  865. const old = this.current;
  866. this.stateStack.push(old);
  867. this.current = old.clone();
  868. this.current.resumeSMaskCtx = null;
  869. }
  870. restore() {
  871. if (this.current.resumeSMaskCtx) {
  872. this.resumeSMaskGroup();
  873. }
  874. if (this.current.activeSMask !== null && (this.stateStack.length === 0 || this.stateStack[this.stateStack.length - 1].activeSMask !== this.current.activeSMask)) {
  875. this.endSMaskGroup();
  876. }
  877. if (this.stateStack.length !== 0) {
  878. this.current = this.stateStack.pop();
  879. this.ctx.restore();
  880. this.pendingClip = null;
  881. this._cachedGetSinglePixelWidth = null;
  882. } else {
  883. this.current.activeSMask = null;
  884. }
  885. }
  886. transform(a, b, c, d, e, f) {
  887. this.ctx.transform(a, b, c, d, e, f);
  888. this._cachedGetSinglePixelWidth = null;
  889. }
  890. constructPath(ops, args) {
  891. const ctx = this.ctx;
  892. const current = this.current;
  893. let x = current.x,
  894. y = current.y;
  895. for (let i = 0, j = 0, ii = ops.length; i < ii; i++) {
  896. switch (ops[i] | 0) {
  897. case _util.OPS.rectangle:
  898. x = args[j++];
  899. y = args[j++];
  900. const width = args[j++];
  901. const height = args[j++];
  902. const xw = x + width;
  903. const yh = y + height;
  904. ctx.moveTo(x, y);
  905. if (width === 0 || height === 0) {
  906. ctx.lineTo(xw, yh);
  907. } else {
  908. ctx.lineTo(xw, y);
  909. ctx.lineTo(xw, yh);
  910. ctx.lineTo(x, yh);
  911. }
  912. ctx.closePath();
  913. break;
  914. case _util.OPS.moveTo:
  915. x = args[j++];
  916. y = args[j++];
  917. ctx.moveTo(x, y);
  918. break;
  919. case _util.OPS.lineTo:
  920. x = args[j++];
  921. y = args[j++];
  922. ctx.lineTo(x, y);
  923. break;
  924. case _util.OPS.curveTo:
  925. x = args[j + 4];
  926. y = args[j + 5];
  927. ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
  928. j += 6;
  929. break;
  930. case _util.OPS.curveTo2:
  931. ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
  932. x = args[j + 2];
  933. y = args[j + 3];
  934. j += 4;
  935. break;
  936. case _util.OPS.curveTo3:
  937. x = args[j + 2];
  938. y = args[j + 3];
  939. ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
  940. j += 4;
  941. break;
  942. case _util.OPS.closePath:
  943. ctx.closePath();
  944. break;
  945. }
  946. }
  947. current.setCurrentPoint(x, y);
  948. }
  949. closePath() {
  950. this.ctx.closePath();
  951. }
  952. stroke(consumePath) {
  953. consumePath = typeof consumePath !== "undefined" ? consumePath : true;
  954. const ctx = this.ctx;
  955. const strokeColor = this.current.strokeColor;
  956. ctx.globalAlpha = this.current.strokeAlpha;
  957. if (this.contentVisible) {
  958. if (typeof strokeColor === "object" && strokeColor?.getPattern) {
  959. const lineWidth = this.getSinglePixelWidth();
  960. ctx.save();
  961. ctx.strokeStyle = strokeColor.getPattern(ctx, this);
  962. ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
  963. ctx.stroke();
  964. ctx.restore();
  965. } else {
  966. const lineWidth = this.getSinglePixelWidth();
  967. if (lineWidth < 0 && -lineWidth >= this.current.lineWidth) {
  968. ctx.save();
  969. ctx.resetTransform();
  970. ctx.lineWidth = Math.round(this._combinedScaleFactor);
  971. ctx.stroke();
  972. ctx.restore();
  973. } else {
  974. ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
  975. ctx.stroke();
  976. }
  977. }
  978. }
  979. if (consumePath) {
  980. this.consumePath();
  981. }
  982. ctx.globalAlpha = this.current.fillAlpha;
  983. }
  984. closeStroke() {
  985. this.closePath();
  986. this.stroke();
  987. }
  988. fill(consumePath) {
  989. consumePath = typeof consumePath !== "undefined" ? consumePath : true;
  990. const ctx = this.ctx;
  991. const fillColor = this.current.fillColor;
  992. const isPatternFill = this.current.patternFill;
  993. let needRestore = false;
  994. if (isPatternFill) {
  995. ctx.save();
  996. ctx.fillStyle = fillColor.getPattern(ctx, this);
  997. needRestore = true;
  998. }
  999. if (this.contentVisible) {
  1000. if (this.pendingEOFill) {
  1001. ctx.fill("evenodd");
  1002. this.pendingEOFill = false;
  1003. } else {
  1004. ctx.fill();
  1005. }
  1006. }
  1007. if (needRestore) {
  1008. ctx.restore();
  1009. }
  1010. if (consumePath) {
  1011. this.consumePath();
  1012. }
  1013. }
  1014. eoFill() {
  1015. this.pendingEOFill = true;
  1016. this.fill();
  1017. }
  1018. fillStroke() {
  1019. this.fill(false);
  1020. this.stroke(false);
  1021. this.consumePath();
  1022. }
  1023. eoFillStroke() {
  1024. this.pendingEOFill = true;
  1025. this.fillStroke();
  1026. }
  1027. closeFillStroke() {
  1028. this.closePath();
  1029. this.fillStroke();
  1030. }
  1031. closeEOFillStroke() {
  1032. this.pendingEOFill = true;
  1033. this.closePath();
  1034. this.fillStroke();
  1035. }
  1036. endPath() {
  1037. this.consumePath();
  1038. }
  1039. clip() {
  1040. this.pendingClip = NORMAL_CLIP;
  1041. }
  1042. eoClip() {
  1043. this.pendingClip = EO_CLIP;
  1044. }
  1045. beginText() {
  1046. this.current.textMatrix = _util.IDENTITY_MATRIX;
  1047. this.current.textMatrixScale = 1;
  1048. this.current.x = this.current.lineX = 0;
  1049. this.current.y = this.current.lineY = 0;
  1050. }
  1051. endText() {
  1052. const paths = this.pendingTextPaths;
  1053. const ctx = this.ctx;
  1054. if (paths === undefined) {
  1055. ctx.beginPath();
  1056. return;
  1057. }
  1058. ctx.save();
  1059. ctx.beginPath();
  1060. for (let i = 0; i < paths.length; i++) {
  1061. const path = paths[i];
  1062. ctx.setTransform.apply(ctx, path.transform);
  1063. ctx.translate(path.x, path.y);
  1064. path.addToPath(ctx, path.fontSize);
  1065. }
  1066. ctx.restore();
  1067. ctx.clip();
  1068. ctx.beginPath();
  1069. delete this.pendingTextPaths;
  1070. }
  1071. setCharSpacing(spacing) {
  1072. this.current.charSpacing = spacing;
  1073. }
  1074. setWordSpacing(spacing) {
  1075. this.current.wordSpacing = spacing;
  1076. }
  1077. setHScale(scale) {
  1078. this.current.textHScale = scale / 100;
  1079. }
  1080. setLeading(leading) {
  1081. this.current.leading = -leading;
  1082. }
  1083. setFont(fontRefName, size) {
  1084. const fontObj = this.commonObjs.get(fontRefName);
  1085. const current = this.current;
  1086. if (!fontObj) {
  1087. throw new Error(`Can't find font for ${fontRefName}`);
  1088. }
  1089. current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX;
  1090. if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) {
  1091. (0, _util.warn)("Invalid font matrix for font " + fontRefName);
  1092. }
  1093. if (size < 0) {
  1094. size = -size;
  1095. current.fontDirection = -1;
  1096. } else {
  1097. current.fontDirection = 1;
  1098. }
  1099. this.current.font = fontObj;
  1100. this.current.fontSize = size;
  1101. if (fontObj.isType3Font) {
  1102. return;
  1103. }
  1104. const name = fontObj.loadedName || "sans-serif";
  1105. let bold = "normal";
  1106. if (fontObj.black) {
  1107. bold = "900";
  1108. } else if (fontObj.bold) {
  1109. bold = "bold";
  1110. }
  1111. const italic = fontObj.italic ? "italic" : "normal";
  1112. const typeface = `"${name}", ${fontObj.fallbackName}`;
  1113. let browserFontSize = size;
  1114. if (size < MIN_FONT_SIZE) {
  1115. browserFontSize = MIN_FONT_SIZE;
  1116. } else if (size > MAX_FONT_SIZE) {
  1117. browserFontSize = MAX_FONT_SIZE;
  1118. }
  1119. this.current.fontSizeScale = size / browserFontSize;
  1120. this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`;
  1121. }
  1122. setTextRenderingMode(mode) {
  1123. this.current.textRenderingMode = mode;
  1124. }
  1125. setTextRise(rise) {
  1126. this.current.textRise = rise;
  1127. }
  1128. moveText(x, y) {
  1129. this.current.x = this.current.lineX += x;
  1130. this.current.y = this.current.lineY += y;
  1131. }
  1132. setLeadingMoveText(x, y) {
  1133. this.setLeading(-y);
  1134. this.moveText(x, y);
  1135. }
  1136. setTextMatrix(a, b, c, d, e, f) {
  1137. this.current.textMatrix = [a, b, c, d, e, f];
  1138. this.current.textMatrixScale = Math.hypot(a, b);
  1139. this.current.x = this.current.lineX = 0;
  1140. this.current.y = this.current.lineY = 0;
  1141. }
  1142. nextLine() {
  1143. this.moveText(0, this.current.leading);
  1144. }
  1145. paintChar(character, x, y, patternTransform, resetLineWidthToOne) {
  1146. const ctx = this.ctx;
  1147. const current = this.current;
  1148. const font = current.font;
  1149. const textRenderingMode = current.textRenderingMode;
  1150. const fontSize = current.fontSize / current.fontSizeScale;
  1151. const fillStrokeMode = textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
  1152. const isAddToPathSet = !!(textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG);
  1153. const patternFill = current.patternFill && !font.missingFile;
  1154. let addToPath;
  1155. if (font.disableFontFace || isAddToPathSet || patternFill) {
  1156. addToPath = font.getPathGenerator(this.commonObjs, character);
  1157. }
  1158. if (font.disableFontFace || patternFill) {
  1159. ctx.save();
  1160. ctx.translate(x, y);
  1161. ctx.beginPath();
  1162. addToPath(ctx, fontSize);
  1163. if (patternTransform) {
  1164. ctx.setTransform.apply(ctx, patternTransform);
  1165. }
  1166. if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1167. ctx.fill();
  1168. }
  1169. if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1170. if (resetLineWidthToOne) {
  1171. ctx.resetTransform();
  1172. ctx.lineWidth = Math.round(this._combinedScaleFactor);
  1173. }
  1174. ctx.stroke();
  1175. }
  1176. ctx.restore();
  1177. } else {
  1178. if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1179. ctx.fillText(character, x, y);
  1180. }
  1181. if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1182. if (resetLineWidthToOne) {
  1183. ctx.save();
  1184. ctx.moveTo(x, y);
  1185. ctx.resetTransform();
  1186. ctx.lineWidth = Math.round(this._combinedScaleFactor);
  1187. ctx.strokeText(character, 0, 0);
  1188. ctx.restore();
  1189. } else {
  1190. ctx.strokeText(character, x, y);
  1191. }
  1192. }
  1193. }
  1194. if (isAddToPathSet) {
  1195. const paths = this.pendingTextPaths || (this.pendingTextPaths = []);
  1196. paths.push({
  1197. transform: ctx.mozCurrentTransform,
  1198. x,
  1199. y,
  1200. fontSize,
  1201. addToPath
  1202. });
  1203. }
  1204. }
  1205. get isFontSubpixelAAEnabled() {
  1206. const {
  1207. context: ctx
  1208. } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10);
  1209. ctx.scale(1.5, 1);
  1210. ctx.fillText("I", 0, 10);
  1211. const data = ctx.getImageData(0, 0, 10, 10).data;
  1212. let enabled = false;
  1213. for (let i = 3; i < data.length; i += 4) {
  1214. if (data[i] > 0 && data[i] < 255) {
  1215. enabled = true;
  1216. break;
  1217. }
  1218. }
  1219. return (0, _util.shadow)(this, "isFontSubpixelAAEnabled", enabled);
  1220. }
  1221. showText(glyphs) {
  1222. const current = this.current;
  1223. const font = current.font;
  1224. if (font.isType3Font) {
  1225. return this.showType3Text(glyphs);
  1226. }
  1227. const fontSize = current.fontSize;
  1228. if (fontSize === 0) {
  1229. return undefined;
  1230. }
  1231. const ctx = this.ctx;
  1232. const fontSizeScale = current.fontSizeScale;
  1233. const charSpacing = current.charSpacing;
  1234. const wordSpacing = current.wordSpacing;
  1235. const fontDirection = current.fontDirection;
  1236. const textHScale = current.textHScale * fontDirection;
  1237. const glyphsLength = glyphs.length;
  1238. const vertical = font.vertical;
  1239. const spacingDir = vertical ? 1 : -1;
  1240. const defaultVMetrics = font.defaultVMetrics;
  1241. const widthAdvanceScale = fontSize * current.fontMatrix[0];
  1242. const simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
  1243. ctx.save();
  1244. let patternTransform;
  1245. if (current.patternFill) {
  1246. ctx.save();
  1247. const pattern = current.fillColor.getPattern(ctx, this);
  1248. patternTransform = ctx.mozCurrentTransform;
  1249. ctx.restore();
  1250. ctx.fillStyle = pattern;
  1251. }
  1252. ctx.transform.apply(ctx, current.textMatrix);
  1253. ctx.translate(current.x, current.y + current.textRise);
  1254. if (fontDirection > 0) {
  1255. ctx.scale(textHScale, -1);
  1256. } else {
  1257. ctx.scale(textHScale, 1);
  1258. }
  1259. let lineWidth = current.lineWidth;
  1260. let resetLineWidthToOne = false;
  1261. const scale = current.textMatrixScale;
  1262. if (scale === 0 || lineWidth === 0) {
  1263. const fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
  1264. if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
  1265. this._cachedGetSinglePixelWidth = null;
  1266. lineWidth = this.getSinglePixelWidth();
  1267. resetLineWidthToOne = lineWidth < 0;
  1268. }
  1269. } else {
  1270. lineWidth /= scale;
  1271. }
  1272. if (fontSizeScale !== 1.0) {
  1273. ctx.scale(fontSizeScale, fontSizeScale);
  1274. lineWidth /= fontSizeScale;
  1275. }
  1276. ctx.lineWidth = lineWidth;
  1277. let x = 0,
  1278. i;
  1279. for (i = 0; i < glyphsLength; ++i) {
  1280. const glyph = glyphs[i];
  1281. if ((0, _util.isNum)(glyph)) {
  1282. x += spacingDir * glyph * fontSize / 1000;
  1283. continue;
  1284. }
  1285. let restoreNeeded = false;
  1286. const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
  1287. const character = glyph.fontChar;
  1288. const accent = glyph.accent;
  1289. let scaledX, scaledY;
  1290. let width = glyph.width;
  1291. if (vertical) {
  1292. const vmetric = glyph.vmetric || defaultVMetrics;
  1293. const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale;
  1294. const vy = vmetric[2] * widthAdvanceScale;
  1295. width = vmetric ? -vmetric[0] : width;
  1296. scaledX = vx / fontSizeScale;
  1297. scaledY = (x + vy) / fontSizeScale;
  1298. } else {
  1299. scaledX = x / fontSizeScale;
  1300. scaledY = 0;
  1301. }
  1302. if (font.remeasure && width > 0) {
  1303. const measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale;
  1304. if (width < measuredWidth && this.isFontSubpixelAAEnabled) {
  1305. const characterScaleX = width / measuredWidth;
  1306. restoreNeeded = true;
  1307. ctx.save();
  1308. ctx.scale(characterScaleX, 1);
  1309. scaledX /= characterScaleX;
  1310. } else if (width !== measuredWidth) {
  1311. scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale;
  1312. }
  1313. }
  1314. if (this.contentVisible && (glyph.isInFont || font.missingFile)) {
  1315. if (simpleFillText && !accent) {
  1316. ctx.fillText(character, scaledX, scaledY);
  1317. } else {
  1318. this.paintChar(character, scaledX, scaledY, patternTransform, resetLineWidthToOne);
  1319. if (accent) {
  1320. const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale;
  1321. const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale;
  1322. this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternTransform, resetLineWidthToOne);
  1323. }
  1324. }
  1325. }
  1326. let charWidth;
  1327. if (vertical) {
  1328. charWidth = width * widthAdvanceScale - spacing * fontDirection;
  1329. } else {
  1330. charWidth = width * widthAdvanceScale + spacing * fontDirection;
  1331. }
  1332. x += charWidth;
  1333. if (restoreNeeded) {
  1334. ctx.restore();
  1335. }
  1336. }
  1337. if (vertical) {
  1338. current.y -= x;
  1339. } else {
  1340. current.x += x * textHScale;
  1341. }
  1342. ctx.restore();
  1343. return undefined;
  1344. }
  1345. showType3Text(glyphs) {
  1346. const ctx = this.ctx;
  1347. const current = this.current;
  1348. const font = current.font;
  1349. const fontSize = current.fontSize;
  1350. const fontDirection = current.fontDirection;
  1351. const spacingDir = font.vertical ? 1 : -1;
  1352. const charSpacing = current.charSpacing;
  1353. const wordSpacing = current.wordSpacing;
  1354. const textHScale = current.textHScale * fontDirection;
  1355. const fontMatrix = current.fontMatrix || _util.FONT_IDENTITY_MATRIX;
  1356. const glyphsLength = glyphs.length;
  1357. const isTextInvisible = current.textRenderingMode === _util.TextRenderingMode.INVISIBLE;
  1358. let i, glyph, width, spacingLength;
  1359. if (isTextInvisible || fontSize === 0) {
  1360. return;
  1361. }
  1362. this._cachedGetSinglePixelWidth = null;
  1363. ctx.save();
  1364. ctx.transform.apply(ctx, current.textMatrix);
  1365. ctx.translate(current.x, current.y);
  1366. ctx.scale(textHScale, fontDirection);
  1367. for (i = 0; i < glyphsLength; ++i) {
  1368. glyph = glyphs[i];
  1369. if ((0, _util.isNum)(glyph)) {
  1370. spacingLength = spacingDir * glyph * fontSize / 1000;
  1371. this.ctx.translate(spacingLength, 0);
  1372. current.x += spacingLength * textHScale;
  1373. continue;
  1374. }
  1375. const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
  1376. const operatorList = font.charProcOperatorList[glyph.operatorListId];
  1377. if (!operatorList) {
  1378. (0, _util.warn)(`Type3 character "${glyph.operatorListId}" is not available.`);
  1379. continue;
  1380. }
  1381. if (this.contentVisible) {
  1382. this.processingType3 = glyph;
  1383. this.save();
  1384. ctx.scale(fontSize, fontSize);
  1385. ctx.transform.apply(ctx, fontMatrix);
  1386. this.executeOperatorList(operatorList);
  1387. this.restore();
  1388. }
  1389. const transformed = _util.Util.applyTransform([glyph.width, 0], fontMatrix);
  1390. width = transformed[0] * fontSize + spacing;
  1391. ctx.translate(width, 0);
  1392. current.x += width * textHScale;
  1393. }
  1394. ctx.restore();
  1395. this.processingType3 = null;
  1396. }
  1397. setCharWidth(xWidth, yWidth) {}
  1398. setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) {
  1399. this.ctx.rect(llx, lly, urx - llx, ury - lly);
  1400. this.clip();
  1401. this.endPath();
  1402. }
  1403. getColorN_Pattern(IR) {
  1404. let pattern;
  1405. if (IR[0] === "TilingPattern") {
  1406. const color = IR[1];
  1407. const baseTransform = this.baseTransform || this.ctx.mozCurrentTransform.slice();
  1408. const canvasGraphicsFactory = {
  1409. createCanvasGraphics: ctx => {
  1410. return new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory);
  1411. }
  1412. };
  1413. pattern = new _pattern_helper.TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform);
  1414. } else {
  1415. pattern = (0, _pattern_helper.getShadingPattern)(IR);
  1416. }
  1417. return pattern;
  1418. }
  1419. setStrokeColorN() {
  1420. this.current.strokeColor = this.getColorN_Pattern(arguments);
  1421. }
  1422. setFillColorN() {
  1423. this.current.fillColor = this.getColorN_Pattern(arguments);
  1424. this.current.patternFill = true;
  1425. }
  1426. setStrokeRGBColor(r, g, b) {
  1427. const color = _util.Util.makeHexColor(r, g, b);
  1428. this.ctx.strokeStyle = color;
  1429. this.current.strokeColor = color;
  1430. }
  1431. setFillRGBColor(r, g, b) {
  1432. const color = _util.Util.makeHexColor(r, g, b);
  1433. this.ctx.fillStyle = color;
  1434. this.current.fillColor = color;
  1435. this.current.patternFill = false;
  1436. }
  1437. shadingFill(patternIR) {
  1438. if (!this.contentVisible) {
  1439. return;
  1440. }
  1441. const ctx = this.ctx;
  1442. this.save();
  1443. const pattern = (0, _pattern_helper.getShadingPattern)(patternIR);
  1444. ctx.fillStyle = pattern.getPattern(ctx, this, true);
  1445. const inv = ctx.mozCurrentTransformInverse;
  1446. if (inv) {
  1447. const canvas = ctx.canvas;
  1448. const width = canvas.width;
  1449. const height = canvas.height;
  1450. const bl = _util.Util.applyTransform([0, 0], inv);
  1451. const br = _util.Util.applyTransform([0, height], inv);
  1452. const ul = _util.Util.applyTransform([width, 0], inv);
  1453. const ur = _util.Util.applyTransform([width, height], inv);
  1454. const x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
  1455. const y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
  1456. const x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
  1457. const y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
  1458. this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
  1459. } else {
  1460. this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
  1461. }
  1462. this.restore();
  1463. }
  1464. beginInlineImage() {
  1465. (0, _util.unreachable)("Should not call beginInlineImage");
  1466. }
  1467. beginImageData() {
  1468. (0, _util.unreachable)("Should not call beginImageData");
  1469. }
  1470. paintFormXObjectBegin(matrix, bbox) {
  1471. if (!this.contentVisible) {
  1472. return;
  1473. }
  1474. this.save();
  1475. this.baseTransformStack.push(this.baseTransform);
  1476. if (Array.isArray(matrix) && matrix.length === 6) {
  1477. this.transform.apply(this, matrix);
  1478. }
  1479. this.baseTransform = this.ctx.mozCurrentTransform;
  1480. if (bbox) {
  1481. const width = bbox[2] - bbox[0];
  1482. const height = bbox[3] - bbox[1];
  1483. this.ctx.rect(bbox[0], bbox[1], width, height);
  1484. this.clip();
  1485. this.endPath();
  1486. }
  1487. }
  1488. paintFormXObjectEnd() {
  1489. if (!this.contentVisible) {
  1490. return;
  1491. }
  1492. this.restore();
  1493. this.baseTransform = this.baseTransformStack.pop();
  1494. }
  1495. beginGroup(group) {
  1496. if (!this.contentVisible) {
  1497. return;
  1498. }
  1499. this.save();
  1500. const currentCtx = this.ctx;
  1501. if (!group.isolated) {
  1502. (0, _util.info)("TODO: Support non-isolated groups.");
  1503. }
  1504. if (group.knockout) {
  1505. (0, _util.warn)("Knockout groups not supported.");
  1506. }
  1507. const currentTransform = currentCtx.mozCurrentTransform;
  1508. if (group.matrix) {
  1509. currentCtx.transform.apply(currentCtx, group.matrix);
  1510. }
  1511. if (!group.bbox) {
  1512. throw new Error("Bounding box is required.");
  1513. }
  1514. let bounds = _util.Util.getAxialAlignedBoundingBox(group.bbox, currentCtx.mozCurrentTransform);
  1515. const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height];
  1516. bounds = _util.Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
  1517. const offsetX = Math.floor(bounds[0]);
  1518. const offsetY = Math.floor(bounds[1]);
  1519. let drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
  1520. let drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
  1521. let scaleX = 1,
  1522. scaleY = 1;
  1523. if (drawnWidth > MAX_GROUP_SIZE) {
  1524. scaleX = drawnWidth / MAX_GROUP_SIZE;
  1525. drawnWidth = MAX_GROUP_SIZE;
  1526. }
  1527. if (drawnHeight > MAX_GROUP_SIZE) {
  1528. scaleY = drawnHeight / MAX_GROUP_SIZE;
  1529. drawnHeight = MAX_GROUP_SIZE;
  1530. }
  1531. let cacheId = "groupAt" + this.groupLevel;
  1532. if (group.smask) {
  1533. cacheId += "_smask_" + this.smaskCounter++ % 2;
  1534. }
  1535. const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true);
  1536. const groupCtx = scratchCanvas.context;
  1537. groupCtx.scale(1 / scaleX, 1 / scaleY);
  1538. groupCtx.translate(-offsetX, -offsetY);
  1539. groupCtx.transform.apply(groupCtx, currentTransform);
  1540. if (group.smask) {
  1541. this.smaskStack.push({
  1542. canvas: scratchCanvas.canvas,
  1543. context: groupCtx,
  1544. offsetX,
  1545. offsetY,
  1546. scaleX,
  1547. scaleY,
  1548. subtype: group.smask.subtype,
  1549. backdrop: group.smask.backdrop,
  1550. transferMap: group.smask.transferMap || null,
  1551. startTransformInverse: null
  1552. });
  1553. } else {
  1554. currentCtx.setTransform(1, 0, 0, 1, 0, 0);
  1555. currentCtx.translate(offsetX, offsetY);
  1556. currentCtx.scale(scaleX, scaleY);
  1557. }
  1558. copyCtxState(currentCtx, groupCtx);
  1559. this.ctx = groupCtx;
  1560. this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
  1561. this.groupStack.push(currentCtx);
  1562. this.groupLevel++;
  1563. this.current.activeSMask = null;
  1564. }
  1565. endGroup(group) {
  1566. if (!this.contentVisible) {
  1567. return;
  1568. }
  1569. this.groupLevel--;
  1570. const groupCtx = this.ctx;
  1571. this.ctx = this.groupStack.pop();
  1572. if (this.ctx.imageSmoothingEnabled !== undefined) {
  1573. this.ctx.imageSmoothingEnabled = false;
  1574. } else {
  1575. this.ctx.mozImageSmoothingEnabled = false;
  1576. }
  1577. if (group.smask) {
  1578. this.tempSMask = this.smaskStack.pop();
  1579. } else {
  1580. this.ctx.drawImage(groupCtx.canvas, 0, 0);
  1581. }
  1582. this.restore();
  1583. }
  1584. beginAnnotations() {
  1585. this.save();
  1586. if (this.baseTransform) {
  1587. this.ctx.setTransform.apply(this.ctx, this.baseTransform);
  1588. }
  1589. }
  1590. endAnnotations() {
  1591. this.restore();
  1592. }
  1593. beginAnnotation(rect, transform, matrix) {
  1594. this.save();
  1595. resetCtxToDefault(this.ctx);
  1596. this.current = new CanvasExtraState();
  1597. if (Array.isArray(rect) && rect.length === 4) {
  1598. const width = rect[2] - rect[0];
  1599. const height = rect[3] - rect[1];
  1600. this.ctx.rect(rect[0], rect[1], width, height);
  1601. this.clip();
  1602. this.endPath();
  1603. }
  1604. this.transform.apply(this, transform);
  1605. this.transform.apply(this, matrix);
  1606. }
  1607. endAnnotation() {
  1608. this.restore();
  1609. }
  1610. paintImageMaskXObject(img) {
  1611. if (!this.contentVisible) {
  1612. return;
  1613. }
  1614. const ctx = this.ctx;
  1615. const width = img.width,
  1616. height = img.height;
  1617. const fillColor = this.current.fillColor;
  1618. const isPatternFill = this.current.patternFill;
  1619. const glyph = this.processingType3;
  1620. if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) {
  1621. if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {
  1622. glyph.compiled = compileType3Glyph({
  1623. data: img.data,
  1624. width,
  1625. height
  1626. });
  1627. } else {
  1628. glyph.compiled = null;
  1629. }
  1630. }
  1631. if (glyph?.compiled) {
  1632. glyph.compiled(ctx);
  1633. return;
  1634. }
  1635. const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
  1636. const maskCtx = maskCanvas.context;
  1637. maskCtx.save();
  1638. putBinaryImageMask(maskCtx, img);
  1639. maskCtx.globalCompositeOperation = "source-in";
  1640. maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor;
  1641. maskCtx.fillRect(0, 0, width, height);
  1642. maskCtx.restore();
  1643. this.paintInlineImageXObject(maskCanvas.canvas);
  1644. }
  1645. paintImageMaskXObjectRepeat(imgData, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
  1646. if (!this.contentVisible) {
  1647. return;
  1648. }
  1649. const width = imgData.width;
  1650. const height = imgData.height;
  1651. const fillColor = this.current.fillColor;
  1652. const isPatternFill = this.current.patternFill;
  1653. const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
  1654. const maskCtx = maskCanvas.context;
  1655. maskCtx.save();
  1656. putBinaryImageMask(maskCtx, imgData);
  1657. maskCtx.globalCompositeOperation = "source-in";
  1658. maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor;
  1659. maskCtx.fillRect(0, 0, width, height);
  1660. maskCtx.restore();
  1661. const ctx = this.ctx;
  1662. for (let i = 0, ii = positions.length; i < ii; i += 2) {
  1663. ctx.save();
  1664. ctx.transform(scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]);
  1665. ctx.scale(1, -1);
  1666. ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
  1667. ctx.restore();
  1668. }
  1669. }
  1670. paintImageMaskXObjectGroup(images) {
  1671. if (!this.contentVisible) {
  1672. return;
  1673. }
  1674. const ctx = this.ctx;
  1675. const fillColor = this.current.fillColor;
  1676. const isPatternFill = this.current.patternFill;
  1677. for (let i = 0, ii = images.length; i < ii; i++) {
  1678. const image = images[i];
  1679. const width = image.width,
  1680. height = image.height;
  1681. const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
  1682. const maskCtx = maskCanvas.context;
  1683. maskCtx.save();
  1684. putBinaryImageMask(maskCtx, image);
  1685. maskCtx.globalCompositeOperation = "source-in";
  1686. maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor;
  1687. maskCtx.fillRect(0, 0, width, height);
  1688. maskCtx.restore();
  1689. ctx.save();
  1690. ctx.transform.apply(ctx, image.transform);
  1691. ctx.scale(1, -1);
  1692. ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
  1693. ctx.restore();
  1694. }
  1695. }
  1696. paintImageXObject(objId) {
  1697. if (!this.contentVisible) {
  1698. return;
  1699. }
  1700. const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
  1701. if (!imgData) {
  1702. (0, _util.warn)("Dependent image isn't ready yet");
  1703. return;
  1704. }
  1705. this.paintInlineImageXObject(imgData);
  1706. }
  1707. paintImageXObjectRepeat(objId, scaleX, scaleY, positions) {
  1708. if (!this.contentVisible) {
  1709. return;
  1710. }
  1711. const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
  1712. if (!imgData) {
  1713. (0, _util.warn)("Dependent image isn't ready yet");
  1714. return;
  1715. }
  1716. const width = imgData.width;
  1717. const height = imgData.height;
  1718. const map = [];
  1719. for (let i = 0, ii = positions.length; i < ii; i += 2) {
  1720. map.push({
  1721. transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]],
  1722. x: 0,
  1723. y: 0,
  1724. w: width,
  1725. h: height
  1726. });
  1727. }
  1728. this.paintInlineImageXObjectGroup(imgData, map);
  1729. }
  1730. paintInlineImageXObject(imgData) {
  1731. if (!this.contentVisible) {
  1732. return;
  1733. }
  1734. const width = imgData.width;
  1735. const height = imgData.height;
  1736. const ctx = this.ctx;
  1737. this.save();
  1738. ctx.scale(1 / width, -1 / height);
  1739. const currentTransform = ctx.mozCurrentTransformInverse;
  1740. let widthScale = Math.max(Math.hypot(currentTransform[0], currentTransform[1]), 1);
  1741. let heightScale = Math.max(Math.hypot(currentTransform[2], currentTransform[3]), 1);
  1742. let imgToPaint, tmpCanvas, tmpCtx;
  1743. if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) {
  1744. imgToPaint = imgData;
  1745. } else {
  1746. tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
  1747. tmpCtx = tmpCanvas.context;
  1748. putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
  1749. imgToPaint = tmpCanvas.canvas;
  1750. }
  1751. let paintWidth = width,
  1752. paintHeight = height;
  1753. let tmpCanvasId = "prescale1";
  1754. while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) {
  1755. let newWidth = paintWidth,
  1756. newHeight = paintHeight;
  1757. if (widthScale > 2 && paintWidth > 1) {
  1758. newWidth = Math.ceil(paintWidth / 2);
  1759. widthScale /= paintWidth / newWidth;
  1760. }
  1761. if (heightScale > 2 && paintHeight > 1) {
  1762. newHeight = Math.ceil(paintHeight / 2);
  1763. heightScale /= paintHeight / newHeight;
  1764. }
  1765. tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
  1766. tmpCtx = tmpCanvas.context;
  1767. tmpCtx.clearRect(0, 0, newWidth, newHeight);
  1768. tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight);
  1769. imgToPaint = tmpCanvas.canvas;
  1770. paintWidth = newWidth;
  1771. paintHeight = newHeight;
  1772. tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1";
  1773. }
  1774. ctx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight, 0, -height, width, height);
  1775. if (this.imageLayer) {
  1776. const position = this.getCanvasPosition(0, -height);
  1777. this.imageLayer.appendImage({
  1778. imgData,
  1779. left: position[0],
  1780. top: position[1],
  1781. width: width / currentTransform[0],
  1782. height: height / currentTransform[3]
  1783. });
  1784. }
  1785. this.restore();
  1786. }
  1787. paintInlineImageXObjectGroup(imgData, map) {
  1788. if (!this.contentVisible) {
  1789. return;
  1790. }
  1791. const ctx = this.ctx;
  1792. const w = imgData.width;
  1793. const h = imgData.height;
  1794. const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h);
  1795. const tmpCtx = tmpCanvas.context;
  1796. putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
  1797. for (let i = 0, ii = map.length; i < ii; i++) {
  1798. const entry = map[i];
  1799. ctx.save();
  1800. ctx.transform.apply(ctx, entry.transform);
  1801. ctx.scale(1, -1);
  1802. ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
  1803. if (this.imageLayer) {
  1804. const position = this.getCanvasPosition(entry.x, entry.y);
  1805. this.imageLayer.appendImage({
  1806. imgData,
  1807. left: position[0],
  1808. top: position[1],
  1809. width: w,
  1810. height: h
  1811. });
  1812. }
  1813. ctx.restore();
  1814. }
  1815. }
  1816. paintSolidColorImageMask() {
  1817. if (!this.contentVisible) {
  1818. return;
  1819. }
  1820. this.ctx.fillRect(0, 0, 1, 1);
  1821. }
  1822. markPoint(tag) {}
  1823. markPointProps(tag, properties) {}
  1824. beginMarkedContent(tag) {
  1825. this.markedContentStack.push({
  1826. visible: true
  1827. });
  1828. }
  1829. beginMarkedContentProps(tag, properties) {
  1830. if (tag === "OC") {
  1831. this.markedContentStack.push({
  1832. visible: this.optionalContentConfig.isVisible(properties)
  1833. });
  1834. } else {
  1835. this.markedContentStack.push({
  1836. visible: true
  1837. });
  1838. }
  1839. this.contentVisible = this.isContentVisible();
  1840. }
  1841. endMarkedContent() {
  1842. this.markedContentStack.pop();
  1843. this.contentVisible = this.isContentVisible();
  1844. }
  1845. beginCompat() {}
  1846. endCompat() {}
  1847. consumePath() {
  1848. const ctx = this.ctx;
  1849. if (this.pendingClip) {
  1850. if (this.pendingClip === EO_CLIP) {
  1851. ctx.clip("evenodd");
  1852. } else {
  1853. ctx.clip();
  1854. }
  1855. this.pendingClip = null;
  1856. }
  1857. ctx.beginPath();
  1858. }
  1859. getSinglePixelWidth() {
  1860. if (this._cachedGetSinglePixelWidth === null) {
  1861. const m = this.ctx.mozCurrentTransform;
  1862. const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]);
  1863. const sqNorm1 = m[0] ** 2 + m[2] ** 2;
  1864. const sqNorm2 = m[1] ** 2 + m[3] ** 2;
  1865. const pixelHeight = Math.sqrt(Math.max(sqNorm1, sqNorm2)) / absDet;
  1866. if (sqNorm1 !== sqNorm2 && this._combinedScaleFactor * pixelHeight > 1) {
  1867. this._cachedGetSinglePixelWidth = -(this._combinedScaleFactor * pixelHeight);
  1868. } else if (absDet > Number.EPSILON) {
  1869. this._cachedGetSinglePixelWidth = pixelHeight;
  1870. } else {
  1871. this._cachedGetSinglePixelWidth = 1;
  1872. }
  1873. }
  1874. return this._cachedGetSinglePixelWidth;
  1875. }
  1876. getCanvasPosition(x, y) {
  1877. const transform = this.ctx.mozCurrentTransform;
  1878. return [transform[0] * x + transform[2] * y + transform[4], transform[1] * x + transform[3] * y + transform[5]];
  1879. }
  1880. isContentVisible() {
  1881. for (let i = this.markedContentStack.length - 1; i >= 0; i--) {
  1882. if (!this.markedContentStack[i].visible) {
  1883. return false;
  1884. }
  1885. }
  1886. return true;
  1887. }
  1888. }
  1889. for (const op in _util.OPS) {
  1890. CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op];
  1891. }
  1892. return CanvasGraphics;
  1893. }();
  1894. exports.CanvasGraphics = CanvasGraphics;