• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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