]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/pwg-ppd.c
Merge changes from CUPS 1.5svn-r9352.
[thirdparty/cups.git] / cups / pwg-ppd.c
CommitLineData
54afec33
MS
1/*
2 * "$Id$"
3 *
4 * PWG PPD mapping API implementation for CUPS.
5 *
6 * Copyright 2010 by Apple Inc.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. 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 * Contents:
17 *
18 * _pwgCreateWithPPD() - Create PWG mapping data from a PPD file.
cc754834
MS
19 * _pwgGetBin() - Get the PWG output-bin keyword associated with a
20 * PPD OutputBin.
54afec33
MS
21 * _pwgGetInputSlot() - Get the PPD InputSlot associated with the job
22 * attributes or a keyword string.
23 * _pwgGetMediaType() - Get the PPD MediaType associated with the job
24 * attributes or a keyword string.
cc754834
MS
25 * _pwgGetOutputBin() - Get the PPD OutputBin associated with the
26 * keyword string.
54afec33
MS
27 * _pwgGetPageSize() - Get the PPD PageSize associated with the job
28 * attributes or a keyword string.
29 * _pwgGetSize() - Get the PWG size associated with a PPD PageSize.
30 * _pwgGetSource() - Get the PWG media-source associated with a PPD
31 * InputSlot.
32 * _pwgGetType() - Get the PWG media-type associated with a PPD
33 * MediaType.
34 * _pwgInputSlotForSource() - Get the InputSlot name for the given PWG source.
35 * _pwgMediaTypeForType() - Get the MediaType name for the given PWG type.
36 * _pwgPageSizeForMedia() - Get the PageSize name for the given media.
37 * pwg_ppdize_name() - Convert an IPP keyword to a PPD keyword.
38 * pwg_unppdize_name() - Convert a PPD keyword to a lowercase IPP
39 * keyword.
40 */
41
42/*
43 * Include necessary headers...
44 */
45
71e16022 46#include "cups-private.h"
54afec33
MS
47#include <math.h>
48
49
7cf5915e
MS
50/*
51 * Macro to test for two almost-equal PWG measurements.
52 */
53
54#define _PWG_EQUIVALENT(x, y) (abs((x)-(y)) < 2)
55
56
54afec33
MS
57/*
58 * Local functions...
59 */
60
61static void pwg_ppdize_name(const char *ipp, char *name, size_t namesize);
62static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize);
63
64
65/*
66 * '_pwgCreateWithPPD()' - Create PWG mapping data from a PPD file.
67 */
68
69_pwg_t * /* O - PWG mapping data */
70_pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
71{
7cf5915e 72 int i, j, k; /* Looping vars */
c7017ecc
MS
73 _pwg_t *pwg; /* PWG mapping data */
74 ppd_option_t *input_slot, /* InputSlot option */
75 *media_type, /* MediaType option */
76 *output_bin, /* OutputBin option */
77 *color_model, /* ColorModel option */
78 *duplex; /* Duplex option */
79 ppd_choice_t *choice; /* Current InputSlot/MediaType */
80 _pwg_map_t *map; /* Current source/type map */
81 ppd_attr_t *ppd_attr; /* Current PPD preset attribute */
82 int num_options; /* Number of preset options and props */
83 cups_option_t *options; /* Preset options and properties */
84 ppd_size_t *ppd_size; /* Current PPD size */
85 _pwg_size_t *pwg_size; /* Current PWG size */
86 char pwg_keyword[3 + PPD_MAX_NAME + 1 + 12 + 1 + 12 + 3],
54afec33 87 /* PWG keyword string */
c7017ecc
MS
88 ppd_name[PPD_MAX_NAME];
89 /* Normalized PPD name */
90 const char *pwg_name; /* Standard PWG media name */
91 _pwg_media_t *pwg_media; /* PWG media data */
92 _pwg_output_mode_t pwg_output_mode;/* output-mode index */
93 _pwg_print_quality_t pwg_print_quality;
94 /* print-quality index */
7cf5915e
MS
95 int similar; /* Are the old and new size similar? */
96 _pwg_size_t *old_size; /* Current old size */
97 int old_imageable, /* Old imageable length in 2540ths */
10d09e33
MS
98 old_borderless, /* Old borderless state */
99 old_known_pwg; /* Old PWG name is well-known */
7cf5915e
MS
100 int new_width, /* New width in 2540ths */
101 new_length, /* New length in 2540ths */
102 new_left, /* New left margin in 2540ths */
103 new_bottom, /* New bottom margin in 2540ths */
104 new_right, /* New right margin in 2540ths */
105 new_top, /* New top margin in 2540ths */
106 new_imageable, /* New imageable length in 2540ths */
10d09e33
MS
107 new_borderless, /* New borderless state */
108 new_known_pwg; /* New PWG name is well-known */
7cf5915e 109 _pwg_size_t *new_size; /* New size to add, if any */
54afec33
MS
110
111
112 DEBUG_printf(("_pwgCreateWithPPD(ppd=%p)", ppd));
113
114 /*
115 * Range check input...
116 */
117
118 if (!ppd)
119 return (NULL);
120
121 /*
122 * Allocate memory...
123 */
124
125 if ((pwg = calloc(1, sizeof(_pwg_t))) == NULL)
126 {
127 DEBUG_puts("_pwgCreateWithPPD: Unable to allocate _pwg_t.");
128 goto create_error;
129 }
130
131 /*
132 * Copy and convert size data...
133 */
134
135 if (ppd->num_sizes == 0)
136 {
137 DEBUG_puts("_pwgCreateWithPPD: No page sizes in PPD.");
138 goto create_error;
139 }
140
141 if ((pwg->sizes = calloc(ppd->num_sizes, sizeof(_pwg_size_t))) == NULL)
142 {
143 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_size_t's.",
144 ppd->num_sizes));
145 goto create_error;
146 }
147
54afec33
MS
148 for (i = ppd->num_sizes, pwg_size = pwg->sizes, ppd_size = ppd->sizes;
149 i > 0;
150 i --, ppd_size ++)
151 {
152 /*
153 * Don't copy over custom size...
154 */
155
156 if (!strcasecmp(ppd_size->name, "Custom"))
157 continue;
7cf5915e 158
54afec33
MS
159 /*
160 * Convert the PPD size name to the corresponding PWG keyword name.
161 */
162
163 if ((pwg_media = _pwgMediaForPPD(ppd_size->name)) != NULL)
164 {
165 /*
166 * Standard name, do we have conflicts?
167 */
168
169 for (j = 0; j < pwg->num_sizes; j ++)
170 if (!strcmp(pwg->sizes[j].map.pwg, pwg_media->pwg))
171 {
172 pwg_media = NULL;
173 break;
174 }
175 }
176
177 if (pwg_media)
178 {
179 /*
180 * Standard name and no conflicts, use it!
181 */
182
10d09e33
MS
183 pwg_name = pwg_media->pwg;
184 new_known_pwg = 1;
54afec33
MS
185 }
186 else
187 {
188 /*
189 * Not a standard name; convert it to a PWG vendor name of the form:
190 *
191 * pp_lowerppd_WIDTHxHEIGHTuu
192 */
193
10d09e33
MS
194 pwg_name = pwg_keyword;
195 new_known_pwg = 0;
54afec33
MS
196
197 pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name));
198 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name,
199 _PWG_FROMPTS(ppd_size->width),
200 _PWG_FROMPTS(ppd_size->length));
201 }
202
203 /*
7cf5915e
MS
204 * If we have a similar paper with non-zero margins then we only
205 * want to keep it if it has a larger imageable area length.
54afec33
MS
206 */
207
7cf5915e
MS
208 new_width = _PWG_FROMPTS(ppd_size->width);
209 new_length = _PWG_FROMPTS(ppd_size->length);
210 new_left = _PWG_FROMPTS(ppd_size->left);
211 new_bottom = _PWG_FROMPTS(ppd_size->bottom);
212 new_right = _PWG_FROMPTS(ppd_size->width - ppd_size->right);
213 new_top = _PWG_FROMPTS(ppd_size->length - ppd_size->top);
214 new_imageable = new_length - new_top - new_bottom;
10d09e33
MS
215 new_borderless = new_bottom == 0 && new_top == 0 &&
216 new_left == 0 && new_right == 0;
7cf5915e
MS
217
218 for (k = pwg->num_sizes, similar = 0, old_size = pwg->sizes, new_size = NULL;
219 k > 0 && !similar;
220 k --, old_size ++)
221 {
222 old_imageable = old_size->length - old_size->top - old_size->bottom;
223 old_borderless = old_size->left == 0 && old_size->bottom == 0 &&
224 old_size->right == 0 && old_size->top == 0;
10d09e33
MS
225 old_known_pwg = strncmp(old_size->map.pwg, "oe_", 3) &&
226 strncmp(old_size->map.pwg, "om_", 3);
227
7cf5915e
MS
228 similar = old_borderless == new_borderless &&
229 _PWG_EQUIVALENT(old_size->width, new_width) &&
230 _PWG_EQUIVALENT(old_size->length, new_length);
231
10d09e33
MS
232 if (similar &&
233 (new_known_pwg || (!old_known_pwg && new_imageable > old_imageable)))
7cf5915e
MS
234 {
235 /*
10d09e33
MS
236 * The new paper has a larger imageable area so it could replace
237 * the older paper. Regardless of the imageable area, we always
238 * prefer the size with a well-known PWG name.
7cf5915e
MS
239 */
240
241 new_size = old_size;
242 _cupsStrFree(old_size->map.ppd);
243 _cupsStrFree(old_size->map.pwg);
244 }
245 }
246
247 if (!similar)
248 {
249 /*
250 * The paper was unique enough to deserve its own entry so add it to the
251 * end.
252 */
253
254 new_size = pwg_size ++;
255 pwg->num_sizes ++;
256 }
257
258 if (new_size)
259 {
260 /*
261 * Save this size...
262 */
263
264 new_size->map.ppd = _cupsStrAlloc(ppd_size->name);
265 new_size->map.pwg = _cupsStrAlloc(pwg_name);
266 new_size->width = new_width;
267 new_size->length = new_length;
268 new_size->left = new_left;
269 new_size->bottom = new_bottom;
270 new_size->right = new_right;
271 new_size->top = new_top;
272 }
54afec33
MS
273 }
274
275 if (ppd->variable_sizes)
276 {
277 /*
278 * Generate custom size data...
279 */
280
281 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
282 _PWG_FROMPTS(ppd->custom_max[0]),
283 _PWG_FROMPTS(ppd->custom_max[1]));
284 pwg->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
285 pwg->custom_max_width = _PWG_FROMPTS(ppd->custom_max[0]);
286 pwg->custom_max_length = _PWG_FROMPTS(ppd->custom_max[1]);
287
288 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
289 _PWG_FROMPTS(ppd->custom_min[0]),
290 _PWG_FROMPTS(ppd->custom_min[1]));
291 pwg->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
292 pwg->custom_min_width = _PWG_FROMPTS(ppd->custom_min[0]);
293 pwg->custom_min_length = _PWG_FROMPTS(ppd->custom_min[1]);
294
295 pwg->custom_size.left = _PWG_FROMPTS(ppd->custom_margins[0]);
296 pwg->custom_size.bottom = _PWG_FROMPTS(ppd->custom_margins[1]);
297 pwg->custom_size.right = _PWG_FROMPTS(ppd->custom_margins[2]);
298 pwg->custom_size.top = _PWG_FROMPTS(ppd->custom_margins[3]);
299 }
300
301 /*
302 * Copy and convert InputSlot data...
303 */
304
4220952d
MS
305 if ((input_slot = ppdFindOption(ppd, "InputSlot")) == NULL)
306 input_slot = ppdFindOption(ppd, "HPPaperSource");
307
308 if (input_slot)
54afec33 309 {
4220952d
MS
310 pwg->source_option = _cupsStrAlloc(input_slot->keyword);
311
54afec33
MS
312 if ((pwg->sources = calloc(input_slot->num_choices,
313 sizeof(_pwg_map_t))) == NULL)
314 {
315 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
316 "for InputSlot.", input_slot->num_choices));
317 goto create_error;
318 }
319
320 pwg->num_sources = input_slot->num_choices;
321
322 for (i = input_slot->num_choices, choice = input_slot->choices,
323 map = pwg->sources;
324 i > 0;
325 i --, choice ++, map ++)
326 {
327 if (!strncasecmp(choice->choice, "Auto", 4) ||
328 !strcasecmp(choice->choice, "Default"))
329 pwg_name = "auto";
330 else if (!strcasecmp(choice->choice, "Cassette"))
aaf19ab0 331 pwg_name = "main";
4220952d
MS
332 else if (!strcasecmp(choice->choice, "PhotoTray"))
333 pwg_name = "photo";
334 else if (!strcasecmp(choice->choice, "CDTray"))
335 pwg_name = "disc";
54afec33
MS
336 else if (!strncasecmp(choice->choice, "Multipurpose", 12) ||
337 !strcasecmp(choice->choice, "MP") ||
338 !strcasecmp(choice->choice, "MPTray"))
aaf19ab0 339 pwg_name = "alternate";
54afec33 340 else if (!strcasecmp(choice->choice, "LargeCapacity"))
aaf19ab0 341 pwg_name = "large-capacity";
54afec33 342 else if (!strncasecmp(choice->choice, "Lower", 5))
aaf19ab0 343 pwg_name = "bottom";
54afec33 344 else if (!strncasecmp(choice->choice, "Middle", 6))
aaf19ab0 345 pwg_name = "middle";
54afec33 346 else if (!strncasecmp(choice->choice, "Upper", 5))
aaf19ab0 347 pwg_name = "top";
54afec33 348 else if (!strncasecmp(choice->choice, "Side", 4))
aaf19ab0 349 pwg_name = "side";
54afec33 350 else if (!strcasecmp(choice->choice, "Roll") ||
aaf19ab0 351 !strcasecmp(choice->choice, "Roll1"))
54afec33
MS
352 pwg_name = "main-roll";
353 else if (!strcasecmp(choice->choice, "Roll2"))
354 pwg_name = "alternate-roll";
355 else
356 {
357 /*
358 * Convert PPD name to lowercase...
359 */
360
361 pwg_name = pwg_keyword;
362 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
363 }
364
365 map->pwg = _cupsStrAlloc(pwg_name);
366 map->ppd = _cupsStrAlloc(choice->choice);
367 }
368 }
369
370 /*
371 * Copy and convert MediaType data...
372 */
373
374 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
375 {
376 if ((pwg->types = calloc(media_type->num_choices,
377 sizeof(_pwg_map_t))) == NULL)
378 {
379 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
aaf19ab0 380 "for MediaType.", media_type->num_choices));
54afec33
MS
381 goto create_error;
382 }
383
384 pwg->num_types = media_type->num_choices;
385
386 for (i = media_type->num_choices, choice = media_type->choices,
387 map = pwg->types;
388 i > 0;
389 i --, choice ++, map ++)
390 {
391 if (!strncasecmp(choice->choice, "Auto", 4) ||
392 !strcasecmp(choice->choice, "Any") ||
393 !strcasecmp(choice->choice, "Default"))
394 pwg_name = "auto";
395 else if (!strncasecmp(choice->choice, "Card", 4))
396 pwg_name = "cardstock";
397 else if (!strncasecmp(choice->choice, "Env", 3))
398 pwg_name = "envelope";
399 else if (!strncasecmp(choice->choice, "Gloss", 5))
400 pwg_name = "photographic-glossy";
401 else if (!strcasecmp(choice->choice, "HighGloss"))
402 pwg_name = "photographic-high-gloss";
403 else if (!strcasecmp(choice->choice, "Matte"))
404 pwg_name = "photographic-matte";
405 else if (!strncasecmp(choice->choice, "Plain", 5))
406 pwg_name = "stationery";
407 else if (!strncasecmp(choice->choice, "Coated", 6))
408 pwg_name = "stationery-coated";
409 else if (!strcasecmp(choice->choice, "Inkjet"))
410 pwg_name = "stationery-inkjet";
411 else if (!strcasecmp(choice->choice, "Letterhead"))
412 pwg_name = "stationery-letterhead";
413 else if (!strncasecmp(choice->choice, "Preprint", 8))
414 pwg_name = "stationery-preprinted";
415 else if (!strncasecmp(choice->choice, "Transparen", 10))
416 pwg_name = "transparency";
417 else
418 {
419 /*
420 * Convert PPD name to lowercase...
421 */
422
423 pwg_name = pwg_keyword;
424 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
425 }
426
427 map->pwg = _cupsStrAlloc(pwg_name);
428 map->ppd = _cupsStrAlloc(choice->choice);
429 }
430 }
431
cc754834
MS
432
433 /*
434 * Copy and convert OutputBin data...
435 */
436
437 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
438 {
439 if ((pwg->bins = calloc(output_bin->num_choices,
440 sizeof(_pwg_map_t))) == NULL)
441 {
442 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
443 "for OutputBin.", output_bin->num_choices));
444 goto create_error;
445 }
446
447 pwg->num_bins = output_bin->num_choices;
448
449 for (i = output_bin->num_choices, choice = output_bin->choices,
450 map = pwg->bins;
451 i > 0;
452 i --, choice ++, map ++)
453 {
454 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
455
456 map->pwg = _cupsStrAlloc(pwg_keyword);
457 map->ppd = _cupsStrAlloc(choice->choice);
458 }
459 }
460
c7017ecc
MS
461 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
462 {
463 /*
464 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
465 */
466
467 const char *quality, /* com.apple.print.preset.quality value */
468 *output_mode, /* com.apple.print.preset.output-mode value */
7cf5915e
MS
469 *color_model_val, /* ColorModel choice */
470 *graphics_type, /* com.apple.print.preset.graphicsType value */
471 *paper_coating; /* com.apple.print.preset.media-front-coating value */
c7017ecc
MS
472
473
474 do
475 {
476 num_options = _ppdParseOptions(ppd_attr->value, 0, &options,
477 _PPD_PARSE_ALL);
478
479 if ((quality = cupsGetOption("com.apple.print.preset.quality",
480 num_options, options)) != NULL)
481 {
482 /*
483 * Get the print-quality for this preset...
484 */
485
486 if (!strcmp(quality, "low"))
487 pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
488 else if (!strcmp(quality, "high"))
489 pwg_print_quality = _PWG_PRINT_QUALITY_HIGH;
490 else
491 pwg_print_quality = _PWG_PRINT_QUALITY_NORMAL;
492
7cf5915e
MS
493 /*
494 * Ignore graphicsType "Photo" presets that are not high quality.
495 */
496
497 graphics_type = cupsGetOption("com.apple.print.preset.graphicsType",
498 num_options, options);
499
500 if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH && graphics_type &&
501 !strcmp(graphics_type, "Photo"))
502 continue;
503
504 /*
505 * Ignore presets for normal and draft quality where the coating
506 * isn't "none" or "autodetect".
507 */
508
509 paper_coating = cupsGetOption(
510 "com.apple.print.preset.media-front-coating",
511 num_options, options);
512
513 if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH && paper_coating &&
514 strcmp(paper_coating, "none") &&
515 strcmp(paper_coating, "autodetect"))
516 continue;
517
c7017ecc
MS
518 /*
519 * Get the output mode for this preset...
520 */
521
522 output_mode = cupsGetOption("com.apple.print.preset.output-mode",
523 num_options, options);
524 color_model_val = cupsGetOption("ColorModel", num_options, options);
525
526 if (output_mode)
527 {
528 if (!strcmp(output_mode, "monochrome"))
529 pwg_output_mode = _PWG_OUTPUT_MODE_MONOCHROME;
530 else
531 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
532 }
533 else if (color_model_val)
534 {
535 if (!strcasecmp(color_model_val, "Gray"))
536 pwg_output_mode = _PWG_OUTPUT_MODE_MONOCHROME;
537 else
538 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
539 }
540 else
541 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
542
543 /*
544 * Save the options for this combination as needed...
545 */
546
547 if (!pwg->num_presets[pwg_output_mode][pwg_print_quality])
548 pwg->num_presets[pwg_output_mode][pwg_print_quality] =
549 _ppdParseOptions(ppd_attr->value, 0,
550 pwg->presets[pwg_output_mode] +
551 pwg_print_quality, _PPD_PARSE_OPTIONS);
552 }
553
554 cupsFreeOptions(num_options, options);
555 }
556 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL);
557 }
558
559 if (!pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] &&
560 !pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] &&
4220952d 561 !pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH])
c7017ecc
MS
562 {
563 /*
4220952d
MS
564 * Try adding some common color options to create grayscale presets. These
565 * are listed in order of popularity...
c7017ecc
MS
566 */
567
4220952d
MS
568 const char *color_option = NULL, /* Color control option */
569 *gray_choice = NULL; /* Choice to select grayscale */
c7017ecc 570
4220952d
MS
571 if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL &&
572 ppdFindChoice(color_model, "Gray"))
c7017ecc 573 {
4220952d
MS
574 color_option = "ColorModel";
575 gray_choice = "Gray";
576 }
577 else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL &&
578 ppdFindChoice(color_model, "grayscale"))
579 {
580 color_option = "HPColorMode";
581 gray_choice = "grayscale";
582 }
583 else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL &&
584 ppdFindChoice(color_model, "Mono"))
585 {
586 color_option = "BRMonoColor";
587 gray_choice = "Mono";
588 }
589 else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL &&
590 ppdFindChoice(color_model, "1"))
591 {
592 color_option = "CNIJSGrayScale";
593 gray_choice = "1";
594 }
595 else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL &&
596 ppdFindChoice(color_model, "True"))
597 {
598 color_option = "HPColorAsGray";
599 gray_choice = "True";
600 }
c7017ecc 601
4220952d
MS
602 if (color_option && gray_choice)
603 {
604 /*
605 * Copy and convert ColorModel (output-mode) data...
606 */
c7017ecc 607
4220952d
MS
608 cups_option_t *coption, /* Color option */
609 *moption; /* Monochrome option */
610
611 for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
612 pwg_print_quality < _PWG_PRINT_QUALITY_MAX;
613 pwg_print_quality ++)
614 {
615 if (pwg->num_presets[_PWG_OUTPUT_MODE_COLOR][pwg_print_quality])
c7017ecc 616 {
4220952d
MS
617 /*
618 * Copy the color options...
619 */
620
621 num_options = pwg->num_presets[_PWG_OUTPUT_MODE_COLOR]
622 [pwg_print_quality];
623 options = calloc(sizeof(cups_option_t), num_options);
624
625 if (options)
c7017ecc 626 {
4220952d
MS
627 for (i = num_options, moption = options,
628 coption = pwg->presets[_PWG_OUTPUT_MODE_COLOR]
629 [pwg_print_quality];
630 i > 0;
631 i --, moption ++, coption ++)
632 {
633 moption->name = _cupsStrRetain(coption->name);
634 moption->value = _cupsStrRetain(coption->value);
635 }
636
637 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
638 num_options;
639 pwg->presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
640 options;
c7017ecc 641 }
c7017ecc 642 }
4220952d
MS
643 else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL)
644 continue;
c7017ecc 645
4220952d
MS
646 /*
647 * Add the grayscale option to the preset...
648 */
c7017ecc 649
4220952d
MS
650 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
651 cupsAddOption(color_option, gray_choice,
652 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME]
653 [pwg_print_quality],
654 pwg->presets[_PWG_OUTPUT_MODE_MONOCHROME] +
655 pwg_print_quality);
656 }
c7017ecc
MS
657 }
658 }
659
660 /*
661 * Copy and convert Duplex (sides) data...
662 */
663
664 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
665 if ((duplex = ppdFindOption(ppd, "JCLDuplex")) == NULL)
666 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
667 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
668 duplex = ppdFindOption(ppd, "KD03Duplex");
669
670 if (duplex)
671 {
672 pwg->sides_option = _cupsStrAlloc(duplex->keyword);
673
674 for (i = duplex->num_choices, choice = duplex->choices;
675 i > 0;
676 i --, choice ++)
677 {
678 if ((!strcasecmp(choice->choice, "None") ||
679 !strcasecmp(choice->choice, "False")) && !pwg->sides_1sided)
680 pwg->sides_1sided = _cupsStrAlloc(choice->choice);
681 else if ((!strcasecmp(choice->choice, "DuplexNoTumble") ||
682 !strcasecmp(choice->choice, "LongEdge") ||
683 !strcasecmp(choice->choice, "Top")) && !pwg->sides_2sided_long)
684 pwg->sides_2sided_long = _cupsStrAlloc(choice->choice);
685 else if ((!strcasecmp(choice->choice, "DuplexTumble") ||
686 !strcasecmp(choice->choice, "ShortEdge") ||
687 !strcasecmp(choice->choice, "Bottom")) &&
688 !pwg->sides_2sided_short)
689 pwg->sides_2sided_short = _cupsStrAlloc(choice->choice);
690 }
691 }
692
54afec33
MS
693 return (pwg);
694
695 /*
696 * If we get here we need to destroy the PWG mapping data and return NULL...
697 */
698
699 create_error:
700
701 _cupsSetError(IPP_INTERNAL_ERROR, _("Out of memory."), 1);
702 _pwgDestroy(pwg);
703
704 return (NULL);
705}
706
707
cc754834
MS
708/*
709 * '_pwgGetBin()' - Get the PWG output-bin keyword associated with a PPD
710 * OutputBin.
711 */
712
713const char * /* O - output-bin or NULL */
714_pwgGetBin(_pwg_t *pwg, /* I - PWG mapping data */
715 const char *output_bin) /* I - PPD OutputBin string */
716{
717 int i; /* Looping var */
718
719
720 /*
721 * Range check input...
722 */
723
724 if (!pwg || !output_bin)
725 return (NULL);
726
727 /*
728 * Look up the OutputBin string...
729 */
730
731
732 for (i = 0; i < pwg->num_bins; i ++)
733 if (!strcasecmp(output_bin, pwg->bins[i].ppd))
734 return (pwg->bins[i].pwg);
735
736 return (NULL);
737}
738
739
54afec33
MS
740/*
741 * '_pwgGetInputSlot()' - Get the PPD InputSlot associated with the job
742 * attributes or a keyword string.
743 */
744
745const char * /* O - PPD InputSlot or NULL */
746_pwgGetInputSlot(_pwg_t *pwg, /* I - PWG mapping data */
747 ipp_t *job, /* I - Job attributes or NULL */
748 const char *keyword) /* I - Keyword string or NULL */
749{
750 /*
751 * Range check input...
752 */
753
754 if (!pwg || pwg->num_sources == 0 || (!job && !keyword))
755 return (NULL);
756
757 if (job && !keyword)
758 {
759 /*
760 * Lookup the media-col attribute and any media-source found there...
761 */
762
763 ipp_attribute_t *media_col, /* media-col attribute */
764 *media_source; /* media-source attribute */
4220952d
MS
765 _pwg_size_t size; /* Dimensional size */
766 int margins_set; /* Were the margins set? */
54afec33
MS
767
768 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
769 if (media_col &&
770 (media_source = ippFindAttribute(media_col->values[0].collection,
771 "media-source",
772 IPP_TAG_KEYWORD)) != NULL)
4220952d
MS
773 {
774 /*
775 * Use the media-source value from media-col...
776 */
777
54afec33 778 keyword = media_source->values[0].string.text;
4220952d
MS
779 }
780 else if (_pwgInitSize(&size, job, &margins_set))
781 {
782 /*
783 * For media <= 5x7, look for a photo tray...
784 */
785
786 if (size.width <= (5 * 2540) && size.length <= (7 * 2540))
787 keyword = "photo";
788 }
54afec33
MS
789 }
790
791 if (keyword)
792 {
793 int i; /* Looping var */
794
795 for (i = 0; i < pwg->num_sources; i ++)
796 if (!strcasecmp(keyword, pwg->sources[i].pwg))
797 return (pwg->sources[i].ppd);
798 }
799
800 return (NULL);
801}
802
803
804/*
805 * '_pwgGetMediaType()' - Get the PPD MediaType associated with the job
806 * attributes or a keyword string.
807 */
808
809const char * /* O - PPD MediaType or NULL */
810_pwgGetMediaType(_pwg_t *pwg, /* I - PWG mapping data */
811 ipp_t *job, /* I - Job attributes or NULL */
812 const char *keyword) /* I - Keyword string or NULL */
813{
814 /*
815 * Range check input...
816 */
817
818 if (!pwg || pwg->num_types == 0 || (!job && !keyword))
819 return (NULL);
820
821 if (job && !keyword)
822 {
823 /*
824 * Lookup the media-col attribute and any media-source found there...
825 */
826
827 ipp_attribute_t *media_col, /* media-col attribute */
828 *media_type; /* media-type attribute */
829
830 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
831 if (media_col)
832 {
833 if ((media_type = ippFindAttribute(media_col->values[0].collection,
834 "media-type",
835 IPP_TAG_KEYWORD)) == NULL)
836 media_type = ippFindAttribute(media_col->values[0].collection,
837 "media-type", IPP_TAG_NAME);
838
839 if (media_type)
840 keyword = media_type->values[0].string.text;
841 }
842 }
843
844 if (keyword)
845 {
846 int i; /* Looping var */
847
848 for (i = 0; i < pwg->num_types; i ++)
849 if (!strcasecmp(keyword, pwg->types[i].pwg))
850 return (pwg->types[i].ppd);
851 }
852
853 return (NULL);
854}
855
856
cc754834
MS
857/*
858 * '_pwgGetOutputBin()' - Get the PPD OutputBin associated with the keyword
859 * string.
860 */
861
862const char * /* O - PPD OutputBin or NULL */
863_pwgGetOutputBin(_pwg_t *pwg, /* I - PWG mapping data */
864 const char *output_bin)/* I - Keyword string */
865{
866 int i; /* Looping var */
867
868
869 /*
870 * Range check input...
871 */
872
873 if (!pwg || !output_bin)
874 return (NULL);
875
876 /*
877 * Look up the OutputBin string...
878 */
879
880
881 for (i = 0; i < pwg->num_bins; i ++)
882 if (!strcasecmp(output_bin, pwg->bins[i].pwg))
883 return (pwg->bins[i].ppd);
884
885 return (NULL);
886}
887
888
54afec33
MS
889/*
890 * '_pwgGetPageSize()' - Get the PPD PageSize associated with the job
891 * attributes or a keyword string.
892 */
893
894const char * /* O - PPD PageSize or NULL */
895_pwgGetPageSize(_pwg_t *pwg, /* I - PWG mapping data */
896 ipp_t *job, /* I - Job attributes or NULL */
897 const char *keyword, /* I - Keyword string or NULL */
898 int *exact) /* I - 1 if exact match, 0 otherwise */
899{
900 int i; /* Looping var */
901 _pwg_size_t *size, /* Current size */
902 *closest, /* Closest size */
903 jobsize; /* Size data from job */
904 int margins_set, /* Were the margins set? */
905 dwidth, /* Difference in width */
906 dlength, /* Difference in length */
907 dleft, /* Difference in left margins */
908 dright, /* Difference in right margins */
909 dbottom, /* Difference in bottom margins */
910 dtop, /* Difference in top margins */
911 dmin, /* Minimum difference */
912 dclosest; /* Closest difference */
7cf5915e 913 const char *ppd_name; /* PPD media name */
54afec33
MS
914
915
6c48a6ca
MS
916 DEBUG_printf(("_pwgGetPageSize(pwg=%p, job=%p, keyword=\"%s\", exact=%p)",
917 pwg, job, keyword, exact));
918
54afec33
MS
919 /*
920 * Range check input...
921 */
922
923 if (!pwg || (!job && !keyword))
924 return (NULL);
925
926 if (exact)
927 *exact = 0;
928
7cf5915e
MS
929 ppd_name = keyword;
930
931 if (job)
932 {
933 /*
934 * Try getting the PPD media name from the job attributes...
935 */
936
937 ipp_attribute_t *attr; /* Job attribute */
938
939 if ((attr = ippFindAttribute(job, "PageSize", IPP_TAG_ZERO)) == NULL)
940 if ((attr = ippFindAttribute(job, "PageRegion", IPP_TAG_ZERO)) == NULL)
941 attr = ippFindAttribute(job, "media", IPP_TAG_ZERO);
942
6c48a6ca
MS
943#ifdef DEBUG
944 if (attr)
945 DEBUG_printf(("1_pwgGetPageSize: Found attribute %s (%s)", attr->name,
946 ippTagString(attr->value_tag)));
947 else
948 DEBUG_puts("1_pwgGetPageSize: Did not find media attribute.");
949#endif /* DEBUG */
950
7cf5915e
MS
951 if (attr && (attr->value_tag == IPP_TAG_NAME ||
952 attr->value_tag == IPP_TAG_KEYWORD))
953 ppd_name = attr->values[0].string.text;
954 }
955
6c48a6ca
MS
956 DEBUG_printf(("1_pwgGetPageSize: ppd_name=\"%s\"", ppd_name));
957
7cf5915e
MS
958 if (ppd_name)
959 {
960 /*
961 * Try looking up the named PPD size first...
962 */
963
964 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
6c48a6ca
MS
965 {
966 DEBUG_printf(("2_pwgGetPageSize: size[%d]=[\"%s\" \"%s\"]",
967 (int)(size - pwg->sizes), size->map.pwg, size->map.ppd));
968
7cf5915e 969 if (!strcasecmp(ppd_name, size->map.ppd))
6c48a6ca
MS
970 {
971 if (exact)
972 *exact = 1;
973
974 DEBUG_printf(("1_pwgGetPageSize: Returning \"%s\"", ppd_name));
975
7cf5915e 976 return (ppd_name);
6c48a6ca
MS
977 }
978 }
7cf5915e
MS
979 }
980
54afec33
MS
981 if (job && !keyword)
982 {
983 /*
984 * Get the size using media-col or media, with the preference being
985 * media-col.
986 */
987
988 if (!_pwgInitSize(&jobsize, job, &margins_set))
989 return (NULL);
aaf19ab0 990 }
54afec33
MS
991 else
992 {
993 /*
994 * Get the size using a media keyword...
995 */
996
997 _pwg_media_t *media; /* Media definition */
998
999
1000 if ((media = _pwgMediaForPWG(keyword)) == NULL)
1001 if ((media = _pwgMediaForLegacy(keyword)) == NULL)
7cf5915e
MS
1002 if ((media = _pwgMediaForPPD(keyword)) == NULL)
1003 return (NULL);
54afec33
MS
1004
1005 jobsize.width = media->width;
1006 jobsize.length = media->length;
1007 margins_set = 0;
1008 }
1009
1010 /*
1011 * Now that we have the dimensions and possibly the margins, look at the
1012 * available sizes and find the match...
1013 */
1014
1015 closest = NULL;
1016 dclosest = 999999999;
1017
1018 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
1019 {
1020 /*
1021 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
1022 * is just about 176/2540ths...
1023 */
1024
1025 dwidth = size->width - jobsize.width;
1026 dlength = size->length - jobsize.length;
1027
1028 if (dwidth <= -176 || dwidth >= 176 || dlength <= -176 || dlength >= 176)
1029 continue;
1030
1031 if (margins_set)
1032 {
1033 /*
1034 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
1035 */
1036
1037 dleft = size->left - jobsize.left;
1038 dright = size->right - jobsize.right;
1039 dtop = size->top - jobsize.top;
1040 dbottom = size->bottom - jobsize.bottom;
1041
1042 if (dleft <= -35 || dleft >= 35 || dright <= -35 || dright >= 35 ||
1043 dtop <= -35 || dtop >= 35 || dbottom <= -35 || dbottom >= 35)
1044 {
1045 dleft = dleft < 0 ? -dleft : dleft;
1046 dright = dright < 0 ? -dright : dright;
1047 dbottom = dbottom < 0 ? -dbottom : dbottom;
1048 dtop = dtop < 0 ? -dtop : dtop;
1049 dmin = dleft + dright + dbottom + dtop;
1050
1051 if (dmin < dclosest)
1052 {
1053 dclosest = dmin;
1054 closest = size;
1055 }
1056
1057 continue;
1058 }
1059 }
1060
1061 if (exact)
1062 *exact = 1;
1063
6c48a6ca
MS
1064 DEBUG_printf(("1_pwgGetPageSize: Returning \"%s\"", size->map.ppd));
1065
54afec33
MS
1066 return (size->map.ppd);
1067 }
1068
1069 if (closest)
6c48a6ca
MS
1070 {
1071 DEBUG_printf(("1_pwgGetPageSize: Returning \"%s\" (closest)",
1072 closest->map.ppd));
1073
54afec33 1074 return (closest->map.ppd);
6c48a6ca 1075 }
54afec33
MS
1076
1077 /*
1078 * If we get here we need to check for custom page size support...
1079 */
1080
1081 if (jobsize.width >= pwg->custom_min_width &&
1082 jobsize.width <= pwg->custom_max_width &&
1083 jobsize.length >= pwg->custom_min_length &&
1084 jobsize.length <= pwg->custom_max_length)
1085 {
1086 /*
1087 * In range, format as Custom.WWWWxLLLL (points).
1088 */
1089
1090 snprintf(pwg->custom_ppd_size, sizeof(pwg->custom_ppd_size), "Custom.%dx%d",
1091 (int)_PWG_TOPTS(jobsize.width), (int)_PWG_TOPTS(jobsize.length));
1092
1093 if (margins_set && exact)
1094 {
1095 dleft = pwg->custom_size.left - jobsize.left;
1096 dright = pwg->custom_size.right - jobsize.right;
1097 dtop = pwg->custom_size.top - jobsize.top;
1098 dbottom = pwg->custom_size.bottom - jobsize.bottom;
1099
1100 if (dleft > -35 && dleft < 35 && dright > -35 && dright < 35 &&
1101 dtop > -35 && dtop < 35 && dbottom > -35 && dbottom < 35)
1102 *exact = 1;
1103 }
1104 else if (exact)
1105 *exact = 1;
1106
6c48a6ca
MS
1107 DEBUG_printf(("1_pwgGetPageSize: Returning \"%s\" (custom)",
1108 pwg->custom_ppd_size));
1109
54afec33
MS
1110 return (pwg->custom_ppd_size);
1111 }
1112
1113 /*
1114 * No custom page size support or the size is out of range - return NULL.
1115 */
1116
6c48a6ca
MS
1117 DEBUG_puts("1_pwgGetPageSize: Returning NULL");
1118
54afec33
MS
1119 return (NULL);
1120}
1121
1122
1123/*
1124 * '_pwgGetSize()' - Get the PWG size associated with a PPD PageSize.
1125 */
1126
1127_pwg_size_t * /* O - PWG size or NULL */
1128_pwgGetSize(_pwg_t *pwg, /* I - PWG mapping data */
1129 const char *page_size) /* I - PPD PageSize */
1130{
1131 int i;
1132 _pwg_size_t *size; /* Current size */
1133
1134
cc754834
MS
1135 /*
1136 * Range check input...
1137 */
1138
1139 if (!pwg || !page_size)
1140 return (NULL);
1141
54afec33
MS
1142 if (!strncasecmp(page_size, "Custom.", 7))
1143 {
1144 /*
1145 * Custom size; size name can be one of the following:
1146 *
1147 * Custom.WIDTHxLENGTHin - Size in inches
1148 * Custom.WIDTHxLENGTHft - Size in feet
1149 * Custom.WIDTHxLENGTHcm - Size in centimeters
1150 * Custom.WIDTHxLENGTHmm - Size in millimeters
1151 * Custom.WIDTHxLENGTHm - Size in meters
1152 * Custom.WIDTHxLENGTH[pt] - Size in points
1153 */
1154
1155 double w, l; /* Width and length of page */
1156 char *ptr; /* Pointer into PageSize */
1157 struct lconv *loc; /* Locale data */
1158
1159 loc = localeconv();
1160 w = (float)_cupsStrScand(page_size + 7, &ptr, loc);
1161 if (!ptr || *ptr != 'x')
1162 return (NULL);
1163
1164 l = (float)_cupsStrScand(ptr + 1, &ptr, loc);
1165 if (!ptr)
1166 return (NULL);
1167
1168 if (!strcasecmp(ptr, "in"))
1169 {
1170 w *= 2540.0;
1171 l *= 2540.0;
1172 }
1173 else if (!strcasecmp(ptr, "ft"))
1174 {
1175 w *= 12.0 * 2540.0;
1176 l *= 12.0 * 2540.0;
1177 }
1178 else if (!strcasecmp(ptr, "mm"))
1179 {
1180 w *= 100.0;
1181 l *= 100.0;
1182 }
1183 else if (!strcasecmp(ptr, "cm"))
1184 {
1185 w *= 1000.0;
1186 l *= 1000.0;
1187 }
1188 else if (!strcasecmp(ptr, "m"))
1189 {
1190 w *= 100000.0;
1191 l *= 100000.0;
1192 }
1193 else
1194 {
1195 w *= 2540.0 / 72.0;
1196 l *= 2540.0 / 72.0;
1197 }
1198
1199 pwg->custom_size.width = (int)w;
1200 pwg->custom_size.length = (int)l;
1201
1202 return (&(pwg->custom_size));
1203 }
1204
1205 /*
1206 * Not a custom size - look it up...
1207 */
1208
1209 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
1210 if (!strcasecmp(page_size, size->map.ppd))
1211 return (size);
1212
1213 return (NULL);
1214}
1215
1216
1217/*
1218 * '_pwgGetSource()' - Get the PWG media-source associated with a PPD InputSlot.
1219 */
1220
1221const char * /* O - PWG media-source keyword */
1222_pwgGetSource(_pwg_t *pwg, /* I - PWG mapping data */
1223 const char *input_slot) /* I - PPD InputSlot */
1224{
1225 int i; /* Looping var */
1226 _pwg_map_t *source; /* Current source */
1227
1228
cc754834
MS
1229 /*
1230 * Range check input...
1231 */
1232
1233 if (!pwg || !input_slot)
1234 return (NULL);
1235
54afec33
MS
1236 for (i = pwg->num_sources, source = pwg->sources; i > 0; i --, source ++)
1237 if (!strcasecmp(input_slot, source->ppd))
1238 return (source->pwg);
1239
1240 return (NULL);
1241}
1242
1243
1244/*
1245 * '_pwgGetType()' - Get the PWG media-type associated with a PPD MediaType.
1246 */
1247
1248const char * /* O - PWG media-type keyword */
1249_pwgGetType(_pwg_t *pwg, /* I - PWG mapping data */
1250 const char *media_type) /* I - PPD MediaType */
1251{
1252 int i; /* Looping var */
1253 _pwg_map_t *type; /* Current type */
1254
1255
cc754834
MS
1256 /*
1257 * Range check input...
1258 */
1259
1260 if (!pwg || !media_type)
1261 return (NULL);
1262
54afec33
MS
1263 for (i = pwg->num_types, type = pwg->types; i > 0; i --, type ++)
1264 if (!strcasecmp(media_type, type->ppd))
1265 return (type->pwg);
1266
1267 return (NULL);
1268}
1269
1270
1271/*
1272 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG source.
1273 */
1274
1275const char * /* O - InputSlot name */
1276_pwgInputSlotForSource(
1277 const char *media_source, /* I - PWG media-source */
1278 char *name, /* I - Name buffer */
1279 size_t namesize) /* I - Size of name buffer */
1280{
cc754834
MS
1281 /*
1282 * Range check input...
1283 */
1284
1285 if (!media_source || !name || namesize < PPD_MAX_NAME)
1286 return (NULL);
1287
aaf19ab0 1288 if (strcasecmp(media_source, "main"))
54afec33 1289 strlcpy(name, "Cassette", namesize);
aaf19ab0 1290 else if (strcasecmp(media_source, "alternate"))
54afec33 1291 strlcpy(name, "Multipurpose", namesize);
aaf19ab0 1292 else if (strcasecmp(media_source, "large-capacity"))
54afec33 1293 strlcpy(name, "LargeCapacity", namesize);
aaf19ab0 1294 else if (strcasecmp(media_source, "bottom"))
54afec33 1295 strlcpy(name, "Lower", namesize);
aaf19ab0 1296 else if (strcasecmp(media_source, "middle"))
54afec33 1297 strlcpy(name, "Middle", namesize);
aaf19ab0 1298 else if (strcasecmp(media_source, "top"))
54afec33 1299 strlcpy(name, "Upper", namesize);
aaf19ab0 1300 else if (strcasecmp(media_source, "rear"))
54afec33 1301 strlcpy(name, "Rear", namesize);
aaf19ab0 1302 else if (strcasecmp(media_source, "side"))
54afec33 1303 strlcpy(name, "Side", namesize);
aaf19ab0 1304 else if (strcasecmp(media_source, "envelope"))
54afec33
MS
1305 strlcpy(name, "Envelope", namesize);
1306 else if (strcasecmp(media_source, "main-roll"))
1307 strlcpy(name, "Roll", namesize);
1308 else if (strcasecmp(media_source, "alternate-roll"))
1309 strlcpy(name, "Roll2", namesize);
1310 else
1311 pwg_ppdize_name(media_source, name, namesize);
1312
1313 return (name);
1314}
1315
1316
1317/*
1318 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG type.
1319 */
1320
1321const char * /* O - MediaType name */
1322_pwgMediaTypeForType(
1323 const char *media_type, /* I - PWG media-source */
1324 char *name, /* I - Name buffer */
1325 size_t namesize) /* I - Size of name buffer */
1326{
cc754834
MS
1327 /*
1328 * Range check input...
1329 */
1330
1331 if (!media_type || !name || namesize < PPD_MAX_NAME)
1332 return (NULL);
1333
54afec33
MS
1334 if (strcasecmp(media_type, "auto"))
1335 strlcpy(name, "Auto", namesize);
1336 else if (strcasecmp(media_type, "cardstock"))
1337 strlcpy(name, "Cardstock", namesize);
1338 else if (strcasecmp(media_type, "envelope"))
1339 strlcpy(name, "Envelope", namesize);
1340 else if (strcasecmp(media_type, "photographic-glossy"))
1341 strlcpy(name, "Glossy", namesize);
1342 else if (strcasecmp(media_type, "photographic-high-gloss"))
1343 strlcpy(name, "HighGloss", namesize);
1344 else if (strcasecmp(media_type, "photographic-matte"))
1345 strlcpy(name, "Matte", namesize);
1346 else if (strcasecmp(media_type, "stationery"))
1347 strlcpy(name, "Plain", namesize);
1348 else if (strcasecmp(media_type, "stationery-coated"))
1349 strlcpy(name, "Coated", namesize);
1350 else if (strcasecmp(media_type, "stationery-inkjet"))
1351 strlcpy(name, "Inkjet", namesize);
1352 else if (strcasecmp(media_type, "stationery-letterhead"))
1353 strlcpy(name, "Letterhead", namesize);
1354 else if (strcasecmp(media_type, "stationery-preprinted"))
1355 strlcpy(name, "Preprinted", namesize);
1356 else if (strcasecmp(media_type, "transparency"))
1357 strlcpy(name, "Transparency", namesize);
1358 else
1359 pwg_ppdize_name(media_type, name, namesize);
1360
1361 return (name);
1362}
1363
1364
1365/*
1366 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
1367 */
1368
1369const char * /* O - PageSize name */
1370_pwgPageSizeForMedia(
1371 _pwg_media_t *media, /* I - Media */
1372 char *name, /* I - PageSize name buffer */
1373 size_t namesize) /* I - Size of name buffer */
1374{
1375 const char *sizeptr, /* Pointer to size in PWG name */
1376 *dimptr; /* Pointer to dimensions in PWG name */
1377
1378
1379 /*
1380 * Range check input...
1381 */
1382
1383 if (!media || !name || namesize < PPD_MAX_NAME)
1384 return (NULL);
1385
1386 /*
1387 * Copy or generate a PageSize name...
1388 */
1389
1390 if (media->ppd)
1391 {
1392 /*
1393 * Use a standard Adobe name...
1394 */
1395
1396 strlcpy(name, media->ppd, namesize);
1397 }
1398 else if (!media->pwg || !strncmp(media->pwg, "custom_", 7) ||
1399 (sizeptr = strchr(media->pwg, '_')) == NULL ||
1400 (dimptr = strchr(sizeptr + 1, '_')) == NULL ||
7cf5915e 1401 (size_t)(dimptr - sizeptr) > namesize)
54afec33
MS
1402 {
1403 /*
1404 * Use a name of the form "wNNNhNNN"...
1405 */
1406
1407 snprintf(name, namesize, "w%dh%d", (int)_PWG_TOPTS(media->width),
1408 (int)_PWG_TOPTS(media->length));
1409 }
1410 else
1411 {
1412 /*
1413 * Copy the size name from class_sizename_dimensions...
1414 */
1415
1416 memcpy(name, sizeptr + 1, dimptr - sizeptr - 1);
1417 name[dimptr - sizeptr - 1] = '\0';
1418 }
1419
1420 return (name);
1421}
1422
1423
1424/*
1425 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
1426 */
1427
1428static void
1429pwg_ppdize_name(const char *ipp, /* I - IPP keyword */
1430 char *name, /* I - Name buffer */
1431 size_t namesize) /* I - Size of name buffer */
1432{
1433 char *ptr, /* Pointer into name buffer */
1434 *end; /* End of name buffer */
1435
1436
1437 *name = toupper(*ipp++);
1438
1439 for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
1440 {
7cf5915e 1441 if (*ipp == '-' && _cups_isalpha(ipp[1]))
54afec33
MS
1442 {
1443 ipp ++;
1444 *ptr++ = toupper(*ipp++ & 255);
1445 }
1446 else
1447 *ptr++ = *ipp++;
1448 }
1449
1450 *ptr = '\0';
1451}
1452
1453
1454/*
1455 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
1456 */
1457
1458static void
1459pwg_unppdize_name(const char *ppd, /* I - PPD keyword */
1460 char *name, /* I - Name buffer */
1461 size_t namesize) /* I - Size of name buffer */
1462{
1463 char *ptr, /* Pointer into name buffer */
1464 *end; /* End of name buffer */
1465
1466
1467 for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++)
1468 {
7cf5915e 1469 if (_cups_isalnum(*ppd) || *ppd == '-')
54afec33 1470 *ptr++ = tolower(*ppd & 255);
7cf5915e 1471 else if (*ppd == '_' || *ppd == '.')
54afec33
MS
1472 *ptr++ = '-';
1473
7cf5915e
MS
1474 if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) &&
1475 _cups_isupper(ppd[1]) && ptr < end)
54afec33
MS
1476 *ptr++ = '-';
1477 }
1478
1479 *ptr = '\0';
1480}
1481
1482
1483/*
1484 * End of "$Id$".
1485 */