2 * CUPS raster to PWG raster format filter for CUPS.
4 * Copyright 2011, 2014-2017 Apple Inc.
6 * These coded instructions, statements, and computer programs are the
7 * property of Apple Inc. and are protected by Federal copyright law.
8 * Distribution and use rights are outlined in the file "LICENSE.txt"
9 * which should have been included with this file. If this file is
10 * missing or damaged, see the license at "http://www.cups.org/".
14 * Include necessary headers...
17 #include <cups/cups-private.h>
18 #include <cups/ppd-private.h>
19 #include <cups/raster.h>
25 * 'main()' - Main entry for filter.
28 int /* O - Exit status */
29 main(int argc
, /* I - Number of command-line args */
30 char *argv
[]) /* I - Command-line arguments */
32 const char *final_content_type
;
33 /* FINAL_CONTENT_TYPE env var */
34 int fd
; /* Raster file */
35 cups_raster_t
*inras
, /* Input raster stream */
36 *outras
; /* Output raster stream */
37 cups_page_header2_t inheader
, /* Input raster page header */
38 outheader
; /* Output raster page header */
39 unsigned y
; /* Current line */
40 unsigned char *line
; /* Line buffer */
41 unsigned page
= 0, /* Current page */
42 page_width
, /* Actual page width */
43 page_height
, /* Actual page height */
44 page_top
, /* Top margin */
45 page_bottom
, /* Bottom margin */
46 page_left
, /* Left margin */
47 linesize
, /* Bytes per line */
48 lineoffset
; /* Offset into line */
49 unsigned char white
; /* White pixel */
50 ppd_file_t
*ppd
; /* PPD file */
51 ppd_attr_t
*back
; /* cupsBackSide attribute */
52 _ppd_cache_t
*cache
; /* PPD cache */
53 pwg_size_t
*pwg_size
; /* PWG media size */
54 pwg_media_t
*pwg_media
; /* PWG media name */
55 int num_options
; /* Number of options */
56 cups_option_t
*options
= NULL
;/* Options */
57 const char *val
; /* Option value */
60 if (argc
< 6 || argc
> 7)
62 puts("Usage: rastertopwg job user title copies options [filename]");
67 if ((fd
= open(argv
[6], O_RDONLY
)) < 0)
69 perror("ERROR: Unable to open print file");
76 if ((final_content_type
= getenv("FINAL_CONTENT_TYPE")) == NULL
)
77 final_content_type
= "image/pwg-raster";
79 inras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
80 outras
= cupsRasterOpen(1, !strcmp(final_content_type
, "image/pwg-raster") ? CUPS_RASTER_WRITE_PWG
: CUPS_RASTER_WRITE_APPLE
);
82 ppd
= ppdOpenFile(getenv("PPD"));
83 back
= ppdFindAttr(ppd
, "cupsBackSide", NULL
);
85 num_options
= cupsParseOptions(argv
[5], 0, &options
);
88 cupsMarkOptions(ppd
, num_options
, options
);
90 cache
= ppd
? ppd
->cache
: NULL
;
92 while (cupsRasterReadHeader2(inras
, &inheader
))
95 * Show page device dictionary...
98 fprintf(stderr
, "DEBUG: Duplex = %d\n", inheader
.Duplex
);
99 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", inheader
.HWResolution
[0], inheader
.HWResolution
[1]);
100 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", inheader
.ImagingBoundingBox
[0], inheader
.ImagingBoundingBox
[1], inheader
.ImagingBoundingBox
[2], inheader
.ImagingBoundingBox
[3]);
101 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", inheader
.Margins
[0], inheader
.Margins
[1]);
102 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", inheader
.ManualFeed
);
103 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", inheader
.MediaPosition
);
104 fprintf(stderr
, "DEBUG: NumCopies = %d\n", inheader
.NumCopies
);
105 fprintf(stderr
, "DEBUG: Orientation = %d\n", inheader
.Orientation
);
106 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", inheader
.PageSize
[0], inheader
.PageSize
[1]);
107 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", inheader
.cupsWidth
);
108 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", inheader
.cupsHeight
);
109 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", inheader
.cupsMediaType
);
110 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", inheader
.cupsBitsPerColor
);
111 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", inheader
.cupsBitsPerPixel
);
112 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", inheader
.cupsBytesPerLine
);
113 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", inheader
.cupsColorOrder
);
114 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", inheader
.cupsColorSpace
);
115 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", inheader
.cupsCompression
);
118 * Compute the real raster size...
123 fprintf(stderr
, "PAGE: %d %d\n", page
, inheader
.NumCopies
);
125 page_width
= (unsigned)(inheader
.cupsPageSize
[0] * inheader
.HWResolution
[0] / 72.0);
126 page_height
= (unsigned)(inheader
.cupsPageSize
[1] * inheader
.HWResolution
[1] / 72.0);
127 page_left
= (unsigned)(inheader
.cupsImagingBBox
[0] * inheader
.HWResolution
[0] / 72.0);
128 page_bottom
= (unsigned)(inheader
.cupsImagingBBox
[1] * inheader
.HWResolution
[1] / 72.0);
129 page_top
= page_height
- page_bottom
- inheader
.cupsHeight
;
130 linesize
= (page_width
* inheader
.cupsBitsPerPixel
+ 7) / 8;
131 lineoffset
= page_left
* inheader
.cupsBitsPerPixel
/ 8; /* Round down */
133 if (page_left
> page_width
|| page_top
> page_height
|| page_bottom
> page_height
)
135 _cupsLangPrintFilter(stderr
, "ERROR", _("Unsupported raster data."));
136 fprintf(stderr
, "DEBUG: Bad bottom/left/top margin on page %d.\n", page
);
140 switch (inheader
.cupsColorSpace
)
143 case CUPS_CSPACE_RGB
:
144 case CUPS_CSPACE_SW
:
145 case CUPS_CSPACE_SRGB
:
146 case CUPS_CSPACE_ADOBERGB
:
151 case CUPS_CSPACE_CMYK
:
152 case CUPS_CSPACE_DEVICE1
:
153 case CUPS_CSPACE_DEVICE2
:
154 case CUPS_CSPACE_DEVICE3
:
155 case CUPS_CSPACE_DEVICE4
:
156 case CUPS_CSPACE_DEVICE5
:
157 case CUPS_CSPACE_DEVICE6
:
158 case CUPS_CSPACE_DEVICE7
:
159 case CUPS_CSPACE_DEVICE8
:
160 case CUPS_CSPACE_DEVICE9
:
161 case CUPS_CSPACE_DEVICEA
:
162 case CUPS_CSPACE_DEVICEB
:
163 case CUPS_CSPACE_DEVICEC
:
164 case CUPS_CSPACE_DEVICED
:
165 case CUPS_CSPACE_DEVICEE
:
166 case CUPS_CSPACE_DEVICEF
:
171 _cupsLangPrintFilter(stderr
, "ERROR", _("Unsupported raster data."));
172 fprintf(stderr
, "DEBUG: Unsupported cupsColorSpace %d on page %d.\n",
173 inheader
.cupsColorSpace
, page
);
177 if (inheader
.cupsColorOrder
!= CUPS_ORDER_CHUNKED
)
179 _cupsLangPrintFilter(stderr
, "ERROR", _("Unsupported raster data."));
180 fprintf(stderr
, "DEBUG: Unsupported cupsColorOrder %d on page %d.\n",
181 inheader
.cupsColorOrder
, page
);
185 if (inheader
.cupsBitsPerPixel
!= 1 &&
186 inheader
.cupsBitsPerColor
!= 8 && inheader
.cupsBitsPerColor
!= 16)
188 _cupsLangPrintFilter(stderr
, "ERROR", _("Unsupported raster data."));
189 fprintf(stderr
, "DEBUG: Unsupported cupsBitsPerColor %d on page %d.\n",
190 inheader
.cupsBitsPerColor
, page
);
194 memcpy(&outheader
, &inheader
, sizeof(outheader
));
195 outheader
.cupsWidth
= page_width
;
196 outheader
.cupsHeight
= page_height
;
197 outheader
.cupsBytesPerLine
= linesize
;
199 outheader
.cupsInteger
[14] = 0; /* VendorIdentifier */
200 outheader
.cupsInteger
[15] = 0; /* VendorLength */
202 if ((val
= cupsGetOption("print-content-optimize", num_options
,
205 if (!strcmp(val
, "automatic"))
206 strlcpy(outheader
.OutputType
, "Automatic",
207 sizeof(outheader
.OutputType
));
208 else if (!strcmp(val
, "graphics"))
209 strlcpy(outheader
.OutputType
, "Graphics", sizeof(outheader
.OutputType
));
210 else if (!strcmp(val
, "photo"))
211 strlcpy(outheader
.OutputType
, "Photo", sizeof(outheader
.OutputType
));
212 else if (!strcmp(val
, "text"))
213 strlcpy(outheader
.OutputType
, "Text", sizeof(outheader
.OutputType
));
214 else if (!strcmp(val
, "text-and-graphics"))
215 strlcpy(outheader
.OutputType
, "TextAndGraphics",
216 sizeof(outheader
.OutputType
));
219 fputs("DEBUG: Unsupported print-content-optimize value.\n", stderr
);
220 outheader
.OutputType
[0] = '\0';
224 if ((val
= cupsGetOption("print-quality", num_options
, options
)) != NULL
)
226 unsigned quality
= (unsigned)atoi(val
); /* print-quality value */
228 if (quality
>= IPP_QUALITY_DRAFT
&& quality
<= IPP_QUALITY_HIGH
)
229 outheader
.cupsInteger
[8] = quality
;
232 fprintf(stderr
, "DEBUG: Unsupported print-quality %d.\n", quality
);
233 outheader
.cupsInteger
[8] = 0;
237 if ((val
= cupsGetOption("print-rendering-intent", num_options
,
240 if (!strcmp(val
, "absolute"))
241 strlcpy(outheader
.cupsRenderingIntent
, "Absolute",
242 sizeof(outheader
.cupsRenderingIntent
));
243 else if (!strcmp(val
, "automatic"))
244 strlcpy(outheader
.cupsRenderingIntent
, "Automatic",
245 sizeof(outheader
.cupsRenderingIntent
));
246 else if (!strcmp(val
, "perceptual"))
247 strlcpy(outheader
.cupsRenderingIntent
, "Perceptual",
248 sizeof(outheader
.cupsRenderingIntent
));
249 else if (!strcmp(val
, "relative"))
250 strlcpy(outheader
.cupsRenderingIntent
, "Relative",
251 sizeof(outheader
.cupsRenderingIntent
));
252 else if (!strcmp(val
, "relative-bpc"))
253 strlcpy(outheader
.cupsRenderingIntent
, "RelativeBpc",
254 sizeof(outheader
.cupsRenderingIntent
));
255 else if (!strcmp(val
, "saturation"))
256 strlcpy(outheader
.cupsRenderingIntent
, "Saturation",
257 sizeof(outheader
.cupsRenderingIntent
));
260 fputs("DEBUG: Unsupported print-rendering-intent value.\n", stderr
);
261 outheader
.cupsRenderingIntent
[0] = '\0';
265 if (inheader
.cupsPageSizeName
[0] &&
266 (pwg_size
= _ppdCacheGetSize(cache
, inheader
.cupsPageSizeName
)) != NULL
)
268 strlcpy(outheader
.cupsPageSizeName
, pwg_size
->map
.pwg
,
269 sizeof(outheader
.cupsPageSizeName
));
273 pwg_media
= pwgMediaForSize((int)(2540.0 * inheader
.cupsPageSize
[0] / 72.0),
274 (int)(2540.0 * inheader
.cupsPageSize
[1] / 72.0));
277 strlcpy(outheader
.cupsPageSizeName
, pwg_media
->pwg
,
278 sizeof(outheader
.cupsPageSizeName
));
281 fprintf(stderr
, "DEBUG: Unsupported PageSize %.2fx%.2f.\n",
282 inheader
.cupsPageSize
[0], inheader
.cupsPageSize
[1]);
283 outheader
.cupsPageSizeName
[0] = '\0';
287 if (inheader
.Duplex
&& !(page
& 1) &&
288 back
&& _cups_strcasecmp(back
->value
, "Normal"))
290 if (_cups_strcasecmp(back
->value
, "Flipped"))
294 outheader
.cupsInteger
[1] = ~0U;/* CrossFeedTransform */
295 outheader
.cupsInteger
[2] = 1; /* FeedTransform */
297 outheader
.cupsInteger
[3] = page_width
- page_left
-
300 outheader
.cupsInteger
[4] = page_top
;
302 outheader
.cupsInteger
[5] = page_width
- page_left
;
304 outheader
.cupsInteger
[6] = page_height
- page_bottom
;
309 outheader
.cupsInteger
[1] = 1; /* CrossFeedTransform */
310 outheader
.cupsInteger
[2] = ~0U;/* FeedTransform */
312 outheader
.cupsInteger
[3] = page_left
;
314 outheader
.cupsInteger
[4] = page_bottom
;
316 outheader
.cupsInteger
[5] = page_left
+ inheader
.cupsWidth
;
318 outheader
.cupsInteger
[6] = page_height
- page_top
;
322 else if (_cups_strcasecmp(back
->value
, "ManualTumble"))
326 outheader
.cupsInteger
[1] = ~0U;/* CrossFeedTransform */
327 outheader
.cupsInteger
[2] = ~0U;/* FeedTransform */
329 outheader
.cupsInteger
[3] = page_width
- page_left
-
332 outheader
.cupsInteger
[4] = page_bottom
;
334 outheader
.cupsInteger
[5] = page_width
- page_left
;
336 outheader
.cupsInteger
[6] = page_height
- page_top
;
341 outheader
.cupsInteger
[1] = 1; /* CrossFeedTransform */
342 outheader
.cupsInteger
[2] = 1; /* FeedTransform */
344 outheader
.cupsInteger
[3] = page_left
;
346 outheader
.cupsInteger
[4] = page_top
;
348 outheader
.cupsInteger
[5] = page_left
+ inheader
.cupsWidth
;
350 outheader
.cupsInteger
[6] = page_height
- page_bottom
;
354 else if (_cups_strcasecmp(back
->value
, "Rotated"))
358 outheader
.cupsInteger
[1] = ~0U;/* CrossFeedTransform */
359 outheader
.cupsInteger
[2] = ~0U;/* FeedTransform */
361 outheader
.cupsInteger
[3] = page_width
- page_left
-
364 outheader
.cupsInteger
[4] = page_bottom
;
366 outheader
.cupsInteger
[5] = page_width
- page_left
;
368 outheader
.cupsInteger
[6] = page_height
- page_top
;
373 outheader
.cupsInteger
[1] = 1; /* CrossFeedTransform */
374 outheader
.cupsInteger
[2] = 1; /* FeedTransform */
376 outheader
.cupsInteger
[3] = page_left
;
378 outheader
.cupsInteger
[4] = page_top
;
380 outheader
.cupsInteger
[5] = page_left
+ inheader
.cupsWidth
;
382 outheader
.cupsInteger
[6] = page_height
- page_bottom
;
389 * Unsupported value...
392 fputs("DEBUG: Unsupported cupsBackSide value.\n", stderr
);
394 outheader
.cupsInteger
[1] = 1; /* CrossFeedTransform */
395 outheader
.cupsInteger
[2] = 1; /* FeedTransform */
397 outheader
.cupsInteger
[3] = page_left
;
399 outheader
.cupsInteger
[4] = page_top
;
401 outheader
.cupsInteger
[5] = page_left
+ inheader
.cupsWidth
;
403 outheader
.cupsInteger
[6] = page_height
- page_bottom
;
409 outheader
.cupsInteger
[1] = 1; /* CrossFeedTransform */
410 outheader
.cupsInteger
[2] = 1; /* FeedTransform */
412 outheader
.cupsInteger
[3] = page_left
;
414 outheader
.cupsInteger
[4] = page_top
;
416 outheader
.cupsInteger
[5] = page_left
+ inheader
.cupsWidth
;
418 outheader
.cupsInteger
[6] = page_height
- page_bottom
;
422 if (!cupsRasterWriteHeader2(outras
, &outheader
))
424 _cupsLangPrintFilter(stderr
, "ERROR", _("Error sending raster data."));
425 fprintf(stderr
, "DEBUG: Unable to write header for page %d.\n", page
);
430 * Copy raster data...
433 if (linesize
< inheader
.cupsBytesPerLine
)
434 linesize
= inheader
.cupsBytesPerLine
;
436 if ((lineoffset
+ inheader
.cupsBytesPerLine
) > linesize
)
437 lineoffset
= linesize
- inheader
.cupsBytesPerLine
;
439 line
= malloc(linesize
);
441 memset(line
, white
, linesize
);
442 for (y
= page_top
; y
> 0; y
--)
443 if (!cupsRasterWritePixels(outras
, line
, outheader
.cupsBytesPerLine
))
445 _cupsLangPrintFilter(stderr
, "ERROR", _("Error sending raster data."));
446 fprintf(stderr
, "DEBUG: Unable to write line %d for page %d.\n",
447 page_top
- y
+ 1, page
);
451 for (y
= inheader
.cupsHeight
; y
> 0; y
--)
453 if (cupsRasterReadPixels(inras
, line
+ lineoffset
, inheader
.cupsBytesPerLine
) != inheader
.cupsBytesPerLine
)
455 _cupsLangPrintFilter(stderr
, "ERROR", _("Error reading raster data."));
456 fprintf(stderr
, "DEBUG: Unable to read line %d for page %d.\n",
457 inheader
.cupsHeight
- y
+ page_top
+ 1, page
);
461 if (!cupsRasterWritePixels(outras
, line
, outheader
.cupsBytesPerLine
))
463 _cupsLangPrintFilter(stderr
, "ERROR", _("Error sending raster data."));
464 fprintf(stderr
, "DEBUG: Unable to write line %d for page %d.\n",
465 inheader
.cupsHeight
- y
+ page_top
+ 1, page
);
470 memset(line
, white
, linesize
);
471 for (y
= page_bottom
; y
> 0; y
--)
472 if (!cupsRasterWritePixels(outras
, line
, outheader
.cupsBytesPerLine
))
474 _cupsLangPrintFilter(stderr
, "ERROR", _("Error sending raster data."));
475 fprintf(stderr
, "DEBUG: Unable to write line %d for page %d.\n",
476 page_bottom
- y
+ page_top
+ inheader
.cupsHeight
+ 1, page
);
483 cupsRasterClose(inras
);
487 cupsRasterClose(outras
);