1 //========================================================================
2 //
3 // ImageOutputDev.cc
4 //
5 // Copyright 1998-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 //========================================================================
10 //
11 // Modified under the Poppler project - http://poppler.freedesktop.org
12 //
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
15 //
16 // Copyright (C) 2005, 2007, 2011, 2018, 2019, 2021 Albert Astals Cid <aacid@kde.org>
17 // Copyright (C) 2006 Rainer Keller <class321@gmx.de>
18 // Copyright (C) 2008 Timothy Lee <timothy.lee@siriushk.com>
19 // Copyright (C) 2008 Vasile Gaburici <gaburici@cs.umd.edu>
20 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
21 // Copyright (C) 2009 William Bader <williambader@hotmail.com>
22 // Copyright (C) 2010 Jakob Voss <jakob.voss@gbv.de>
23 // Copyright (C) 2012, 2013, 2017, 2018 Adrian Johnson <ajohnson@redneon.com>
24 // Copyright (C) 2013 Thomas Fischer <fischer@unix-ag.uni-kl.de>
25 // Copyright (C) 2013 Hib Eris <hib@hiberis.nl>
26 // Copyright (C) 2017 Caolán McNamara <caolanm@redhat.com>
27 // Copyright (C) 2018 Andreas Gruenbacher <agruenba@redhat.com>
28 // Copyright (C) 2020 mrbax <12640-mrbax@users.noreply.gitlab.freedesktop.org>
29 //
30 // To see a description of the changes please see the Changelog file that
31 // came with your tarball or type make ChangeLog if you are building from git
32 //
33 //========================================================================
34
35 #include "config.h"
36 #include <poppler-config.h>
37
38 #include <cstdio>
39 #include <cstdlib>
40 #include <cstddef>
41 #include <cctype>
42 #include <cmath>
43 #include "goo/gmem.h"
44 #include "goo/NetPBMWriter.h"
45 #include "goo/PNGWriter.h"
46 #include "goo/TiffWriter.h"
47 #include "Error.h"
48 #include "GfxState.h"
49 #include "Object.h"
50 #include "Stream.h"
51 #include "JBIG2Stream.h"
52 #include "ImageOutputDev.h"
53
ImageOutputDev(char * fileRootA,bool pageNamesA,bool listImagesA)54 ImageOutputDev::ImageOutputDev(char *fileRootA, bool pageNamesA, bool listImagesA)
55 {
56 listImages = listImagesA;
57 if (!listImages) {
58 fileRoot = copyString(fileRootA);
59 fileName = (char *)gmalloc(strlen(fileRoot) + 45);
60 }
61 outputPNG = false;
62 outputTiff = false;
63 dumpJPEG = false;
64 dumpJP2 = false;
65 dumpJBIG2 = false;
66 dumpCCITT = false;
67 pageNames = pageNamesA;
68 imgNum = 0;
69 pageNum = 0;
70 ok = true;
71 if (listImages) {
72 printf("page num type width height color comp bpc enc interp object ID x-ppi y-ppi size ratio\n");
73 printf("--------------------------------------------------------------------------------------------\n");
74 }
75 }
76
~ImageOutputDev()77 ImageOutputDev::~ImageOutputDev()
78 {
79 if (!listImages) {
80 gfree(fileName);
81 gfree(fileRoot);
82 }
83 }
84
setFilename(const char * fileExt)85 void ImageOutputDev::setFilename(const char *fileExt)
86 {
87 if (pageNames) {
88 sprintf(fileName, "%s-%03d-%03d.%s", fileRoot, pageNum, imgNum, fileExt);
89 } else {
90 sprintf(fileName, "%s-%03d.%s", fileRoot, imgNum, fileExt);
91 }
92 }
93
94 // Print a floating point number between 0 - 9999 using 4 characters
95 // eg '1.23', '12.3', ' 123', '1234'
96 //
97 // We need to be careful to handle the cases where rounding adds an
98 // extra digit before the decimal. eg printf("%4.2f", 9.99999)
99 // outputs "10.00" instead of "9.99".
printNumber(double d)100 static void printNumber(double d)
101 {
102 char buf[10];
103
104 if (d < 10.0) {
105 sprintf(buf, "%4.2f", d);
106 buf[4] = 0;
107 printf("%s", buf);
108 } else if (d < 100.0) {
109 sprintf(buf, "%4.1f", d);
110 if (!isdigit(buf[3])) {
111 buf[3] = 0;
112 printf(" %s", buf);
113 } else {
114 printf("%s", buf);
115 }
116 } else {
117 printf("%4.0f", d);
118 }
119 }
120
listImage(GfxState * state,Object * ref,Stream * str,int width,int height,GfxImageColorMap * colorMap,bool interpolate,bool inlineImg,ImageType imageType)121 void ImageOutputDev::listImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, bool inlineImg, ImageType imageType)
122 {
123 const char *type;
124 const char *colorspace;
125 const char *enc;
126 int components, bpc;
127
128 printf("%4d %5d ", pageNum, imgNum);
129 type = "";
130 switch (imageType) {
131 case imgImage:
132 type = "image";
133 break;
134 case imgStencil:
135 type = "stencil";
136 break;
137 case imgMask:
138 type = "mask";
139 break;
140 case imgSmask:
141 type = "smask";
142 break;
143 }
144 printf("%-7s %5d %5d ", type, width, height);
145
146 colorspace = "-";
147 /* masks and stencils default to ncomps = 1 and bpc = 1 */
148 components = 1;
149 bpc = 1;
150 if (colorMap && colorMap->isOk()) {
151 switch (colorMap->getColorSpace()->getMode()) {
152 case csDeviceGray:
153 case csCalGray:
154 colorspace = "gray";
155 break;
156 case csDeviceRGB:
157 case csCalRGB:
158 colorspace = "rgb";
159 break;
160 case csDeviceCMYK:
161 colorspace = "cmyk";
162 break;
163 case csLab:
164 colorspace = "lab";
165 break;
166 case csICCBased:
167 colorspace = "icc";
168 break;
169 case csIndexed:
170 colorspace = "index";
171 break;
172 case csSeparation:
173 colorspace = "sep";
174 break;
175 case csDeviceN:
176 colorspace = "devn";
177 break;
178 case csPattern:
179 default:
180 colorspace = "-";
181 break;
182 }
183 components = colorMap->getNumPixelComps();
184 bpc = colorMap->getBits();
185 }
186 printf("%-5s %2d %2d ", colorspace, components, bpc);
187
188 switch (str->getKind()) {
189 case strCCITTFax:
190 enc = "ccitt";
191 break;
192 case strDCT:
193 enc = "jpeg";
194 break;
195 case strJPX:
196 enc = "jpx";
197 break;
198 case strJBIG2:
199 enc = "jbig2";
200 break;
201 case strFile:
202 case strFlate:
203 case strCachedFile:
204 case strASCIIHex:
205 case strASCII85:
206 case strLZW:
207 case strRunLength:
208 case strWeird:
209 default:
210 enc = "image";
211 break;
212 }
213 printf("%-5s ", enc);
214
215 printf("%-3s ", interpolate ? "yes" : "no");
216
217 if (inlineImg) {
218 printf("[inline] ");
219 } else if (ref->isRef()) {
220 const Ref imageRef = ref->getRef();
221 if (imageRef.gen >= 100000) {
222 printf("[none] ");
223 } else {
224 printf(" %6d %2d ", imageRef.num, imageRef.gen);
225 }
226 } else {
227 printf("[none] ");
228 }
229
230 const double *mat = state->getCTM();
231 double width2 = sqrt(mat[0] * mat[0] + mat[1] * mat[1]);
232 double height2 = sqrt(mat[2] * mat[2] + mat[3] * mat[3]);
233 double xppi = fabs(width * 72.0 / width2);
234 double yppi = fabs(height * 72.0 / height2);
235 if (xppi < 1.0)
236 printf("%5.3f ", xppi);
237 else
238 printf("%5.0f ", xppi);
239 if (yppi < 1.0)
240 printf("%5.3f ", yppi);
241 else
242 printf("%5.0f ", yppi);
243
244 Goffset embedSize = -1;
245 if (inlineImg)
246 embedSize = getInlineImageLength(str, width, height, colorMap);
247 else
248 embedSize = str->getBaseStream()->getLength();
249
250 long long imageSize = 0;
251 if (colorMap && colorMap->isOk())
252 imageSize = ((long long)width * height * colorMap->getNumPixelComps() * colorMap->getBits()) / 8;
253 else
254 imageSize = (long long)width * height / 8; // mask
255
256 double ratio = -1.0;
257 if (imageSize > 0)
258 ratio = 100.0 * embedSize / imageSize;
259
260 if (embedSize < 0) {
261 printf(" - ");
262 } else if (embedSize <= 9999) {
263 printf("%4lldB", embedSize);
264 } else {
265 double d = embedSize / 1024.0;
266 if (d <= 9999.0) {
267 printNumber(d);
268 putchar('K');
269 } else {
270 d /= 1024.0;
271 if (d <= 9999.0) {
272 printNumber(d);
273 putchar('M');
274 } else {
275 d /= 1024.0;
276 printNumber(d);
277 putchar('G');
278 }
279 }
280 }
281
282 if (ratio > 9.9)
283 printf(" %3.0f%%\n", ratio);
284 else if (ratio >= 0.0)
285 printf(" %3.1f%%\n", ratio);
286 else
287 printf(" - \n");
288
289 ++imgNum;
290 }
291
getInlineImageLength(Stream * str,int width,int height,GfxImageColorMap * colorMap)292 long ImageOutputDev::getInlineImageLength(Stream *str, int width, int height, GfxImageColorMap *colorMap)
293 {
294 long len;
295
296 if (colorMap) {
297 ImageStream *imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits());
298 imgStr->reset();
299 for (int y = 0; y < height; y++)
300 imgStr->getLine();
301
302 imgStr->close();
303 delete imgStr;
304 } else {
305 str->reset();
306 for (int y = 0; y < height; y++) {
307 int size = (width + 7) / 8;
308 for (int x = 0; x < size; x++)
309 str->getChar();
310 }
311 }
312
313 EmbedStream *embedStr = (EmbedStream *)(str->getBaseStream());
314 embedStr->rewind();
315 len = 0;
316 while (embedStr->getChar() != EOF)
317 len++;
318
319 embedStr->restore();
320
321 return len;
322 }
323
writeRawImage(Stream * str,const char * ext)324 void ImageOutputDev::writeRawImage(Stream *str, const char *ext)
325 {
326 FILE *f;
327 int c;
328
329 // open the image file
330 setFilename(ext);
331 ++imgNum;
332 if (!(f = fopen(fileName, "wb"))) {
333 error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
334 return;
335 }
336
337 // initialize stream
338 str = str->getNextStream();
339 str->reset();
340
341 // copy the stream
342 while ((c = str->getChar()) != EOF)
343 fputc(c, f);
344
345 str->close();
346 fclose(f);
347 }
348
writeImageFile(ImgWriter * writer,ImageFormat format,const char * ext,Stream * str,int width,int height,GfxImageColorMap * colorMap)349 void ImageOutputDev::writeImageFile(ImgWriter *writer, ImageFormat format, const char *ext, Stream *str, int width, int height, GfxImageColorMap *colorMap)
350 {
351 FILE *f = nullptr; /* squelch bogus compiler warning */
352 ImageStream *imgStr = nullptr;
353 unsigned char *row;
354 unsigned char *rowp;
355 unsigned char *p;
356 GfxRGB rgb;
357 GfxCMYK cmyk;
358 GfxGray gray;
359 unsigned char zero[gfxColorMaxComps];
360 int invert_bits;
361
362 if (writer) {
363 setFilename(ext);
364 ++imgNum;
365 if (!(f = fopen(fileName, "wb"))) {
366 error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
367 return;
368 }
369
370 if (!writer->init(f, width, height, 72, 72)) {
371 error(errIO, -1, "Error writing '{0:s}'", fileName);
372 return;
373 }
374 }
375
376 int pixelSize = sizeof(unsigned int);
377 if (format == imgRGB48)
378 pixelSize = 2 * sizeof(unsigned int);
379
380 row = (unsigned char *)gmallocn_checkoverflow(width, pixelSize);
381 if (!row) {
382 error(errIO, -1, "Image data for '{0:s}' is too big. {1:d} width with {2:d} bytes per pixel", fileName, width, pixelSize);
383 return;
384 }
385
386 if (format != imgMonochrome) {
387 // initialize stream
388 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits());
389 imgStr->reset();
390 } else {
391 // initialize stream
392 str->reset();
393 }
394
395 // PDF masks use 0 = draw current color, 1 = leave unchanged.
396 // We invert this to provide the standard interpretation of alpha
397 // (0 = transparent, 1 = opaque). If the colorMap already inverts
398 // the mask we leave the data unchanged.
399 invert_bits = 0xff;
400 if (colorMap) {
401 memset(zero, 0, sizeof(zero));
402 colorMap->getGray(zero, &gray);
403 if (colToByte(gray) == 0)
404 invert_bits = 0x00;
405 }
406
407 // for each line...
408 for (int y = 0; y < height; y++) {
409 switch (format) {
410 case imgRGB:
411 p = imgStr->getLine();
412 rowp = row;
413 for (int x = 0; x < width; ++x) {
414 if (p) {
415 colorMap->getRGB(p, &rgb);
416 *rowp++ = colToByte(rgb.r);
417 *rowp++ = colToByte(rgb.g);
418 *rowp++ = colToByte(rgb.b);
419 p += colorMap->getNumPixelComps();
420 } else {
421 *rowp++ = 0;
422 *rowp++ = 0;
423 *rowp++ = 0;
424 }
425 }
426 if (writer)
427 writer->writeRow(&row);
428 break;
429
430 case imgRGB48: {
431 p = imgStr->getLine();
432 unsigned short *rowp16 = reinterpret_cast<unsigned short *>(row);
433 for (int x = 0; x < width; ++x) {
434 if (p) {
435 colorMap->getRGB(p, &rgb);
436 *rowp16++ = colToShort(rgb.r);
437 *rowp16++ = colToShort(rgb.g);
438 *rowp16++ = colToShort(rgb.b);
439 p += colorMap->getNumPixelComps();
440 } else {
441 *rowp16++ = 0;
442 *rowp16++ = 0;
443 *rowp16++ = 0;
444 }
445 }
446 if (writer)
447 writer->writeRow(&row);
448 break;
449 }
450
451 case imgCMYK:
452 p = imgStr->getLine();
453 rowp = row;
454 for (int x = 0; x < width; ++x) {
455 if (p) {
456 colorMap->getCMYK(p, &cmyk);
457 *rowp++ = colToByte(cmyk.c);
458 *rowp++ = colToByte(cmyk.m);
459 *rowp++ = colToByte(cmyk.y);
460 *rowp++ = colToByte(cmyk.k);
461 p += colorMap->getNumPixelComps();
462 } else {
463 *rowp++ = 0;
464 *rowp++ = 0;
465 *rowp++ = 0;
466 *rowp++ = 0;
467 }
468 }
469 if (writer)
470 writer->writeRow(&row);
471 break;
472
473 case imgGray:
474 p = imgStr->getLine();
475 rowp = row;
476 for (int x = 0; x < width; ++x) {
477 if (p) {
478 colorMap->getGray(p, &gray);
479 *rowp++ = colToByte(gray);
480 p += colorMap->getNumPixelComps();
481 } else {
482 *rowp++ = 0;
483 }
484 }
485 if (writer)
486 writer->writeRow(&row);
487 break;
488
489 case imgMonochrome:
490 int size = (width + 7) / 8;
491 for (int x = 0; x < size; x++)
492 row[x] = str->getChar() ^ invert_bits;
493 if (writer)
494 writer->writeRow(&row);
495 break;
496 }
497 }
498
499 gfree(row);
500 if (format != imgMonochrome) {
501 imgStr->close();
502 delete imgStr;
503 }
504 str->close();
505 if (writer) {
506 writer->close();
507 fclose(f);
508 }
509 }
510
writeImage(GfxState * state,Object * ref,Stream * str,int width,int height,GfxImageColorMap * colorMap,bool inlineImg)511 void ImageOutputDev::writeImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool inlineImg)
512 {
513 ImageFormat format;
514 EmbedStream *embedStr;
515
516 if (inlineImg) {
517 embedStr = (EmbedStream *)(str->getBaseStream());
518 // Record the stream. This determines the size.
519 getInlineImageLength(str, width, height, colorMap);
520 // Reading the stream again will return EOF at end of recording.
521 embedStr->rewind();
522 }
523
524 if (dumpJPEG && str->getKind() == strDCT) {
525 // dump JPEG file
526 writeRawImage(str, "jpg");
527
528 } else if (dumpJP2 && str->getKind() == strJPX && !inlineImg) {
529 // dump JPEG2000 file
530 writeRawImage(str, "jp2");
531
532 } else if (dumpJBIG2 && str->getKind() == strJBIG2 && !inlineImg) {
533 // dump JBIG2 globals stream if available
534 JBIG2Stream *jb2Str = static_cast<JBIG2Stream *>(str);
535 Object *globals = jb2Str->getGlobalsStream();
536 if (globals->isStream()) {
537 FILE *f;
538 int c;
539 Stream *globalsStr = globals->getStream();
540
541 setFilename("jb2g");
542 if (!(f = fopen(fileName, "wb"))) {
543 error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
544 return;
545 }
546 globalsStr->reset();
547 while ((c = globalsStr->getChar()) != EOF)
548 fputc(c, f);
549 globalsStr->close();
550 fclose(f);
551 }
552
553 // dump JBIG2 embedded file
554 writeRawImage(str, "jb2e");
555
556 } else if (dumpCCITT && str->getKind() == strCCITTFax) {
557 // write CCITT parameters
558 CCITTFaxStream *ccittStr = static_cast<CCITTFaxStream *>(str);
559 FILE *f;
560 setFilename("params");
561 if (!(f = fopen(fileName, "wb"))) {
562 error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
563 return;
564 }
565 if (ccittStr->getEncoding() < 0)
566 fprintf(f, "-4 ");
567 else if (ccittStr->getEncoding() == 0)
568 fprintf(f, "-1 ");
569 else
570 fprintf(f, "-2 ");
571
572 if (ccittStr->getEndOfLine())
573 fprintf(f, "-A ");
574 else
575 fprintf(f, "-P ");
576
577 fprintf(f, "-X %d ", ccittStr->getColumns());
578
579 if (ccittStr->getBlackIs1())
580 fprintf(f, "-W ");
581 else
582 fprintf(f, "-B ");
583
584 fprintf(f, "-M\n"); // PDF uses MSB first
585
586 fclose(f);
587
588 // dump CCITT file
589 writeRawImage(str, "ccitt");
590
591 } else if (outputPNG && !(outputTiff && colorMap && (colorMap->getColorSpace()->getMode() == csDeviceCMYK || (colorMap->getColorSpace()->getMode() == csICCBased && colorMap->getNumPixelComps() == 4)))) {
592 // output in PNG format
593
594 #ifdef ENABLE_LIBPNG
595 ImgWriter *writer;
596
597 if (!colorMap || (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1)) {
598 writer = new PNGWriter(PNGWriter::MONOCHROME);
599 format = imgMonochrome;
600 } else if (colorMap->getColorSpace()->getMode() == csDeviceGray || colorMap->getColorSpace()->getMode() == csCalGray) {
601 writer = new PNGWriter(PNGWriter::GRAY);
602 format = imgGray;
603 } else if ((colorMap->getColorSpace()->getMode() == csDeviceRGB || colorMap->getColorSpace()->getMode() == csCalRGB || (colorMap->getColorSpace()->getMode() == csICCBased && colorMap->getNumPixelComps() == 3))
604 && colorMap->getBits() > 8) {
605 writer = new PNGWriter(PNGWriter::RGB48);
606 format = imgRGB48;
607 } else {
608 writer = new PNGWriter(PNGWriter::RGB);
609 format = imgRGB;
610 }
611
612 writeImageFile(writer, format, "png", str, width, height, colorMap);
613
614 delete writer;
615 #endif
616 } else if (outputTiff) {
617 // output in TIFF format
618
619 #ifdef ENABLE_LIBTIFF
620 ImgWriter *writer;
621
622 if (!colorMap || (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1)) {
623 writer = new TiffWriter(TiffWriter::MONOCHROME);
624 format = imgMonochrome;
625 } else if (colorMap->getColorSpace()->getMode() == csDeviceGray || colorMap->getColorSpace()->getMode() == csCalGray) {
626 writer = new TiffWriter(TiffWriter::GRAY);
627 format = imgGray;
628 } else if (colorMap->getColorSpace()->getMode() == csDeviceCMYK || (colorMap->getColorSpace()->getMode() == csICCBased && colorMap->getNumPixelComps() == 4)) {
629 writer = new TiffWriter(TiffWriter::CMYK);
630 format = imgCMYK;
631 } else if ((colorMap->getColorSpace()->getMode() == csDeviceRGB || colorMap->getColorSpace()->getMode() == csCalRGB || (colorMap->getColorSpace()->getMode() == csICCBased && colorMap->getNumPixelComps() == 3))
632 && colorMap->getBits() > 8) {
633 writer = new TiffWriter(TiffWriter::RGB48);
634 format = imgRGB48;
635 } else {
636 writer = new TiffWriter(TiffWriter::RGB);
637 format = imgRGB;
638 }
639
640 writeImageFile(writer, format, "tif", str, width, height, colorMap);
641
642 delete writer;
643 #endif
644 } else {
645 // output in PPM/PBM format
646 ImgWriter *writer;
647
648 if (!colorMap || (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1)) {
649 writer = new NetPBMWriter(NetPBMWriter::MONOCHROME);
650 format = imgMonochrome;
651 } else {
652 writer = new NetPBMWriter(NetPBMWriter::RGB);
653 format = imgRGB;
654 }
655
656 writeImageFile(writer, format, format == imgRGB ? "ppm" : "pbm", str, width, height, colorMap);
657
658 delete writer;
659 }
660
661 if (inlineImg)
662 embedStr->restore();
663 }
664
tilingPatternFill(GfxState * state,Gfx * gfx,Catalog * cat,GfxTilingPattern * tPat,const double * mat,int x0,int y0,int x1,int y1,double xStep,double yStep)665 bool ImageOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, GfxTilingPattern *tPat, const double *mat, int x0, int y0, int x1, int y1, double xStep, double yStep)
666 {
667 return true;
668 // do nothing -- this avoids the potentially slow loop in Gfx.cc
669 }
670
drawImageMask(GfxState * state,Object * ref,Stream * str,int width,int height,bool invert,bool interpolate,bool inlineImg)671 void ImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg)
672 {
673 if (listImages)
674 listImage(state, ref, str, width, height, nullptr, interpolate, inlineImg, imgStencil);
675 else
676 writeImage(state, ref, str, width, height, nullptr, inlineImg);
677 }
678
drawImage(GfxState * state,Object * ref,Stream * str,int width,int height,GfxImageColorMap * colorMap,bool interpolate,const int * maskColors,bool inlineImg)679 void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg)
680 {
681 if (listImages)
682 listImage(state, ref, str, width, height, colorMap, interpolate, inlineImg, imgImage);
683 else
684 writeImage(state, ref, str, width, height, colorMap, inlineImg);
685 }
686
drawMaskedImage(GfxState * state,Object * ref,Stream * str,int width,int height,GfxImageColorMap * colorMap,bool interpolate,Stream * maskStr,int maskWidth,int maskHeight,bool maskInvert,bool maskInterpolate)687 void ImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, bool maskInvert, bool maskInterpolate)
688 {
689 if (listImages) {
690 listImage(state, ref, str, width, height, colorMap, interpolate, false, imgImage);
691 listImage(state, ref, str, maskWidth, maskHeight, nullptr, maskInterpolate, false, imgMask);
692 } else {
693 writeImage(state, ref, str, width, height, colorMap, false);
694 writeImage(state, ref, maskStr, maskWidth, maskHeight, nullptr, false);
695 }
696 }
697
drawSoftMaskedImage(GfxState * state,Object * ref,Stream * str,int width,int height,GfxImageColorMap * colorMap,bool interpolate,Stream * maskStr,int maskWidth,int maskHeight,GfxImageColorMap * maskColorMap,bool maskInterpolate)698 void ImageOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap,
699 bool maskInterpolate)
700 {
701 if (listImages) {
702 listImage(state, ref, str, width, height, colorMap, interpolate, false, imgImage);
703 listImage(state, ref, maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate, false, imgSmask);
704 } else {
705 writeImage(state, ref, str, width, height, colorMap, false);
706 writeImage(state, ref, maskStr, maskWidth, maskHeight, maskColorMap, false);
707 }
708 }
709