From 8d46550c4ff3d4a1923cfc4c42e3fd4d154a7624 Mon Sep 17 00:00:00 2001 From: William Bader Date: Fri, 29 Nov 2019 01:55:29 -0500 Subject: Improve pdftops -optimizecolorspace by implementing the CMYK to K conversion in more places. This fixes the conversion of the PDF in poppler/poppler#833 --- poppler/PSOutputDev.cc | 181 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 132 insertions(+), 49 deletions(-) diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc index a7c86f8f..511a6ebb 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -23,7 +23,7 @@ // Copyright (C) 2009-2013 Thomas Freitag // Copyright (C) 2009 Till Kamppeter // Copyright (C) 2009 Carlos Garcia Campos -// Copyright (C) 2009, 2011, 2012, 2014-2017 William Bader +// Copyright (C) 2009, 2011, 2012, 2014-2017, 2019 William Bader // Copyright (C) 2009 Kovid Goyal // Copyright (C) 2009-2011, 2013-2015, 2017 Adrian Johnson // Copyright (C) 2012, 2014 Fabio D'Urso @@ -4105,6 +4105,16 @@ void PSOutputDev::updateFillColor(GfxState *state) { m = colToDbl(cmyk.m); y = colToDbl(cmyk.y); k = colToDbl(cmyk.k); + if (getOptimizeColorSpace()) { + double g; + g = 0.299*c + 0.587*m + 0.114*y; + if ((fabs(m - c) < 0.01 && fabs(m - y) < 0.01) || + (fabs(m - c) < 0.2 && fabs(m - y) < 0.2 && k + g > 1.5)) { + c = m = y = 0.0; + k += g; + if (k > 1.0) k = 1.0; + } + } writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k); addProcessColor(c, m, y, k); } @@ -4162,6 +4172,16 @@ void PSOutputDev::updateStrokeColor(GfxState *state) { m = colToDbl(cmyk.m); y = colToDbl(cmyk.y); k = colToDbl(cmyk.k); + if (getOptimizeColorSpace()) { + double g; + g = 0.299*c + 0.587*m + 0.114*y; + if ((fabs(m - c) < 0.01 && fabs(m - y) < 0.01) || + (fabs(m - c) < 0.2 && fabs(m - y) < 0.2 && k + g > 1.5)) { + c = m = y = 0.0; + k += g; + if (k > 1.0) k = 1.0; + } + } writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k); addProcessColor(c, m, y, k); } @@ -5479,79 +5499,142 @@ void PSOutputDev::doImageL1Sep(Object *ref, GfxImageColorMap *colorMap, bool checkProcessColor; char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null unsigned char digit; + bool isGray; // explicit masking if (maskStr && !(maskColors && colorMap)) { maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert); } - // width, height, matrix, bits per component - writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep{5:s}\n", - width, height, - width, -height, height, - useBinary ? "Bin" : ""); - // allocate a line buffer lineBuf = (unsigned char *)gmallocn(width, 4); + // scan for all gray + if (getOptimizeColorSpace()) { + ImageStream *imgCheckStr; + imgCheckStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgCheckStr->reset(); + isGray = true; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + imgCheckStr->getPixel(pixBuf); + colorMap->getCMYK(pixBuf, &cmyk); + if (colToByte(cmyk.c) != colToByte(cmyk.m) || colToByte(cmyk.c) != colToByte(cmyk.y)) { + isGray = false; + y = height; // end outer loop + break; + } + } + } + imgCheckStr->close(); + delete imgCheckStr; + } else { + isGray = false; + } + // set up to process the data stream imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgStr->reset(); + // width, height, matrix, bits per component + writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1{5:s}{6:s}\n", + width, height, + width, -height, height, + isGray ? "" : "Sep", + useBinary ? "Bin" : ""); + // process the data stream checkProcessColor = true; i = 0; - for (y = 0; y < height; ++y) { - // read the line - if (checkProcessColor) { - checkProcessColor = (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0); - } - if (checkProcessColor) { - for (x = 0; x < width; ++x) { - imgStr->getPixel(pixBuf); - colorMap->getCMYK(pixBuf, &cmyk); - lineBuf[4*x+0] = colToByte(cmyk.c); - lineBuf[4*x+1] = colToByte(cmyk.m); - lineBuf[4*x+2] = colToByte(cmyk.y); - lineBuf[4*x+3] = colToByte(cmyk.k); - addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), - colToDbl(cmyk.y), colToDbl(cmyk.k)); + if (isGray) { + int g; + for (y = 0; y < height; ++y) { + + // read the line + if (checkProcessColor) { + checkProcessColor = ((psProcessBlack & processColors) == 0); } - } else { for (x = 0; x < width; ++x) { - imgStr->getPixel(pixBuf); - colorMap->getCMYK(pixBuf, &cmyk); - lineBuf[4*x+0] = colToByte(cmyk.c); - lineBuf[4*x+1] = colToByte(cmyk.m); - lineBuf[4*x+2] = colToByte(cmyk.y); - lineBuf[4*x+3] = colToByte(cmyk.k); + imgStr->getPixel(pixBuf); + colorMap->getCMYK(pixBuf, &cmyk); + g = colToByte(cmyk.c) + colToByte(cmyk.k); + if (checkProcessColor && g > 0) { + processColors |= psProcessBlack; + } + g = 255 - g; + if (g < 0) g = 0; + if (useBinary) { + hexBuf[i++] = g; + } else { + digit = g / 16; + hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0'); + digit = g % 16; + hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0'); + } + if (i >= 64) { + if (!useBinary) { + hexBuf[i++] = '\n'; + } + writePSBuf(hexBuf, i); + i = 0; + } } } + } else { + for (y = 0; y < height; ++y) { - // write one line of each color component - if (useBinary) { - for (comp = 0; comp < 4; ++comp) { - for (x = 0; x < width; ++x) { - hexBuf[i++] = lineBuf[4*x + comp]; - if (i >= 64) { - writePSBuf(hexBuf, i); - i = 0; - } - } + // read the line + if (checkProcessColor) { + checkProcessColor = (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0); } - } else { - for (comp = 0; comp < 4; ++comp) { + if (checkProcessColor) { for (x = 0; x < width; ++x) { - digit = lineBuf[4*x + comp] / 16; - hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0'); - digit = lineBuf[4*x + comp] % 16; - hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0'); - if (i >= 64) { - hexBuf[i++] = '\n'; - writePSBuf(hexBuf, i); - i = 0; + imgStr->getPixel(pixBuf); + colorMap->getCMYK(pixBuf, &cmyk); + lineBuf[4*x+0] = colToByte(cmyk.c); + lineBuf[4*x+1] = colToByte(cmyk.m); + lineBuf[4*x+2] = colToByte(cmyk.y); + lineBuf[4*x+3] = colToByte(cmyk.k); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } + } else { + for (x = 0; x < width; ++x) { + imgStr->getPixel(pixBuf); + colorMap->getCMYK(pixBuf, &cmyk); + lineBuf[4*x+0] = colToByte(cmyk.c); + lineBuf[4*x+1] = colToByte(cmyk.m); + lineBuf[4*x+2] = colToByte(cmyk.y); + lineBuf[4*x+3] = colToByte(cmyk.k); + } + } + + // write one line of each color component + if (useBinary) { + for (comp = 0; comp < 4; ++comp) { + for (x = 0; x < width; ++x) { + hexBuf[i++] = lineBuf[4*x + comp]; + if (i >= 64) { + writePSBuf(hexBuf, i); + i = 0; + } + } + } + } else { + for (comp = 0; comp < 4; ++comp) { + for (x = 0; x < width; ++x) { + digit = lineBuf[4*x + comp] / 16; + hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0'); + digit = lineBuf[4*x + comp] % 16; + hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0'); + if (i >= 64) { + hexBuf[i++] = '\n'; + writePSBuf(hexBuf, i); + i = 0; + } } } } -- cgit v1.2.3