I don't know if this patch is useful without the outstanding overprint
patch for Splash, but I finished implementation of the two new options:
-overprint renders the PDF in in splashCMYK8 first and converts the CMYK
Splash bitmap to RGB during writing (compiler switch SPLASH_CMYK must be
set on pdftoppm and on poppler library). It's implemented for png, jpeg
and tiff, tested for png and jpeg but should work with tiff, too.
USE_CMS is not implemented in the moment, the conversion from CMYK to
RGB is done with a copy from the GfxState-routines.
-jpegcmyk produces a jpg in CMYK colorspace (compiler switch SPLASH_CMYK
must be set on pdftoppm and on poppler library).
Because overprint is not implemented yet, the overprint option changes
nothing in the moment. So this option can be used as a zero state for
overprinting to see which PDF renders differently with the outstanding
first implementation of overprinting.
Thomas
Am 21.03.2011 20:47, schrieb Albert Astals Cid:
A Dilluns, 21 de març de 2011, Thomas Freitag va escriure:
Hi all!
4. Support of overprint in pdftoppm
To support overprint in pdftoppm we have to enable SPLASH_CMYK in
pdftoppm and use it for rendering. But all output formats defined in
pdftoppm uses RGB as output colorspace, and even the main output formats
ppm and png do not support CMYK colorspace. Therefore we have to
possibilities to support overprinting in pdftoppm:
a) The easiest way would be to specify a new output format like i.e.
jpegcmyk and create a jpeg image in CMYK colorspace where overprinting
will be supported.
b) The more interesting way is to add a new parameter -overprint, when
set use splashCMYK8 as colorMode and when writing the output file
convert it to RGB. The first implementation could use the poor
colorspace conversion in Splash to convert the CMYK bitmap to RGB, but
we should think of use little cms to do that work for us, which of
course means that compiling pdftoppm will become more complex.
Any suggestions from the community to point 4?
Both seem interesting :-)
Albert
Thomas
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
.
diff --git a/goo/ImgWriter.h b/goo/ImgWriter.h
index f44c85d..0795934 100644
--- a/goo/ImgWriter.h
+++ b/goo/ImgWriter.h
@@ -27,6 +27,7 @@ class ImgWriter
virtual bool writeRow(unsigned char **row) = 0;
virtual bool close() = 0;
+ virtual bool supportCMYK() { return 0; }
};
#endif
diff --git a/goo/JpegWriter.cc b/goo/JpegWriter.cc
index c9b7052..18c9771 100644
--- a/goo/JpegWriter.cc
+++ b/goo/JpegWriter.cc
@@ -27,13 +27,13 @@ void outputMessage(j_common_ptr cinfo)
error(-1, "%s", buffer);
}
-JpegWriter::JpegWriter(int q, bool p)
-: progressive(p), quality(q)
+JpegWriter::JpegWriter(int q, bool p, J_COLOR_SPACE cm)
+: progressive(p), quality(q), colorMode(cm)
{
}
-JpegWriter::JpegWriter()
-: progressive(false), quality(-1)
+JpegWriter::JpegWriter(J_COLOR_SPACE cm)
+: progressive(false), quality(-1), colorMode(cm)
{
}
@@ -61,9 +61,24 @@ bool JpegWriter::init(FILE *f, int width, int height, int
hDPI, int vDPI)
cinfo.density_unit = 1; // dots per inch
cinfo.X_density = hDPI;
cinfo.Y_density = vDPI;
- cinfo.input_components = 3; /* # of color components per pixel */
- cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
- jpeg_set_defaults(&cinfo);
+ cinfo.in_color_space = colorMode; /* colorspace of input image */
+ /* # of color components per pixel */
+ switch (colorMode) {
+ case JCS_GRAYSCALE:
+ cinfo.input_components = 1;
+ break;
+ case JCS_RGB:
+ cinfo.input_components = 3;
+ break;
+ case JCS_CMYK:
+ cinfo.input_components = 4;
+ break;
+ }
+ jpeg_set_defaults(&cinfo);
+ if (cinfo.in_color_space == JCS_CMYK) {
+ jpeg_set_colorspace(&cinfo, JCS_YCCK);
+ cinfo.write_JFIF_header = TRUE;
+ }
// Set quality
if( quality >= 0 && quality <= 100 ) {
@@ -83,16 +98,36 @@ bool JpegWriter::init(FILE *f, int width, int height, int
hDPI, int vDPI)
bool JpegWriter::writePointers(unsigned char **rowPointers, int rowCount)
{
+ if (colorMode == JCS_CMYK) {
+ for (int y = 0; y < rowCount; y++) {
+ unsigned char *row = rowPointers[y];
+ for (unsigned int x = 0; x < cinfo.image_width; x++) {
+ for (int n = 0; n < 4; n++) {
+ *row = 0xff - *row;
+ row++;
+ }
+ }
+ }
+ }
// Write all rows to the file
jpeg_write_scanlines(&cinfo, rowPointers, rowCount);
return true;
}
-bool JpegWriter::writeRow(unsigned char **row)
+bool JpegWriter::writeRow(unsigned char **rowPointer)
{
+ if (colorMode == JCS_CMYK) {
+ unsigned char *row = rowPointer[0];
+ for (unsigned int x = 0; x < cinfo.image_width; x++) {
+ for (int n = 0; n < 4; n++) {
+ *row = 0xff - *row;
+ row++;
+ }
+ }
+ }
// Write the row to the file
- jpeg_write_scanlines(&cinfo, row, 1);
+ jpeg_write_scanlines(&cinfo, rowPointer, 1);
return true;
}
diff --git a/goo/JpegWriter.h b/goo/JpegWriter.h
index 1f7a738..5e27798 100644
--- a/goo/JpegWriter.h
+++ b/goo/JpegWriter.h
@@ -29,8 +29,8 @@ extern "C" {
class JpegWriter : public ImgWriter
{
public:
- JpegWriter(int quality, bool progressive);
- JpegWriter();
+ JpegWriter(int quality, bool progressive, J_COLOR_SPACE
colorMode = JCS_RGB);
+ JpegWriter(J_COLOR_SPACE colorMode = JCS_RGB);
~JpegWriter();
bool init(FILE *f, int width, int height, int hDPI, int vDPI);
@@ -39,10 +39,12 @@ class JpegWriter : public ImgWriter
bool writeRow(unsigned char **row);
bool close();
+ bool supportCMYK() { return colorMode == JCS_CMYK; }
private:
bool progressive;
int quality;
+ J_COLOR_SPACE colorMode;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
};
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index 7c26e54..16a8bd2 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -302,6 +302,11 @@ SplashError
SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in
#endif
#ifdef ENABLE_LIBJPEG
+ #ifdef SPLASH_CMYK
+ case splashFormatJpegCMYK:
+ writer = new JpegWriter(JCS_CMYK);
+ break;
+ #endif
case splashFormatJpeg:
writer = new JpegWriter();
break;
@@ -329,8 +334,98 @@ SplashError
SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in
return e;
}
+// from GfxState.h
+static inline double byteToDbl(Guchar x) {
+ return (double)x / (double)255.0;
+}
+
+static inline Guchar dblToByte(double x) {
+ return (x * 255.0);
+}
+
+// from GfxState_helpers.h
+static inline double clip01(double x) {
+ return (x < 0) ? 0 : (x > 1) ? 1 : x;
+}
+
+static inline void cmykToRGBMatrixMultiplication(const double &c, const double
&m, const double &y, const double &k, const double &c1, const double &m1, const
double &y1, const double &k1, double &r, double &g, double &b)
+{
+ double x;
+ // this is a matrix multiplication, unrolled for performance
+ // C M Y K
+ x = c1 * m1 * y1 * k1; // 0 0 0 0
+ r = g = b = x;
+ x = c1 * m1 * y1 * k; // 0 0 0 1
+ r += 0.1373 * x;
+ g += 0.1216 * x;
+ b += 0.1255 * x;
+ x = c1 * m1 * y * k1; // 0 0 1 0
+ r += x;
+ g += 0.9490 * x;
+ x = c1 * m1 * y * k; // 0 0 1 1
+ r += 0.1098 * x;
+ g += 0.1020 * x;
+ x = c1 * m * y1 * k1; // 0 1 0 0
+ r += 0.9255 * x;
+ b += 0.5490 * x;
+ x = c1 * m * y1 * k; // 0 1 0 1
+ r += 0.1412 * x;
+ x = c1 * m * y * k1; // 0 1 1 0
+ r += 0.9294 * x;
+ g += 0.1098 * x;
+ b += 0.1412 * x;
+ x = c1 * m * y * k; // 0 1 1 1
+ r += 0.1333 * x;
+ x = c * m1 * y1 * k1; // 1 0 0 0
+ g += 0.6784 * x;
+ b += 0.9373 * x;
+ x = c * m1 * y1 * k; // 1 0 0 1
+ g += 0.0588 * x;
+ b += 0.1412 * x;
+ x = c * m1 * y * k1; // 1 0 1 0
+ g += 0.6510 * x;
+ b += 0.3137 * x;
+ x = c * m1 * y * k; // 1 0 1 1
+ g += 0.0745 * x;
+ x = c * m * y1 * k1; // 1 1 0 0
+ r += 0.1804 * x;
+ g += 0.1922 * x;
+ b += 0.5725 * x;
+ x = c * m * y1 * k; // 1 1 0 1
+ b += 0.0078 * x;
+ x = c * m * y * k1; // 1 1 1 0
+ r += 0.2118 * x;
+ g += 0.2119 * x;
+ b += 0.2235 * x;
+}
+
+void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) {
+ SplashColor col;
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+ for (int x = 0; x < width; x++) {
+ getPixel(x, yl, col);
+ c = byteToDbl(col[0]);
+ m = byteToDbl(col[1]);
+ y = byteToDbl(col[2]);
+ k = byteToDbl(col[3]);
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g,
b);
+ *line++ = dblToByte(clip01(r));
+ *line++ = dblToByte(clip01(g));
+ *line++ = dblToByte(clip01(b));
+ }
+}
+
SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI,
int vDPI) {
- if (mode != splashModeRGB8 && mode != splashModeMono8 && mode !=
splashModeMono1 && mode != splashModeXBGR8) {
+ if (mode != splashModeRGB8 && mode != splashModeMono8 && mode !=
splashModeMono1 && mode != splashModeXBGR8
+#if SPLASH_CMYK
+ && mode != splashModeCMYK8
+#endif
+ ) {
error(-1, "unsupported SplashBitmap mode");
return splashErrGeneric;
}
@@ -340,6 +435,35 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer,
FILE *f, int hDPI, int
}
switch (mode) {
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ if (writer->supportCMYK()) {
+ SplashColorPtr row;
+ unsigned char **row_pointers = new unsigned char*[height];
+ row = data;
+
+ for (int y = 0; y < height; ++y) {
+ row_pointers[y] = row;
+ row += rowSize;
+ }
+ if (!writer->writePointers(row_pointers, height)) {
+ delete[] row_pointers;
+ return splashErrGeneric;
+ }
+ delete[] row_pointers;
+ } else {
+ unsigned char *row = new unsigned char[3 * width];
+ for (int y = 0; y < height; y++) {
+ getRGBLine(y, row);
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
+ delete[] row;
+ }
+ break;
+#endif
case splashModeRGB8:
{
SplashColorPtr row;
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index b276a61..3336507 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -71,6 +71,7 @@ public:
SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI);
void getPixel(int x, int y, SplashColorPtr pixel);
+ void getRGBLine(int y, SplashColorPtr line);
Guchar getAlpha(int x, int y);
private:
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h
index 273c32d..72d41d9 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -162,7 +162,8 @@ typedef int SplashError;
enum SplashImageFileFormat {
splashFormatJpeg,
splashFormatPng,
- splashFormatTiff
+ splashFormatTiff,
+ splashFormatJpegCMYK
};
#endif
diff --git a/utils/pdftoppm.cc b/utils/pdftoppm.cc
index 8a7c702..7b7eaca 100644
--- a/utils/pdftoppm.cc
+++ b/utils/pdftoppm.cc
@@ -71,7 +71,9 @@ static GBool mono = gFalse;
static GBool gray = gFalse;
static GBool png = gFalse;
static GBool jpeg = gFalse;
+static GBool jpegcmyk = gFalse;
static GBool tiff = gFalse;
+static GBool overprint = gFalse;
static char enableFreeTypeStr[16] = "";
static char antialiasStr[16] = "";
static char vectorAntialiasStr[16] = "";
@@ -129,8 +131,16 @@ static const ArgDesc argDesc[] = {
"generate a PNG file"},
#endif
#if ENABLE_LIBJPEG
- {"-jpeg", argFlag, &jpeg, 0,
+ {"-jpeg", argFlag, &jpeg, 0,
"generate a JPEG file"},
+#if SPLASH_CMYK
+ {"-jpegcmyk",argFlag, &jpegcmyk, 0,
+ "generate a CMYK JPEG file"},
+#endif
+#endif
+#if SPLASH_CMYK
+ {"-overprint",argFlag, &overprint, 0,
+ "enable overprint"},
#endif
#if ENABLE_LIBTIFF
{"-tiff", argFlag, &tiff, 0,
@@ -191,6 +201,8 @@ static void savePageSlice(PDFDoc *doc,
bitmap->writeImgFile(splashFormatPng, ppmFile, x_resolution,
y_resolution);
} else if (jpeg) {
bitmap->writeImgFile(splashFormatJpeg, ppmFile, x_resolution,
y_resolution);
+ } else if (jpegcmyk) {
+ bitmap->writeImgFile(splashFormatJpegCMYK, ppmFile, x_resolution,
y_resolution);
} else if (tiff) {
bitmap->writeImgFile(splashFormatTiff, ppmFile, x_resolution,
y_resolution, TiffCompressionStr);
} else {
@@ -337,11 +349,24 @@ int main(int argc, char *argv[]) {
}
// write PPM files
- paperColor[0] = 255;
- paperColor[1] = 255;
- paperColor[2] = 255;
+#if SPLASH_CMYK
+ if (jpegcmyk || overprint) {
+ paperColor[0] = 0;
+ paperColor[1] = 0;
+ paperColor[2] = 0;
+ paperColor[3] = 0;
+ } else
+#endif
+ {
+ paperColor[0] = 255;
+ paperColor[1] = 255;
+ paperColor[2] = 255;
+ }
splashOut = new SplashOutputDev(mono ? splashModeMono1 :
gray ? splashModeMono8 :
+#if SPLASH_CMYK
+ (jpegcmyk || overprint) ?
splashModeCMYK8 :
+#endif
splashModeRGB8, 4,
gFalse, paperColor);
splashOut->startDoc(doc->getXRef());
@@ -377,7 +402,7 @@ int main(int argc, char *argv[]) {
pg_h = tmp;
}
if (ppmRoot != NULL) {
- const char *ext = png ? "png" : jpeg ? "jpg" : tiff ? "tif" : mono ?
"pbm" : gray ? "pgm" : "ppm";
+ const char *ext = png ? "png" : (jpeg || jpegcmyk) ? "jpg" : tiff ?
"tif" : mono ? "pbm" : gray ? "pgm" : "ppm";
if (singleFile) {
snprintf(ppmFile, PPM_FILE_SZ, "%.*s.%s",
PPM_FILE_SZ - 32, ppmRoot, ext);
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler