1 /*
2 Copyright (c) 2008-2011 BBR Inc. All rights reserved.
3 Copyright (c) 2012-2019 by Till Kamppeter
4 Copyright (c) 2019 by Tanmay Anand.
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 */
26 /*
27 pdftoraster.cc
28 pdf to raster filter
29 */
30
31 #include <config.h>
32 #include <cups/cups.h>
33 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
34 #define HAVE_CUPS_1_7 1
35 #endif
36
37 #define USE_CMS
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #ifdef HAVE_CPP_POPPLER_VERSION_H
42 #include <poppler/cpp/poppler-version.h>
43 #endif
44 #include <cups/ppd.h>
45 #include <stdarg.h>
46 #include <cups/raster.h>
47 #include <cupsfilters/image.h>
48 #include <cupsfilters/raster.h>
49 #include <cupsfilters/colormanager.h>
50 #include <strings.h>
51 #include <math.h>
52 #include <poppler/cpp/poppler-document.h>
53 #include <poppler/cpp/poppler-page.h>
54 #include <poppler/cpp/poppler-global.h>
55 #include <poppler/cpp/poppler-image.h>
56 #include <poppler/cpp/poppler-page-renderer.h>
57 #include <poppler/cpp/poppler-rectangle.h>
58 #ifdef USE_LCMS1
59 #include <lcms.h>
60 #define cmsColorSpaceSignature icColorSpaceSignature
61 #define cmsSetLogErrorHandler cmsSetErrorHandler
62 #define cmsToneCurve LPGAMMATABLE
63 #define cmsSigXYZData icSigXYZData
64 #define cmsSigLuvData icSigLuvData
65 #define cmsSigLabData icSigLabData
66 #define cmsSigYCbCrData icSigYCbCrData
67 #define cmsSigYxyData icSigYxyData
68 #define cmsSigRgbData icSigRgbData
69 #define cmsSigHsvData icSigHsvData
70 #define cmsSigHlsData icSigHlsData
71 #define cmsSigCmyData icSigCmyData
72 #define cmsSig3colorData icSig3colorData
73 #define cmsSigGrayData icSigGrayData
74 #define cmsSigCmykData icSigCmykData
75 #define cmsSig4colorData icSig4colorData
76 #define cmsSig2colorData icSig2colorData
77 #define cmsSig5colorData icSig5colorData
78 #define cmsSig6colorData icSig6colorData
79 #define cmsSig7colorData icSig7colorData
80 #define cmsSig8colorData icSig8colorData
81 #define cmsSig9colorData icSig9colorData
82 #define cmsSig10colorData icSig10colorData
83 #define cmsSig11colorData icSig11colorData
84 #define cmsSig12colorData icSig12colorData
85 #define cmsSig13colorData icSig13colorData
86 #define cmsSig14colorData icSig14colorData
87 #define cmsSig15colorData icSig15colorData
88 #else
89 #include <lcms2.h>
90 #endif
91
92 #define MAX_CHECK_COMMENT_LINES 20
93 #define MAX_BYTES_PER_PIXEL 32
94
95 namespace {
96 typedef unsigned char *(*ConvertLineFunc)(unsigned char *src,
97 unsigned char *dst, unsigned int row, unsigned int plane,
98 unsigned int pixels, unsigned int size);
99 typedef unsigned char *(*ConvertCSpaceFunc)(unsigned char *src,
100 unsigned char *pixelBuf, unsigned int x, unsigned int y);
101 typedef unsigned char *(*ConvertBitsFunc)(unsigned char *src,
102 unsigned char *dst, unsigned int x, unsigned int y);
103 typedef void (*WritePixelFunc)(unsigned char *dst,
104 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf);
105
106 int exitCode = 0;
107 int pwgraster = 0;
108 int deviceCopies = 1;
109 bool deviceCollate = false;
110 cups_page_header2_t header;
111 ppd_file_t *ppd = 0;
112 char pageSizeRequested[64];
113 unsigned int bitmapoffset[2];
114 unsigned int popplerBitsPerPixel;
115 unsigned int popplerNumColors;
116 /* image swapping */
117 bool swap_image_x = false;
118 bool swap_image_y = false;
119 /* margin swapping */
120 bool swap_margin_x = false;
121 bool swap_margin_y = false;
122 bool allocLineBuf = false;
123 ConvertLineFunc convertLineOdd;
124 ConvertLineFunc convertLineEven;
125 ConvertCSpaceFunc convertCSpace;
126 ConvertBitsFunc convertBits;
127 WritePixelFunc writePixel;
128 unsigned int nplanes;
129 unsigned int nbands;
130 unsigned int bytesPerLine; /* number of bytes per line */
131 /* Note: When CUPS_ORDER_BANDED,
132 cupsBytesPerLine = bytesPerLine*cupsNumColors */
133 unsigned char revTable[256] = {
134 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
135 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
136 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
137 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
138 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
139 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
140 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
141 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
142 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
143 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
144 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
145 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
146 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
147 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
148 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
149 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
150 };
151 unsigned int dither1[16][16] = {
152 {0,128,32,160,8,136,40,168,2,130,34,162,10,138,42,170},
153 {192,64,224,96,200,72,232,104,194,66,226,98,202,74,234,106},
154 {48,176,16,144,56,184,24,152,50,178,18,146,58,186,26,154},
155 {240,112,208,80,248,120,216,88,242,114,210,82,250,122,218,90},
156 {12,140,44,172,4,132,36,164,14,142,46,174,6,134,38,166},
157 {204,76,236,108,196,68,228,100,206,78,238,110,198,70,230,102},
158 {60,188,28,156,52,180,20,148,62,190,30,158,54,182,22,150},
159 {252,124,220,92,244,116,212,84,254,126,222,94,246,118,214,86},
160 {3,131,35,163,11,139,43,171,1,129,33,161,9,137,41,169},
161 {195,67,227,99,203,75,235,107,193,65,225,97,201,73,233,105},
162 {51,179,19,147,59,187,27,155,49,177,17,145,57,185,25,153},
163 {243,115,211,83,251,123,219,91,241,113,209,81,249,121,217,89},
164 {15,143,47,175,7,135,39,167,13,141,45,173,5,133,37,165},
165 {207,79,239,111,199,71,231,103,205,77,237,109,197,69,229,101},
166 {63,191,31,159,55,183,23,151,61,189,29,157,53,181,21,149},
167 {255,127,223,95,247,119,215,87,253,125,221,93,245,117,213,85}
168 };
169 unsigned int dither2[8][8] = {
170 {0,32,8,40,2,34,10,42},
171 {48,16,56,24,50,18,58,26},
172 {12,44,4,36,14,46,6,38},
173 {60,28,52,20,62,30,54,22},
174 {3,35,11,43,1,33,9,41},
175 {51,19,59,27,49,17,57,25},
176 {15,47,7,39,13,45,5,37},
177 {63,31,55,23,61,29,53,21}
178 };
179 unsigned int dither4[4][4] = {
180 {0,8,2,10},
181 {12,4,14,6},
182 {3,11,1,9},
183 {15,7,13,5}
184 };
185
186 /* for color profiles */
187 cmsHPROFILE colorProfile = NULL;
188 cmsHPROFILE popplerColorProfile = NULL;
189 cmsHTRANSFORM colorTransform = NULL;
190 cmsCIEXYZ D65WhitePoint;
191 int renderingIntent = INTENT_PERCEPTUAL;
192 int cm_disabled = 0;
193 cm_calibration_t cm_calibrate;
194 }
195
adobergb_wp()196 cmsCIExyY adobergb_wp()
197 {
198 double * xyY = cmWhitePointAdobeRgb();
199 cmsCIExyY wp;
200
201 wp.x = xyY[0];
202 wp.y = xyY[1];
203 wp.Y = xyY[2];
204
205 return wp;
206 }
207
sgray_wp()208 cmsCIExyY sgray_wp()
209 {
210 double * xyY = cmWhitePointSGray();
211 cmsCIExyY wp;
212
213 wp.x = xyY[0];
214 wp.y = xyY[1];
215 wp.Y = xyY[2];
216
217 return wp;
218 }
219
adobergb_matrix()220 cmsCIExyYTRIPLE adobergb_matrix()
221 {
222 cmsCIExyYTRIPLE m;
223
224 double * matrix = cmMatrixAdobeRgb();
225
226 m.Red.x = matrix[0];
227 m.Red.y = matrix[1];
228 m.Red.Y = matrix[2];
229 m.Green.x = matrix[3];
230 m.Green.y = matrix[4];
231 m.Green.Y = matrix[5];
232 m.Blue.x = matrix[6];
233 m.Blue.y = matrix[7];
234 m.Blue.Y = matrix[8];
235
236 return m;
237 }
238
adobergb_profile()239 cmsHPROFILE adobergb_profile()
240 {
241 cmsHPROFILE adobergb;
242
243 cmsCIExyY wp;
244 cmsCIExyYTRIPLE primaries;
245
246 #if USE_LCMS1
247 cmsToneCurve Gamma = cmsBuildGamma(256, 2.2);
248 cmsToneCurve Gamma3[3];
249 #else
250 cmsToneCurve * Gamma = cmsBuildGamma(NULL, 2.2);
251 cmsToneCurve * Gamma3[3];
252 #endif
253 Gamma3[0] = Gamma3[1] = Gamma3[2] = Gamma;
254
255 // Build AdobeRGB profile
256 primaries = adobergb_matrix();
257 wp = adobergb_wp();
258 adobergb = cmsCreateRGBProfile(&wp, &primaries, Gamma3);
259
260 return adobergb;
261 }
262
sgray_profile()263 cmsHPROFILE sgray_profile()
264 {
265 cmsHPROFILE sgray;
266
267 cmsCIExyY wp;
268
269 #if USE_LCMS1
270 cmsToneCurve Gamma = cmsBuildGamma(256, 2.2);
271 #else
272 cmsToneCurve * Gamma = cmsBuildGamma(NULL, 2.2);
273 #endif
274 // Build sGray profile
275 wp = sgray_wp();
276 sgray = cmsCreateGrayProfile(&wp, Gamma);
277
278 return sgray;
279 }
280
281
282 #ifdef USE_LCMS1
lcmsErrorHandler(int ErrorCode,const char * ErrorText)283 static int lcmsErrorHandler(int ErrorCode, const char *ErrorText)
284 {
285 fprintf(stderr, "ERROR: %s\n",ErrorText);
286 return 1;
287 }
288 #else
lcmsErrorHandler(cmsContext contextId,cmsUInt32Number ErrorCode,const char * ErrorText)289 static void lcmsErrorHandler(cmsContext contextId, cmsUInt32Number ErrorCode,
290 const char *ErrorText)
291 {
292 fprintf(stderr, "ERROR: %s\n",ErrorText);
293 }
294 #endif
295
296
297
handleRqeuiresPageRegion()298 static void handleRqeuiresPageRegion() {
299 ppd_choice_t *mf;
300 ppd_choice_t *is;
301 ppd_attr_t *rregions = NULL;
302 ppd_size_t *size;
303
304 if ((size = ppdPageSize(ppd,NULL)) == NULL) return;
305 mf = ppdFindMarkedChoice(ppd,"ManualFeed");
306 if ((is = ppdFindMarkedChoice(ppd,"InputSlot")) != NULL) {
307 rregions = ppdFindAttr(ppd,"RequiresPageRegion",is->choice);
308 }
309 if (rregions == NULL) {
310 rregions = ppdFindAttr(ppd,"RequiresPageRegion","All");
311 }
312 if (!strcasecmp(size->name,"Custom") || (!mf && !is) ||
313 (mf && !strcasecmp(mf->choice,"False") &&
314 (!is || (is->code && !is->code[0]))) ||
315 (!rregions && ppd->num_filters > 0)) {
316 ppdMarkOption(ppd,"PageSize",size->name);
317 } else if (rregions && rregions->value
318 && !strcasecmp(rregions->value,"True")) {
319 ppdMarkOption(ppd,"PageRegion",size->name);
320 } else {
321 ppd_choice_t *page;
322
323 if ((page = ppdFindMarkedChoice(ppd,"PageSize")) != NULL) {
324 page->marked = 0;
325 cupsArrayRemove(ppd->marked,page);
326 }
327 if ((page = ppdFindMarkedChoice(ppd,"PageRegion")) != NULL) {
328 page->marked = 0;
329 cupsArrayRemove(ppd->marked, page);
330 }
331 }
332 }
333
parseOpts(int argc,char ** argv)334 static void parseOpts(int argc, char **argv)
335 {
336 int num_options = 0;
337 cups_option_t *options = 0;
338 char *profile = 0;
339 const char *t = NULL;
340 ppd_attr_t *attr;
341
342 if (argc < 6 || argc > 7) {
343 fprintf(stderr, "ERROR: Usage: %s job-id user title copies options [file]\n",
344 argv[0]);
345 exit(1);
346 }
347
348 #ifdef HAVE_CUPS_1_7
349 t = getenv("FINAL_CONTENT_TYPE");
350 if (t && strcasestr(t, "pwg"))
351 pwgraster = 1;
352 #endif /* HAVE_CUPS_1_7 */
353
354 ppd = ppdOpenFile(getenv("PPD"));
355 if (ppd == NULL)
356 fprintf(stderr, "DEBUG: PPD file is not specified.\n");
357 if (ppd)
358 ppdMarkDefaults(ppd);
359 options = NULL;
360 num_options = cupsParseOptions(argv[5],0,&options);
361 if (ppd) {
362 cupsMarkOptions(ppd,num_options,options);
363 handleRqeuiresPageRegion();
364 cupsRasterInterpretPPD(&header,ppd,num_options,options,0);
365 attr = ppdFindAttr(ppd,"pdftorasterRenderingIntent",NULL);
366 if (attr != NULL && attr->value != NULL) {
367 if (strcasecmp(attr->value,"PERCEPTUAL") != 0) {
368 renderingIntent = INTENT_PERCEPTUAL;
369 } else if (strcasecmp(attr->value,"RELATIVE_COLORIMETRIC") != 0) {
370 renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
371 } else if (strcasecmp(attr->value,"SATURATION") != 0) {
372 renderingIntent = INTENT_SATURATION;
373 } else if (strcasecmp(attr->value,"ABSOLUTE_COLORIMETRIC") != 0) {
374 renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
375 }
376 }
377 if (header.Duplex) {
378 /* analyze options relevant to Duplex */
379 const char *backside = "";
380 /* APDuplexRequiresFlippedMargin */
381 enum {
382 FM_NO, FM_FALSE, FM_TRUE
383 } flippedMargin = FM_NO;
384
385 attr = ppdFindAttr(ppd,"cupsBackSide",NULL);
386 if (attr != NULL && attr->value != NULL) {
387 ppd->flip_duplex = 0;
388 backside = attr->value;
389 } else if (ppd->flip_duplex) {
390 backside = "Rotated"; /* compatible with Max OS and GS 8.71 */
391 }
392
393 attr = ppdFindAttr(ppd,"APDuplexRequiresFlippedMargin",NULL);
394 if (attr != NULL && attr->value != NULL) {
395 if (strcasecmp(attr->value,"true") == 0) {
396 flippedMargin = FM_TRUE;
397 } else {
398 flippedMargin = FM_FALSE;
399 }
400 }
401 if (strcasecmp(backside,"ManualTumble") == 0 && header.Tumble) {
402 swap_image_x = swap_image_y = true;
403 swap_margin_x = swap_margin_y = true;
404 if (flippedMargin == FM_TRUE) {
405 swap_margin_y = false;
406 }
407 } else if (strcasecmp(backside,"Rotated") == 0 && !header.Tumble) {
408 swap_image_x = swap_image_y = true;
409 swap_margin_x = swap_margin_y = true;
410 if (flippedMargin == FM_TRUE) {
411 swap_margin_y = false;
412 }
413 } else if (strcasecmp(backside,"Flipped") == 0) {
414 if (header.Tumble) {
415 swap_image_x = true;
416 swap_margin_x = swap_margin_y = true;
417 } else {
418 swap_image_y = true;
419 }
420 if (flippedMargin == FM_FALSE) {
421 swap_margin_y = !swap_margin_y;
422 }
423 }
424 }
425
426 /* support the CUPS "cm-calibration" option */
427 cm_calibrate = cmGetCupsColorCalibrateMode(options, num_options);
428
429 if (cm_calibrate == CM_CALIBRATION_ENABLED)
430 cm_disabled = 1;
431 else
432 cm_disabled = cmIsPrinterCmDisabled(getenv("PRINTER"));
433
434 if (!cm_disabled)
435 cmGetPrinterIccProfile(getenv("PRINTER"), &profile, ppd);
436
437 if (profile != NULL) {
438 colorProfile = cmsOpenProfileFromFile(profile,"r");
439 free(profile);
440 }
441
442 #ifdef HAVE_CUPS_1_7
443 if ((attr = ppdFindAttr(ppd,"PWGRaster",0)) != 0 &&
444 (!strcasecmp(attr->value, "true")
445 || !strcasecmp(attr->value, "on") ||
446 !strcasecmp(attr->value, "yes")))
447 pwgraster = 1;
448 if (pwgraster == 1)
449 cupsRasterParseIPPOptions(&header, num_options, options, pwgraster, 0);
450 #endif /* HAVE_CUPS_1_7 */
451 } else {
452 #ifdef HAVE_CUPS_1_7
453 pwgraster = 1;
454 t = cupsGetOption("media-class", num_options, options);
455 if (t == NULL)
456 t = cupsGetOption("MediaClass", num_options, options);
457 if (t != NULL)
458 {
459 if (strcasestr(t, "pwg"))
460 pwgraster = 1;
461 else
462 pwgraster = 0;
463 }
464 cupsRasterParseIPPOptions(&header,num_options,options,pwgraster,1);
465 #else
466 fprintf(stderr, "ERROR: No PPD file specified.\n");
467 exit(1);
468 #endif /* HAVE_CUPS_1_7 */
469 }
470 strncpy(pageSizeRequested, header.cupsPageSizeName, 64);
471 fprintf(stderr, "DEBUG: Page size requested: %s\n",
472 header.cupsPageSizeName);
473 }
474
parsePDFTOPDFComment(FILE * fp)475 static void parsePDFTOPDFComment(FILE *fp)
476 {
477 char buf[4096];
478 int i;
479
480 /* skip until PDF start header */
481 while (fgets(buf,sizeof(buf),fp) != 0) {
482 if (strncmp(buf,"%PDF",4) == 0) {
483 break;
484 }
485 }
486 for (i = 0;i < MAX_CHECK_COMMENT_LINES;i++) {
487 if (fgets(buf,sizeof(buf),fp) == 0) break;
488 if (strncmp(buf,"%%PDFTOPDFNumCopies",19) == 0) {
489 char *p;
490
491 p = strchr(buf+19,':');
492 deviceCopies = atoi(p+1);
493 } else if (strncmp(buf,"%%PDFTOPDFCollate",17) == 0) {
494 char *p;
495
496 p = strchr(buf+17,':');
497 while (*p == ' ' || *p == '\t') p++;
498 if (strncasecmp(p,"true",4) == 0) {
499 deviceCollate = true;
500 } else {
501 deviceCollate = false;
502 }
503 }
504 }
505 }
506
reverseLine(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)507 static unsigned char *reverseLine(unsigned char *src, unsigned char *dst,
508 unsigned int row, unsigned int plane, unsigned int pixels,
509 unsigned int size)
510 {
511 unsigned char *p = src;
512
513 for (unsigned int j = 0;j < size;j++,p++) {
514 *p = ~*p;
515 }
516 return src;
517 }
518
reverseLineSwapByte(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)519 static unsigned char *reverseLineSwapByte(unsigned char *src,
520 unsigned char *dst, unsigned int row, unsigned int plane,
521 unsigned int pixels, unsigned int size)
522 {
523 unsigned char *bp = src+size-1;
524 unsigned char *dp = dst;
525
526 for (unsigned int j = 0;j < size;j++,bp--,dp++) {
527 *dp = ~*bp;
528 }
529 return dst;
530 }
531
532
reverseLineSwapBit(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)533 static unsigned char *reverseLineSwapBit(unsigned char *src,
534 unsigned char *dst, unsigned int row, unsigned int plane,
535 unsigned int pixels, unsigned int size)
536 {
537 unsigned char *bp;
538 unsigned char *dp;
539 unsigned int npadbits = (size*8)-pixels;
540
541 if (npadbits == 0) {
542 bp = src+size-1;
543 dp = dst;
544 for (unsigned int j = 0;j < size;j++,bp--,dp++) {
545 *dp = revTable[(unsigned char)(~*bp)];
546 }
547 } else {
548 unsigned int pd,d;
549 unsigned int sw;
550
551 size = (pixels+7)/8;
552 sw = (size*8)-pixels;
553 bp = src+size-1;
554 dp = dst;
555
556 pd = *bp--;
557 for (unsigned int j = 1;j < size;j++,bp--,dp++) {
558 d = *bp;
559 *dp = ~revTable[(((d << 8) | pd) >> sw) & 0xff];
560 pd = d;
561 }
562 *dp = ~revTable[(pd >> sw) & 0xff];
563 }
564 return dst;
565 }
566
rgbToCMYKLine(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)567 static unsigned char *rgbToCMYKLine(unsigned char *src, unsigned char *dst,
568 unsigned int row, unsigned int plane, unsigned int pixels,
569 unsigned int size)
570 {
571 cupsImageRGBToCMYK(src,dst,pixels);
572 return dst;
573 }
574
rgbToCMYKLineSwap(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)575 static unsigned char *rgbToCMYKLineSwap(unsigned char *src, unsigned char *dst,
576 unsigned int row, unsigned int plane, unsigned int pixels,
577 unsigned int size)
578 {
579 unsigned char *bp = src+(pixels-1)*3;
580 unsigned char *dp = dst;
581
582 for (unsigned int i = 0;i < pixels;i++, bp -= 3, dp += 4) {
583 cupsImageRGBToCMYK(bp,dp,1);
584 }
585 return dst;
586 }
587
rgbToCMYLine(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)588 static unsigned char *rgbToCMYLine(unsigned char *src, unsigned char *dst,
589 unsigned int row, unsigned int plane, unsigned int pixels,
590 unsigned int size)
591 {
592 cupsImageRGBToCMY(src,dst,pixels);
593 return dst;
594 }
595
rgbToCMYLineSwap(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)596 static unsigned char *rgbToCMYLineSwap(unsigned char *src, unsigned char *dst,
597 unsigned int row, unsigned int plane, unsigned int pixels,
598 unsigned int size)
599 {
600 unsigned char *bp = src+size-3;
601 unsigned char *dp = dst;
602
603 for (unsigned int i = 0;i < pixels;i++, bp -= 3, dp += 3) {
604 cupsImageRGBToCMY(bp,dp,1);
605 }
606 return dst;
607 }
608
rgbToKCMYLine(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)609 static unsigned char *rgbToKCMYLine(unsigned char *src, unsigned char *dst,
610 unsigned int row, unsigned int plane, unsigned int pixels,
611 unsigned int size)
612 {
613 unsigned char *bp = src;
614 unsigned char *dp = dst;
615 unsigned char d;
616
617 cupsImageRGBToCMYK(src,dst,pixels);
618 /* CMYK to KCMY */
619 for (unsigned int i = 0;i < pixels;i++, bp += 3, dp += 4) {
620 d = dp[3];
621 dp[3] = dp[2];
622 dp[2] = dp[1];
623 dp[1] = dp[0];
624 dp[0] = d;
625 }
626 return dst;
627 }
628
rgbToKCMYLineSwap(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)629 static unsigned char *rgbToKCMYLineSwap(unsigned char *src, unsigned char *dst,
630 unsigned int row, unsigned int plane, unsigned int pixels,
631 unsigned int size)
632 {
633 unsigned char *bp = src+(pixels-1)*3;
634 unsigned char *dp = dst;
635 unsigned char d;
636
637 for (unsigned int i = 0;i < pixels;i++, bp -= 3, dp += 4) {
638 cupsImageRGBToCMYK(bp,dp,1);
639 /* CMYK to KCMY */
640 d = dp[3];
641 dp[3] = dp[2];
642 dp[2] = dp[1];
643 dp[1] = dp[0];
644 dp[0] = d;
645 }
646 return dst;
647 }
648
lineNoop(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)649 static unsigned char *lineNoop(unsigned char *src, unsigned char *dst,
650 unsigned int row, unsigned int plane, unsigned int pixels,
651 unsigned int size)
652 {
653 /* do nothing */
654 return src;
655 }
656
lineSwap24(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)657 static unsigned char *lineSwap24(unsigned char *src, unsigned char *dst,
658 unsigned int row, unsigned int plane, unsigned int pixels,
659 unsigned int size)
660 {
661 unsigned char *bp = src+size-3;
662 unsigned char *dp = dst;
663
664 for (unsigned int i = 0;i < pixels;i++, bp -= 3, dp += 3) {
665 dp[0] = bp[0];
666 dp[1] = bp[1];
667 dp[2] = bp[2];
668 }
669 return dst;
670 }
671
lineSwapByte(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)672 static unsigned char *lineSwapByte(unsigned char *src, unsigned char *dst,
673 unsigned int row, unsigned int plane, unsigned int pixels,
674 unsigned int size)
675 {
676 unsigned char *bp = src+size-1;
677 unsigned char *dp = dst;
678
679 for (unsigned int j = 0;j < size;j++,bp--,dp++) {
680 *dp = *bp;
681 }
682 return dst;
683 }
684
lineSwapBit(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)685 static unsigned char *lineSwapBit(unsigned char *src, unsigned char *dst,
686 unsigned int row, unsigned int plane, unsigned int pixels,
687 unsigned int size)
688 {
689 unsigned char *bp;
690 unsigned char *dp;
691 unsigned int npadbits = (size*8)-pixels;
692
693 if (npadbits == 0) {
694 bp = src+size-1;
695 dp = dst;
696 for (unsigned int j = 0;j < size;j++,bp--,dp++) {
697 *dp = revTable[*bp];
698 }
699 } else {
700 unsigned int pd,d;
701 unsigned int sw;
702
703 size = (pixels+7)/8;
704 sw = (size*8)-pixels;
705 bp = src+size-1;
706 dp = dst;
707
708 pd = *bp--;
709 for (unsigned int j = 1;j < size;j++,bp--,dp++) {
710 d = *bp;
711 *dp = revTable[(((d << 8) | pd) >> sw) & 0xff];
712 pd = d;
713 }
714 *dp = revTable[(pd >> sw) & 0xff];
715 }
716 return dst;
717 }
718
719 typedef struct _funcTable {
720 enum cups_cspace_e cspace;
721 unsigned int bitsPerPixel;
722 unsigned int bitsPerColor;
723 ConvertLineFunc convertLine;
724 bool allocLineBuf;
725 ConvertLineFunc convertLineSwap;
726 bool allocLineBufSwap;
727 } FuncTable;
728
729 static FuncTable specialCaseFuncs[] = {
730 {CUPS_CSPACE_K,8,8,reverseLine,false,reverseLineSwapByte,true},
731 {CUPS_CSPACE_K,1,1,reverseLine,false,reverseLineSwapBit,true},
732 {CUPS_CSPACE_GOLD,8,8,reverseLine,false,reverseLineSwapByte,true},
733 {CUPS_CSPACE_GOLD,1,1,reverseLine,false,reverseLineSwapBit,true},
734 {CUPS_CSPACE_SILVER,8,8,reverseLine,false,reverseLineSwapByte,true},
735 {CUPS_CSPACE_SILVER,1,1,reverseLine,false,reverseLineSwapBit,true},
736 {CUPS_CSPACE_CMYK,32,8,rgbToCMYKLine,true,rgbToCMYKLineSwap,true},
737 {CUPS_CSPACE_KCMY,32,8,rgbToKCMYLine,true,rgbToKCMYLineSwap,true},
738 {CUPS_CSPACE_CMY,24,8,rgbToCMYLine,true,rgbToCMYLineSwap,true},
739 {CUPS_CSPACE_RGB,24,8,lineNoop,false,lineSwap24,true},
740 {CUPS_CSPACE_SRGB,24,8,lineNoop,false,lineSwap24,true},
741 {CUPS_CSPACE_ADOBERGB,24,8,lineNoop,false,lineSwap24,true},
742 {CUPS_CSPACE_W,8,8,lineNoop,false,lineSwapByte,true},
743 {CUPS_CSPACE_W,1,1,lineNoop,false,lineSwapBit,true},
744 {CUPS_CSPACE_SW,8,8,lineNoop,false,lineSwapByte,true},
745 {CUPS_CSPACE_SW,1,1,lineNoop,false,lineSwapBit,true},
746 {CUPS_CSPACE_WHITE,8,8,lineNoop,false,lineSwapByte,true},
747 {CUPS_CSPACE_WHITE,1,1,lineNoop,false,lineSwapBit,true},
748 {CUPS_CSPACE_RGB,0,0,NULL,false,NULL,false} /* end mark */
749 };
750
convertCSpaceNone(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)751 static unsigned char *convertCSpaceNone(unsigned char *src,
752 unsigned char *pixelBuf, unsigned int x, unsigned int y)
753 {
754 return src;
755 }
756
convertCSpaceWithProfiles(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)757 static unsigned char *convertCSpaceWithProfiles(unsigned char *src,
758 unsigned char *pixelBuf, unsigned int x, unsigned int y)
759 {
760 cmsDoTransform(colorTransform,src,pixelBuf,1);
761 return pixelBuf;
762 }
763
convertCSpaceXYZ8(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)764 static unsigned char *convertCSpaceXYZ8(unsigned char *src,
765 unsigned char *pixelBuf, unsigned int x, unsigned int y)
766 {
767 double alab[3];
768
769 cmsDoTransform(colorTransform,src,alab,1);
770 cmsCIELab lab;
771 cmsCIEXYZ xyz;
772
773 lab.L = alab[0];
774 lab.a = alab[1];
775 lab.b = alab[2];
776
777 cmsLab2XYZ(&D65WhitePoint,&xyz,&lab);
778 pixelBuf[0] = 231.8181*xyz.X+0.5;
779 pixelBuf[1] = 231.8181*xyz.Y+0.5;
780 pixelBuf[2] = 231.8181*xyz.Z+0.5;
781 return pixelBuf;
782 }
783
convertCSpaceXYZ16(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)784 static unsigned char *convertCSpaceXYZ16(unsigned char *src,
785 unsigned char *pixelBuf, unsigned int x, unsigned int y)
786 {
787 double alab[3];
788 unsigned short *sd = (unsigned short *)pixelBuf;
789
790 cmsDoTransform(colorTransform,src,alab,1);
791 cmsCIELab lab;
792 cmsCIEXYZ xyz;
793
794 lab.L = alab[0];
795 lab.a = alab[1];
796 lab.b = alab[2];
797
798 cmsLab2XYZ(&D65WhitePoint,&xyz,&lab);
799 sd[0] = 59577.2727*xyz.X+0.5;
800 sd[1] = 59577.2727*xyz.Y+0.5;
801 sd[2] = 59577.2727*xyz.Z+0.5;
802 return pixelBuf;
803 }
804
convertCSpaceLab8(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)805 static unsigned char *convertCSpaceLab8(unsigned char *src,
806 unsigned char *pixelBuf, unsigned int x, unsigned int y)
807 {
808 double lab[3];
809 cmsDoTransform(colorTransform,src,lab,1);
810 pixelBuf[0] = 2.55*lab[0]+0.5;
811 pixelBuf[1] = lab[1]+128.5;
812 pixelBuf[2] = lab[2]+128.5;
813 return pixelBuf;
814 }
815
convertCSpaceLab16(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)816 static unsigned char *convertCSpaceLab16(unsigned char *src,
817 unsigned char *pixelBuf, unsigned int x, unsigned int y)
818 {
819 double lab[3];
820 cmsDoTransform(colorTransform,src,lab,1);
821 unsigned short *sd = (unsigned short *)pixelBuf;
822 sd[0] = 655.35*lab[0]+0.5;
823 sd[1] = 256*(lab[1]+128)+0.5;
824 sd[2] = 256*(lab[2]+128)+0.5;
825 return pixelBuf;
826 }
827
RGB8toRGBA(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)828 static unsigned char *RGB8toRGBA(unsigned char *src, unsigned char *pixelBuf,
829 unsigned int x, unsigned int y)
830 {
831 unsigned char *dp = pixelBuf;
832
833 for (int i = 0;i < 3;i++) {
834 *dp++ = *src++;
835 }
836 *dp = 255;
837 return pixelBuf;
838 }
839
RGB8toRGBW(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)840 static unsigned char *RGB8toRGBW(unsigned char *src, unsigned char *pixelBuf,
841 unsigned int x, unsigned int y)
842 {
843 unsigned char cmyk[4];
844 unsigned char *dp = pixelBuf;
845
846 cupsImageRGBToCMYK(src,cmyk,1);
847 for (int i = 0;i < 4;i++) {
848 *dp++ = ~cmyk[i];
849 }
850 return pixelBuf;
851 }
852
RGB8toCMYK(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)853 static unsigned char *RGB8toCMYK(unsigned char *src, unsigned char *pixelBuf,
854 unsigned int x, unsigned int y)
855 {
856 cupsImageRGBToCMYK(src,pixelBuf,1);
857 return pixelBuf;
858 }
859
RGB8toCMY(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)860 static unsigned char *RGB8toCMY(unsigned char *src, unsigned char *pixelBuf,
861 unsigned int x, unsigned int y)
862 {
863 cupsImageRGBToCMY(src,pixelBuf,1);
864 return pixelBuf;
865 }
866
RGB8toYMC(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)867 static unsigned char *RGB8toYMC(unsigned char *src, unsigned char *pixelBuf,
868 unsigned int x, unsigned int y)
869 {
870 cupsImageRGBToCMY(src,pixelBuf,1);
871 /* swap C and Y */
872 unsigned char d = pixelBuf[0];
873 pixelBuf[0] = pixelBuf[2];
874 pixelBuf[2] = d;
875 return pixelBuf;
876 }
877
RGB8toKCMY(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)878 static unsigned char *RGB8toKCMY(unsigned char *src, unsigned char *pixelBuf,
879 unsigned int x, unsigned int y)
880 {
881 cupsImageRGBToCMYK(src,pixelBuf,1);
882 unsigned char d = pixelBuf[3];
883 pixelBuf[3] = pixelBuf[2];
884 pixelBuf[2] = pixelBuf[1];
885 pixelBuf[1] = pixelBuf[0];
886 pixelBuf[0] = d;
887 return pixelBuf;
888 }
889
RGB8toKCMYcm(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)890 static unsigned char *RGB8toKCMYcm(unsigned char *src, unsigned char *pixelBuf,
891 unsigned int x, unsigned int y)
892 {
893 unsigned char cmyk[4];
894 unsigned char c;
895 unsigned char d;
896
897 cupsImageRGBToCMYK(src,cmyk,1);
898 c = 0;
899 d = dither1[y & 0xf][x & 0xf];
900 /* K */
901 if (cmyk[3] > d) {
902 c |= 0x20;
903 }
904 /* C */
905 if (cmyk[0] > d) {
906 c |= 0x10;
907 }
908 /* M */
909 if (cmyk[1] > d) {
910 c |= 0x08;
911 }
912 /* Y */
913 if (cmyk[2] > d) {
914 c |= 0x04;
915 }
916 if (c == 0x18) { /* Blue */
917 c = 0x11; /* cyan + light magenta */
918 } else if (c == 0x14) { /* Green */
919 c = 0x06; /* light cyan + yellow */
920 }
921 *pixelBuf = c;
922 return pixelBuf;
923 }
924
RGB8toYMCK(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)925 static unsigned char *RGB8toYMCK(unsigned char *src, unsigned char *pixelBuf,
926 unsigned int x, unsigned int y)
927 {
928 cupsImageRGBToCMYK(src,pixelBuf,1);
929 /* swap C and Y */
930 unsigned char d = pixelBuf[0];
931 pixelBuf[0] = pixelBuf[2];
932 pixelBuf[2] = d;
933 return pixelBuf;
934 }
935
W8toK8(unsigned char * src,unsigned char * pixelBuf,unsigned int x,unsigned int y)936 static unsigned char *W8toK8(unsigned char *src, unsigned char *pixelBuf,
937 unsigned int x, unsigned int y)
938 {
939 *pixelBuf = ~(*src);
940 return pixelBuf;
941 }
942
convertBitsNoop(unsigned char * src,unsigned char * dst,unsigned int x,unsigned int y)943 static unsigned char *convertBitsNoop(unsigned char *src, unsigned char *dst,
944 unsigned int x, unsigned int y)
945 {
946 return src;
947 }
948
convert8to1(unsigned char * src,unsigned char * dst,unsigned int x,unsigned int y)949 static unsigned char *convert8to1(unsigned char *src, unsigned char *dst,
950 unsigned int x, unsigned int y)
951 {
952 unsigned char c = 0;
953 /* assumed that max number of colors is 4 */
954 for (unsigned int i = 0;i < header.cupsNumColors;i++) {
955 c <<= 1;
956 /* ordered dithering */
957 if (src[i] > dither1[y & 0xf][x & 0xf]) {
958 c |= 0x1;
959 }
960 }
961 *dst = c;
962 return dst;
963 }
964
convert8to2(unsigned char * src,unsigned char * dst,unsigned int x,unsigned int y)965 static unsigned char *convert8to2(unsigned char *src, unsigned char *dst,
966 unsigned int x, unsigned int y)
967 {
968 unsigned char c = 0;
969 /* assumed that max number of colors is 4 */
970 for (unsigned int i = 0;i < header.cupsNumColors;i++) {
971 unsigned int d;
972
973 c <<= 2;
974 /* ordered dithering */
975 d = src[i] + dither2[y & 0x7][x & 0x7];
976 if (d > 255) d = 255;
977 c |= d >> 6;
978 }
979 *dst = c;
980 return dst;
981 }
982
convert8to4(unsigned char * src,unsigned char * dst,unsigned int x,unsigned int y)983 static unsigned char *convert8to4(unsigned char *src, unsigned char *dst,
984 unsigned int x, unsigned int y)
985 {
986 unsigned short c = 0;
987
988 /* assumed that max number of colors is 4 */
989 for (unsigned int i = 0;i < header.cupsNumColors;i++) {
990 unsigned int d;
991
992 c <<= 4;
993 /* ordered dithering */
994 d = src[i] + dither4[y & 0x3][x & 0x3];
995 if (d > 255) d = 255;
996 c |= d >> 4;
997 }
998 if (header.cupsNumColors < 3) {
999 dst[0] = c;
1000 } else {
1001 dst[0] = c >> 8;
1002 dst[1] = c;
1003 }
1004 return dst;
1005 }
1006
convert8to16(unsigned char * src,unsigned char * dst,unsigned int x,unsigned int y)1007 static unsigned char *convert8to16(unsigned char *src, unsigned char *dst,
1008 unsigned int x, unsigned int y)
1009 {
1010 /* assumed that max number of colors is 4 */
1011 for (unsigned int i = 0;i < header.cupsNumColors;i++) {
1012 dst[i*2] = src[i];
1013 dst[i*2+1] = src[i];
1014 }
1015 return dst;
1016 }
1017
writePixel1(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1018 static void writePixel1(unsigned char *dst,
1019 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1020 {
1021 switch (header.cupsNumColors) {
1022 case 1:
1023 {
1024 unsigned int bo = pixeli & 0x7;
1025 if ((pixeli & 7) == 0) dst[pixeli/8] = 0;
1026 dst[pixeli/8] |= *pixelBuf << (7-bo);
1027 }
1028 break;
1029 case 6:
1030 dst[pixeli] = *pixelBuf;
1031 break;
1032 case 3:
1033 case 4:
1034 default:
1035 {
1036 unsigned int qo = (pixeli & 0x1)*4;
1037 if ((pixeli & 1) == 0) dst[pixeli/2] = 0;
1038 dst[pixeli/2] |= *pixelBuf << (4-qo);
1039 }
1040 break;
1041 }
1042 }
1043
writePlanePixel1(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1044 static void writePlanePixel1(unsigned char *dst,
1045 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1046 {
1047 unsigned int bo = pixeli & 0x7;
1048 unsigned char so = header.cupsNumColors - plane - 1;
1049 if ((pixeli & 7) == 0) dst[pixeli/8] = 0;
1050 dst[pixeli/8] |= ((*pixelBuf >> so) & 1) << (7-bo);
1051 }
1052
writePixel2(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1053 static void writePixel2(unsigned char *dst,
1054 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1055 {
1056 switch (header.cupsNumColors) {
1057 case 1:
1058 {
1059 unsigned int bo = (pixeli & 0x3)*2;
1060 if ((pixeli & 3) == 0) dst[pixeli/4] = 0;
1061 dst[pixeli/4] |= *pixelBuf << (6-bo);
1062 }
1063 break;
1064 case 3:
1065 case 4:
1066 default:
1067 dst[pixeli] = *pixelBuf;
1068 break;
1069 }
1070 }
1071
writePlanePixel2(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1072 static void writePlanePixel2(unsigned char *dst,
1073 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1074 {
1075 unsigned int bo = (pixeli & 0x3)*2;
1076 unsigned char so = (header.cupsNumColors - plane - 1)*2;
1077 if ((pixeli & 3) == 0) dst[pixeli/4] = 0;
1078 dst[pixeli/4] |= ((*pixelBuf >> so) & 3) << (6-bo);
1079 }
1080
writePixel4(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1081 static void writePixel4(unsigned char *dst,
1082 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1083 {
1084 switch (header.cupsNumColors) {
1085 case 1:
1086 {
1087 unsigned int bo = (pixeli & 0x1)*4;
1088 if ((pixeli & 1) == 0) dst[pixeli/2] = 0;
1089 dst[pixeli/2] |= *pixelBuf << (4-bo);
1090 }
1091 break;
1092 case 3:
1093 case 4:
1094 default:
1095 dst[pixeli*2] = pixelBuf[0];
1096 dst[pixeli*2+1] = pixelBuf[1];
1097 break;
1098 }
1099 }
1100
writePlanePixel4(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1101 static void writePlanePixel4(unsigned char *dst,
1102 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1103 {
1104 unsigned short c = (pixelBuf[0] << 8) | pixelBuf[1];
1105 unsigned int bo = (pixeli & 0x1)*4;
1106 unsigned char so = (header.cupsNumColors - plane - 1)*4;
1107 if ((pixeli & 1) == 0) dst[pixeli/2] = 0;
1108 dst[pixeli/2] |= ((c >> so) & 0xf) << (4-bo);
1109 }
1110
writePixel8(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1111 static void writePixel8(unsigned char *dst,
1112 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1113 {
1114 unsigned char *dp = dst + pixeli*header.cupsNumColors;
1115 for (unsigned int i = 0;i < header.cupsNumColors;i++) {
1116 dp[i] = pixelBuf[i];
1117 }
1118 }
1119
writePlanePixel8(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1120 static void writePlanePixel8(unsigned char *dst,
1121 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1122 {
1123 dst[pixeli] = pixelBuf[plane];
1124 }
1125
writePixel16(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1126 static void writePixel16(unsigned char *dst,
1127 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1128 {
1129 unsigned char *dp = dst + pixeli*header.cupsNumColors*2;
1130 for (unsigned int i = 0;i < header.cupsNumColors*2;i++) {
1131 dp[i] = pixelBuf[i];
1132 }
1133 }
1134
writePlanePixel16(unsigned char * dst,unsigned int plane,unsigned int pixeli,unsigned char * pixelBuf)1135 static void writePlanePixel16(unsigned char *dst,
1136 unsigned int plane, unsigned int pixeli, unsigned char *pixelBuf)
1137 {
1138 dst[pixeli*2] = pixelBuf[plane*2];
1139 dst[pixeli*2+1] = pixelBuf[plane*2+1];
1140 }
1141
convertLineChunked(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)1142 static unsigned char *convertLineChunked(unsigned char *src, unsigned char *dst,
1143 unsigned int row, unsigned int plane, unsigned int pixels,
1144 unsigned int size)
1145 {
1146 /* Assumed that BitsPerColor is 8 */
1147 for (unsigned int i = 0;i < pixels;i++) {
1148 unsigned char pixelBuf1[MAX_BYTES_PER_PIXEL];
1149 unsigned char pixelBuf2[MAX_BYTES_PER_PIXEL];
1150 unsigned char *pb;
1151
1152 pb = convertCSpace(src+i*popplerNumColors,pixelBuf1,i,row);
1153 pb = convertBits(pb,pixelBuf2,i,row);
1154 writePixel(dst,0,i,pb);
1155 }
1156 return dst;
1157 }
1158
convertLineChunkedSwap(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)1159 static unsigned char *convertLineChunkedSwap(unsigned char *src,
1160 unsigned char *dst, unsigned int row, unsigned int plane,
1161 unsigned int pixels, unsigned int size)
1162 {
1163 /* Assumed that BitsPerColor is 8 */
1164 for (unsigned int i = 0;i < pixels;i++) {
1165 unsigned char pixelBuf1[MAX_BYTES_PER_PIXEL];
1166 unsigned char pixelBuf2[MAX_BYTES_PER_PIXEL];
1167 unsigned char *pb;
1168
1169 pb = convertCSpace(src+(pixels-i-1)*popplerNumColors,pixelBuf1,i,row);
1170 pb = convertBits(pb,pixelBuf2,i,row);
1171 writePixel(dst,0,i,pb);
1172 }
1173 return dst;
1174 }
1175
convertLinePlane(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)1176 static unsigned char *convertLinePlane(unsigned char *src, unsigned char *dst,
1177 unsigned int row, unsigned int plane, unsigned int pixels,
1178 unsigned int size)
1179 {
1180 /* Assumed that BitsPerColor is 8 */
1181 for (unsigned int i = 0;i < pixels;i++) {
1182 unsigned char pixelBuf1[MAX_BYTES_PER_PIXEL];
1183 unsigned char pixelBuf2[MAX_BYTES_PER_PIXEL];
1184 unsigned char *pb;
1185
1186 pb = convertCSpace(src+i*popplerNumColors,pixelBuf1,i,row);
1187 pb = convertBits(pb,pixelBuf2,i,row);
1188 writePixel(dst,plane,i,pb);
1189 }
1190 return dst;
1191 }
1192
convertLinePlaneSwap(unsigned char * src,unsigned char * dst,unsigned int row,unsigned int plane,unsigned int pixels,unsigned int size)1193 static unsigned char *convertLinePlaneSwap(unsigned char *src,
1194 unsigned char *dst, unsigned int row, unsigned int plane,
1195 unsigned int pixels, unsigned int size)
1196 {
1197 for (unsigned int i = 0;i < pixels;i++) {
1198 unsigned char pixelBuf1[MAX_BYTES_PER_PIXEL];
1199 unsigned char pixelBuf2[MAX_BYTES_PER_PIXEL];
1200 unsigned char *pb;
1201
1202 pb = convertCSpace(src+(pixels-i-1)*popplerNumColors,pixelBuf1,i,row);
1203 pb = convertBits(pb,pixelBuf2,i,row);
1204 writePixel(dst,plane,i,pb);
1205 }
1206 return dst;
1207 }
1208
1209 /* handle special cases which are appear in gutenprint's PPDs. */
selectSpecialCase()1210 static bool selectSpecialCase()
1211 {
1212 int i;
1213
1214 for (i = 0;specialCaseFuncs[i].bitsPerPixel > 0;i++) {
1215 if (header.cupsColorSpace == specialCaseFuncs[i].cspace
1216 && header.cupsBitsPerPixel == specialCaseFuncs[i].bitsPerPixel
1217 && header.cupsBitsPerColor == specialCaseFuncs[i].bitsPerColor) {
1218 convertLineOdd = specialCaseFuncs[i].convertLine;
1219 if (header.Duplex && swap_image_x) {
1220 convertLineEven = specialCaseFuncs[i].convertLineSwap;
1221 allocLineBuf = specialCaseFuncs[i].allocLineBufSwap;
1222 } else {
1223 convertLineEven = specialCaseFuncs[i].convertLine;
1224 allocLineBuf = specialCaseFuncs[i].allocLineBuf;
1225 }
1226 return true; /* found */
1227 }
1228 }
1229 return false;
1230 }
1231
getCMSColorSpaceType(cmsColorSpaceSignature cs)1232 static unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs)
1233 {
1234 switch (cs) {
1235 case cmsSigXYZData:
1236 return PT_XYZ;
1237 break;
1238 case cmsSigLabData:
1239 return PT_Lab;
1240 break;
1241 case cmsSigLuvData:
1242 return PT_YUV;
1243 break;
1244 case cmsSigYCbCrData:
1245 return PT_YCbCr;
1246 break;
1247 case cmsSigYxyData:
1248 return PT_Yxy;
1249 break;
1250 case cmsSigRgbData:
1251 return PT_RGB;
1252 break;
1253 case cmsSigGrayData:
1254 return PT_GRAY;
1255 break;
1256 case cmsSigHsvData:
1257 return PT_HSV;
1258 break;
1259 case cmsSigHlsData:
1260 return PT_HLS;
1261 break;
1262 case cmsSigCmykData:
1263 return PT_CMYK;
1264 break;
1265 case cmsSigCmyData:
1266 return PT_CMY;
1267 break;
1268 case cmsSig2colorData:
1269 case cmsSig3colorData:
1270 case cmsSig4colorData:
1271 case cmsSig5colorData:
1272 case cmsSig6colorData:
1273 case cmsSig7colorData:
1274 case cmsSig8colorData:
1275 case cmsSig9colorData:
1276 case cmsSig10colorData:
1277 case cmsSig11colorData:
1278 case cmsSig12colorData:
1279 case cmsSig13colorData:
1280 case cmsSig14colorData:
1281 case cmsSig15colorData:
1282 default:
1283 break;
1284 }
1285 return PT_RGB;
1286 }
1287
1288 /* select convertLine function */
selectConvertFunc(cups_raster_t * raster)1289 static void selectConvertFunc(cups_raster_t *raster)
1290 {
1291 if ((colorProfile == NULL || popplerColorProfile == colorProfile)
1292 && (header.cupsColorOrder == CUPS_ORDER_CHUNKED
1293 || header.cupsNumColors == 1)) {
1294 if (selectSpecialCase()) return;
1295 }
1296
1297 switch (header.cupsColorOrder) {
1298 case CUPS_ORDER_BANDED:
1299 case CUPS_ORDER_PLANAR:
1300 if (header.cupsNumColors > 1) {
1301 convertLineEven = convertLinePlaneSwap;
1302 convertLineOdd = convertLinePlane;
1303 break;
1304 }
1305 default:
1306 case CUPS_ORDER_CHUNKED:
1307 convertLineEven = convertLineChunkedSwap;
1308 convertLineOdd = convertLineChunked;
1309 break;
1310 }
1311 if (!header.Duplex || !swap_image_x) {
1312 convertLineEven = convertLineOdd;
1313 }
1314 allocLineBuf = true;
1315
1316 if (colorProfile != NULL && popplerColorProfile != colorProfile) {
1317 unsigned int bytes;
1318
1319 switch (header.cupsColorSpace) {
1320 case CUPS_CSPACE_CIELab:
1321 case CUPS_CSPACE_ICC1:
1322 case CUPS_CSPACE_ICC2:
1323 case CUPS_CSPACE_ICC3:
1324 case CUPS_CSPACE_ICC4:
1325 case CUPS_CSPACE_ICC5:
1326 case CUPS_CSPACE_ICC6:
1327 case CUPS_CSPACE_ICC7:
1328 case CUPS_CSPACE_ICC8:
1329 case CUPS_CSPACE_ICC9:
1330 case CUPS_CSPACE_ICCA:
1331 case CUPS_CSPACE_ICCB:
1332 case CUPS_CSPACE_ICCC:
1333 case CUPS_CSPACE_ICCD:
1334 case CUPS_CSPACE_ICCE:
1335 case CUPS_CSPACE_ICCF:
1336 if (header.cupsBitsPerColor == 8) {
1337 convertCSpace = convertCSpaceLab8;
1338 } else {
1339 /* 16 bits */
1340 convertCSpace = convertCSpaceLab16;
1341 }
1342 bytes = 0; /* double */
1343 break;
1344 case CUPS_CSPACE_CIEXYZ:
1345 if (header.cupsBitsPerColor == 8) {
1346 convertCSpace = convertCSpaceXYZ8;
1347 } else {
1348 /* 16 bits */
1349 convertCSpace = convertCSpaceXYZ16;
1350 }
1351 bytes = 0; /* double */
1352 break;
1353 default:
1354 convertCSpace = convertCSpaceWithProfiles;
1355 bytes = header.cupsBitsPerColor/8;
1356 break;
1357 }
1358 convertBits = convertBitsNoop; /* convert bits in convertCSpace */
1359 if (popplerColorProfile == NULL) {
1360 popplerColorProfile = cmsCreate_sRGBProfile();
1361 }
1362 unsigned int dcst = getCMSColorSpaceType(cmsGetColorSpace(colorProfile));
1363 if ((colorTransform = cmsCreateTransform(popplerColorProfile,
1364 COLORSPACE_SH(PT_RGB) |CHANNELS_SH(3) | BYTES_SH(1),
1365 colorProfile,
1366 COLORSPACE_SH(dcst) |
1367 CHANNELS_SH(header.cupsNumColors) | BYTES_SH(bytes),
1368 renderingIntent,0)) == 0) {
1369 fprintf(stderr, "ERROR: Can't create color transform");
1370 exit(1);
1371 }
1372 } else {
1373 /* select convertCSpace function */
1374 switch (header.cupsColorSpace) {
1375 case CUPS_CSPACE_CIELab:
1376 case CUPS_CSPACE_ICC1:
1377 case CUPS_CSPACE_ICC2:
1378 case CUPS_CSPACE_ICC3:
1379 case CUPS_CSPACE_ICC4:
1380 case CUPS_CSPACE_ICC5:
1381 case CUPS_CSPACE_ICC6:
1382 case CUPS_CSPACE_ICC7:
1383 case CUPS_CSPACE_ICC8:
1384 case CUPS_CSPACE_ICC9:
1385 case CUPS_CSPACE_ICCA:
1386 case CUPS_CSPACE_ICCB:
1387 case CUPS_CSPACE_ICCC:
1388 case CUPS_CSPACE_ICCD:
1389 case CUPS_CSPACE_ICCE:
1390 case CUPS_CSPACE_ICCF:
1391 case CUPS_CSPACE_CIEXYZ:
1392 convertCSpace = convertCSpaceNone;
1393 break;
1394 case CUPS_CSPACE_CMY:
1395 convertCSpace = RGB8toCMY;
1396 break;
1397 case CUPS_CSPACE_YMC:
1398 convertCSpace = RGB8toYMC;
1399 break;
1400 case CUPS_CSPACE_CMYK:
1401 convertCSpace = RGB8toCMYK;
1402 break;
1403 case CUPS_CSPACE_KCMY:
1404 convertCSpace = RGB8toKCMY;
1405 break;
1406 case CUPS_CSPACE_KCMYcm:
1407 if (header.cupsBitsPerColor > 1) {
1408 convertCSpace = RGB8toKCMY;
1409 } else {
1410 convertCSpace = RGB8toKCMYcm;
1411 }
1412 break;
1413 case CUPS_CSPACE_GMCS:
1414 case CUPS_CSPACE_GMCK:
1415 case CUPS_CSPACE_YMCK:
1416 convertCSpace = RGB8toYMCK;
1417 break;
1418 case CUPS_CSPACE_RGBW:
1419 convertCSpace = RGB8toRGBW;
1420 break;
1421 case CUPS_CSPACE_RGBA:
1422 convertCSpace = RGB8toRGBA;
1423 break;
1424 case CUPS_CSPACE_RGB:
1425 case CUPS_CSPACE_SRGB:
1426 case CUPS_CSPACE_ADOBERGB:
1427 convertCSpace = convertCSpaceNone;
1428 break;
1429 case CUPS_CSPACE_W:
1430 case CUPS_CSPACE_SW:
1431 case CUPS_CSPACE_WHITE:
1432 convertCSpace = convertCSpaceNone;
1433 break;
1434 case CUPS_CSPACE_K:
1435 case CUPS_CSPACE_GOLD:
1436 case CUPS_CSPACE_SILVER:
1437 convertCSpace = W8toK8;
1438 break;
1439 default:
1440 fprintf(stderr, "ERROR: Specified ColorSpace is not supported\n" );
1441 exit(1);
1442 break;
1443 }
1444 /* select convertBits function */
1445 switch (header.cupsBitsPerColor) {
1446 case 2:
1447 convertBits = convert8to2;
1448 break;
1449 case 4:
1450 convertBits = convert8to4;
1451 break;
1452 case 16:
1453 convertBits = convert8to16;
1454 break;
1455 case 1:
1456 if (header.cupsNumColors == 1
1457 || header.cupsColorSpace == CUPS_CSPACE_KCMYcm) {
1458 convertBits = convertBitsNoop;
1459 } else {
1460 convertBits = convert8to1;
1461 }
1462 break;
1463 case 8:
1464 default:
1465 convertBits = convertBitsNoop;
1466 break;
1467 }
1468 }
1469 /* select writePixel function */
1470 switch (header.cupsBitsPerColor) {
1471 case 2:
1472 if (header.cupsColorOrder == CUPS_ORDER_CHUNKED
1473 || header.cupsNumColors == 1) {
1474 writePixel = writePixel2;
1475 } else {
1476 writePixel = writePlanePixel2;
1477 }
1478 break;
1479 case 4:
1480 if (header.cupsColorOrder == CUPS_ORDER_CHUNKED
1481 || header.cupsNumColors == 1) {
1482 writePixel = writePixel4;
1483 } else {
1484 writePixel = writePlanePixel4;
1485 }
1486 break;
1487 case 16:
1488 if (header.cupsColorOrder == CUPS_ORDER_CHUNKED
1489 || header.cupsNumColors == 1) {
1490 writePixel = writePixel16;
1491 } else {
1492 writePixel = writePlanePixel16;
1493 }
1494 break;
1495 case 1:
1496 if (header.cupsColorOrder == CUPS_ORDER_CHUNKED
1497 || header.cupsNumColors == 1) {
1498 writePixel = writePixel1;
1499 } else {
1500 writePixel = writePlanePixel1;
1501 }
1502 break;
1503 case 8:
1504 default:
1505 if (header.cupsColorOrder == CUPS_ORDER_CHUNKED
1506 || header.cupsNumColors == 1) {
1507 writePixel = writePixel8;
1508 } else {
1509 writePixel = writePlanePixel8;
1510 }
1511 break;
1512 }
1513 }
1514
onebitpixel(unsigned char * src,unsigned char * dst,unsigned int width,unsigned int height)1515 static unsigned char *onebitpixel(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height){
1516 unsigned char *temp;
1517 temp=dst;
1518 int cnt=0;
1519 for(unsigned int i=0;i<height;i++){
1520 for(unsigned int j=0;j<width;j+=8){
1521 unsigned char tem=0;
1522 for(int k=0;k<8;k++){
1523 cnt++;
1524 tem <<=1;
1525 unsigned int var=*src;
1526 if(var > dither1[i & 0xf][(j+k) & 0xf]){
1527 tem |= 0x1;
1528 }
1529 src +=1;
1530 }
1531 *dst=tem;
1532 dst+=1;
1533 }
1534 }
1535 return temp;
1536 }
1537
1538
removeAlpha(unsigned char * src,unsigned char * dst,unsigned int width,unsigned int height)1539 static unsigned char *removeAlpha(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height){
1540 unsigned char *temp;
1541 temp=dst;
1542 for(unsigned int i=0;i<height;i++){
1543 for(unsigned int j=0;j<width;j++){
1544 dst[0]=src[2];
1545 dst[1]=src[1];
1546 dst[2]=src[0];
1547 src+=4;
1548 dst+=3;
1549 }
1550 }
1551 return temp;
1552 }
1553
writePageImage(cups_raster_t * raster,poppler::document * doc,int pageNo)1554 static void writePageImage(cups_raster_t *raster, poppler::document *doc,
1555 int pageNo)
1556 {
1557 ConvertLineFunc convertLine;
1558 unsigned char *lineBuf = NULL;
1559 unsigned char *dp;
1560 unsigned int rowsize;
1561
1562 poppler::page *current_page =doc->create_page(pageNo-1);
1563 poppler::page_renderer pr;
1564 pr.set_render_hint(poppler::page_renderer::antialiasing, true);
1565 pr.set_render_hint(poppler::page_renderer::text_antialiasing, true);
1566
1567 unsigned char *colordata,*newdata,*graydata,*onebitdata;
1568 unsigned int pixel_count;
1569 poppler::image im;
1570 //render the page according to the colourspace and generate the requried data
1571 switch (header.cupsColorSpace) {
1572 case CUPS_CSPACE_W://gray
1573 case CUPS_CSPACE_K://black
1574 case CUPS_CSPACE_SW://sgray
1575 if(header.cupsBitsPerColor==1){ //special case for 1-bit colorspaces
1576 im = pr.render_page(current_page,header.HWResolution[0],header.HWResolution[1],bitmapoffset[0],bitmapoffset[1],bytesPerLine*8,header.cupsHeight);
1577 newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
1578 newdata = removeAlpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
1579 graydata=(unsigned char *)malloc(sizeof(char)*im.width()*im.height());
1580 cupsImageRGBToWhite(newdata,graydata,im.width()*im.height());
1581 onebitdata=(unsigned char *)malloc(sizeof(char)*bytesPerLine*im.height());
1582 onebitpixel(graydata,onebitdata,im.width(),im.height());
1583 colordata=onebitdata;
1584 rowsize=bytesPerLine;
1585 }
1586 else{
1587 im = pr.render_page(current_page,header.HWResolution[0],header.HWResolution[1],bitmapoffset[0],bitmapoffset[1],header.cupsWidth,header.cupsHeight);
1588 newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
1589 newdata = removeAlpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
1590 pixel_count=im.width()*im.height();
1591 graydata=(unsigned char *)malloc(sizeof(char)*im.width()*im.height());
1592 cupsImageRGBToWhite(newdata,graydata,pixel_count);
1593 colordata=graydata;
1594 rowsize=header.cupsWidth;
1595 }
1596
1597 break;
1598 case CUPS_CSPACE_RGB:
1599 case CUPS_CSPACE_ADOBERGB:
1600 case CUPS_CSPACE_CMYK:
1601 case CUPS_CSPACE_SRGB:
1602 case CUPS_CSPACE_CMY:
1603 case CUPS_CSPACE_RGBW:
1604 default:
1605 im = pr.render_page(current_page,header.HWResolution[0],header.HWResolution[1],bitmapoffset[0],bitmapoffset[1],header.cupsWidth,header.cupsHeight);
1606 newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
1607 newdata = removeAlpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
1608 pixel_count=im.width()*im.height();
1609 rowsize=header.cupsWidth*3;
1610 colordata=newdata;
1611 break;
1612 }
1613
1614
1615 if (allocLineBuf) lineBuf = new unsigned char [bytesPerLine];
1616 if ((pageNo & 1) == 0) {
1617 convertLine = convertLineEven;
1618 } else {
1619 convertLine = convertLineOdd;
1620 }
1621 if (header.Duplex && (pageNo & 1) == 0 && swap_image_y) {
1622 for (unsigned int plane = 0;plane < nplanes;plane++) {
1623 unsigned char *bp = colordata + (header.cupsHeight - 1) * rowsize;
1624
1625 for (unsigned int h = header.cupsHeight;h > 0;h--) {
1626 for (unsigned int band = 0;band < nbands;band++) {
1627 dp = convertLine(bp,lineBuf,h - 1,plane+band,header.cupsWidth,
1628 bytesPerLine);
1629 cupsRasterWritePixels(raster,dp,bytesPerLine);
1630 }
1631 bp -= rowsize;
1632 }
1633 }
1634 } else {
1635 for (unsigned int plane = 0;plane < nplanes;plane++) {
1636 unsigned char *bp = colordata;
1637
1638 for (unsigned int h = 0;h < header.cupsHeight;h++) {
1639 for (unsigned int band = 0;band < nbands;band++) {
1640 dp = convertLine(bp,lineBuf,h,plane+band,header.cupsWidth,
1641 bytesPerLine);
1642 cupsRasterWritePixels(raster,dp,bytesPerLine);
1643 }
1644 bp += rowsize;
1645 }
1646 }
1647 }
1648 free(colordata);
1649 if (allocLineBuf) delete[] lineBuf;
1650 }
1651
outPage(poppler::document * doc,int pageNo,cups_raster_t * raster)1652 static void outPage(poppler::document *doc, int pageNo,
1653 cups_raster_t *raster)
1654 {
1655 int rotate = 0;
1656 double paperdimensions[2], /* Physical size of the paper */
1657 margins[4]; /* Physical margins of print */
1658 ppd_size_t *size; /* Page size */
1659 ppd_size_t *size_matched = NULL;
1660 double l, swap;
1661 int imageable_area_fit = 0;
1662 int i;
1663
1664 poppler::page *current_page =doc->create_page(pageNo-1);
1665 poppler::page_box_enum box = poppler::page_box_enum::media_box;
1666 poppler::rectf mediaBox = current_page->page_rect(box);
1667 poppler::page::orientation_enum orient = current_page->orientation();
1668 switch (orient) {
1669 case poppler::page::landscape: rotate=90;
1670 break;
1671 case poppler::page::upside_down: rotate=180;
1672 break;
1673 case poppler::page::seascape: rotate=270;
1674 break;
1675 default:rotate=0;
1676 }
1677 fprintf(stderr, "DEBUG: mediaBox = [ %f %f %f %f ]; rotate = %d\n",
1678 mediaBox.left(), mediaBox.top(), mediaBox.right(), mediaBox.bottom(), rotate);
1679 l = mediaBox.width();
1680 if (l < 0) l = -l;
1681 if (rotate == 90 || rotate == 270)
1682 header.PageSize[1] = (unsigned)l;
1683 else
1684 header.PageSize[0] = (unsigned)l;
1685 l = mediaBox.height();
1686 if (l < 0) l = -l;
1687 if (rotate == 90 || rotate == 270)
1688 header.PageSize[0] = (unsigned)l;
1689 else
1690 header.PageSize[1] = (unsigned)l;
1691
1692 memset(paperdimensions, 0, sizeof(paperdimensions));
1693 memset(margins, 0, sizeof(margins));
1694 if (ppd) {
1695 imageable_area_fit = 0;
1696 size_matched = NULL;
1697 for (i = ppd->num_sizes, size = ppd->sizes;
1698 i > 0;
1699 i --, size ++)
1700 /* Skip page sizes which conflict with settings of the other options */
1701 /* TODO XXX */
1702 /* Find size of document's page under the PPD page sizes */
1703 if (fabs(header.PageSize[1] - size->length) / size->length < 0.01 &&
1704 fabs(header.PageSize[0] - size->width) / size->width < 0.01 &&
1705 (size_matched == NULL ||
1706 !strcasecmp(pageSizeRequested, size->name)))
1707 size_matched = size;
1708 if (size_matched == NULL)
1709 /* Input page size does not fit any of the PPD's sizes, try to fit
1710 the input page size into the imageable areas of the PPD's sizes */
1711 for (i = ppd->num_sizes, size = ppd->sizes;
1712 i > 0;
1713 i --, size ++)
1714 if (fabs(header.PageSize[1] - size->top + size->bottom) /
1715 size->length < 0.01 &&
1716 fabs(header.PageSize[0] - size->right + size->left) /
1717 size->width < 0.01 &&
1718 (size_matched == NULL ||
1719 !strcasecmp(pageSizeRequested, size->name))) {
1720 fprintf(stderr, "DEBUG: Imageable area fit\n");
1721 imageable_area_fit = 1;
1722 size_matched = size;
1723 }
1724 if (size_matched) {
1725 /*
1726 * Standard size...
1727 */
1728 size = size_matched;
1729 fprintf(stderr, "DEBUG: size = %s\n", size->name);
1730 paperdimensions[0] = size->width;
1731 paperdimensions[1] = size->length;
1732 if (pwgraster == 0) {
1733 margins[0] = size->left;
1734 margins[1] = size->bottom;
1735 margins[2] = size->width - size->right;
1736 margins[3] = size->length - size->top;
1737 }
1738 strncpy(header.cupsPageSizeName, size->name, 64);
1739 } else {
1740 /*
1741 * No matching portrait size; look for a matching size in
1742 * landscape orientation...
1743 */
1744
1745 imageable_area_fit = 0;
1746 size_matched = 0;
1747 for (i = ppd->num_sizes, size = ppd->sizes;
1748 i > 0;
1749 i --, size ++)
1750 if (fabs(header.PageSize[0] - size->length) / size->length < 0.01 &&
1751 fabs(header.PageSize[1] - size->width) / size->width < 0.01 &&
1752 (size_matched == NULL ||
1753 !strcasecmp(pageSizeRequested, size->name)))
1754 size_matched = size;
1755 if (size_matched == NULL)
1756 /* Input page size does not fit any of the PPD's sizes, try to fit
1757 the input page size into the imageable areas of the PPD's sizes */
1758 for (i = ppd->num_sizes, size = ppd->sizes;
1759 i > 0;
1760 i --, size ++)
1761 if (fabs(header.PageSize[0] - size->top + size->bottom) /
1762 size->length < 0.01 &&
1763 fabs(header.PageSize[1] - size->right + size->left) /
1764 size->width < 0.01 &&
1765 (size_matched == NULL ||
1766 !strcasecmp(pageSizeRequested, size->name))) {
1767 fprintf(stderr, "DEBUG: Imageable area fit\n");
1768 imageable_area_fit = 1;
1769 size_matched = size;
1770 }
1771 if (size_matched) {
1772 /*
1773 * Standard size in landscape orientation...
1774 */
1775 size = size_matched;
1776 fprintf(stderr, "DEBUG: landscape size = %s\n", size->name);
1777 paperdimensions[0] = size->width;
1778 paperdimensions[1] = size->length;
1779 if (pwgraster == 0) {
1780 margins[0] = size->left;
1781 margins[1] = size->bottom;
1782 margins[2] = size->width - size->right;
1783 margins[3] = size->length - size->top;
1784 }
1785 strncpy(header.cupsPageSizeName, size->name, 64);
1786 } else {
1787 /*
1788 * Custom size...
1789 */
1790 fprintf(stderr, "DEBUG: size = Custom\n");
1791 paperdimensions[1] = size->length;
1792 for (i = 0; i < 2; i ++)
1793 paperdimensions[i] = header.PageSize[i];
1794 if (pwgraster == 0)
1795 for (i = 0; i < 4; i ++)
1796 margins[i] = ppd->custom_margins[i];
1797 snprintf(header.cupsPageSizeName, 64,
1798 "Custom.%dx%d",
1799 header.PageSize[0], header.PageSize[1]);
1800 }
1801 }
1802 } else {
1803 for (i = 0; i < 2; i ++)
1804 paperdimensions[i] = header.PageSize[i];
1805 if (header.cupsImagingBBox[3] > 0.0) {
1806 /* Set margins if we have a bounding box defined ... */
1807 if (pwgraster == 0) {
1808 margins[0] = header.cupsImagingBBox[0];
1809 margins[1] = header.cupsImagingBBox[1];
1810 margins[2] = paperdimensions[0] - header.cupsImagingBBox[2];
1811 margins[3] = paperdimensions[1] - header.cupsImagingBBox[3];
1812 }
1813 } else
1814 /* ... otherwise use zero margins */
1815 for (i = 0; i < 4; i ++)
1816 margins[i] = 0.0;
1817 /*margins[0] = 0.0;
1818 margins[1] = 0.0;
1819 margins[2] = header.PageSize[0];
1820 margins[3] = header.PageSize[1];*/
1821 }
1822
1823 if (header.Duplex && (pageNo & 1) == 0) {
1824 /* backside: change margin if needed */
1825 if (swap_margin_x) {
1826 swap = margins[2]; margins[2] = margins[0]; margins[0] = swap;
1827 }
1828 if (swap_margin_y) {
1829 swap = margins[3]; margins[3] = margins[1]; margins[1] = swap;
1830 }
1831 }
1832
1833 if (imageable_area_fit == 0) {
1834 bitmapoffset[0] = margins[0] / 72.0 * header.HWResolution[0];
1835 bitmapoffset[1] = margins[3] / 72.0 * header.HWResolution[1];
1836 } else {
1837 bitmapoffset[0] = 0;
1838 bitmapoffset[1] = 0;
1839 }
1840
1841 /* write page header */
1842 if (pwgraster == 0) {
1843 header.cupsWidth = ((paperdimensions[0] - margins[0] - margins[2]) /
1844 72.0 * header.HWResolution[0]) + 0.5;
1845 header.cupsHeight = ((paperdimensions[1] - margins[1] - margins[3]) /
1846 72.0 * header.HWResolution[1]) + 0.5;
1847 } else {
1848 header.cupsWidth = (paperdimensions[0] /
1849 72.0 * header.HWResolution[0]) + 0.5;
1850 header.cupsHeight = (paperdimensions[1] /
1851 72.0 * header.HWResolution[1]) + 0.5;
1852 }
1853 for (i = 0; i < 2; i ++) {
1854 header.cupsPageSize[i] = paperdimensions[i];
1855 header.PageSize[i] = (unsigned int)(header.cupsPageSize[i] + 0.5);
1856 if (pwgraster == 0)
1857 header.Margins[i] = margins[i] + 0.5;
1858 else
1859 header.Margins[i] = 0;
1860 }
1861 if (pwgraster == 0) {
1862 header.cupsImagingBBox[0] = margins[0];
1863 header.cupsImagingBBox[1] = margins[1];
1864 header.cupsImagingBBox[2] = paperdimensions[0] - margins[2];
1865 header.cupsImagingBBox[3] = paperdimensions[1] - margins[3];
1866 for (i = 0; i < 4; i ++)
1867 header.ImagingBoundingBox[i] =
1868 (unsigned int)(header.cupsImagingBBox[i] + 0.5);
1869 } else
1870 for (i = 0; i < 4; i ++) {
1871 header.cupsImagingBBox[i] = 0.0;
1872 header.ImagingBoundingBox[i] = 0;
1873 }
1874
1875 bytesPerLine = header.cupsBytesPerLine = (header.cupsBitsPerPixel *
1876 header.cupsWidth + 7) / 8;
1877 if (header.cupsColorOrder == CUPS_ORDER_BANDED) {
1878 header.cupsBytesPerLine *= header.cupsNumColors;
1879 }
1880 if (!cupsRasterWriteHeader2(raster,&header)) {
1881 fprintf(stderr, "ERROR: Can't write page %d header\n",pageNo );
1882 exit(1);
1883 }
1884
1885 /* write page image */
1886 writePageImage(raster,doc,pageNo);
1887 }
1888
setPopplerColorProfile()1889 static void setPopplerColorProfile()
1890 {
1891 if (header.cupsBitsPerColor != 8 && header.cupsBitsPerColor != 16) {
1892 /* color Profile is not supported */
1893 return;
1894 }
1895 /* set poppler color profile */
1896 switch (header.cupsColorSpace) {
1897 case CUPS_CSPACE_CIELab:
1898 case CUPS_CSPACE_ICC1:
1899 case CUPS_CSPACE_ICC2:
1900 case CUPS_CSPACE_ICC3:
1901 case CUPS_CSPACE_ICC4:
1902 case CUPS_CSPACE_ICC5:
1903 case CUPS_CSPACE_ICC6:
1904 case CUPS_CSPACE_ICC7:
1905 case CUPS_CSPACE_ICC8:
1906 case CUPS_CSPACE_ICC9:
1907 case CUPS_CSPACE_ICCA:
1908 case CUPS_CSPACE_ICCB:
1909 case CUPS_CSPACE_ICCC:
1910 case CUPS_CSPACE_ICCD:
1911 case CUPS_CSPACE_ICCE:
1912 case CUPS_CSPACE_ICCF:
1913 if (colorProfile == NULL) {
1914 cmsCIExyY wp;
1915 #ifdef USE_LCMS1
1916 cmsWhitePointFromTemp(6504,&wp); /* D65 White point */
1917 #else
1918 cmsWhitePointFromTemp(&wp,6504); /* D65 White point */
1919 #endif
1920 colorProfile = cmsCreateLab4Profile(&wp);
1921 }
1922 break;
1923 case CUPS_CSPACE_CIEXYZ:
1924 if (colorProfile == NULL) {
1925 /* tansform color space via CIELab */
1926 cmsCIExyY wp;
1927 #ifdef USE_LCMS1
1928 cmsWhitePointFromTemp(6504,&wp); /* D65 White point */
1929 #else
1930 cmsWhitePointFromTemp(&wp,6504); /* D65 White point */
1931 #endif
1932 cmsxyY2XYZ(&D65WhitePoint,&wp);
1933 colorProfile = cmsCreateLab4Profile(&wp);
1934 }
1935 break;
1936 case CUPS_CSPACE_SRGB:
1937 colorProfile = cmsCreate_sRGBProfile();
1938 break;
1939 case CUPS_CSPACE_ADOBERGB:
1940 colorProfile = adobergb_profile();
1941 break;
1942 case CUPS_CSPACE_SW:
1943 colorProfile = sgray_profile();
1944 break;
1945 case CUPS_CSPACE_RGB:
1946 case CUPS_CSPACE_K:
1947 case CUPS_CSPACE_W:
1948 case CUPS_CSPACE_WHITE:
1949 case CUPS_CSPACE_GOLD:
1950 case CUPS_CSPACE_SILVER:
1951 /* We can set specified profile to poppler profile */
1952 popplerColorProfile = colorProfile;
1953 break;
1954 case CUPS_CSPACE_CMYK:
1955 case CUPS_CSPACE_KCMY:
1956 case CUPS_CSPACE_KCMYcm:
1957 case CUPS_CSPACE_YMCK:
1958 case CUPS_CSPACE_RGBA:
1959 case CUPS_CSPACE_RGBW:
1960 case CUPS_CSPACE_GMCK:
1961 case CUPS_CSPACE_GMCS:
1962 case CUPS_CSPACE_CMY:
1963 case CUPS_CSPACE_YMC:
1964 /* use standard RGB */
1965 popplerColorProfile = NULL;
1966 break;
1967 default:
1968 fprintf(stderr, "ERROR: Specified ColorSpace is not supported\n" );
1969 exit(1);
1970 break;
1971 }
1972 }
1973
main(int argc,char * argv[])1974 int main(int argc, char *argv[]) {
1975 poppler::document *doc;
1976 int i;
1977 int npages=0;
1978 cups_raster_t *raster;
1979
1980 cmsSetLogErrorHandler(lcmsErrorHandler);
1981 parseOpts(argc, argv);
1982
1983 if (argc == 6) {
1984 /* stdin */
1985 int fd;
1986 char name[BUFSIZ];
1987 char buf[BUFSIZ];
1988 int n;
1989
1990 fd = cupsTempFd(name,sizeof(name));
1991 if (fd < 0) {
1992 fprintf(stderr, "ERROR: Can't create temporary file\n");
1993 exit(1);
1994 }
1995
1996 /* copy stdin to the tmp file */
1997 while ((n = read(0,buf,BUFSIZ)) > 0) {
1998 if (write(fd,buf,n) != n) {
1999 fprintf(stderr, "ERROR: Can't copy stdin to temporary file\n" );
2000 close(fd);
2001 exit(1);
2002 }
2003 }
2004 close(fd);
2005 doc=poppler::document::load_from_file(name,"","");
2006 /* remove name */
2007 unlink(name);
2008 } else {
2009 /* argc == 7 filenmae is specified */
2010 FILE *fp;
2011
2012 if ((fp = fopen(argv[6],"rb")) == 0) {
2013 fprintf(stderr, "ERROR: Can't open input file %s\n",argv[6]);
2014 exit(1);
2015 }
2016 parsePDFTOPDFComment(fp);
2017 fclose(fp);
2018 doc=poppler::document::load_from_file(argv[6],"","");
2019 }
2020
2021 if(doc != NULL)
2022 npages = doc->pages();
2023
2024 /* fix NumCopies, Collate ccording to PDFTOPDFComments */
2025 header.NumCopies = deviceCopies;
2026 header.Collate = deviceCollate ? CUPS_TRUE : CUPS_FALSE;
2027 /* fixed other values that pdftopdf handles */
2028 header.MirrorPrint = CUPS_FALSE;
2029 header.Orientation = CUPS_ORIENT_0;
2030
2031 if (header.cupsBitsPerColor != 1
2032 && header.cupsBitsPerColor != 2
2033 && header.cupsBitsPerColor != 4
2034 && header.cupsBitsPerColor != 8
2035 && header.cupsBitsPerColor != 16) {
2036 fprintf(stderr, "ERROR: Specified color format is not supported\n");
2037 exit(1);
2038 }
2039 if (header.cupsColorOrder == CUPS_ORDER_PLANAR) {
2040 nplanes = header.cupsNumColors;
2041 } else {
2042 nplanes = 1;
2043 }
2044 if (header.cupsColorOrder == CUPS_ORDER_BANDED) {
2045 nbands = header.cupsNumColors;
2046 } else {
2047 nbands = 1;
2048 }
2049 /* set image's values */
2050 switch (header.cupsColorSpace) {
2051 case CUPS_CSPACE_CIELab:
2052 case CUPS_CSPACE_ICC1:
2053 case CUPS_CSPACE_ICC2:
2054 case CUPS_CSPACE_ICC3:
2055 case CUPS_CSPACE_ICC4:
2056 case CUPS_CSPACE_ICC5:
2057 case CUPS_CSPACE_ICC6:
2058 case CUPS_CSPACE_ICC7:
2059 case CUPS_CSPACE_ICC8:
2060 case CUPS_CSPACE_ICC9:
2061 case CUPS_CSPACE_ICCA:
2062 case CUPS_CSPACE_ICCB:
2063 case CUPS_CSPACE_ICCC:
2064 case CUPS_CSPACE_ICCD:
2065 case CUPS_CSPACE_ICCE:
2066 case CUPS_CSPACE_ICCF:
2067 case CUPS_CSPACE_CIEXYZ:
2068 if (header.cupsColorOrder != CUPS_ORDER_CHUNKED
2069 || (header.cupsBitsPerColor != 8
2070 && header.cupsBitsPerColor != 16)) {
2071 fprintf(stderr, "ERROR: Specified color format is not supported\n");
2072 exit(1);
2073 }
2074 case CUPS_CSPACE_RGB:
2075 case CUPS_CSPACE_SRGB:
2076 case CUPS_CSPACE_ADOBERGB:
2077 case CUPS_CSPACE_CMY:
2078 case CUPS_CSPACE_YMC:
2079 case CUPS_CSPACE_CMYK:
2080 case CUPS_CSPACE_KCMY:
2081 case CUPS_CSPACE_KCMYcm:
2082 case CUPS_CSPACE_YMCK:
2083 case CUPS_CSPACE_RGBA:
2084 case CUPS_CSPACE_RGBW:
2085 case CUPS_CSPACE_GMCK:
2086 case CUPS_CSPACE_GMCS:
2087 popplerBitsPerPixel = 24;
2088 popplerNumColors = 3;
2089 break;
2090 case CUPS_CSPACE_K:
2091 case CUPS_CSPACE_W:
2092 case CUPS_CSPACE_SW:
2093 case CUPS_CSPACE_WHITE:
2094 case CUPS_CSPACE_GOLD:
2095 case CUPS_CSPACE_SILVER:
2096 if (header.cupsBitsPerColor == 1
2097 && header.cupsBitsPerPixel == 1) {
2098 popplerBitsPerPixel = 1;
2099 } else {
2100 popplerBitsPerPixel = 8;
2101 }
2102 /* set paper color white */
2103 popplerNumColors = 1;
2104 break;
2105 default:
2106 fprintf(stderr, "ERROR: Specified ColorSpace is not supported\n");
2107 exit(1);
2108 break;
2109 }
2110
2111 if (!cm_disabled) {
2112 setPopplerColorProfile();
2113 }
2114
2115 if ((raster = cupsRasterOpen(1, pwgraster ? CUPS_RASTER_WRITE_PWG :
2116 CUPS_RASTER_WRITE)) == 0) {
2117 fprintf(stderr, "ERROR: Can't open raster stream\n");
2118 exit(1);
2119 }
2120 selectConvertFunc(raster);
2121 if(doc != NULL){
2122 for (i = 1;i <= npages;i++) {
2123 outPage(doc,i,raster);
2124 }
2125 } else
2126 fprintf(stderr, "DEBUG: Input is empty, outputting empty file.\n");
2127
2128 cupsRasterClose(raster);
2129
2130 delete doc;
2131 if (ppd != NULL) {
2132 ppdClose(ppd);
2133 }
2134 if (colorProfile != NULL) {
2135 cmsCloseProfile(colorProfile);
2136 }
2137 if (popplerColorProfile != NULL && popplerColorProfile != colorProfile) {
2138 cmsCloseProfile(popplerColorProfile);
2139 }
2140 if (colorTransform != NULL) {
2141 cmsDeleteTransform(colorTransform);
2142 }
2143
2144 return exitCode;
2145 }
2146
2147 /* replace memory allocation methods for memory check */
2148 /* For compatibility with g++ >= 4.7 compilers _GLIBCXX_THROW
2149 * should be used as a guard, otherwise use traditional definition */
2150 #ifndef _GLIBCXX_THROW
2151 #define _GLIBCXX_THROW throw
2152 #endif
2153
operator new(size_t size)2154 void * operator new(size_t size) _GLIBCXX_THROW (std::bad_alloc)
2155 {
2156 return malloc(size);
2157 }
2158
operator delete(void * p)2159 void operator delete(void *p) throw ()
2160 {
2161 free(p);
2162 }
2163
operator new[](size_t size)2164 void * operator new[](size_t size) _GLIBCXX_THROW (std::bad_alloc)
2165 {
2166 return malloc(size);
2167 }
2168
operator delete[](void * p)2169 void operator delete[](void *p) throw ()
2170 {
2171 free(p);
2172 }
2173