1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | "use strict";
|
23 |
|
24 | Object.defineProperty(exports, "__esModule", {
|
25 | value: true
|
26 | });
|
27 | exports.PDFImage = void 0;
|
28 |
|
29 | var _util = require("../shared/util.js");
|
30 |
|
31 | var _image_utils = require("../shared/image_utils.js");
|
32 |
|
33 | var _base_stream = require("./base_stream.js");
|
34 |
|
35 | var _colorspace = require("./colorspace.js");
|
36 |
|
37 | var _decode_stream = require("./decode_stream.js");
|
38 |
|
39 | var _jpeg_stream = require("./jpeg_stream.js");
|
40 |
|
41 | var _jpx = require("./jpx.js");
|
42 |
|
43 | var _primitives = require("./primitives.js");
|
44 |
|
45 | function decodeAndClamp(value, addend, coefficient, max) {
|
46 | value = addend + value * coefficient;
|
47 |
|
48 | if (value < 0) {
|
49 | value = 0;
|
50 | } else if (value > max) {
|
51 | value = max;
|
52 | }
|
53 |
|
54 | return value;
|
55 | }
|
56 |
|
57 | function resizeImageMask(src, bpc, w1, h1, w2, h2) {
|
58 | const length = w2 * h2;
|
59 | let dest;
|
60 |
|
61 | if (bpc <= 8) {
|
62 | dest = new Uint8Array(length);
|
63 | } else if (bpc <= 16) {
|
64 | dest = new Uint16Array(length);
|
65 | } else {
|
66 | dest = new Uint32Array(length);
|
67 | }
|
68 |
|
69 | const xRatio = w1 / w2;
|
70 | const yRatio = h1 / h2;
|
71 | let i,
|
72 | j,
|
73 | py,
|
74 | newIndex = 0,
|
75 | oldIndex;
|
76 | const xScaled = new Uint16Array(w2);
|
77 | const w1Scanline = w1;
|
78 |
|
79 | for (i = 0; i < w2; i++) {
|
80 | xScaled[i] = Math.floor(i * xRatio);
|
81 | }
|
82 |
|
83 | for (i = 0; i < h2; i++) {
|
84 | py = Math.floor(i * yRatio) * w1Scanline;
|
85 |
|
86 | for (j = 0; j < w2; j++) {
|
87 | oldIndex = py + xScaled[j];
|
88 | dest[newIndex++] = src[oldIndex];
|
89 | }
|
90 | }
|
91 |
|
92 | return dest;
|
93 | }
|
94 |
|
95 | class PDFImage {
|
96 | constructor({
|
97 | xref,
|
98 | res,
|
99 | image,
|
100 | isInline = false,
|
101 | smask = null,
|
102 | mask = null,
|
103 | isMask = false,
|
104 | pdfFunctionFactory,
|
105 | localColorSpaceCache
|
106 | }) {
|
107 | this.image = image;
|
108 | const dict = image.dict;
|
109 | const filter = dict.get("F", "Filter");
|
110 | let filterName;
|
111 |
|
112 | if (filter instanceof _primitives.Name) {
|
113 | filterName = filter.name;
|
114 | } else if (Array.isArray(filter)) {
|
115 | const filterZero = xref.fetchIfRef(filter[0]);
|
116 |
|
117 | if (filterZero instanceof _primitives.Name) {
|
118 | filterName = filterZero.name;
|
119 | }
|
120 | }
|
121 |
|
122 | switch (filterName) {
|
123 | case "JPXDecode":
|
124 | const jpxImage = new _jpx.JpxImage();
|
125 | jpxImage.parseImageProperties(image.stream);
|
126 | image.stream.reset();
|
127 | image.width = jpxImage.width;
|
128 | image.height = jpxImage.height;
|
129 | image.bitsPerComponent = jpxImage.bitsPerComponent;
|
130 | image.numComps = jpxImage.componentsCount;
|
131 | break;
|
132 |
|
133 | case "JBIG2Decode":
|
134 | image.bitsPerComponent = 1;
|
135 | image.numComps = 1;
|
136 | break;
|
137 | }
|
138 |
|
139 | let width = dict.get("W", "Width");
|
140 | let height = dict.get("H", "Height");
|
141 |
|
142 | if (Number.isInteger(image.width) && image.width > 0 && Number.isInteger(image.height) && image.height > 0 && (image.width !== width || image.height !== height)) {
|
143 | (0, _util.warn)("PDFImage - using the Width/Height of the image data, " + "rather than the image dictionary.");
|
144 | width = image.width;
|
145 | height = image.height;
|
146 | }
|
147 |
|
148 | if (width < 1 || height < 1) {
|
149 | throw new _util.FormatError(`Invalid image width: ${width} or height: ${height}`);
|
150 | }
|
151 |
|
152 | this.width = width;
|
153 | this.height = height;
|
154 | this.interpolate = dict.get("I", "Interpolate");
|
155 | this.imageMask = dict.get("IM", "ImageMask") || false;
|
156 | this.matte = dict.get("Matte") || false;
|
157 | let bitsPerComponent = image.bitsPerComponent;
|
158 |
|
159 | if (!bitsPerComponent) {
|
160 | bitsPerComponent = dict.get("BPC", "BitsPerComponent");
|
161 |
|
162 | if (!bitsPerComponent) {
|
163 | if (this.imageMask) {
|
164 | bitsPerComponent = 1;
|
165 | } else {
|
166 | throw new _util.FormatError(`Bits per component missing in image: ${this.imageMask}`);
|
167 | }
|
168 | }
|
169 | }
|
170 |
|
171 | this.bpc = bitsPerComponent;
|
172 |
|
173 | if (!this.imageMask) {
|
174 | let colorSpace = dict.getRaw("CS") || dict.getRaw("ColorSpace");
|
175 |
|
176 | if (!colorSpace) {
|
177 | (0, _util.info)("JPX images (which do not require color spaces)");
|
178 |
|
179 | switch (image.numComps) {
|
180 | case 1:
|
181 | colorSpace = _primitives.Name.get("DeviceGray");
|
182 | break;
|
183 |
|
184 | case 3:
|
185 | colorSpace = _primitives.Name.get("DeviceRGB");
|
186 | break;
|
187 |
|
188 | case 4:
|
189 | colorSpace = _primitives.Name.get("DeviceCMYK");
|
190 | break;
|
191 |
|
192 | default:
|
193 | throw new Error(`JPX images with ${image.numComps} color components not supported.`);
|
194 | }
|
195 | }
|
196 |
|
197 | this.colorSpace = _colorspace.ColorSpace.parse({
|
198 | cs: colorSpace,
|
199 | xref,
|
200 | resources: isInline ? res : null,
|
201 | pdfFunctionFactory,
|
202 | localColorSpaceCache
|
203 | });
|
204 | this.numComps = this.colorSpace.numComps;
|
205 | }
|
206 |
|
207 | this.decode = dict.getArray("D", "Decode");
|
208 | this.needsDecode = false;
|
209 |
|
210 | if (this.decode && (this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode, bitsPerComponent) || isMask && !_colorspace.ColorSpace.isDefaultDecode(this.decode, 1))) {
|
211 | this.needsDecode = true;
|
212 | const max = (1 << bitsPerComponent) - 1;
|
213 | this.decodeCoefficients = [];
|
214 | this.decodeAddends = [];
|
215 | const isIndexed = this.colorSpace && this.colorSpace.name === "Indexed";
|
216 |
|
217 | for (let i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
|
218 | const dmin = this.decode[i];
|
219 | const dmax = this.decode[i + 1];
|
220 | this.decodeCoefficients[j] = isIndexed ? (dmax - dmin) / max : dmax - dmin;
|
221 | this.decodeAddends[j] = isIndexed ? dmin : max * dmin;
|
222 | }
|
223 | }
|
224 |
|
225 | if (smask) {
|
226 | this.smask = new PDFImage({
|
227 | xref,
|
228 | res,
|
229 | image: smask,
|
230 | isInline,
|
231 | pdfFunctionFactory,
|
232 | localColorSpaceCache
|
233 | });
|
234 | } else if (mask) {
|
235 | if (mask instanceof _base_stream.BaseStream) {
|
236 | const maskDict = mask.dict,
|
237 | imageMask = maskDict.get("IM", "ImageMask");
|
238 |
|
239 | if (!imageMask) {
|
240 | (0, _util.warn)("Ignoring /Mask in image without /ImageMask.");
|
241 | } else {
|
242 | this.mask = new PDFImage({
|
243 | xref,
|
244 | res,
|
245 | image: mask,
|
246 | isInline,
|
247 | isMask: true,
|
248 | pdfFunctionFactory,
|
249 | localColorSpaceCache
|
250 | });
|
251 | }
|
252 | } else {
|
253 | this.mask = mask;
|
254 | }
|
255 | }
|
256 | }
|
257 |
|
258 | static async buildImage({
|
259 | xref,
|
260 | res,
|
261 | image,
|
262 | isInline = false,
|
263 | pdfFunctionFactory,
|
264 | localColorSpaceCache
|
265 | }) {
|
266 | const imageData = image;
|
267 | let smaskData = null;
|
268 | let maskData = null;
|
269 | const smask = image.dict.get("SMask");
|
270 | const mask = image.dict.get("Mask");
|
271 |
|
272 | if (smask) {
|
273 | if (smask instanceof _base_stream.BaseStream) {
|
274 | smaskData = smask;
|
275 | } else {
|
276 | (0, _util.warn)("Unsupported /SMask format.");
|
277 | }
|
278 | } else if (mask) {
|
279 | if (mask instanceof _base_stream.BaseStream || Array.isArray(mask)) {
|
280 | maskData = mask;
|
281 | } else {
|
282 | (0, _util.warn)("Unsupported /Mask format.");
|
283 | }
|
284 | }
|
285 |
|
286 | return new PDFImage({
|
287 | xref,
|
288 | res,
|
289 | image: imageData,
|
290 | isInline,
|
291 | smask: smaskData,
|
292 | mask: maskData,
|
293 | pdfFunctionFactory,
|
294 | localColorSpaceCache
|
295 | });
|
296 | }
|
297 |
|
298 | static createRawMask({
|
299 | imgArray,
|
300 | width,
|
301 | height,
|
302 | imageIsFromDecodeStream,
|
303 | inverseDecode,
|
304 | interpolate
|
305 | }) {
|
306 | const computedLength = (width + 7 >> 3) * height;
|
307 | const actualLength = imgArray.byteLength;
|
308 | const haveFullData = computedLength === actualLength;
|
309 | let data, i;
|
310 |
|
311 | if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) {
|
312 | data = imgArray;
|
313 | } else if (!inverseDecode) {
|
314 | data = new Uint8Array(imgArray);
|
315 | } else {
|
316 | data = new Uint8Array(computedLength);
|
317 | data.set(imgArray);
|
318 | data.fill(0xff, actualLength);
|
319 | }
|
320 |
|
321 | if (inverseDecode) {
|
322 | for (i = 0; i < actualLength; i++) {
|
323 | data[i] ^= 0xff;
|
324 | }
|
325 | }
|
326 |
|
327 | return {
|
328 | data,
|
329 | width,
|
330 | height,
|
331 | interpolate
|
332 | };
|
333 | }
|
334 |
|
335 | static createMask({
|
336 | imgArray,
|
337 | width,
|
338 | height,
|
339 | imageIsFromDecodeStream,
|
340 | inverseDecode,
|
341 | interpolate
|
342 | }) {
|
343 | const isSingleOpaquePixel = width === 1 && height === 1 && inverseDecode === (imgArray.length === 0 || !!(imgArray[0] & 128));
|
344 |
|
345 | if (isSingleOpaquePixel) {
|
346 | return {
|
347 | isSingleOpaquePixel
|
348 | };
|
349 | }
|
350 |
|
351 | if (_util.FeatureTest.isOffscreenCanvasSupported) {
|
352 | const canvas = new OffscreenCanvas(width, height);
|
353 | const ctx = canvas.getContext("2d");
|
354 | const imgData = ctx.createImageData(width, height);
|
355 | (0, _image_utils.applyMaskImageData)({
|
356 | src: imgArray,
|
357 | dest: imgData.data,
|
358 | width,
|
359 | height,
|
360 | inverseDecode
|
361 | });
|
362 | ctx.putImageData(imgData, 0, 0);
|
363 | const bitmap = canvas.transferToImageBitmap();
|
364 | return {
|
365 | data: null,
|
366 | width,
|
367 | height,
|
368 | interpolate,
|
369 | bitmap
|
370 | };
|
371 | }
|
372 |
|
373 | return this.createRawMask({
|
374 | imgArray,
|
375 | width,
|
376 | height,
|
377 | inverseDecode,
|
378 | imageIsFromDecodeStream,
|
379 | interpolate
|
380 | });
|
381 | }
|
382 |
|
383 | get drawWidth() {
|
384 | return Math.max(this.width, this.smask && this.smask.width || 0, this.mask && this.mask.width || 0);
|
385 | }
|
386 |
|
387 | get drawHeight() {
|
388 | return Math.max(this.height, this.smask && this.smask.height || 0, this.mask && this.mask.height || 0);
|
389 | }
|
390 |
|
391 | decodeBuffer(buffer) {
|
392 | const bpc = this.bpc;
|
393 | const numComps = this.numComps;
|
394 | const decodeAddends = this.decodeAddends;
|
395 | const decodeCoefficients = this.decodeCoefficients;
|
396 | const max = (1 << bpc) - 1;
|
397 | let i, ii;
|
398 |
|
399 | if (bpc === 1) {
|
400 | for (i = 0, ii = buffer.length; i < ii; i++) {
|
401 | buffer[i] = +!buffer[i];
|
402 | }
|
403 |
|
404 | return;
|
405 | }
|
406 |
|
407 | let index = 0;
|
408 |
|
409 | for (i = 0, ii = this.width * this.height; i < ii; i++) {
|
410 | for (let j = 0; j < numComps; j++) {
|
411 | buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j], decodeCoefficients[j], max);
|
412 | index++;
|
413 | }
|
414 | }
|
415 | }
|
416 |
|
417 | getComponents(buffer) {
|
418 | const bpc = this.bpc;
|
419 |
|
420 | if (bpc === 8) {
|
421 | return buffer;
|
422 | }
|
423 |
|
424 | const width = this.width;
|
425 | const height = this.height;
|
426 | const numComps = this.numComps;
|
427 | const length = width * height * numComps;
|
428 | let bufferPos = 0;
|
429 | let output;
|
430 |
|
431 | if (bpc <= 8) {
|
432 | output = new Uint8Array(length);
|
433 | } else if (bpc <= 16) {
|
434 | output = new Uint16Array(length);
|
435 | } else {
|
436 | output = new Uint32Array(length);
|
437 | }
|
438 |
|
439 | const rowComps = width * numComps;
|
440 | const max = (1 << bpc) - 1;
|
441 | let i = 0,
|
442 | ii,
|
443 | buf;
|
444 |
|
445 | if (bpc === 1) {
|
446 | let mask, loop1End, loop2End;
|
447 |
|
448 | for (let j = 0; j < height; j++) {
|
449 | loop1End = i + (rowComps & ~7);
|
450 | loop2End = i + rowComps;
|
451 |
|
452 | while (i < loop1End) {
|
453 | buf = buffer[bufferPos++];
|
454 | output[i] = buf >> 7 & 1;
|
455 | output[i + 1] = buf >> 6 & 1;
|
456 | output[i + 2] = buf >> 5 & 1;
|
457 | output[i + 3] = buf >> 4 & 1;
|
458 | output[i + 4] = buf >> 3 & 1;
|
459 | output[i + 5] = buf >> 2 & 1;
|
460 | output[i + 6] = buf >> 1 & 1;
|
461 | output[i + 7] = buf & 1;
|
462 | i += 8;
|
463 | }
|
464 |
|
465 | if (i < loop2End) {
|
466 | buf = buffer[bufferPos++];
|
467 | mask = 128;
|
468 |
|
469 | while (i < loop2End) {
|
470 | output[i++] = +!!(buf & mask);
|
471 | mask >>= 1;
|
472 | }
|
473 | }
|
474 | }
|
475 | } else {
|
476 | let bits = 0;
|
477 | buf = 0;
|
478 |
|
479 | for (i = 0, ii = length; i < ii; ++i) {
|
480 | if (i % rowComps === 0) {
|
481 | buf = 0;
|
482 | bits = 0;
|
483 | }
|
484 |
|
485 | while (bits < bpc) {
|
486 | buf = buf << 8 | buffer[bufferPos++];
|
487 | bits += 8;
|
488 | }
|
489 |
|
490 | const remainingBits = bits - bpc;
|
491 | let value = buf >> remainingBits;
|
492 |
|
493 | if (value < 0) {
|
494 | value = 0;
|
495 | } else if (value > max) {
|
496 | value = max;
|
497 | }
|
498 |
|
499 | output[i] = value;
|
500 | buf &= (1 << remainingBits) - 1;
|
501 | bits = remainingBits;
|
502 | }
|
503 | }
|
504 |
|
505 | return output;
|
506 | }
|
507 |
|
508 | fillOpacity(rgbaBuf, width, height, actualHeight, image) {
|
509 | const smask = this.smask;
|
510 | const mask = this.mask;
|
511 | let alphaBuf, sw, sh, i, ii, j;
|
512 |
|
513 | if (smask) {
|
514 | sw = smask.width;
|
515 | sh = smask.height;
|
516 | alphaBuf = new Uint8ClampedArray(sw * sh);
|
517 | smask.fillGrayBuffer(alphaBuf);
|
518 |
|
519 | if (sw !== width || sh !== height) {
|
520 | alphaBuf = resizeImageMask(alphaBuf, smask.bpc, sw, sh, width, height);
|
521 | }
|
522 | } else if (mask) {
|
523 | if (mask instanceof PDFImage) {
|
524 | sw = mask.width;
|
525 | sh = mask.height;
|
526 | alphaBuf = new Uint8ClampedArray(sw * sh);
|
527 | mask.numComps = 1;
|
528 | mask.fillGrayBuffer(alphaBuf);
|
529 |
|
530 | for (i = 0, ii = sw * sh; i < ii; ++i) {
|
531 | alphaBuf[i] = 255 - alphaBuf[i];
|
532 | }
|
533 |
|
534 | if (sw !== width || sh !== height) {
|
535 | alphaBuf = resizeImageMask(alphaBuf, mask.bpc, sw, sh, width, height);
|
536 | }
|
537 | } else if (Array.isArray(mask)) {
|
538 | alphaBuf = new Uint8ClampedArray(width * height);
|
539 | const numComps = this.numComps;
|
540 |
|
541 | for (i = 0, ii = width * height; i < ii; ++i) {
|
542 | let opacity = 0;
|
543 | const imageOffset = i * numComps;
|
544 |
|
545 | for (j = 0; j < numComps; ++j) {
|
546 | const color = image[imageOffset + j];
|
547 | const maskOffset = j * 2;
|
548 |
|
549 | if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
|
550 | opacity = 255;
|
551 | break;
|
552 | }
|
553 | }
|
554 |
|
555 | alphaBuf[i] = opacity;
|
556 | }
|
557 | } else {
|
558 | throw new _util.FormatError("Unknown mask format.");
|
559 | }
|
560 | }
|
561 |
|
562 | if (alphaBuf) {
|
563 | for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
|
564 | rgbaBuf[j] = alphaBuf[i];
|
565 | }
|
566 | } else {
|
567 | for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
|
568 | rgbaBuf[j] = 255;
|
569 | }
|
570 | }
|
571 | }
|
572 |
|
573 | undoPreblend(buffer, width, height) {
|
574 | const matte = this.smask && this.smask.matte;
|
575 |
|
576 | if (!matte) {
|
577 | return;
|
578 | }
|
579 |
|
580 | const matteRgb = this.colorSpace.getRgb(matte, 0);
|
581 | const matteR = matteRgb[0];
|
582 | const matteG = matteRgb[1];
|
583 | const matteB = matteRgb[2];
|
584 | const length = width * height * 4;
|
585 |
|
586 | for (let i = 0; i < length; i += 4) {
|
587 | const alpha = buffer[i + 3];
|
588 |
|
589 | if (alpha === 0) {
|
590 | buffer[i] = 255;
|
591 | buffer[i + 1] = 255;
|
592 | buffer[i + 2] = 255;
|
593 | continue;
|
594 | }
|
595 |
|
596 | const k = 255 / alpha;
|
597 | buffer[i] = (buffer[i] - matteR) * k + matteR;
|
598 | buffer[i + 1] = (buffer[i + 1] - matteG) * k + matteG;
|
599 | buffer[i + 2] = (buffer[i + 2] - matteB) * k + matteB;
|
600 | }
|
601 | }
|
602 |
|
603 | createImageData(forceRGBA = false) {
|
604 | const drawWidth = this.drawWidth;
|
605 | const drawHeight = this.drawHeight;
|
606 | const imgData = {
|
607 | width: drawWidth,
|
608 | height: drawHeight,
|
609 | interpolate: this.interpolate,
|
610 | kind: 0,
|
611 | data: null
|
612 | };
|
613 | const numComps = this.numComps;
|
614 | const originalWidth = this.width;
|
615 | const originalHeight = this.height;
|
616 | const bpc = this.bpc;
|
617 | const rowBytes = originalWidth * numComps * bpc + 7 >> 3;
|
618 |
|
619 | if (!forceRGBA) {
|
620 | let kind;
|
621 |
|
622 | if (this.colorSpace.name === "DeviceGray" && bpc === 1) {
|
623 | kind = _util.ImageKind.GRAYSCALE_1BPP;
|
624 | } else if (this.colorSpace.name === "DeviceRGB" && bpc === 8 && !this.needsDecode) {
|
625 | kind = _util.ImageKind.RGB_24BPP;
|
626 | }
|
627 |
|
628 | if (kind && !this.smask && !this.mask && drawWidth === originalWidth && drawHeight === originalHeight) {
|
629 | imgData.kind = kind;
|
630 | imgData.data = this.getImageBytes(originalHeight * rowBytes, {});
|
631 |
|
632 | if (this.needsDecode) {
|
633 | (0, _util.assert)(kind === _util.ImageKind.GRAYSCALE_1BPP, "PDFImage.createImageData: The image must be grayscale.");
|
634 | const buffer = imgData.data;
|
635 |
|
636 | for (let i = 0, ii = buffer.length; i < ii; i++) {
|
637 | buffer[i] ^= 0xff;
|
638 | }
|
639 | }
|
640 |
|
641 | return imgData;
|
642 | }
|
643 |
|
644 | if (this.image instanceof _jpeg_stream.JpegStream && !this.smask && !this.mask) {
|
645 | let imageLength = originalHeight * rowBytes;
|
646 |
|
647 | switch (this.colorSpace.name) {
|
648 | case "DeviceGray":
|
649 | imageLength *= 3;
|
650 |
|
651 | case "DeviceRGB":
|
652 | case "DeviceCMYK":
|
653 | imgData.kind = _util.ImageKind.RGB_24BPP;
|
654 | imgData.data = this.getImageBytes(imageLength, {
|
655 | drawWidth,
|
656 | drawHeight,
|
657 | forceRGB: true
|
658 | });
|
659 | return imgData;
|
660 | }
|
661 | }
|
662 | }
|
663 |
|
664 | const imgArray = this.getImageBytes(originalHeight * rowBytes, {
|
665 | internal: true
|
666 | });
|
667 | const actualHeight = 0 | imgArray.length / rowBytes * drawHeight / originalHeight;
|
668 | const comps = this.getComponents(imgArray);
|
669 | let alpha01, maybeUndoPreblend;
|
670 |
|
671 | if (!forceRGBA && !this.smask && !this.mask) {
|
672 | imgData.kind = _util.ImageKind.RGB_24BPP;
|
673 | imgData.data = new Uint8ClampedArray(drawWidth * drawHeight * 3);
|
674 | alpha01 = 0;
|
675 | maybeUndoPreblend = false;
|
676 | } else {
|
677 | imgData.kind = _util.ImageKind.RGBA_32BPP;
|
678 | imgData.data = new Uint8ClampedArray(drawWidth * drawHeight * 4);
|
679 | alpha01 = 1;
|
680 | maybeUndoPreblend = true;
|
681 | this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight, comps);
|
682 | }
|
683 |
|
684 | if (this.needsDecode) {
|
685 | this.decodeBuffer(comps);
|
686 | }
|
687 |
|
688 | this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight, drawWidth, drawHeight, actualHeight, bpc, comps, alpha01);
|
689 |
|
690 | if (maybeUndoPreblend) {
|
691 | this.undoPreblend(imgData.data, drawWidth, actualHeight);
|
692 | }
|
693 |
|
694 | return imgData;
|
695 | }
|
696 |
|
697 | fillGrayBuffer(buffer) {
|
698 | const numComps = this.numComps;
|
699 |
|
700 | if (numComps !== 1) {
|
701 | throw new _util.FormatError(`Reading gray scale from a color image: ${numComps}`);
|
702 | }
|
703 |
|
704 | const width = this.width;
|
705 | const height = this.height;
|
706 | const bpc = this.bpc;
|
707 | const rowBytes = width * numComps * bpc + 7 >> 3;
|
708 | const imgArray = this.getImageBytes(height * rowBytes, {
|
709 | internal: true
|
710 | });
|
711 | const comps = this.getComponents(imgArray);
|
712 | let i, length;
|
713 |
|
714 | if (bpc === 1) {
|
715 | length = width * height;
|
716 |
|
717 | if (this.needsDecode) {
|
718 | for (i = 0; i < length; ++i) {
|
719 | buffer[i] = comps[i] - 1 & 255;
|
720 | }
|
721 | } else {
|
722 | for (i = 0; i < length; ++i) {
|
723 | buffer[i] = -comps[i] & 255;
|
724 | }
|
725 | }
|
726 |
|
727 | return;
|
728 | }
|
729 |
|
730 | if (this.needsDecode) {
|
731 | this.decodeBuffer(comps);
|
732 | }
|
733 |
|
734 | length = width * height;
|
735 | const scale = 255 / ((1 << bpc) - 1);
|
736 |
|
737 | for (i = 0; i < length; ++i) {
|
738 | buffer[i] = scale * comps[i];
|
739 | }
|
740 | }
|
741 |
|
742 | getImageBytes(length, {
|
743 | drawWidth,
|
744 | drawHeight,
|
745 | forceRGB = false,
|
746 | internal = false
|
747 | }) {
|
748 | this.image.reset();
|
749 | this.image.drawWidth = drawWidth || this.width;
|
750 | this.image.drawHeight = drawHeight || this.height;
|
751 | this.image.forceRGB = !!forceRGB;
|
752 | const imageBytes = this.image.getBytes(length);
|
753 |
|
754 | if (internal || this.image instanceof _decode_stream.DecodeStream) {
|
755 | return imageBytes;
|
756 | }
|
757 |
|
758 | (0, _util.assert)(imageBytes instanceof Uint8Array, 'PDFImage.getImageBytes: Unsupported "imageBytes" type.');
|
759 | return new Uint8Array(imageBytes);
|
760 | }
|
761 |
|
762 | }
|
763 |
|
764 | exports.PDFImage = PDFImage; |
\ | No newline at end of file |