Spaces:
Running
Running
| //======================================================================== | |
| // | |
| // ImageOutputDev.cc | |
| // | |
| // Copyright 1998-2003 Glyph & Cog, LLC | |
| // | |
| //======================================================================== | |
| //======================================================================== | |
| // | |
| // Modified under the Poppler project - http://poppler.freedesktop.org | |
| // | |
| // All changes made under the Poppler project to this file are licensed | |
| // under GPL version 2 or later | |
| // | |
| // Copyright (C) 2005, 2007, 2011, 2018, 2019, 2021, 2022 Albert Astals Cid <aacid@kde.org> | |
| // Copyright (C) 2006 Rainer Keller <class321@gmx.de> | |
| // Copyright (C) 2008 Timothy Lee <timothy.lee@siriushk.com> | |
| // Copyright (C) 2008 Vasile Gaburici <gaburici@cs.umd.edu> | |
| // Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org> | |
| // Copyright (C) 2009 William Bader <williambader@hotmail.com> | |
| // Copyright (C) 2010 Jakob Voss <jakob.voss@gbv.de> | |
| // Copyright (C) 2012, 2013, 2017, 2018 Adrian Johnson <ajohnson@redneon.com> | |
| // Copyright (C) 2013 Thomas Fischer <fischer@unix-ag.uni-kl.de> | |
| // Copyright (C) 2013 Hib Eris <hib@hiberis.nl> | |
| // Copyright (C) 2017 Caolán McNamara <caolanm@redhat.com> | |
| // Copyright (C) 2018 Andreas Gruenbacher <agruenba@redhat.com> | |
| // Copyright (C) 2020 mrbax <12640-mrbax@users.noreply.gitlab.freedesktop.org> | |
| // Copyright (C) 2024 Fernando Herrera <fherrera@onirica.com> | |
| // Copyright (C) 2024 Sebastian J. Bronner <waschtl@sbronner.com> | |
| // | |
| // To see a description of the changes please see the Changelog file that | |
| // came with your tarball or type make ChangeLog if you are building from git | |
| // | |
| //======================================================================== | |
| ImageOutputDev::ImageOutputDev(char *fileRootA, bool pageNamesA, bool listImagesA) | |
| { | |
| listImages = listImagesA; | |
| if (!listImages) { | |
| fileRoot = copyString(fileRootA); | |
| fileName = (char *)gmalloc(strlen(fileRoot) + 45); | |
| } | |
| outputPNG = false; | |
| outputTiff = false; | |
| dumpJPEG = false; | |
| dumpJP2 = false; | |
| dumpJBIG2 = false; | |
| dumpCCITT = false; | |
| pageNames = pageNamesA; | |
| printFilenames = false; | |
| imgNum = 0; | |
| pageNum = 0; | |
| errorCode = 0; | |
| if (listImages) { | |
| printf("page num type width height color comp bpc enc interp object ID x-ppi y-ppi size ratio\n"); | |
| printf("--------------------------------------------------------------------------------------------\n"); | |
| } | |
| } | |
| ImageOutputDev::~ImageOutputDev() | |
| { | |
| if (!listImages) { | |
| gfree(fileName); | |
| gfree(fileRoot); | |
| } | |
| } | |
| void ImageOutputDev::setFilename(const char *fileExt) | |
| { | |
| if (pageNames) { | |
| sprintf(fileName, "%s-%03d-%03d.%s", fileRoot, pageNum, imgNum, fileExt); | |
| } else { | |
| sprintf(fileName, "%s-%03d.%s", fileRoot, imgNum, fileExt); | |
| } | |
| } | |
| // Print a floating point number between 0 - 9999 using 4 characters | |
| // eg '1.23', '12.3', ' 123', '1234' | |
| // | |
| // We need to be careful to handle the cases where rounding adds an | |
| // extra digit before the decimal. eg printf("%4.2f", 9.99999) | |
| // outputs "10.00" instead of "9.99". | |
| static void printNumber(double d) | |
| { | |
| char buf[10]; | |
| if (d < 10.0) { | |
| sprintf(buf, "%4.2f", d); | |
| buf[4] = 0; | |
| printf("%s", buf); | |
| } else if (d < 100.0) { | |
| sprintf(buf, "%4.1f", d); | |
| if (!isdigit(buf[3])) { | |
| buf[3] = 0; | |
| printf(" %s", buf); | |
| } else { | |
| printf("%s", buf); | |
| } | |
| } else { | |
| printf("%4.0f", d); | |
| } | |
| } | |
| void ImageOutputDev::listImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, bool inlineImg, ImageType imageType) | |
| { | |
| const char *type; | |
| const char *colorspace; | |
| const char *enc; | |
| int components, bpc; | |
| printf("%4d %5d ", pageNum, imgNum); | |
| type = ""; | |
| switch (imageType) { | |
| case imgImage: | |
| type = "image"; | |
| break; | |
| case imgStencil: | |
| type = "stencil"; | |
| break; | |
| case imgMask: | |
| type = "mask"; | |
| break; | |
| case imgSmask: | |
| type = "smask"; | |
| break; | |
| } | |
| printf("%-7s %5d %5d ", type, width, height); | |
| colorspace = "-"; | |
| /* masks and stencils default to ncomps = 1 and bpc = 1 */ | |
| components = 1; | |
| bpc = 1; | |
| if (colorMap && colorMap->isOk()) { | |
| switch (colorMap->getColorSpace()->getMode()) { | |
| case csDeviceGray: | |
| case csCalGray: | |
| colorspace = "gray"; | |
| break; | |
| case csDeviceRGB: | |
| case csCalRGB: | |
| colorspace = "rgb"; | |
| break; | |
| case csDeviceCMYK: | |
| colorspace = "cmyk"; | |
| break; | |
| case csLab: | |
| colorspace = "lab"; | |
| break; | |
| case csICCBased: | |
| colorspace = "icc"; | |
| break; | |
| case csIndexed: | |
| colorspace = "index"; | |
| break; | |
| case csSeparation: | |
| colorspace = "sep"; | |
| break; | |
| case csDeviceN: | |
| colorspace = "devn"; | |
| break; | |
| case csPattern: | |
| default: | |
| colorspace = "-"; | |
| break; | |
| } | |
| components = colorMap->getNumPixelComps(); | |
| bpc = colorMap->getBits(); | |
| } | |
| printf("%-5s %2d %2d ", colorspace, components, bpc); | |
| switch (str->getKind()) { | |
| case strCCITTFax: | |
| enc = "ccitt"; | |
| break; | |
| case strDCT: | |
| enc = "jpeg"; | |
| break; | |
| case strJPX: | |
| enc = "jpx"; | |
| break; | |
| case strJBIG2: | |
| enc = "jbig2"; | |
| break; | |
| case strFile: | |
| case strFlate: | |
| case strCachedFile: | |
| case strASCIIHex: | |
| case strASCII85: | |
| case strLZW: | |
| case strRunLength: | |
| case strWeird: | |
| default: | |
| enc = "image"; | |
| break; | |
| } | |
| printf("%-5s ", enc); | |
| printf("%-3s ", interpolate ? "yes" : "no"); | |
| if (inlineImg) { | |
| printf("[inline] "); | |
| } else if (ref->isRef()) { | |
| const Ref imageRef = ref->getRef(); | |
| if (imageRef.gen >= 100000) { | |
| printf("[none] "); | |
| } else { | |
| printf(" %6d %2d ", imageRef.num, imageRef.gen); | |
| } | |
| } else { | |
| printf("[none] "); | |
| } | |
| const double *mat = state->getCTM(); | |
| double width2 = sqrt(mat[0] * mat[0] + mat[1] * mat[1]); | |
| double height2 = sqrt(mat[2] * mat[2] + mat[3] * mat[3]); | |
| double xppi = fabs(width * 72.0 / width2); | |
| double yppi = fabs(height * 72.0 / height2); | |
| if (xppi < 1.0) { | |
| printf("%5.3f ", xppi); | |
| } else { | |
| printf("%5.0f ", xppi); | |
| } | |
| if (yppi < 1.0) { | |
| printf("%5.3f ", yppi); | |
| } else { | |
| printf("%5.0f ", yppi); | |
| } | |
| Goffset embedSize = -1; | |
| if (inlineImg) { | |
| embedSize = getInlineImageLength(str, width, height, colorMap); | |
| } else { | |
| embedSize = str->getBaseStream()->getLength(); | |
| } | |
| long long imageSize = 0; | |
| if (colorMap && colorMap->isOk()) { | |
| imageSize = ((long long)width * height * colorMap->getNumPixelComps() * colorMap->getBits()) / 8; | |
| } else { | |
| imageSize = (long long)width * height / 8; // mask | |
| } | |
| double ratio = -1.0; | |
| if (imageSize > 0) { | |
| ratio = 100.0 * embedSize / imageSize; | |
| } | |
| if (embedSize < 0) { | |
| printf(" - "); | |
| } else if (embedSize <= 9999) { | |
| printf("%4lldB", embedSize); | |
| } else { | |
| double d = embedSize / 1024.0; | |
| if (d <= 9999.0) { | |
| printNumber(d); | |
| putchar('K'); | |
| } else { | |
| d /= 1024.0; | |
| if (d <= 9999.0) { | |
| printNumber(d); | |
| putchar('M'); | |
| } else { | |
| d /= 1024.0; | |
| printNumber(d); | |
| putchar('G'); | |
| } | |
| } | |
| } | |
| if (ratio > 9.9) { | |
| printf(" %3.0f%%\n", ratio); | |
| } else if (ratio >= 0.0) { | |
| printf(" %3.1f%%\n", ratio); | |
| } else { | |
| printf(" - \n"); | |
| } | |
| ++imgNum; | |
| } | |
| long ImageOutputDev::getInlineImageLength(Stream *str, int width, int height, GfxImageColorMap *colorMap) | |
| { | |
| long len; | |
| if (colorMap) { | |
| ImageStream *imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); | |
| imgStr->reset(); | |
| for (int y = 0; y < height; y++) { | |
| imgStr->getLine(); | |
| } | |
| imgStr->close(); | |
| delete imgStr; | |
| } else { | |
| str->reset(); | |
| for (int y = 0; y < height; y++) { | |
| int size = (width + 7) / 8; | |
| for (int x = 0; x < size; x++) { | |
| str->getChar(); | |
| } | |
| } | |
| } | |
| EmbedStream *embedStr = (EmbedStream *)(str->getBaseStream()); | |
| embedStr->rewind(); | |
| len = 0; | |
| while (embedStr->getChar() != EOF) { | |
| len++; | |
| } | |
| embedStr->restore(); | |
| return len; | |
| } | |
| void ImageOutputDev::writeRawImage(Stream *str, const char *ext) | |
| { | |
| FILE *f; | |
| int c; | |
| // open the image file | |
| setFilename(ext); | |
| ++imgNum; | |
| if (!(f = fopen(fileName, "wb"))) { | |
| error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); | |
| errorCode = 2; | |
| return; | |
| } | |
| // initialize stream | |
| str = str->getNextStream(); | |
| str->reset(); | |
| // copy the stream | |
| while ((c = str->getChar()) != EOF) { | |
| fputc(c, f); | |
| } | |
| str->close(); | |
| fclose(f); | |
| } | |
| void ImageOutputDev::writeImageFile(ImgWriter *writer, ImageFormat format, const char *ext, Stream *str, int width, int height, GfxImageColorMap *colorMap) | |
| { | |
| FILE *f = nullptr; /* squelch bogus compiler warning */ | |
| ImageStream *imgStr = nullptr; | |
| unsigned char *row; | |
| unsigned char *rowp; | |
| unsigned char *p; | |
| GfxRGB rgb; | |
| GfxCMYK cmyk; | |
| GfxGray gray; | |
| unsigned char zero[gfxColorMaxComps]; | |
| int invert_bits; | |
| if (writer) { | |
| setFilename(ext); | |
| ++imgNum; | |
| if (!(f = fopen(fileName, "wb"))) { | |
| error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); | |
| errorCode = 2; | |
| return; | |
| } | |
| if (!writer->init(f, width, height, 72, 72)) { | |
| error(errIO, -1, "Error writing '{0:s}'", fileName); | |
| errorCode = 2; | |
| return; | |
| } | |
| } | |
| int pixelSize = sizeof(unsigned int); | |
| if (format == imgRGB48) { | |
| pixelSize = 2 * sizeof(unsigned int); | |
| } | |
| row = (unsigned char *)gmallocn_checkoverflow(width, pixelSize); | |
| if (!row) { | |
| error(errIO, -1, "Image data for '{0:s}' is too big. {1:d} width with {2:d} bytes per pixel", fileName, width, pixelSize); | |
| errorCode = 99; | |
| return; | |
| } | |
| if (format != imgMonochrome) { | |
| // initialize stream | |
| imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); | |
| imgStr->reset(); | |
| } else { | |
| // initialize stream | |
| str->reset(); | |
| } | |
| // PDF masks use 0 = draw current color, 1 = leave unchanged. | |
| // We invert this to provide the standard interpretation of alpha | |
| // (0 = transparent, 1 = opaque). If the colorMap already inverts | |
| // the mask we leave the data unchanged. | |
| invert_bits = 0xff; | |
| if (colorMap) { | |
| memset(zero, 0, sizeof(zero)); | |
| colorMap->getGray(zero, &gray); | |
| if (colToByte(gray) == 0) { | |
| invert_bits = 0x00; | |
| } | |
| } | |
| // for each line... | |
| for (int y = 0; y < height; y++) { | |
| switch (format) { | |
| case imgRGB: | |
| p = imgStr->getLine(); | |
| rowp = row; | |
| for (int x = 0; x < width; ++x) { | |
| if (p) { | |
| colorMap->getRGB(p, &rgb); | |
| *rowp++ = colToByte(rgb.r); | |
| *rowp++ = colToByte(rgb.g); | |
| *rowp++ = colToByte(rgb.b); | |
| p += colorMap->getNumPixelComps(); | |
| } else { | |
| *rowp++ = 0; | |
| *rowp++ = 0; | |
| *rowp++ = 0; | |
| } | |
| } | |
| if (writer) { | |
| writer->writeRow(&row); | |
| } | |
| break; | |
| case imgRGB48: { | |
| p = imgStr->getLine(); | |
| unsigned short *rowp16 = reinterpret_cast<unsigned short *>(row); | |
| for (int x = 0; x < width; ++x) { | |
| if (p) { | |
| colorMap->getRGB(p, &rgb); | |
| *rowp16++ = colToShort(rgb.r); | |
| *rowp16++ = colToShort(rgb.g); | |
| *rowp16++ = colToShort(rgb.b); | |
| p += colorMap->getNumPixelComps(); | |
| } else { | |
| *rowp16++ = 0; | |
| *rowp16++ = 0; | |
| *rowp16++ = 0; | |
| } | |
| } | |
| if (writer) { | |
| writer->writeRow(&row); | |
| } | |
| break; | |
| } | |
| case imgCMYK: | |
| p = imgStr->getLine(); | |
| rowp = row; | |
| for (int x = 0; x < width; ++x) { | |
| if (p) { | |
| colorMap->getCMYK(p, &cmyk); | |
| *rowp++ = colToByte(cmyk.c); | |
| *rowp++ = colToByte(cmyk.m); | |
| *rowp++ = colToByte(cmyk.y); | |
| *rowp++ = colToByte(cmyk.k); | |
| p += colorMap->getNumPixelComps(); | |
| } else { | |
| *rowp++ = 0; | |
| *rowp++ = 0; | |
| *rowp++ = 0; | |
| *rowp++ = 0; | |
| } | |
| } | |
| if (writer) { | |
| writer->writeRow(&row); | |
| } | |
| break; | |
| case imgGray: | |
| p = imgStr->getLine(); | |
| rowp = row; | |
| for (int x = 0; x < width; ++x) { | |
| if (p) { | |
| colorMap->getGray(p, &gray); | |
| *rowp++ = colToByte(gray); | |
| p += colorMap->getNumPixelComps(); | |
| } else { | |
| *rowp++ = 0; | |
| } | |
| } | |
| if (writer) { | |
| writer->writeRow(&row); | |
| } | |
| break; | |
| case imgMonochrome: | |
| int size = (width + 7) / 8; | |
| for (int x = 0; x < size; x++) { | |
| row[x] = str->getChar() ^ invert_bits; | |
| } | |
| if (writer) { | |
| writer->writeRow(&row); | |
| } | |
| break; | |
| } | |
| } | |
| gfree(row); | |
| if (format != imgMonochrome) { | |
| imgStr->close(); | |
| delete imgStr; | |
| } | |
| str->close(); | |
| if (writer) { | |
| writer->close(); | |
| fclose(f); | |
| } | |
| } | |
| void ImageOutputDev::writeImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool inlineImg) | |
| { | |
| ImageFormat format; | |
| EmbedStream *embedStr; | |
| if (inlineImg) { | |
| embedStr = (EmbedStream *)(str->getBaseStream()); | |
| // Record the stream. This determines the size. | |
| getInlineImageLength(str, width, height, colorMap); | |
| // Reading the stream again will return EOF at end of recording. | |
| embedStr->rewind(); | |
| } | |
| if (dumpJPEG && str->getKind() == strDCT) { | |
| // dump JPEG file | |
| writeRawImage(str, "jpg"); | |
| } else if (dumpJP2 && str->getKind() == strJPX && !inlineImg) { | |
| // dump JPEG2000 file | |
| writeRawImage(str, "jp2"); | |
| } else if (dumpJBIG2 && str->getKind() == strJBIG2 && !inlineImg) { | |
| // dump JBIG2 globals stream if available | |
| JBIG2Stream *jb2Str = static_cast<JBIG2Stream *>(str); | |
| Object *globals = jb2Str->getGlobalsStream(); | |
| if (globals->isStream()) { | |
| FILE *f; | |
| int c; | |
| Stream *globalsStr = globals->getStream(); | |
| setFilename("jb2g"); | |
| if (!(f = fopen(fileName, "wb"))) { | |
| error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); | |
| errorCode = 2; | |
| return; | |
| } | |
| globalsStr->reset(); | |
| while ((c = globalsStr->getChar()) != EOF) { | |
| fputc(c, f); | |
| } | |
| globalsStr->close(); | |
| fclose(f); | |
| } | |
| // dump JBIG2 embedded file | |
| writeRawImage(str, "jb2e"); | |
| } else if (dumpCCITT && str->getKind() == strCCITTFax) { | |
| // write CCITT parameters | |
| CCITTFaxStream *ccittStr = static_cast<CCITTFaxStream *>(str); | |
| FILE *f; | |
| setFilename("params"); | |
| if (!(f = fopen(fileName, "wb"))) { | |
| error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); | |
| errorCode = 2; | |
| return; | |
| } | |
| if (ccittStr->getEncoding() < 0) { | |
| fprintf(f, "-4 "); | |
| } else if (ccittStr->getEncoding() == 0) { | |
| fprintf(f, "-1 "); | |
| } else { | |
| fprintf(f, "-2 "); | |
| } | |
| if (ccittStr->getEndOfLine()) { | |
| fprintf(f, "-A "); | |
| } else { | |
| fprintf(f, "-P "); | |
| } | |
| fprintf(f, "-X %d ", ccittStr->getColumns()); | |
| if (ccittStr->getBlackIs1()) { | |
| fprintf(f, "-W "); | |
| } else { | |
| fprintf(f, "-B "); | |
| } | |
| fprintf(f, "-M\n"); // PDF uses MSB first | |
| fclose(f); | |
| // dump CCITT file | |
| writeRawImage(str, "ccitt"); | |
| } else if (outputPNG && !(outputTiff && colorMap && (colorMap->getColorSpace()->getMode() == csDeviceCMYK || (colorMap->getColorSpace()->getMode() == csICCBased && colorMap->getNumPixelComps() == 4)))) { | |
| // output in PNG format | |
| ImgWriter *writer; | |
| if (!colorMap || (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1)) { | |
| writer = new PNGWriter(PNGWriter::MONOCHROME); | |
| format = imgMonochrome; | |
| } else if (colorMap->getColorSpace()->getMode() == csDeviceGray || colorMap->getColorSpace()->getMode() == csCalGray) { | |
| writer = new PNGWriter(PNGWriter::GRAY); | |
| format = imgGray; | |
| } else if ((colorMap->getColorSpace()->getMode() == csDeviceRGB || colorMap->getColorSpace()->getMode() == csCalRGB || (colorMap->getColorSpace()->getMode() == csICCBased && colorMap->getNumPixelComps() == 3)) | |
| && colorMap->getBits() > 8) { | |
| writer = new PNGWriter(PNGWriter::RGB48); | |
| format = imgRGB48; | |
| } else { | |
| writer = new PNGWriter(PNGWriter::RGB); | |
| format = imgRGB; | |
| } | |
| writeImageFile(writer, format, "png", str, width, height, colorMap); | |
| delete writer; | |
| } else if (outputTiff) { | |
| // output in TIFF format | |
| ImgWriter *writer; | |
| if (!colorMap || (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1)) { | |
| writer = new TiffWriter(TiffWriter::MONOCHROME); | |
| format = imgMonochrome; | |
| } else if (colorMap->getColorSpace()->getMode() == csDeviceGray || colorMap->getColorSpace()->getMode() == csCalGray) { | |
| writer = new TiffWriter(TiffWriter::GRAY); | |
| format = imgGray; | |
| } else if (colorMap->getColorSpace()->getMode() == csDeviceCMYK || (colorMap->getColorSpace()->getMode() == csICCBased && colorMap->getNumPixelComps() == 4)) { | |
| writer = new TiffWriter(TiffWriter::CMYK); | |
| format = imgCMYK; | |
| } else if ((colorMap->getColorSpace()->getMode() == csDeviceRGB || colorMap->getColorSpace()->getMode() == csCalRGB || (colorMap->getColorSpace()->getMode() == csICCBased && colorMap->getNumPixelComps() == 3)) | |
| && colorMap->getBits() > 8) { | |
| writer = new TiffWriter(TiffWriter::RGB48); | |
| format = imgRGB48; | |
| } else { | |
| writer = new TiffWriter(TiffWriter::RGB); | |
| format = imgRGB; | |
| } | |
| writeImageFile(writer, format, "tif", str, width, height, colorMap); | |
| delete writer; | |
| } else { | |
| // output in PPM/PBM format | |
| ImgWriter *writer; | |
| if (!colorMap || (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1)) { | |
| writer = new NetPBMWriter(NetPBMWriter::MONOCHROME); | |
| format = imgMonochrome; | |
| } else { | |
| writer = new NetPBMWriter(NetPBMWriter::RGB); | |
| format = imgRGB; | |
| } | |
| writeImageFile(writer, format, format == imgRGB ? "ppm" : "pbm", str, width, height, colorMap); | |
| delete writer; | |
| } | |
| if (inlineImg) { | |
| embedStr->restore(); | |
| } | |
| if (printFilenames) { | |
| printf("%s\n", fileName); | |
| } | |
| } | |
| 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) | |
| { | |
| return true; | |
| // do nothing -- this avoids the potentially slow loop in Gfx.cc | |
| } | |
| void ImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg) | |
| { | |
| if (listImages) { | |
| listImage(state, ref, str, width, height, nullptr, interpolate, inlineImg, imgStencil); | |
| } else { | |
| writeImage(state, ref, str, width, height, nullptr, inlineImg); | |
| } | |
| } | |
| void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg) | |
| { | |
| if (listImages) { | |
| listImage(state, ref, str, width, height, colorMap, interpolate, inlineImg, imgImage); | |
| } else { | |
| writeImage(state, ref, str, width, height, colorMap, inlineImg); | |
| } | |
| } | |
| 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) | |
| { | |
| if (listImages) { | |
| listImage(state, ref, str, width, height, colorMap, interpolate, false, imgImage); | |
| listImage(state, ref, maskStr, maskWidth, maskHeight, nullptr, maskInterpolate, false, imgMask); | |
| } else { | |
| writeImage(state, ref, str, width, height, colorMap, false); | |
| writeImage(state, ref, maskStr, maskWidth, maskHeight, nullptr, false); | |
| } | |
| } | |
| 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, | |
| bool maskInterpolate) | |
| { | |
| if (listImages) { | |
| listImage(state, ref, str, width, height, colorMap, interpolate, false, imgImage); | |
| listImage(state, ref, maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate, false, imgSmask); | |
| } else { | |
| writeImage(state, ref, str, width, height, colorMap, false); | |
| writeImage(state, ref, maskStr, maskWidth, maskHeight, maskColorMap, false); | |
| } | |
| } | |