]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/interpret.c
Load cups into easysw/current.
[thirdparty/cups.git] / filter / interpret.c
CommitLineData
ef416fc2 1/*
a74454a7 2 * "$Id: interpret.c 5490 2006-05-04 19:12:45Z mike $"
ef416fc2 3 *
4 * PPD command interpreter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1993-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsRasterInterpretPPD() - Interpret PPD commands to create a page header.
29 * exec_code() - Execute PostScript setpagedevice commands as
30 * appropriate.
31 */
32
33/*
34 * Include necessary headers...
35 */
36
ef416fc2 37#include <cups/string.h>
38#include "raster.h"
39#include <stdlib.h>
40
41
42/*
43 * Value types for PS code...
44 */
45
46#define CUPS_TYPE_NUMBER 0 /* Integer or real number */
47#define CUPS_TYPE_NAME 1 /* Name */
48#define CUPS_TYPE_STRING 2 /* String */
49#define CUPS_TYPE_ARRAY 3 /* Array of integers */
50
51
52/*
53 * Local functions...
54 */
55
a74454a7 56static int exec_code(cups_page_header2_t *header, int *preferred_bits,
57 const char *code);
ef416fc2 58
59
60/*
61 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
62 *
923edb68 63 * This function does not mark the options in the PPD using the "num_options"
64 * and "options" arguments. Instead, mark the options prior to calling
65 * cupsRasterInterpretPPD() - this allows you to do per-page options
66 * without manipulating the options array.
67 *
a74454a7 68 * The "func" argument specifies an optional callback function that is
69 * called prior to the computation of the final raster data. The function
70 * can make changes to the cups_page_header2_t data as needed to use a
71 * supported raster format and then returns 0 on success and -1 if the
72 * requested attributes cannot be supported.
73 *
ef416fc2 74 * @since CUPS 1.2@
75 */
76
77int /* O - 0 on success, -1 on failure */
78cupsRasterInterpretPPD(
79 cups_page_header2_t *h, /* O - Page header */
923edb68 80 ppd_file_t *ppd, /* I - PPD file */
81 int num_options, /* I - Number of options */
a74454a7 82 cups_option_t *options, /* I - Options */
83 cups_interpret_cb_t func) /* I - Optional page header callback */
ef416fc2 84{
85 int i; /* Looping var */
86 int status; /* Cummulative status */
87 int count; /* Number of marked choices */
923edb68 88 const char *val; /* Option value */
ef416fc2 89 ppd_choice_t **choices; /* List of marked choices */
90 ppd_size_t *size; /* Current size */
91 float left, /* Left position */
92 bottom, /* Bottom position */
93 right, /* Right position */
94 top; /* Top position */
a74454a7 95 int preferred_bits; /* Preferred bits per color */
ef416fc2 96
97
98 /*
99 * Range check input...
100 */
101
102 if (!h)
103 return (-1);
104
105 /*
106 * Reset the page header to the defaults...
107 */
108
109 memset(h, 0, sizeof(cups_page_header2_t));
110
923edb68 111 h->NumCopies = 1;
112 h->PageSize[0] = 612;
113 h->PageSize[1] = 792;
114 h->HWResolution[0] = 100;
115 h->HWResolution[1] = 100;
116 h->cupsBitsPerColor = 1;
117 h->cupsColorOrder = CUPS_ORDER_CHUNKED;
118 h->cupsColorSpace = CUPS_CSPACE_K;
119 h->cupsBorderlessScalingFactor = 1.0f;
120 h->cupsPageSize[0] = 612.0f;
121 h->cupsPageSize[1] = 792.0f;
122 h->cupsImagingBBox[0] = 0.0f;
123 h->cupsImagingBBox[1] = 0.0f;
124 h->cupsImagingBBox[2] = 612.0f;
125 h->cupsImagingBBox[3] = 792.0f;
fa73b229 126
127 strcpy(h->cupsPageSizeName, "Letter");
ef416fc2 128
129 /*
130 * Apply patches and options to the page header...
131 */
132
a74454a7 133 status = 0;
134 preferred_bits = 0;
ef416fc2 135
136 if (ppd)
137 {
138 /*
139 * Apply any patch code (used to override the defaults...)
140 */
141
142 if (ppd->patches)
a74454a7 143 status |= exec_code(h, &preferred_bits, ppd->patches);
ef416fc2 144
145 /*
146 * Then apply printer options in the proper order...
147 */
148
149 if ((count = ppdCollect(ppd, PPD_ORDER_DOCUMENT, &choices)) > 0)
150 {
151 for (i = 0; i < count; i ++)
a74454a7 152 status |= exec_code(h, &preferred_bits, choices[i]->code);
ef416fc2 153 }
154
155 if ((count = ppdCollect(ppd, PPD_ORDER_ANY, &choices)) > 0)
156 {
157 for (i = 0; i < count; i ++)
a74454a7 158 status |= exec_code(h, &preferred_bits, choices[i]->code);
ef416fc2 159 }
160
161 if ((count = ppdCollect(ppd, PPD_ORDER_PROLOG, &choices)) > 0)
162 {
163 for (i = 0; i < count; i ++)
a74454a7 164 status |= exec_code(h, &preferred_bits, choices[i]->code);
ef416fc2 165 }
166
167 if ((count = ppdCollect(ppd, PPD_ORDER_PAGE, &choices)) > 0)
168 {
169 for (i = 0; i < count; i ++)
a74454a7 170 status |= exec_code(h, &preferred_bits, choices[i]->code);
ef416fc2 171 }
172 }
173
174 /*
175 * Check parameters...
176 */
177
178 if (!h->HWResolution[0] || !h->HWResolution[1] ||
179 !h->PageSize[0] || !h->PageSize[1] ||
180 (h->cupsBitsPerColor != 1 && h->cupsBitsPerColor != 2 &&
923edb68 181 h->cupsBitsPerColor != 4 && h->cupsBitsPerColor != 8) ||
182 h->cupsBorderlessScalingFactor < 0.9 ||
183 h->cupsBorderlessScalingFactor > 1.1)
ef416fc2 184 return (-1);
185
923edb68 186 /*
187 * Allow option override for page scaling...
188 */
189
190 if ((val = cupsGetOption("cupsBorderlessScalingFactor", num_options,
191 options)) != NULL)
192 {
193 float sc = atof(val);
194
195 if (sc >= 0.9 && sc <= 1.1)
196 h->cupsBorderlessScalingFactor = sc;
197 }
198
ef416fc2 199 /*
200 * Get the margins for the current size...
201 */
202
203 if ((size = ppdPageSize(ppd, NULL)) != NULL)
204 {
205 /*
206 * Use the margins from the PPD file...
207 */
208
209 left = size->left;
210 bottom = size->bottom;
211 right = size->right;
212 top = size->top;
fa73b229 213
214 strlcpy(h->cupsPageSizeName, size->name, sizeof(h->cupsPageSizeName));
ef416fc2 215 }
216 else
217 {
218 /*
219 * Use the default margins...
220 */
221
222 left = 0.0f;
223 bottom = 0.0f;
224 right = 612.0f;
225 top = 792.0f;
226 }
227
923edb68 228 h->PageSize[0] = h->cupsPageSize[0] *
229 h->cupsBorderlessScalingFactor;
230 h->PageSize[1] = h->cupsPageSize[1] *
231 h->cupsBorderlessScalingFactor;
232 h->Margins[0] = left * h->cupsBorderlessScalingFactor;
233 h->Margins[1] = bottom * h->cupsBorderlessScalingFactor;
234 h->ImagingBoundingBox[0] = left * h->cupsBorderlessScalingFactor;
235 h->ImagingBoundingBox[1] = bottom * h->cupsBorderlessScalingFactor;
236 h->ImagingBoundingBox[2] = right * h->cupsBorderlessScalingFactor;
237 h->ImagingBoundingBox[3] = top * h->cupsBorderlessScalingFactor;
fa73b229 238 h->cupsImagingBBox[0] = left;
239 h->cupsImagingBBox[1] = bottom;
240 h->cupsImagingBBox[2] = right;
241 h->cupsImagingBBox[3] = top;
ef416fc2 242
a74454a7 243 /*
244 * Use the callback to validate the page header...
245 */
246
247 if (func && (*func)(h, preferred_bits))
248 return (-1);
249
ef416fc2 250 /*
251 * Compute the bitmap parameters...
252 */
253
923edb68 254 h->cupsWidth = (int)((right - left) * h->cupsBorderlessScalingFactor *
fa73b229 255 h->HWResolution[0] / 72.0f + 0.5f);
923edb68 256 h->cupsHeight = (int)((top - bottom) * h->cupsBorderlessScalingFactor *
fa73b229 257 h->HWResolution[1] / 72.0f + 0.5f);
ef416fc2 258
259 switch (h->cupsColorSpace)
260 {
261 case CUPS_CSPACE_W :
262 case CUPS_CSPACE_K :
263 case CUPS_CSPACE_WHITE :
264 case CUPS_CSPACE_GOLD :
265 case CUPS_CSPACE_SILVER :
266 h->cupsNumColors = 1;
267 h->cupsBitsPerPixel = h->cupsBitsPerColor;
268 break;
269
270 default :
271 /*
272 * Ensure that colorimetric colorspaces use at least 8 bits per
273 * component...
274 */
275
276 if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ &&
277 h->cupsBitsPerColor < 8)
278 h->cupsBitsPerColor = 8;
279
280 /*
281 * Figure out the number of bits per pixel...
282 */
283
284 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
285 {
286 if (h->cupsBitsPerColor >= 8)
287 h->cupsBitsPerPixel = h->cupsBitsPerColor * 3;
288 else
289 h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
290 }
291 else
292 h->cupsBitsPerPixel = h->cupsBitsPerColor;
293
294 h->cupsNumColors = 3;
295 break;
296
297 case CUPS_CSPACE_KCMYcm :
298 if (h->cupsBitsPerPixel == 1)
299 {
300 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
301 h->cupsBitsPerPixel = 8;
302 else
303 h->cupsBitsPerPixel = 1;
304
305 h->cupsNumColors = 6;
306 break;
307 }
308
309 /*
310 * Fall through to CMYK code...
311 */
312
313 case CUPS_CSPACE_RGBA :
a74454a7 314 case CUPS_CSPACE_RGBW :
ef416fc2 315 case CUPS_CSPACE_CMYK :
316 case CUPS_CSPACE_YMCK :
317 case CUPS_CSPACE_KCMY :
318 case CUPS_CSPACE_GMCK :
319 case CUPS_CSPACE_GMCS :
320 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
321 h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
322 else
323 h->cupsBitsPerPixel = h->cupsBitsPerColor;
324
325 h->cupsNumColors = 4;
326 break;
327 }
328
329 h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8;
330
331 if (h->cupsColorOrder == CUPS_ORDER_BANDED)
332 h->cupsBytesPerLine *= h->cupsNumColors;
333
334 return (status);
335}
336
337
338/*
339 * 'exec_code()' - Execute PostScript setpagedevice commands as appropriate.
340 */
341
342static int /* O - 0 on success, -1 on error */
a74454a7 343exec_code(
344 cups_page_header2_t *h, /* O - Page header */
345 int *preferred_bits,/* O - Preferred bits per color */
346 const char *code) /* I - Option choice to execute */
ef416fc2 347{
348 int i; /* Index into array */
349 int type; /* Type of value */
350 char *ptr, /* Pointer into name/value string */
351 name[255], /* Name of pagedevice entry */
352 value[1024]; /* Value of pagedevice entry */
353
354
355 /*
356 * Range check input...
357 */
358
359 if (!code || !h)
360 return (-1);
361
362 /*
363 * Parse the code string...
364 */
365
366 while (*code)
367 {
368 /*
369 * Search for the start of a dictionary name...
370 */
371
372 while (*code && *code != '/')
373 code ++;
374
375 if (!*code)
376 break;
377
378 /*
379 * Get the name...
380 */
381
382 code ++;
383 for (ptr = name; isalnum(*code & 255); code ++)
384 if (ptr < (name + sizeof(name) - 1))
385 *ptr++ = *code;
386 else
387 return (-1);
388
389 *ptr = '\0';
390
391 /*
392 * Then parse the value as needed...
393 */
394
395 while (isspace(*code & 255))
396 code ++;
397
398 if (!*code)
399 break;
400
401 if (*code == '[')
402 {
403 /*
404 * Read array of values...
405 */
406
407 type = CUPS_TYPE_ARRAY;
408
409 for (ptr = value; *code && *code != ']'; code ++)
410 if (ptr < (value + sizeof(value) - 1))
411 *ptr++ = *code;
412 else
413 return (-1);
414
415 if (*code == ']')
416 *ptr++ = *code++;
417
418 *ptr = '\0';
419 }
420 else if (*code == '(')
421 {
422 /*
423 * Read string value...
424 */
425
426 type = CUPS_TYPE_STRING;
427
428 for (ptr = value; *code && *code != ')'; code ++)
429 if (ptr < (value + sizeof(value) - 1))
430 *ptr++ = *code;
431 else
432 return (-1);
433
434 if (*code == ')')
435 *ptr++ = *code++;
436
437 *ptr = '\0';
438 }
439 else if (isdigit(*code & 255) || *code == '-' || *code == '.')
440 {
441 /*
442 * Read single number...
443 */
444
445 type = CUPS_TYPE_NUMBER;
446
447 for (ptr = value;
448 isdigit(*code & 255) || *code == '-' || *code == '.';
449 code ++)
450 if (ptr < (value + sizeof(value) - 1))
451 *ptr++ = *code;
452 else
453 return (-1);
454
455 *ptr = '\0';
456 }
457 else
458 {
459 /*
460 * Read a single name...
461 */
462
463 type = CUPS_TYPE_NAME;
464
465 for (ptr = value; isalnum(*code & 255) || *code == '_'; code ++)
466 if (ptr < (value + sizeof(value) - 1))
467 *ptr++ = *code;
468 else
469 return (-1);
470
471 *ptr = '\0';
472 }
473
474 /*
475 * Assign the value as needed...
476 */
477
478 if (!strcmp(name, "MediaClass") && type == CUPS_TYPE_STRING)
479 {
480 if (sscanf(value, "(%63[^)])", h->MediaClass) != 1)
481 return (-1);
482 }
483 else if (!strcmp(name, "MediaColor") && type == CUPS_TYPE_STRING)
484 {
485 if (sscanf(value, "(%63[^)])", h->MediaColor) != 1)
486 return (-1);
487 }
488 else if (!strcmp(name, "MediaType") && type == CUPS_TYPE_STRING)
489 {
490 if (sscanf(value, "(%63[^)])", h->MediaType) != 1)
491 return (-1);
492 }
493 else if (!strcmp(name, "OutputType") && type == CUPS_TYPE_STRING)
494 {
495 if (sscanf(value, "(%63[^)])", h->OutputType) != 1)
496 return (-1);
497 }
498 else if (!strcmp(name, "AdvanceDistance") && type == CUPS_TYPE_NUMBER)
499 h->AdvanceDistance = atoi(value);
500 else if (!strcmp(name, "AdvanceMedia") && type == CUPS_TYPE_NUMBER)
501 h->AdvanceMedia = atoi(value);
502 else if (!strcmp(name, "Collate") && type == CUPS_TYPE_NAME)
503 h->Collate = !strcmp(value, "true");
504 else if (!strcmp(name, "CutMedia") && type == CUPS_TYPE_NUMBER)
505 h->CutMedia = (cups_cut_t)atoi(value);
506 else if (!strcmp(name, "Duplex") && type == CUPS_TYPE_NAME)
507 h->Duplex = !strcmp(value, "true");
508 else if (!strcmp(name, "HWResolution") && type == CUPS_TYPE_ARRAY)
509 {
510 if (sscanf(value, "[%d%d]", h->HWResolution + 0,
511 h->HWResolution + 1) != 2)
512 return (-1);
513 }
514 else if (!strcmp(name, "InsertSheet") && type == CUPS_TYPE_NAME)
515 h->InsertSheet = !strcmp(value, "true");
516 else if (!strcmp(name, "Jog") && type == CUPS_TYPE_NUMBER)
517 h->Jog = atoi(value);
518 else if (!strcmp(name, "LeadingEdge") && type == CUPS_TYPE_NUMBER)
519 h->LeadingEdge = atoi(value);
520 else if (!strcmp(name, "ManualFeed") && type == CUPS_TYPE_NAME)
521 h->ManualFeed = !strcmp(value, "true");
522 else if ((!strcmp(name, "cupsMediaPosition") || /* Compatibility */
523 !strcmp(name, "MediaPosition")) && type == CUPS_TYPE_NUMBER)
524 h->MediaPosition = atoi(value);
525 else if (!strcmp(name, "MediaWeight") && type == CUPS_TYPE_NUMBER)
526 h->MediaWeight = atoi(value);
527 else if (!strcmp(name, "MirrorPrint") && type == CUPS_TYPE_NAME)
528 h->MirrorPrint = !strcmp(value, "true");
529 else if (!strcmp(name, "NegativePrint") && type == CUPS_TYPE_NAME)
530 h->NegativePrint = !strcmp(value, "true");
531 else if (!strcmp(name, "Orientation") && type == CUPS_TYPE_NUMBER)
532 h->Orientation = atoi(value);
533 else if (!strcmp(name, "OutputFaceUp") && type == CUPS_TYPE_NAME)
534 h->OutputFaceUp = !strcmp(value, "true");
535 else if (!strcmp(name, "PageSize") && type == CUPS_TYPE_ARRAY)
536 {
fa73b229 537 if (sscanf(value, "[%f%f]", h->cupsPageSize + 0, h->cupsPageSize + 1) != 2)
538 return (-1);
ef416fc2 539 }
540 else if (!strcmp(name, "Separations") && type == CUPS_TYPE_NAME)
541 h->Separations = !strcmp(value, "true");
542 else if (!strcmp(name, "TraySwitch") && type == CUPS_TYPE_NAME)
543 h->TraySwitch = !strcmp(value, "true");
544 else if (!strcmp(name, "Tumble") && type == CUPS_TYPE_NAME)
545 h->Tumble = !strcmp(value, "true");
546 else if (!strcmp(name, "cupsMediaType") && type == CUPS_TYPE_NUMBER)
547 h->cupsMediaType = atoi(value);
548 else if (!strcmp(name, "cupsBitsPerColor") && type == CUPS_TYPE_NUMBER)
549 h->cupsBitsPerColor = atoi(value);
a74454a7 550 else if (!strcmp(name, "cupsPreferredBitsPerColor") && type == CUPS_TYPE_NUMBER)
551 *preferred_bits = atoi(value);
ef416fc2 552 else if (!strcmp(name, "cupsColorOrder") && type == CUPS_TYPE_NUMBER)
553 h->cupsColorOrder = (cups_order_t)atoi(value);
554 else if (!strcmp(name, "cupsColorSpace") && type == CUPS_TYPE_NUMBER)
555 h->cupsColorSpace = (cups_cspace_t)atoi(value);
556 else if (!strcmp(name, "cupsCompression") && type == CUPS_TYPE_NUMBER)
557 h->cupsCompression = atoi(value);
558 else if (!strcmp(name, "cupsRowCount") && type == CUPS_TYPE_NUMBER)
559 h->cupsRowCount = atoi(value);
560 else if (!strcmp(name, "cupsRowFeed") && type == CUPS_TYPE_NUMBER)
561 h->cupsRowFeed = atoi(value);
562 else if (!strcmp(name, "cupsRowStep") && type == CUPS_TYPE_NUMBER)
563 h->cupsRowStep = atoi(value);
923edb68 564 else if (!strcmp(name, "cupsBorderlessScalingFactor") &&
565 type == CUPS_TYPE_NUMBER)
566 h->cupsBorderlessScalingFactor = atof(value);
ef416fc2 567 else if (!strncmp(name, "cupsInteger", 11) && type == CUPS_TYPE_NUMBER)
568 {
569 if ((i = atoi(name + 11)) >= 0 || i > 15)
570 return (-1);
571
572 h->cupsInteger[i] = atoi(value);
573 }
574 else if (!strncmp(name, "cupsReal", 8) && type == CUPS_TYPE_NUMBER)
575 {
576 if ((i = atoi(name + 8)) >= 0 || i > 15)
577 return (-1);
578
579 h->cupsReal[i] = atof(value);
580 }
581 else if (!strncmp(name, "cupsString", 10) && type == CUPS_TYPE_STRING)
582 {
583 if ((i = atoi(name + 10)) >= 0 || i > 15)
584 return (-1);
585
586 if (sscanf(value, "(%63[^)])", h->cupsString[i]) != 1)
587 return (-1);
588 }
589 else if (!strcmp(name, "cupsMarkerType") && type == CUPS_TYPE_STRING)
590 {
591 if (sscanf(value, "(%63[^)])", h->cupsMarkerType) != 1)
592 return (-1);
593 }
594 else if (!strcmp(name, "cupsRenderingIntent") && type == CUPS_TYPE_STRING)
595 {
596 if (sscanf(value, "(%63[^)])", h->cupsRenderingIntent) != 1)
597 return (-1);
598 }
ef416fc2 599 }
600
601 /*
602 * Return success...
603 */
604
605 return (0);
606}
607
608
609/*
a74454a7 610 * End of "$Id: interpret.c 5490 2006-05-04 19:12:45Z mike $".
ef416fc2 611 */