]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/rastertopwg.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / filter / rastertopwg.c
1 /*
2 * CUPS raster to PWG raster format filter for CUPS.
3 *
4 * Copyright 2011, 2014-2017 Apple Inc.
5 *
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/".
11 */
12
13 /*
14 * Include necessary headers...
15 */
16
17 #include <cups/cups-private.h>
18 #include <cups/ppd-private.h>
19 #include <cups/raster.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22
23
24 /*
25 * 'main()' - Main entry for filter.
26 */
27
28 int /* O - Exit status */
29 main(int argc, /* I - Number of command-line args */
30 char *argv[]) /* I - Command-line arguments */
31 {
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 */
58
59
60 if (argc < 6 || argc > 7)
61 {
62 puts("Usage: rastertopwg job user title copies options [filename]");
63 return (1);
64 }
65 else if (argc == 7)
66 {
67 if ((fd = open(argv[6], O_RDONLY)) < 0)
68 {
69 perror("ERROR: Unable to open print file");
70 return (1);
71 }
72 }
73 else
74 fd = 0;
75
76 if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
77 final_content_type = "image/pwg-raster";
78
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);
81
82 ppd = ppdOpenFile(getenv("PPD"));
83 back = ppdFindAttr(ppd, "cupsBackSide", NULL);
84
85 num_options = cupsParseOptions(argv[5], 0, &options);
86
87 ppdMarkDefaults(ppd);
88 cupsMarkOptions(ppd, num_options, options);
89
90 cache = ppd ? ppd->cache : NULL;
91
92 while (cupsRasterReadHeader2(inras, &inheader))
93 {
94 /*
95 * Show page device dictionary...
96 */
97
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);
116
117 /*
118 * Compute the real raster size...
119 */
120
121 page ++;
122
123 fprintf(stderr, "PAGE: %d %d\n", page, inheader.NumCopies);
124
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 */
132
133 if (page_left > page_width || page_top > page_height || page_bottom > page_height)
134 {
135 _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
136 fprintf(stderr, "DEBUG: Bad bottom/left/top margin on page %d.\n", page);
137 return (1);
138 }
139
140 switch (inheader.cupsColorSpace)
141 {
142 case CUPS_CSPACE_W :
143 case CUPS_CSPACE_RGB :
144 case CUPS_CSPACE_SW :
145 case CUPS_CSPACE_SRGB :
146 case CUPS_CSPACE_ADOBERGB :
147 white = 255;
148 break;
149
150 case CUPS_CSPACE_K :
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 :
167 white = 0;
168 break;
169
170 default :
171 _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
172 fprintf(stderr, "DEBUG: Unsupported cupsColorSpace %d on page %d.\n",
173 inheader.cupsColorSpace, page);
174 return (1);
175 }
176
177 if (inheader.cupsColorOrder != CUPS_ORDER_CHUNKED)
178 {
179 _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
180 fprintf(stderr, "DEBUG: Unsupported cupsColorOrder %d on page %d.\n",
181 inheader.cupsColorOrder, page);
182 return (1);
183 }
184
185 if (inheader.cupsBitsPerPixel != 1 &&
186 inheader.cupsBitsPerColor != 8 && inheader.cupsBitsPerColor != 16)
187 {
188 _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
189 fprintf(stderr, "DEBUG: Unsupported cupsBitsPerColor %d on page %d.\n",
190 inheader.cupsBitsPerColor, page);
191 return (1);
192 }
193
194 memcpy(&outheader, &inheader, sizeof(outheader));
195 outheader.cupsWidth = page_width;
196 outheader.cupsHeight = page_height;
197 outheader.cupsBytesPerLine = linesize;
198
199 outheader.cupsInteger[14] = 0; /* VendorIdentifier */
200 outheader.cupsInteger[15] = 0; /* VendorLength */
201
202 if ((val = cupsGetOption("print-content-optimize", num_options,
203 options)) != NULL)
204 {
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));
217 else
218 {
219 fputs("DEBUG: Unsupported print-content-optimize value.\n", stderr);
220 outheader.OutputType[0] = '\0';
221 }
222 }
223
224 if ((val = cupsGetOption("print-quality", num_options, options)) != NULL)
225 {
226 unsigned quality = (unsigned)atoi(val); /* print-quality value */
227
228 if (quality >= IPP_QUALITY_DRAFT && quality <= IPP_QUALITY_HIGH)
229 outheader.cupsInteger[8] = quality;
230 else
231 {
232 fprintf(stderr, "DEBUG: Unsupported print-quality %d.\n", quality);
233 outheader.cupsInteger[8] = 0;
234 }
235 }
236
237 if ((val = cupsGetOption("print-rendering-intent", num_options,
238 options)) != NULL)
239 {
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));
258 else
259 {
260 fputs("DEBUG: Unsupported print-rendering-intent value.\n", stderr);
261 outheader.cupsRenderingIntent[0] = '\0';
262 }
263 }
264
265 if (inheader.cupsPageSizeName[0] &&
266 (pwg_size = _ppdCacheGetSize(cache, inheader.cupsPageSizeName)) != NULL)
267 {
268 strlcpy(outheader.cupsPageSizeName, pwg_size->map.pwg,
269 sizeof(outheader.cupsPageSizeName));
270 }
271 else
272 {
273 pwg_media = pwgMediaForSize((int)(2540.0 * inheader.cupsPageSize[0] / 72.0),
274 (int)(2540.0 * inheader.cupsPageSize[1] / 72.0));
275
276 if (pwg_media)
277 strlcpy(outheader.cupsPageSizeName, pwg_media->pwg,
278 sizeof(outheader.cupsPageSizeName));
279 else
280 {
281 fprintf(stderr, "DEBUG: Unsupported PageSize %.2fx%.2f.\n",
282 inheader.cupsPageSize[0], inheader.cupsPageSize[1]);
283 outheader.cupsPageSizeName[0] = '\0';
284 }
285 }
286
287 if (inheader.Duplex && !(page & 1) &&
288 back && _cups_strcasecmp(back->value, "Normal"))
289 {
290 if (_cups_strcasecmp(back->value, "Flipped"))
291 {
292 if (inheader.Tumble)
293 {
294 outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
295 outheader.cupsInteger[2] = 1; /* FeedTransform */
296
297 outheader.cupsInteger[3] = page_width - page_left -
298 inheader.cupsWidth;
299 /* ImageBoxLeft */
300 outheader.cupsInteger[4] = page_top;
301 /* ImageBoxTop */
302 outheader.cupsInteger[5] = page_width - page_left;
303 /* ImageBoxRight */
304 outheader.cupsInteger[6] = page_height - page_bottom;
305 /* ImageBoxBottom */
306 }
307 else
308 {
309 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
310 outheader.cupsInteger[2] = ~0U;/* FeedTransform */
311
312 outheader.cupsInteger[3] = page_left;
313 /* ImageBoxLeft */
314 outheader.cupsInteger[4] = page_bottom;
315 /* ImageBoxTop */
316 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
317 /* ImageBoxRight */
318 outheader.cupsInteger[6] = page_height - page_top;
319 /* ImageBoxBottom */
320 }
321 }
322 else if (_cups_strcasecmp(back->value, "ManualTumble"))
323 {
324 if (inheader.Tumble)
325 {
326 outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
327 outheader.cupsInteger[2] = ~0U;/* FeedTransform */
328
329 outheader.cupsInteger[3] = page_width - page_left -
330 inheader.cupsWidth;
331 /* ImageBoxLeft */
332 outheader.cupsInteger[4] = page_bottom;
333 /* ImageBoxTop */
334 outheader.cupsInteger[5] = page_width - page_left;
335 /* ImageBoxRight */
336 outheader.cupsInteger[6] = page_height - page_top;
337 /* ImageBoxBottom */
338 }
339 else
340 {
341 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
342 outheader.cupsInteger[2] = 1; /* FeedTransform */
343
344 outheader.cupsInteger[3] = page_left;
345 /* ImageBoxLeft */
346 outheader.cupsInteger[4] = page_top;
347 /* ImageBoxTop */
348 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
349 /* ImageBoxRight */
350 outheader.cupsInteger[6] = page_height - page_bottom;
351 /* ImageBoxBottom */
352 }
353 }
354 else if (_cups_strcasecmp(back->value, "Rotated"))
355 {
356 if (inheader.Tumble)
357 {
358 outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
359 outheader.cupsInteger[2] = ~0U;/* FeedTransform */
360
361 outheader.cupsInteger[3] = page_width - page_left -
362 inheader.cupsWidth;
363 /* ImageBoxLeft */
364 outheader.cupsInteger[4] = page_bottom;
365 /* ImageBoxTop */
366 outheader.cupsInteger[5] = page_width - page_left;
367 /* ImageBoxRight */
368 outheader.cupsInteger[6] = page_height - page_top;
369 /* ImageBoxBottom */
370 }
371 else
372 {
373 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
374 outheader.cupsInteger[2] = 1; /* FeedTransform */
375
376 outheader.cupsInteger[3] = page_left;
377 /* ImageBoxLeft */
378 outheader.cupsInteger[4] = page_top;
379 /* ImageBoxTop */
380 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
381 /* ImageBoxRight */
382 outheader.cupsInteger[6] = page_height - page_bottom;
383 /* ImageBoxBottom */
384 }
385 }
386 else
387 {
388 /*
389 * Unsupported value...
390 */
391
392 fputs("DEBUG: Unsupported cupsBackSide value.\n", stderr);
393
394 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
395 outheader.cupsInteger[2] = 1; /* FeedTransform */
396
397 outheader.cupsInteger[3] = page_left;
398 /* ImageBoxLeft */
399 outheader.cupsInteger[4] = page_top;
400 /* ImageBoxTop */
401 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
402 /* ImageBoxRight */
403 outheader.cupsInteger[6] = page_height - page_bottom;
404 /* ImageBoxBottom */
405 }
406 }
407 else
408 {
409 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
410 outheader.cupsInteger[2] = 1; /* FeedTransform */
411
412 outheader.cupsInteger[3] = page_left;
413 /* ImageBoxLeft */
414 outheader.cupsInteger[4] = page_top;
415 /* ImageBoxTop */
416 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
417 /* ImageBoxRight */
418 outheader.cupsInteger[6] = page_height - page_bottom;
419 /* ImageBoxBottom */
420 }
421
422 if (!cupsRasterWriteHeader2(outras, &outheader))
423 {
424 _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
425 fprintf(stderr, "DEBUG: Unable to write header for page %d.\n", page);
426 return (1);
427 }
428
429 /*
430 * Copy raster data...
431 */
432
433 if (linesize < inheader.cupsBytesPerLine)
434 linesize = inheader.cupsBytesPerLine;
435
436 if ((lineoffset + inheader.cupsBytesPerLine) > linesize)
437 lineoffset = linesize - inheader.cupsBytesPerLine;
438
439 line = malloc(linesize);
440
441 memset(line, white, linesize);
442 for (y = page_top; y > 0; y --)
443 if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
444 {
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);
448 return (1);
449 }
450
451 for (y = inheader.cupsHeight; y > 0; y --)
452 {
453 if (cupsRasterReadPixels(inras, line + lineoffset, inheader.cupsBytesPerLine) != inheader.cupsBytesPerLine)
454 {
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);
458 return (1);
459 }
460
461 if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
462 {
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);
466 return (1);
467 }
468 }
469
470 memset(line, white, linesize);
471 for (y = page_bottom; y > 0; y --)
472 if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
473 {
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);
477 return (1);
478 }
479
480 free(line);
481 }
482
483 cupsRasterClose(inras);
484 if (fd)
485 close(fd);
486
487 cupsRasterClose(outras);
488
489 return (0);
490 }