]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/rastertopwg.c
Do some code reorganization so that all of the PPD code is separate from the rest.
[thirdparty/cups.git] / filter / rastertopwg.c
1 /*
2 * "$Id$"
3 *
4 * CUPS raster to PWG raster format filter for CUPS.
5 *
6 * Copyright 2011, 2014-2015 Apple Inc.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright law.
10 * Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 * This file is subject to the Apple OS-Developed Software exception.
15 */
16
17 /*
18 * Include necessary headers...
19 */
20
21 #include <cups/cups-private.h>
22 #include <cups/ppd-private.h>
23 #include <cups/raster.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26
27
28 /*
29 * 'main()' - Main entry for filter.
30 */
31
32 int /* O - Exit status */
33 main(int argc, /* I - Number of command-line args */
34 char *argv[]) /* I - Command-line arguments */
35 {
36 int fd; /* Raster file */
37 cups_raster_t *inras, /* Input raster stream */
38 *outras; /* Output raster stream */
39 cups_page_header2_t inheader, /* Input raster page header */
40 outheader; /* Output raster page header */
41 unsigned y; /* Current line */
42 unsigned char *line; /* Line buffer */
43 unsigned page = 0, /* Current page */
44 page_width, /* Actual page width */
45 page_height, /* Actual page height */
46 page_top, /* Top margin */
47 page_bottom, /* Bottom margin */
48 page_left, /* Left margin */
49 linesize, /* Bytes per line */
50 lineoffset; /* Offset into line */
51 unsigned char white; /* White pixel */
52 ppd_file_t *ppd; /* PPD file */
53 ppd_attr_t *back; /* cupsBackSize attribute */
54 _ppd_cache_t *cache; /* PPD cache */
55 _pwg_size_t *pwg_size; /* PWG media size */
56 _pwg_media_t *pwg_media; /* PWG media name */
57 int num_options; /* Number of options */
58 cups_option_t *options = NULL;/* Options */
59 const char *val; /* Option value */
60
61
62 if (argc < 6 || argc > 7)
63 {
64 puts("Usage: rastertopwg job user title copies options [filename]");
65 return (1);
66 }
67 else if (argc == 7)
68 {
69 if ((fd = open(argv[6], O_RDONLY)) < 0)
70 {
71 perror("ERROR: Unable to open print file");
72 return (1);
73 }
74 }
75 else
76 fd = 0;
77
78 inras = cupsRasterOpen(fd, CUPS_RASTER_READ);
79 outras = cupsRasterOpen(1, CUPS_RASTER_WRITE_PWG);
80
81 ppd = ppdOpenFile(getenv("PPD"));
82 back = ppdFindAttr(ppd, "cupsBackSide", NULL);
83
84 num_options = cupsParseOptions(argv[5], 0, &options);
85
86 ppdMarkDefaults(ppd);
87 cupsMarkOptions(ppd, num_options, options);
88
89 cache = ppd ? ppd->cache : NULL;
90
91 while (cupsRasterReadHeader2(inras, &inheader))
92 {
93 /*
94 * Show page device dictionary...
95 */
96
97 fprintf(stderr, "DEBUG: Duplex = %d\n", inheader.Duplex);
98 fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", inheader.HWResolution[0], inheader.HWResolution[1]);
99 fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", inheader.ImagingBoundingBox[0], inheader.ImagingBoundingBox[1], inheader.ImagingBoundingBox[2], inheader.ImagingBoundingBox[3]);
100 fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", inheader.Margins[0], inheader.Margins[1]);
101 fprintf(stderr, "DEBUG: ManualFeed = %d\n", inheader.ManualFeed);
102 fprintf(stderr, "DEBUG: MediaPosition = %d\n", inheader.MediaPosition);
103 fprintf(stderr, "DEBUG: NumCopies = %d\n", inheader.NumCopies);
104 fprintf(stderr, "DEBUG: Orientation = %d\n", inheader.Orientation);
105 fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", inheader.PageSize[0], inheader.PageSize[1]);
106 fprintf(stderr, "DEBUG: cupsWidth = %d\n", inheader.cupsWidth);
107 fprintf(stderr, "DEBUG: cupsHeight = %d\n", inheader.cupsHeight);
108 fprintf(stderr, "DEBUG: cupsMediaType = %d\n", inheader.cupsMediaType);
109 fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", inheader.cupsBitsPerColor);
110 fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", inheader.cupsBitsPerPixel);
111 fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", inheader.cupsBytesPerLine);
112 fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", inheader.cupsColorOrder);
113 fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", inheader.cupsColorSpace);
114 fprintf(stderr, "DEBUG: cupsCompression = %d\n", inheader.cupsCompression);
115
116 /*
117 * Compute the real raster size...
118 */
119
120 page ++;
121
122 fprintf(stderr, "PAGE: %d %d\n", page, inheader.NumCopies);
123
124 page_width = (unsigned)(inheader.cupsPageSize[0] * inheader.HWResolution[0] / 72.0);
125 page_height = (unsigned)(inheader.cupsPageSize[1] * inheader.HWResolution[1] / 72.0);
126 page_left = (unsigned)(inheader.cupsImagingBBox[0] * inheader.HWResolution[0] / 72.0);
127 page_bottom = (unsigned)(inheader.cupsImagingBBox[1] * inheader.HWResolution[1] / 72.0);
128 page_top = page_height - page_bottom - inheader.cupsHeight;
129 linesize = (page_width * inheader.cupsBitsPerPixel + 7) / 8;
130 lineoffset = page_left * inheader.cupsBitsPerPixel / 8; /* Round down */
131
132 if (page_left > page_width || page_top > page_height || page_bottom > page_height)
133 {
134 _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
135 fprintf(stderr, "DEBUG: Bad bottom/left/top margin on page %d.\n", page);
136 return (1);
137 }
138
139 switch (inheader.cupsColorSpace)
140 {
141 case CUPS_CSPACE_W :
142 case CUPS_CSPACE_RGB :
143 case CUPS_CSPACE_SW :
144 case CUPS_CSPACE_SRGB :
145 case CUPS_CSPACE_ADOBERGB :
146 white = 255;
147 break;
148
149 case CUPS_CSPACE_K :
150 case CUPS_CSPACE_CMYK :
151 case CUPS_CSPACE_DEVICE1 :
152 case CUPS_CSPACE_DEVICE2 :
153 case CUPS_CSPACE_DEVICE3 :
154 case CUPS_CSPACE_DEVICE4 :
155 case CUPS_CSPACE_DEVICE5 :
156 case CUPS_CSPACE_DEVICE6 :
157 case CUPS_CSPACE_DEVICE7 :
158 case CUPS_CSPACE_DEVICE8 :
159 case CUPS_CSPACE_DEVICE9 :
160 case CUPS_CSPACE_DEVICEA :
161 case CUPS_CSPACE_DEVICEB :
162 case CUPS_CSPACE_DEVICEC :
163 case CUPS_CSPACE_DEVICED :
164 case CUPS_CSPACE_DEVICEE :
165 case CUPS_CSPACE_DEVICEF :
166 white = 0;
167 break;
168
169 default :
170 _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
171 fprintf(stderr, "DEBUG: Unsupported cupsColorSpace %d on page %d.\n",
172 inheader.cupsColorSpace, page);
173 return (1);
174 }
175
176 if (inheader.cupsColorOrder != CUPS_ORDER_CHUNKED)
177 {
178 _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
179 fprintf(stderr, "DEBUG: Unsupported cupsColorOrder %d on page %d.\n",
180 inheader.cupsColorOrder, page);
181 return (1);
182 }
183
184 if (inheader.cupsBitsPerPixel != 1 &&
185 inheader.cupsBitsPerColor != 8 && inheader.cupsBitsPerColor != 16)
186 {
187 _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
188 fprintf(stderr, "DEBUG: Unsupported cupsBitsPerColor %d on page %d.\n",
189 inheader.cupsBitsPerColor, page);
190 return (1);
191 }
192
193 memcpy(&outheader, &inheader, sizeof(outheader));
194 outheader.cupsWidth = page_width;
195 outheader.cupsHeight = page_height;
196 outheader.cupsBytesPerLine = linesize;
197
198 outheader.cupsInteger[14] = 0; /* VendorIdentifier */
199 outheader.cupsInteger[15] = 0; /* VendorLength */
200
201 if ((val = cupsGetOption("print-content-optimize", num_options,
202 options)) != NULL)
203 {
204 if (!strcmp(val, "automatic"))
205 strlcpy(outheader.OutputType, "Automatic",
206 sizeof(outheader.OutputType));
207 else if (!strcmp(val, "graphics"))
208 strlcpy(outheader.OutputType, "Graphics", sizeof(outheader.OutputType));
209 else if (!strcmp(val, "photo"))
210 strlcpy(outheader.OutputType, "Photo", sizeof(outheader.OutputType));
211 else if (!strcmp(val, "text"))
212 strlcpy(outheader.OutputType, "Text", sizeof(outheader.OutputType));
213 else if (!strcmp(val, "text-and-graphics"))
214 strlcpy(outheader.OutputType, "TextAndGraphics",
215 sizeof(outheader.OutputType));
216 else
217 {
218 fputs("DEBUG: Unsupported print-content-optimize value.\n", stderr);
219 outheader.OutputType[0] = '\0';
220 }
221 }
222
223 if ((val = cupsGetOption("print-quality", num_options, options)) != NULL)
224 {
225 unsigned quality = (unsigned)atoi(val); /* print-quality value */
226
227 if (quality >= IPP_QUALITY_DRAFT && quality <= IPP_QUALITY_HIGH)
228 outheader.cupsInteger[8] = quality;
229 else
230 {
231 fprintf(stderr, "DEBUG: Unsupported print-quality %d.\n", quality);
232 outheader.cupsInteger[8] = 0;
233 }
234 }
235
236 if ((val = cupsGetOption("print-rendering-intent", num_options,
237 options)) != NULL)
238 {
239 if (!strcmp(val, "absolute"))
240 strlcpy(outheader.cupsRenderingIntent, "Absolute",
241 sizeof(outheader.cupsRenderingIntent));
242 else if (!strcmp(val, "automatic"))
243 strlcpy(outheader.cupsRenderingIntent, "Automatic",
244 sizeof(outheader.cupsRenderingIntent));
245 else if (!strcmp(val, "perceptual"))
246 strlcpy(outheader.cupsRenderingIntent, "Perceptual",
247 sizeof(outheader.cupsRenderingIntent));
248 else if (!strcmp(val, "relative"))
249 strlcpy(outheader.cupsRenderingIntent, "Relative",
250 sizeof(outheader.cupsRenderingIntent));
251 else if (!strcmp(val, "relative-bpc"))
252 strlcpy(outheader.cupsRenderingIntent, "RelativeBpc",
253 sizeof(outheader.cupsRenderingIntent));
254 else if (!strcmp(val, "saturation"))
255 strlcpy(outheader.cupsRenderingIntent, "Saturation",
256 sizeof(outheader.cupsRenderingIntent));
257 else
258 {
259 fputs("DEBUG: Unsupported print-rendering-intent value.\n", stderr);
260 outheader.cupsRenderingIntent[0] = '\0';
261 }
262 }
263
264 if (inheader.cupsPageSizeName[0] &&
265 (pwg_size = _ppdCacheGetSize(cache, inheader.cupsPageSizeName)) != NULL)
266 {
267 strlcpy(outheader.cupsPageSizeName, pwg_size->map.pwg,
268 sizeof(outheader.cupsPageSizeName));
269 }
270 else
271 {
272 pwg_media = _pwgMediaForSize((int)(2540.0 * inheader.cupsPageSize[0] /
273 72.0),
274 (int)(2540.0 * inheader.cupsPageSize[1] /
275 72.0));
276
277 if (pwg_media)
278 strlcpy(outheader.cupsPageSizeName, pwg_media->pwg,
279 sizeof(outheader.cupsPageSizeName));
280 else
281 {
282 fprintf(stderr, "DEBUG: Unsupported PageSize %.2fx%.2f.\n",
283 inheader.cupsPageSize[0], inheader.cupsPageSize[1]);
284 outheader.cupsPageSizeName[0] = '\0';
285 }
286 }
287
288 if (inheader.Duplex && !(page & 1) &&
289 back && _cups_strcasecmp(back->value, "Normal"))
290 {
291 if (_cups_strcasecmp(back->value, "Flipped"))
292 {
293 if (inheader.Tumble)
294 {
295 outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
296 outheader.cupsInteger[2] = 1; /* FeedTransform */
297
298 outheader.cupsInteger[3] = page_width - page_left -
299 inheader.cupsWidth;
300 /* ImageBoxLeft */
301 outheader.cupsInteger[4] = page_top;
302 /* ImageBoxTop */
303 outheader.cupsInteger[5] = page_width - page_left;
304 /* ImageBoxRight */
305 outheader.cupsInteger[6] = page_height - page_bottom;
306 /* ImageBoxBottom */
307 }
308 else
309 {
310 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
311 outheader.cupsInteger[2] = ~0U;/* FeedTransform */
312
313 outheader.cupsInteger[3] = page_left;
314 /* ImageBoxLeft */
315 outheader.cupsInteger[4] = page_bottom;
316 /* ImageBoxTop */
317 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
318 /* ImageBoxRight */
319 outheader.cupsInteger[6] = page_height - page_top;
320 /* ImageBoxBottom */
321 }
322 }
323 else if (_cups_strcasecmp(back->value, "ManualTumble"))
324 {
325 if (inheader.Tumble)
326 {
327 outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
328 outheader.cupsInteger[2] = ~0U;/* FeedTransform */
329
330 outheader.cupsInteger[3] = page_width - page_left -
331 inheader.cupsWidth;
332 /* ImageBoxLeft */
333 outheader.cupsInteger[4] = page_bottom;
334 /* ImageBoxTop */
335 outheader.cupsInteger[5] = page_width - page_left;
336 /* ImageBoxRight */
337 outheader.cupsInteger[6] = page_height - page_top;
338 /* ImageBoxBottom */
339 }
340 else
341 {
342 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
343 outheader.cupsInteger[2] = 1; /* FeedTransform */
344
345 outheader.cupsInteger[3] = page_left;
346 /* ImageBoxLeft */
347 outheader.cupsInteger[4] = page_top;
348 /* ImageBoxTop */
349 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
350 /* ImageBoxRight */
351 outheader.cupsInteger[6] = page_height - page_bottom;
352 /* ImageBoxBottom */
353 }
354 }
355 else if (_cups_strcasecmp(back->value, "Rotated"))
356 {
357 if (inheader.Tumble)
358 {
359 outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
360 outheader.cupsInteger[2] = ~0U;/* FeedTransform */
361
362 outheader.cupsInteger[3] = page_width - page_left -
363 inheader.cupsWidth;
364 /* ImageBoxLeft */
365 outheader.cupsInteger[4] = page_bottom;
366 /* ImageBoxTop */
367 outheader.cupsInteger[5] = page_width - page_left;
368 /* ImageBoxRight */
369 outheader.cupsInteger[6] = page_height - page_top;
370 /* ImageBoxBottom */
371 }
372 else
373 {
374 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
375 outheader.cupsInteger[2] = 1; /* FeedTransform */
376
377 outheader.cupsInteger[3] = page_left;
378 /* ImageBoxLeft */
379 outheader.cupsInteger[4] = page_top;
380 /* ImageBoxTop */
381 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
382 /* ImageBoxRight */
383 outheader.cupsInteger[6] = page_height - page_bottom;
384 /* ImageBoxBottom */
385 }
386 }
387 else
388 {
389 /*
390 * Unsupported value...
391 */
392
393 fputs("DEBUG: Unsupported cupsBackSide value.\n", stderr);
394
395 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
396 outheader.cupsInteger[2] = 1; /* FeedTransform */
397
398 outheader.cupsInteger[3] = page_left;
399 /* ImageBoxLeft */
400 outheader.cupsInteger[4] = page_top;
401 /* ImageBoxTop */
402 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
403 /* ImageBoxRight */
404 outheader.cupsInteger[6] = page_height - page_bottom;
405 /* ImageBoxBottom */
406 }
407 }
408 else
409 {
410 outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
411 outheader.cupsInteger[2] = 1; /* FeedTransform */
412
413 outheader.cupsInteger[3] = page_left;
414 /* ImageBoxLeft */
415 outheader.cupsInteger[4] = page_top;
416 /* ImageBoxTop */
417 outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
418 /* ImageBoxRight */
419 outheader.cupsInteger[6] = page_height - page_bottom;
420 /* ImageBoxBottom */
421 }
422
423 if (!cupsRasterWriteHeader2(outras, &outheader))
424 {
425 _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
426 fprintf(stderr, "DEBUG: Unable to write header for page %d.\n", page);
427 return (1);
428 }
429
430 /*
431 * Copy raster data...
432 */
433
434 if (linesize < inheader.cupsBytesPerLine)
435 linesize = inheader.cupsBytesPerLine;
436
437 line = malloc(linesize);
438
439 memset(line, white, linesize);
440 for (y = page_top; y > 0; y --)
441 if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
442 {
443 _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
444 fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
445 page_top - y + 1, page);
446 return (1);
447 }
448
449 for (y = inheader.cupsHeight; y > 0; y --)
450 {
451 if (cupsRasterReadPixels(inras, line + lineoffset, inheader.cupsBytesPerLine) != inheader.cupsBytesPerLine)
452 {
453 _cupsLangPrintFilter(stderr, "ERROR", _("Error reading raster data."));
454 fprintf(stderr, "DEBUG: Unable to read line %d for page %d.\n",
455 inheader.cupsHeight - y + page_top + 1, page);
456 return (1);
457 }
458
459 if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
460 {
461 _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
462 fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
463 inheader.cupsHeight - y + page_top + 1, page);
464 return (1);
465 }
466 }
467
468 memset(line, white, linesize);
469 for (y = page_bottom; y > 0; y --)
470 if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
471 {
472 _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
473 fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
474 page_bottom - y + page_top + inheader.cupsHeight + 1, page);
475 return (1);
476 }
477
478 free(line);
479 }
480
481 cupsRasterClose(inras);
482 if (fd)
483 close(fd);
484
485 cupsRasterClose(outras);
486
487 return (0);
488 }
489
490
491 /*
492 * End of "$Id$".
493 */