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