4 * PWG PPD mapping API implementation for CUPS.
6 * Copyright 2010 by Apple Inc.
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/".
14 * This file is subject to the Apple OS-Developed Software exception.
18 * _pwgCreateWithPPD() - Create PWG mapping data from a PPD file.
19 * _pwgGetBin() - Get the PWG output-bin keyword associated with a
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.
25 * _pwgGetOutputBin() - Get the PPD OutputBin associated with the
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
32 * _pwgGetType() - Get the PWG media-type associated with a PPD
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
43 * Include necessary headers...
46 #include "cups-private.h"
54 static void pwg_ppdize_name(const char *ipp
, char *name
, size_t namesize
);
55 static void pwg_unppdize_name(const char *ppd
, char *name
, size_t namesize
);
59 * '_pwgCreateWithPPD()' - Create PWG mapping data from a PPD file.
62 _pwg_t
* /* O - PWG mapping data */
63 _pwgCreateWithPPD(ppd_file_t
*ppd
) /* I - PPD file */
65 int i
, j
; /* Looping vars */
66 _pwg_t
*pwg
; /* PWG mapping data */
67 ppd_option_t
*input_slot
, /* InputSlot option */
68 *media_type
, /* MediaType option */
69 *output_bin
, /* OutputBin option */
70 *color_model
, /* ColorModel option */
71 *duplex
; /* Duplex option */
72 ppd_choice_t
*choice
; /* Current InputSlot/MediaType */
73 _pwg_map_t
*map
; /* Current source/type map */
74 ppd_attr_t
*ppd_attr
; /* Current PPD preset attribute */
75 int num_options
; /* Number of preset options and props */
76 cups_option_t
*options
; /* Preset options and properties */
77 ppd_size_t
*ppd_size
; /* Current PPD size */
78 _pwg_size_t
*pwg_size
; /* Current PWG size */
79 char pwg_keyword
[3 + PPD_MAX_NAME
+ 1 + 12 + 1 + 12 + 3],
80 /* PWG keyword string */
81 ppd_name
[PPD_MAX_NAME
];
82 /* Normalized PPD name */
83 const char *pwg_name
; /* Standard PWG media name */
84 _pwg_media_t
*pwg_media
; /* PWG media data */
85 _pwg_output_mode_t pwg_output_mode
;/* output-mode index */
86 _pwg_print_quality_t pwg_print_quality
;
87 /* print-quality index */
90 DEBUG_printf(("_pwgCreateWithPPD(ppd=%p)", ppd
));
93 * Range check input...
103 if ((pwg
= calloc(1, sizeof(_pwg_t
))) == NULL
)
105 DEBUG_puts("_pwgCreateWithPPD: Unable to allocate _pwg_t.");
110 * Copy and convert size data...
113 if (ppd
->num_sizes
== 0)
115 DEBUG_puts("_pwgCreateWithPPD: No page sizes in PPD.");
119 if ((pwg
->sizes
= calloc(ppd
->num_sizes
, sizeof(_pwg_size_t
))) == NULL
)
121 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_size_t's.",
126 for (i
= ppd
->num_sizes
, pwg_size
= pwg
->sizes
, ppd_size
= ppd
->sizes
;
131 * Don't copy over custom size...
134 if (!strcasecmp(ppd_size
->name
, "Custom"))
138 * Convert the PPD size name to the corresponding PWG keyword name.
141 if ((pwg_media
= _pwgMediaForPPD(ppd_size
->name
)) != NULL
)
144 * Standard name, do we have conflicts?
147 for (j
= 0; j
< pwg
->num_sizes
; j
++)
148 if (!strcmp(pwg
->sizes
[j
].map
.pwg
, pwg_media
->pwg
))
158 * Standard name and no conflicts, use it!
161 pwg_name
= pwg_media
->pwg
;
166 * Not a standard name; convert it to a PWG vendor name of the form:
168 * pp_lowerppd_WIDTHxHEIGHTuu
171 pwg_name
= pwg_keyword
;
173 pwg_unppdize_name(ppd_size
->name
, ppd_name
, sizeof(ppd_name
));
174 _pwgGenerateSize(pwg_keyword
, sizeof(pwg_keyword
), NULL
, ppd_name
,
175 _PWG_FROMPTS(ppd_size
->width
),
176 _PWG_FROMPTS(ppd_size
->length
));
183 pwg_size
->map
.ppd
= _cupsStrAlloc(ppd_size
->name
);
184 pwg_size
->map
.pwg
= _cupsStrAlloc(pwg_name
);
185 pwg_size
->width
= _PWG_FROMPTS(ppd_size
->width
);
186 pwg_size
->length
= _PWG_FROMPTS(ppd_size
->length
);
187 pwg_size
->left
= _PWG_FROMPTS(ppd_size
->left
);
188 pwg_size
->bottom
= _PWG_FROMPTS(ppd_size
->bottom
);
189 pwg_size
->right
= _PWG_FROMPTS(ppd_size
->width
- ppd_size
->right
);
190 pwg_size
->top
= _PWG_FROMPTS(ppd_size
->length
- ppd_size
->top
);
196 if (ppd
->variable_sizes
)
199 * Generate custom size data...
202 _pwgGenerateSize(pwg_keyword
, sizeof(pwg_keyword
), "custom", "max",
203 _PWG_FROMPTS(ppd
->custom_max
[0]),
204 _PWG_FROMPTS(ppd
->custom_max
[1]));
205 pwg
->custom_max_keyword
= _cupsStrAlloc(pwg_keyword
);
206 pwg
->custom_max_width
= _PWG_FROMPTS(ppd
->custom_max
[0]);
207 pwg
->custom_max_length
= _PWG_FROMPTS(ppd
->custom_max
[1]);
209 _pwgGenerateSize(pwg_keyword
, sizeof(pwg_keyword
), "custom", "min",
210 _PWG_FROMPTS(ppd
->custom_min
[0]),
211 _PWG_FROMPTS(ppd
->custom_min
[1]));
212 pwg
->custom_min_keyword
= _cupsStrAlloc(pwg_keyword
);
213 pwg
->custom_min_width
= _PWG_FROMPTS(ppd
->custom_min
[0]);
214 pwg
->custom_min_length
= _PWG_FROMPTS(ppd
->custom_min
[1]);
216 pwg
->custom_size
.left
= _PWG_FROMPTS(ppd
->custom_margins
[0]);
217 pwg
->custom_size
.bottom
= _PWG_FROMPTS(ppd
->custom_margins
[1]);
218 pwg
->custom_size
.right
= _PWG_FROMPTS(ppd
->custom_margins
[2]);
219 pwg
->custom_size
.top
= _PWG_FROMPTS(ppd
->custom_margins
[3]);
223 * Copy and convert InputSlot data...
226 if ((input_slot
= ppdFindOption(ppd
, "InputSlot")) == NULL
)
227 input_slot
= ppdFindOption(ppd
, "HPPaperSource");
231 pwg
->source_option
= _cupsStrAlloc(input_slot
->keyword
);
233 if ((pwg
->sources
= calloc(input_slot
->num_choices
,
234 sizeof(_pwg_map_t
))) == NULL
)
236 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
237 "for InputSlot.", input_slot
->num_choices
));
241 pwg
->num_sources
= input_slot
->num_choices
;
243 for (i
= input_slot
->num_choices
, choice
= input_slot
->choices
,
246 i
--, choice
++, map
++)
248 if (!strncasecmp(choice
->choice
, "Auto", 4) ||
249 !strcasecmp(choice
->choice
, "Default"))
251 else if (!strcasecmp(choice
->choice
, "Cassette"))
253 else if (!strcasecmp(choice
->choice
, "PhotoTray"))
255 else if (!strcasecmp(choice
->choice
, "CDTray"))
257 else if (!strncasecmp(choice
->choice
, "Multipurpose", 12) ||
258 !strcasecmp(choice
->choice
, "MP") ||
259 !strcasecmp(choice
->choice
, "MPTray"))
260 pwg_name
= "alternate";
261 else if (!strcasecmp(choice
->choice
, "LargeCapacity"))
262 pwg_name
= "large-capacity";
263 else if (!strncasecmp(choice
->choice
, "Lower", 5))
265 else if (!strncasecmp(choice
->choice
, "Middle", 6))
267 else if (!strncasecmp(choice
->choice
, "Upper", 5))
269 else if (!strncasecmp(choice
->choice
, "Side", 4))
271 else if (!strcasecmp(choice
->choice
, "Roll") ||
272 !strcasecmp(choice
->choice
, "Roll1"))
273 pwg_name
= "main-roll";
274 else if (!strcasecmp(choice
->choice
, "Roll2"))
275 pwg_name
= "alternate-roll";
279 * Convert PPD name to lowercase...
282 pwg_name
= pwg_keyword
;
283 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
286 map
->pwg
= _cupsStrAlloc(pwg_name
);
287 map
->ppd
= _cupsStrAlloc(choice
->choice
);
292 * Copy and convert MediaType data...
295 if ((media_type
= ppdFindOption(ppd
, "MediaType")) != NULL
)
297 if ((pwg
->types
= calloc(media_type
->num_choices
,
298 sizeof(_pwg_map_t
))) == NULL
)
300 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
301 "for MediaType.", media_type
->num_choices
));
305 pwg
->num_types
= media_type
->num_choices
;
307 for (i
= media_type
->num_choices
, choice
= media_type
->choices
,
310 i
--, choice
++, map
++)
312 if (!strncasecmp(choice
->choice
, "Auto", 4) ||
313 !strcasecmp(choice
->choice
, "Any") ||
314 !strcasecmp(choice
->choice
, "Default"))
316 else if (!strncasecmp(choice
->choice
, "Card", 4))
317 pwg_name
= "cardstock";
318 else if (!strncasecmp(choice
->choice
, "Env", 3))
319 pwg_name
= "envelope";
320 else if (!strncasecmp(choice
->choice
, "Gloss", 5))
321 pwg_name
= "photographic-glossy";
322 else if (!strcasecmp(choice
->choice
, "HighGloss"))
323 pwg_name
= "photographic-high-gloss";
324 else if (!strcasecmp(choice
->choice
, "Matte"))
325 pwg_name
= "photographic-matte";
326 else if (!strncasecmp(choice
->choice
, "Plain", 5))
327 pwg_name
= "stationery";
328 else if (!strncasecmp(choice
->choice
, "Coated", 6))
329 pwg_name
= "stationery-coated";
330 else if (!strcasecmp(choice
->choice
, "Inkjet"))
331 pwg_name
= "stationery-inkjet";
332 else if (!strcasecmp(choice
->choice
, "Letterhead"))
333 pwg_name
= "stationery-letterhead";
334 else if (!strncasecmp(choice
->choice
, "Preprint", 8))
335 pwg_name
= "stationery-preprinted";
336 else if (!strncasecmp(choice
->choice
, "Transparen", 10))
337 pwg_name
= "transparency";
341 * Convert PPD name to lowercase...
344 pwg_name
= pwg_keyword
;
345 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
348 map
->pwg
= _cupsStrAlloc(pwg_name
);
349 map
->ppd
= _cupsStrAlloc(choice
->choice
);
355 * Copy and convert OutputBin data...
358 if ((output_bin
= ppdFindOption(ppd
, "OutputBin")) != NULL
)
360 if ((pwg
->bins
= calloc(output_bin
->num_choices
,
361 sizeof(_pwg_map_t
))) == NULL
)
363 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
364 "for OutputBin.", output_bin
->num_choices
));
368 pwg
->num_bins
= output_bin
->num_choices
;
370 for (i
= output_bin
->num_choices
, choice
= output_bin
->choices
,
373 i
--, choice
++, map
++)
375 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
377 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
378 map
->ppd
= _cupsStrAlloc(choice
->choice
);
382 if ((ppd_attr
= ppdFindAttr(ppd
, "APPrinterPreset", NULL
)) != NULL
)
385 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
388 const char *quality
, /* com.apple.print.preset.quality value */
389 *output_mode
, /* com.apple.print.preset.output-mode value */
390 *color_model_val
; /* ColorModel choice */
395 num_options
= _ppdParseOptions(ppd_attr
->value
, 0, &options
,
398 if ((quality
= cupsGetOption("com.apple.print.preset.quality",
399 num_options
, options
)) != NULL
)
402 * Get the print-quality for this preset...
405 if (!strcmp(quality
, "low"))
406 pwg_print_quality
= _PWG_PRINT_QUALITY_DRAFT
;
407 else if (!strcmp(quality
, "high"))
408 pwg_print_quality
= _PWG_PRINT_QUALITY_HIGH
;
410 pwg_print_quality
= _PWG_PRINT_QUALITY_NORMAL
;
413 * Get the output mode for this preset...
416 output_mode
= cupsGetOption("com.apple.print.preset.output-mode",
417 num_options
, options
);
418 color_model_val
= cupsGetOption("ColorModel", num_options
, options
);
422 if (!strcmp(output_mode
, "monochrome"))
423 pwg_output_mode
= _PWG_OUTPUT_MODE_MONOCHROME
;
425 pwg_output_mode
= _PWG_OUTPUT_MODE_COLOR
;
427 else if (color_model_val
)
429 if (!strcasecmp(color_model_val
, "Gray"))
430 pwg_output_mode
= _PWG_OUTPUT_MODE_MONOCHROME
;
432 pwg_output_mode
= _PWG_OUTPUT_MODE_COLOR
;
435 pwg_output_mode
= _PWG_OUTPUT_MODE_COLOR
;
438 * Save the options for this combination as needed...
441 if (!pwg
->num_presets
[pwg_output_mode
][pwg_print_quality
])
442 pwg
->num_presets
[pwg_output_mode
][pwg_print_quality
] =
443 _ppdParseOptions(ppd_attr
->value
, 0,
444 pwg
->presets
[pwg_output_mode
] +
445 pwg_print_quality
, _PPD_PARSE_OPTIONS
);
448 cupsFreeOptions(num_options
, options
);
450 while ((ppd_attr
= ppdFindNextAttr(ppd
, "APPrinterPreset", NULL
)) != NULL
);
453 if (!pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_DRAFT
] &&
454 !pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_NORMAL
] &&
455 !pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_HIGH
])
458 * Try adding some common color options to create grayscale presets. These
459 * are listed in order of popularity...
462 const char *color_option
= NULL
, /* Color control option */
463 *gray_choice
= NULL
; /* Choice to select grayscale */
465 if ((color_model
= ppdFindOption(ppd
, "ColorModel")) != NULL
&&
466 ppdFindChoice(color_model
, "Gray"))
468 color_option
= "ColorModel";
469 gray_choice
= "Gray";
471 else if ((color_model
= ppdFindOption(ppd
, "HPColorMode")) != NULL
&&
472 ppdFindChoice(color_model
, "grayscale"))
474 color_option
= "HPColorMode";
475 gray_choice
= "grayscale";
477 else if ((color_model
= ppdFindOption(ppd
, "BRMonoColor")) != NULL
&&
478 ppdFindChoice(color_model
, "Mono"))
480 color_option
= "BRMonoColor";
481 gray_choice
= "Mono";
483 else if ((color_model
= ppdFindOption(ppd
, "CNIJSGrayScale")) != NULL
&&
484 ppdFindChoice(color_model
, "1"))
486 color_option
= "CNIJSGrayScale";
489 else if ((color_model
= ppdFindOption(ppd
, "HPColorAsGray")) != NULL
&&
490 ppdFindChoice(color_model
, "True"))
492 color_option
= "HPColorAsGray";
493 gray_choice
= "True";
496 if (color_option
&& gray_choice
)
499 * Copy and convert ColorModel (output-mode) data...
502 cups_option_t
*coption
, /* Color option */
503 *moption
; /* Monochrome option */
505 for (pwg_print_quality
= _PWG_PRINT_QUALITY_DRAFT
;
506 pwg_print_quality
< _PWG_PRINT_QUALITY_MAX
;
507 pwg_print_quality
++)
509 if (pwg
->num_presets
[_PWG_OUTPUT_MODE_COLOR
][pwg_print_quality
])
512 * Copy the color options...
515 num_options
= pwg
->num_presets
[_PWG_OUTPUT_MODE_COLOR
]
517 options
= calloc(sizeof(cups_option_t
), num_options
);
521 for (i
= num_options
, moption
= options
,
522 coption
= pwg
->presets
[_PWG_OUTPUT_MODE_COLOR
]
525 i
--, moption
++, coption
++)
527 moption
->name
= _cupsStrRetain(coption
->name
);
528 moption
->value
= _cupsStrRetain(coption
->value
);
531 pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][pwg_print_quality
] =
533 pwg
->presets
[_PWG_OUTPUT_MODE_MONOCHROME
][pwg_print_quality
] =
537 else if (pwg_print_quality
!= _PWG_PRINT_QUALITY_NORMAL
)
541 * Add the grayscale option to the preset...
544 pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][pwg_print_quality
] =
545 cupsAddOption(color_option
, gray_choice
,
546 pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
]
548 pwg
->presets
[_PWG_OUTPUT_MODE_MONOCHROME
] +
555 * Copy and convert Duplex (sides) data...
558 if ((duplex
= ppdFindOption(ppd
, "Duplex")) == NULL
)
559 if ((duplex
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
560 if ((duplex
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
561 if ((duplex
= ppdFindOption(ppd
, "EFDuplexing")) == NULL
)
562 duplex
= ppdFindOption(ppd
, "KD03Duplex");
566 pwg
->sides_option
= _cupsStrAlloc(duplex
->keyword
);
568 for (i
= duplex
->num_choices
, choice
= duplex
->choices
;
572 if ((!strcasecmp(choice
->choice
, "None") ||
573 !strcasecmp(choice
->choice
, "False")) && !pwg
->sides_1sided
)
574 pwg
->sides_1sided
= _cupsStrAlloc(choice
->choice
);
575 else if ((!strcasecmp(choice
->choice
, "DuplexNoTumble") ||
576 !strcasecmp(choice
->choice
, "LongEdge") ||
577 !strcasecmp(choice
->choice
, "Top")) && !pwg
->sides_2sided_long
)
578 pwg
->sides_2sided_long
= _cupsStrAlloc(choice
->choice
);
579 else if ((!strcasecmp(choice
->choice
, "DuplexTumble") ||
580 !strcasecmp(choice
->choice
, "ShortEdge") ||
581 !strcasecmp(choice
->choice
, "Bottom")) &&
582 !pwg
->sides_2sided_short
)
583 pwg
->sides_2sided_short
= _cupsStrAlloc(choice
->choice
);
590 * If we get here we need to destroy the PWG mapping data and return NULL...
595 _cupsSetError(IPP_INTERNAL_ERROR
, _("Out of memory."), 1);
603 * '_pwgGetBin()' - Get the PWG output-bin keyword associated with a PPD
607 const char * /* O - output-bin or NULL */
608 _pwgGetBin(_pwg_t
*pwg
, /* I - PWG mapping data */
609 const char *output_bin
) /* I - PPD OutputBin string */
611 int i
; /* Looping var */
615 * Range check input...
618 if (!pwg
|| !output_bin
)
622 * Look up the OutputBin string...
626 for (i
= 0; i
< pwg
->num_bins
; i
++)
627 if (!strcasecmp(output_bin
, pwg
->bins
[i
].ppd
))
628 return (pwg
->bins
[i
].pwg
);
635 * '_pwgGetInputSlot()' - Get the PPD InputSlot associated with the job
636 * attributes or a keyword string.
639 const char * /* O - PPD InputSlot or NULL */
640 _pwgGetInputSlot(_pwg_t
*pwg
, /* I - PWG mapping data */
641 ipp_t
*job
, /* I - Job attributes or NULL */
642 const char *keyword
) /* I - Keyword string or NULL */
645 * Range check input...
648 if (!pwg
|| pwg
->num_sources
== 0 || (!job
&& !keyword
))
654 * Lookup the media-col attribute and any media-source found there...
657 ipp_attribute_t
*media_col
, /* media-col attribute */
658 *media_source
; /* media-source attribute */
659 _pwg_size_t size
; /* Dimensional size */
660 int margins_set
; /* Were the margins set? */
662 media_col
= ippFindAttribute(job
, "media-col", IPP_TAG_BEGIN_COLLECTION
);
664 (media_source
= ippFindAttribute(media_col
->values
[0].collection
,
666 IPP_TAG_KEYWORD
)) != NULL
)
669 * Use the media-source value from media-col...
672 keyword
= media_source
->values
[0].string
.text
;
674 else if (_pwgInitSize(&size
, job
, &margins_set
))
677 * For media <= 5x7, look for a photo tray...
680 if (size
.width
<= (5 * 2540) && size
.length
<= (7 * 2540))
687 int i
; /* Looping var */
689 for (i
= 0; i
< pwg
->num_sources
; i
++)
690 if (!strcasecmp(keyword
, pwg
->sources
[i
].pwg
))
691 return (pwg
->sources
[i
].ppd
);
699 * '_pwgGetMediaType()' - Get the PPD MediaType associated with the job
700 * attributes or a keyword string.
703 const char * /* O - PPD MediaType or NULL */
704 _pwgGetMediaType(_pwg_t
*pwg
, /* I - PWG mapping data */
705 ipp_t
*job
, /* I - Job attributes or NULL */
706 const char *keyword
) /* I - Keyword string or NULL */
709 * Range check input...
712 if (!pwg
|| pwg
->num_types
== 0 || (!job
&& !keyword
))
718 * Lookup the media-col attribute and any media-source found there...
721 ipp_attribute_t
*media_col
, /* media-col attribute */
722 *media_type
; /* media-type attribute */
724 media_col
= ippFindAttribute(job
, "media-col", IPP_TAG_BEGIN_COLLECTION
);
727 if ((media_type
= ippFindAttribute(media_col
->values
[0].collection
,
729 IPP_TAG_KEYWORD
)) == NULL
)
730 media_type
= ippFindAttribute(media_col
->values
[0].collection
,
731 "media-type", IPP_TAG_NAME
);
734 keyword
= media_type
->values
[0].string
.text
;
740 int i
; /* Looping var */
742 for (i
= 0; i
< pwg
->num_types
; i
++)
743 if (!strcasecmp(keyword
, pwg
->types
[i
].pwg
))
744 return (pwg
->types
[i
].ppd
);
752 * '_pwgGetOutputBin()' - Get the PPD OutputBin associated with the keyword
756 const char * /* O - PPD OutputBin or NULL */
757 _pwgGetOutputBin(_pwg_t
*pwg
, /* I - PWG mapping data */
758 const char *output_bin
)/* I - Keyword string */
760 int i
; /* Looping var */
764 * Range check input...
767 if (!pwg
|| !output_bin
)
771 * Look up the OutputBin string...
775 for (i
= 0; i
< pwg
->num_bins
; i
++)
776 if (!strcasecmp(output_bin
, pwg
->bins
[i
].pwg
))
777 return (pwg
->bins
[i
].ppd
);
784 * '_pwgGetPageSize()' - Get the PPD PageSize associated with the job
785 * attributes or a keyword string.
788 const char * /* O - PPD PageSize or NULL */
789 _pwgGetPageSize(_pwg_t
*pwg
, /* I - PWG mapping data */
790 ipp_t
*job
, /* I - Job attributes or NULL */
791 const char *keyword
, /* I - Keyword string or NULL */
792 int *exact
) /* I - 1 if exact match, 0 otherwise */
794 int i
; /* Looping var */
795 _pwg_size_t
*size
, /* Current size */
796 *closest
, /* Closest size */
797 jobsize
; /* Size data from job */
798 int margins_set
, /* Were the margins set? */
799 dwidth
, /* Difference in width */
800 dlength
, /* Difference in length */
801 dleft
, /* Difference in left margins */
802 dright
, /* Difference in right margins */
803 dbottom
, /* Difference in bottom margins */
804 dtop
, /* Difference in top margins */
805 dmin
, /* Minimum difference */
806 dclosest
; /* Closest difference */
810 * Range check input...
813 if (!pwg
|| (!job
&& !keyword
))
822 * Get the size using media-col or media, with the preference being
826 if (!_pwgInitSize(&jobsize
, job
, &margins_set
))
832 * Get the size using a media keyword...
835 _pwg_media_t
*media
; /* Media definition */
838 if ((media
= _pwgMediaForPWG(keyword
)) == NULL
)
839 if ((media
= _pwgMediaForLegacy(keyword
)) == NULL
)
842 jobsize
.width
= media
->width
;
843 jobsize
.length
= media
->length
;
848 * Now that we have the dimensions and possibly the margins, look at the
849 * available sizes and find the match...
853 dclosest
= 999999999;
855 for (i
= pwg
->num_sizes
, size
= pwg
->sizes
; i
> 0; i
--, size
++)
858 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
859 * is just about 176/2540ths...
862 dwidth
= size
->width
- jobsize
.width
;
863 dlength
= size
->length
- jobsize
.length
;
865 if (dwidth
<= -176 || dwidth
>= 176 || dlength
<= -176 || dlength
>= 176)
871 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
874 dleft
= size
->left
- jobsize
.left
;
875 dright
= size
->right
- jobsize
.right
;
876 dtop
= size
->top
- jobsize
.top
;
877 dbottom
= size
->bottom
- jobsize
.bottom
;
879 if (dleft
<= -35 || dleft
>= 35 || dright
<= -35 || dright
>= 35 ||
880 dtop
<= -35 || dtop
>= 35 || dbottom
<= -35 || dbottom
>= 35)
882 dleft
= dleft
< 0 ? -dleft
: dleft
;
883 dright
= dright
< 0 ? -dright
: dright
;
884 dbottom
= dbottom
< 0 ? -dbottom
: dbottom
;
885 dtop
= dtop
< 0 ? -dtop
: dtop
;
886 dmin
= dleft
+ dright
+ dbottom
+ dtop
;
901 return (size
->map
.ppd
);
905 return (closest
->map
.ppd
);
908 * If we get here we need to check for custom page size support...
911 if (jobsize
.width
>= pwg
->custom_min_width
&&
912 jobsize
.width
<= pwg
->custom_max_width
&&
913 jobsize
.length
>= pwg
->custom_min_length
&&
914 jobsize
.length
<= pwg
->custom_max_length
)
917 * In range, format as Custom.WWWWxLLLL (points).
920 snprintf(pwg
->custom_ppd_size
, sizeof(pwg
->custom_ppd_size
), "Custom.%dx%d",
921 (int)_PWG_TOPTS(jobsize
.width
), (int)_PWG_TOPTS(jobsize
.length
));
923 if (margins_set
&& exact
)
925 dleft
= pwg
->custom_size
.left
- jobsize
.left
;
926 dright
= pwg
->custom_size
.right
- jobsize
.right
;
927 dtop
= pwg
->custom_size
.top
- jobsize
.top
;
928 dbottom
= pwg
->custom_size
.bottom
- jobsize
.bottom
;
930 if (dleft
> -35 && dleft
< 35 && dright
> -35 && dright
< 35 &&
931 dtop
> -35 && dtop
< 35 && dbottom
> -35 && dbottom
< 35)
937 return (pwg
->custom_ppd_size
);
941 * No custom page size support or the size is out of range - return NULL.
949 * '_pwgGetSize()' - Get the PWG size associated with a PPD PageSize.
952 _pwg_size_t
* /* O - PWG size or NULL */
953 _pwgGetSize(_pwg_t
*pwg
, /* I - PWG mapping data */
954 const char *page_size
) /* I - PPD PageSize */
957 _pwg_size_t
*size
; /* Current size */
961 * Range check input...
964 if (!pwg
|| !page_size
)
967 if (!strncasecmp(page_size
, "Custom.", 7))
970 * Custom size; size name can be one of the following:
972 * Custom.WIDTHxLENGTHin - Size in inches
973 * Custom.WIDTHxLENGTHft - Size in feet
974 * Custom.WIDTHxLENGTHcm - Size in centimeters
975 * Custom.WIDTHxLENGTHmm - Size in millimeters
976 * Custom.WIDTHxLENGTHm - Size in meters
977 * Custom.WIDTHxLENGTH[pt] - Size in points
980 double w
, l
; /* Width and length of page */
981 char *ptr
; /* Pointer into PageSize */
982 struct lconv
*loc
; /* Locale data */
985 w
= (float)_cupsStrScand(page_size
+ 7, &ptr
, loc
);
986 if (!ptr
|| *ptr
!= 'x')
989 l
= (float)_cupsStrScand(ptr
+ 1, &ptr
, loc
);
993 if (!strcasecmp(ptr
, "in"))
998 else if (!strcasecmp(ptr
, "ft"))
1003 else if (!strcasecmp(ptr
, "mm"))
1008 else if (!strcasecmp(ptr
, "cm"))
1013 else if (!strcasecmp(ptr
, "m"))
1024 pwg
->custom_size
.width
= (int)w
;
1025 pwg
->custom_size
.length
= (int)l
;
1027 return (&(pwg
->custom_size
));
1031 * Not a custom size - look it up...
1034 for (i
= pwg
->num_sizes
, size
= pwg
->sizes
; i
> 0; i
--, size
++)
1035 if (!strcasecmp(page_size
, size
->map
.ppd
))
1043 * '_pwgGetSource()' - Get the PWG media-source associated with a PPD InputSlot.
1046 const char * /* O - PWG media-source keyword */
1047 _pwgGetSource(_pwg_t
*pwg
, /* I - PWG mapping data */
1048 const char *input_slot
) /* I - PPD InputSlot */
1050 int i
; /* Looping var */
1051 _pwg_map_t
*source
; /* Current source */
1055 * Range check input...
1058 if (!pwg
|| !input_slot
)
1061 for (i
= pwg
->num_sources
, source
= pwg
->sources
; i
> 0; i
--, source
++)
1062 if (!strcasecmp(input_slot
, source
->ppd
))
1063 return (source
->pwg
);
1070 * '_pwgGetType()' - Get the PWG media-type associated with a PPD MediaType.
1073 const char * /* O - PWG media-type keyword */
1074 _pwgGetType(_pwg_t
*pwg
, /* I - PWG mapping data */
1075 const char *media_type
) /* I - PPD MediaType */
1077 int i
; /* Looping var */
1078 _pwg_map_t
*type
; /* Current type */
1082 * Range check input...
1085 if (!pwg
|| !media_type
)
1088 for (i
= pwg
->num_types
, type
= pwg
->types
; i
> 0; i
--, type
++)
1089 if (!strcasecmp(media_type
, type
->ppd
))
1097 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG source.
1100 const char * /* O - InputSlot name */
1101 _pwgInputSlotForSource(
1102 const char *media_source
, /* I - PWG media-source */
1103 char *name
, /* I - Name buffer */
1104 size_t namesize
) /* I - Size of name buffer */
1107 * Range check input...
1110 if (!media_source
|| !name
|| namesize
< PPD_MAX_NAME
)
1113 if (strcasecmp(media_source
, "main"))
1114 strlcpy(name
, "Cassette", namesize
);
1115 else if (strcasecmp(media_source
, "alternate"))
1116 strlcpy(name
, "Multipurpose", namesize
);
1117 else if (strcasecmp(media_source
, "large-capacity"))
1118 strlcpy(name
, "LargeCapacity", namesize
);
1119 else if (strcasecmp(media_source
, "bottom"))
1120 strlcpy(name
, "Lower", namesize
);
1121 else if (strcasecmp(media_source
, "middle"))
1122 strlcpy(name
, "Middle", namesize
);
1123 else if (strcasecmp(media_source
, "top"))
1124 strlcpy(name
, "Upper", namesize
);
1125 else if (strcasecmp(media_source
, "rear"))
1126 strlcpy(name
, "Rear", namesize
);
1127 else if (strcasecmp(media_source
, "side"))
1128 strlcpy(name
, "Side", namesize
);
1129 else if (strcasecmp(media_source
, "envelope"))
1130 strlcpy(name
, "Envelope", namesize
);
1131 else if (strcasecmp(media_source
, "main-roll"))
1132 strlcpy(name
, "Roll", namesize
);
1133 else if (strcasecmp(media_source
, "alternate-roll"))
1134 strlcpy(name
, "Roll2", namesize
);
1136 pwg_ppdize_name(media_source
, name
, namesize
);
1143 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG type.
1146 const char * /* O - MediaType name */
1147 _pwgMediaTypeForType(
1148 const char *media_type
, /* I - PWG media-source */
1149 char *name
, /* I - Name buffer */
1150 size_t namesize
) /* I - Size of name buffer */
1153 * Range check input...
1156 if (!media_type
|| !name
|| namesize
< PPD_MAX_NAME
)
1159 if (strcasecmp(media_type
, "auto"))
1160 strlcpy(name
, "Auto", namesize
);
1161 else if (strcasecmp(media_type
, "cardstock"))
1162 strlcpy(name
, "Cardstock", namesize
);
1163 else if (strcasecmp(media_type
, "envelope"))
1164 strlcpy(name
, "Envelope", namesize
);
1165 else if (strcasecmp(media_type
, "photographic-glossy"))
1166 strlcpy(name
, "Glossy", namesize
);
1167 else if (strcasecmp(media_type
, "photographic-high-gloss"))
1168 strlcpy(name
, "HighGloss", namesize
);
1169 else if (strcasecmp(media_type
, "photographic-matte"))
1170 strlcpy(name
, "Matte", namesize
);
1171 else if (strcasecmp(media_type
, "stationery"))
1172 strlcpy(name
, "Plain", namesize
);
1173 else if (strcasecmp(media_type
, "stationery-coated"))
1174 strlcpy(name
, "Coated", namesize
);
1175 else if (strcasecmp(media_type
, "stationery-inkjet"))
1176 strlcpy(name
, "Inkjet", namesize
);
1177 else if (strcasecmp(media_type
, "stationery-letterhead"))
1178 strlcpy(name
, "Letterhead", namesize
);
1179 else if (strcasecmp(media_type
, "stationery-preprinted"))
1180 strlcpy(name
, "Preprinted", namesize
);
1181 else if (strcasecmp(media_type
, "transparency"))
1182 strlcpy(name
, "Transparency", namesize
);
1184 pwg_ppdize_name(media_type
, name
, namesize
);
1191 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
1194 const char * /* O - PageSize name */
1195 _pwgPageSizeForMedia(
1196 _pwg_media_t
*media
, /* I - Media */
1197 char *name
, /* I - PageSize name buffer */
1198 size_t namesize
) /* I - Size of name buffer */
1200 const char *sizeptr
, /* Pointer to size in PWG name */
1201 *dimptr
; /* Pointer to dimensions in PWG name */
1205 * Range check input...
1208 if (!media
|| !name
|| namesize
< PPD_MAX_NAME
)
1212 * Copy or generate a PageSize name...
1218 * Use a standard Adobe name...
1221 strlcpy(name
, media
->ppd
, namesize
);
1223 else if (!media
->pwg
|| !strncmp(media
->pwg
, "custom_", 7) ||
1224 (sizeptr
= strchr(media
->pwg
, '_')) == NULL
||
1225 (dimptr
= strchr(sizeptr
+ 1, '_')) == NULL
||
1226 (dimptr
- sizeptr
) > namesize
)
1229 * Use a name of the form "wNNNhNNN"...
1232 snprintf(name
, namesize
, "w%dh%d", (int)_PWG_TOPTS(media
->width
),
1233 (int)_PWG_TOPTS(media
->length
));
1238 * Copy the size name from class_sizename_dimensions...
1241 memcpy(name
, sizeptr
+ 1, dimptr
- sizeptr
- 1);
1242 name
[dimptr
- sizeptr
- 1] = '\0';
1250 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
1254 pwg_ppdize_name(const char *ipp
, /* I - IPP keyword */
1255 char *name
, /* I - Name buffer */
1256 size_t namesize
) /* I - Size of name buffer */
1258 char *ptr
, /* Pointer into name buffer */
1259 *end
; /* End of name buffer */
1262 *name
= toupper(*ipp
++);
1264 for (ptr
= name
+ 1, end
= name
+ namesize
- 1; *ipp
&& ptr
< end
;)
1266 if (*ipp
== '-' && isalpha(ipp
[1] & 255))
1269 *ptr
++ = toupper(*ipp
++ & 255);
1280 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
1284 pwg_unppdize_name(const char *ppd
, /* I - PPD keyword */
1285 char *name
, /* I - Name buffer */
1286 size_t namesize
) /* I - Size of name buffer */
1288 char *ptr
, /* Pointer into name buffer */
1289 *end
; /* End of name buffer */
1292 for (ptr
= name
, end
= name
+ namesize
- 1; *ppd
&& ptr
< end
; ppd
++)
1294 if (isalnum(*ppd
& 255) || *ppd
== '-' || *ppd
== '.')
1295 *ptr
++ = tolower(*ppd
& 255);
1296 else if (*ppd
== '_')
1299 if (!isupper(*ppd
& 255) && isalnum(*ppd
& 255) &&
1300 isupper(ppd
[1] & 255) && ptr
< end
)