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
)
228 if ((pwg
->sources
= calloc(input_slot
->num_choices
,
229 sizeof(_pwg_map_t
))) == NULL
)
231 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
232 "for InputSlot.", input_slot
->num_choices
));
236 pwg
->num_sources
= input_slot
->num_choices
;
238 for (i
= input_slot
->num_choices
, choice
= input_slot
->choices
,
241 i
--, choice
++, map
++)
243 if (!strncasecmp(choice
->choice
, "Auto", 4) ||
244 !strcasecmp(choice
->choice
, "Default"))
246 else if (!strcasecmp(choice
->choice
, "Cassette"))
248 else if (!strncasecmp(choice
->choice
, "Multipurpose", 12) ||
249 !strcasecmp(choice
->choice
, "MP") ||
250 !strcasecmp(choice
->choice
, "MPTray"))
251 pwg_name
= "alternate";
252 else if (!strcasecmp(choice
->choice
, "LargeCapacity"))
253 pwg_name
= "large-capacity";
254 else if (!strncasecmp(choice
->choice
, "Lower", 5))
256 else if (!strncasecmp(choice
->choice
, "Middle", 6))
258 else if (!strncasecmp(choice
->choice
, "Upper", 5))
260 else if (!strncasecmp(choice
->choice
, "Side", 4))
262 else if (!strcasecmp(choice
->choice
, "Roll") ||
263 !strcasecmp(choice
->choice
, "Roll1"))
264 pwg_name
= "main-roll";
265 else if (!strcasecmp(choice
->choice
, "Roll2"))
266 pwg_name
= "alternate-roll";
270 * Convert PPD name to lowercase...
273 pwg_name
= pwg_keyword
;
274 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
277 map
->pwg
= _cupsStrAlloc(pwg_name
);
278 map
->ppd
= _cupsStrAlloc(choice
->choice
);
283 * Copy and convert MediaType data...
286 if ((media_type
= ppdFindOption(ppd
, "MediaType")) != NULL
)
288 if ((pwg
->types
= calloc(media_type
->num_choices
,
289 sizeof(_pwg_map_t
))) == NULL
)
291 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
292 "for MediaType.", media_type
->num_choices
));
296 pwg
->num_types
= media_type
->num_choices
;
298 for (i
= media_type
->num_choices
, choice
= media_type
->choices
,
301 i
--, choice
++, map
++)
303 if (!strncasecmp(choice
->choice
, "Auto", 4) ||
304 !strcasecmp(choice
->choice
, "Any") ||
305 !strcasecmp(choice
->choice
, "Default"))
307 else if (!strncasecmp(choice
->choice
, "Card", 4))
308 pwg_name
= "cardstock";
309 else if (!strncasecmp(choice
->choice
, "Env", 3))
310 pwg_name
= "envelope";
311 else if (!strncasecmp(choice
->choice
, "Gloss", 5))
312 pwg_name
= "photographic-glossy";
313 else if (!strcasecmp(choice
->choice
, "HighGloss"))
314 pwg_name
= "photographic-high-gloss";
315 else if (!strcasecmp(choice
->choice
, "Matte"))
316 pwg_name
= "photographic-matte";
317 else if (!strncasecmp(choice
->choice
, "Plain", 5))
318 pwg_name
= "stationery";
319 else if (!strncasecmp(choice
->choice
, "Coated", 6))
320 pwg_name
= "stationery-coated";
321 else if (!strcasecmp(choice
->choice
, "Inkjet"))
322 pwg_name
= "stationery-inkjet";
323 else if (!strcasecmp(choice
->choice
, "Letterhead"))
324 pwg_name
= "stationery-letterhead";
325 else if (!strncasecmp(choice
->choice
, "Preprint", 8))
326 pwg_name
= "stationery-preprinted";
327 else if (!strncasecmp(choice
->choice
, "Transparen", 10))
328 pwg_name
= "transparency";
332 * Convert PPD name to lowercase...
335 pwg_name
= pwg_keyword
;
336 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
339 map
->pwg
= _cupsStrAlloc(pwg_name
);
340 map
->ppd
= _cupsStrAlloc(choice
->choice
);
346 * Copy and convert OutputBin data...
349 if ((output_bin
= ppdFindOption(ppd
, "OutputBin")) != NULL
)
351 if ((pwg
->bins
= calloc(output_bin
->num_choices
,
352 sizeof(_pwg_map_t
))) == NULL
)
354 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
355 "for OutputBin.", output_bin
->num_choices
));
359 pwg
->num_bins
= output_bin
->num_choices
;
361 for (i
= output_bin
->num_choices
, choice
= output_bin
->choices
,
364 i
--, choice
++, map
++)
366 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
368 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
369 map
->ppd
= _cupsStrAlloc(choice
->choice
);
373 if ((ppd_attr
= ppdFindAttr(ppd
, "APPrinterPreset", NULL
)) != NULL
)
376 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
379 const char *quality
, /* com.apple.print.preset.quality value */
380 *output_mode
, /* com.apple.print.preset.output-mode value */
381 *color_model_val
; /* ColorModel choice */
386 num_options
= _ppdParseOptions(ppd_attr
->value
, 0, &options
,
389 if ((quality
= cupsGetOption("com.apple.print.preset.quality",
390 num_options
, options
)) != NULL
)
393 * Get the print-quality for this preset...
396 if (!strcmp(quality
, "low"))
397 pwg_print_quality
= _PWG_PRINT_QUALITY_DRAFT
;
398 else if (!strcmp(quality
, "high"))
399 pwg_print_quality
= _PWG_PRINT_QUALITY_HIGH
;
401 pwg_print_quality
= _PWG_PRINT_QUALITY_NORMAL
;
404 * Get the output mode for this preset...
407 output_mode
= cupsGetOption("com.apple.print.preset.output-mode",
408 num_options
, options
);
409 color_model_val
= cupsGetOption("ColorModel", num_options
, options
);
413 if (!strcmp(output_mode
, "monochrome"))
414 pwg_output_mode
= _PWG_OUTPUT_MODE_MONOCHROME
;
416 pwg_output_mode
= _PWG_OUTPUT_MODE_COLOR
;
418 else if (color_model_val
)
420 if (!strcasecmp(color_model_val
, "Gray"))
421 pwg_output_mode
= _PWG_OUTPUT_MODE_MONOCHROME
;
423 pwg_output_mode
= _PWG_OUTPUT_MODE_COLOR
;
426 pwg_output_mode
= _PWG_OUTPUT_MODE_COLOR
;
429 * Save the options for this combination as needed...
432 if (!pwg
->num_presets
[pwg_output_mode
][pwg_print_quality
])
433 pwg
->num_presets
[pwg_output_mode
][pwg_print_quality
] =
434 _ppdParseOptions(ppd_attr
->value
, 0,
435 pwg
->presets
[pwg_output_mode
] +
436 pwg_print_quality
, _PPD_PARSE_OPTIONS
);
439 cupsFreeOptions(num_options
, options
);
441 while ((ppd_attr
= ppdFindNextAttr(ppd
, "APPrinterPreset", NULL
)) != NULL
);
444 if (!pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_DRAFT
] &&
445 !pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_NORMAL
] &&
446 !pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_HIGH
] &&
447 (color_model
= ppdFindOption(ppd
, "ColorModel")) != NULL
&&
448 ppdFindChoice(color_model
, "Gray"))
451 * Copy and convert ColorModel (output-mode) data...
454 cups_option_t
*coption
, /* Color option */
455 *moption
; /* Monochrome option */
457 for (pwg_print_quality
= _PWG_PRINT_QUALITY_DRAFT
;
458 pwg_print_quality
< _PWG_PRINT_QUALITY_MAX
;
459 pwg_print_quality
++)
461 if (pwg
->num_presets
[_PWG_OUTPUT_MODE_COLOR
][pwg_print_quality
])
464 * Copy the color options...
467 num_options
= pwg
->num_presets
[_PWG_OUTPUT_MODE_COLOR
]
469 options
= calloc(sizeof(cups_option_t
), num_options
);
473 for (i
= num_options
, moption
= options
,
474 coption
= pwg
->presets
[_PWG_OUTPUT_MODE_COLOR
]
477 i
--, moption
++, coption
++)
479 moption
->name
= _cupsStrRetain(coption
->name
);
480 moption
->value
= _cupsStrRetain(coption
->value
);
483 pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][pwg_print_quality
] =
485 pwg
->presets
[_PWG_OUTPUT_MODE_MONOCHROME
][pwg_print_quality
] =
489 else if (pwg_print_quality
!= _PWG_PRINT_QUALITY_NORMAL
)
493 * Add ColorModel=Gray to the preset...
496 pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
][pwg_print_quality
] =
497 cupsAddOption("ColorModel", "Gray",
498 pwg
->num_presets
[_PWG_OUTPUT_MODE_MONOCHROME
]
500 pwg
->presets
[_PWG_OUTPUT_MODE_MONOCHROME
] +
506 * Copy and convert Duplex (sides) data...
509 if ((duplex
= ppdFindOption(ppd
, "Duplex")) == NULL
)
510 if ((duplex
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
511 if ((duplex
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
512 if ((duplex
= ppdFindOption(ppd
, "EFDuplexing")) == NULL
)
513 duplex
= ppdFindOption(ppd
, "KD03Duplex");
517 pwg
->sides_option
= _cupsStrAlloc(duplex
->keyword
);
519 for (i
= duplex
->num_choices
, choice
= duplex
->choices
;
523 if ((!strcasecmp(choice
->choice
, "None") ||
524 !strcasecmp(choice
->choice
, "False")) && !pwg
->sides_1sided
)
525 pwg
->sides_1sided
= _cupsStrAlloc(choice
->choice
);
526 else if ((!strcasecmp(choice
->choice
, "DuplexNoTumble") ||
527 !strcasecmp(choice
->choice
, "LongEdge") ||
528 !strcasecmp(choice
->choice
, "Top")) && !pwg
->sides_2sided_long
)
529 pwg
->sides_2sided_long
= _cupsStrAlloc(choice
->choice
);
530 else if ((!strcasecmp(choice
->choice
, "DuplexTumble") ||
531 !strcasecmp(choice
->choice
, "ShortEdge") ||
532 !strcasecmp(choice
->choice
, "Bottom")) &&
533 !pwg
->sides_2sided_short
)
534 pwg
->sides_2sided_short
= _cupsStrAlloc(choice
->choice
);
541 * If we get here we need to destroy the PWG mapping data and return NULL...
546 _cupsSetError(IPP_INTERNAL_ERROR
, _("Out of memory."), 1);
554 * '_pwgGetBin()' - Get the PWG output-bin keyword associated with a PPD
558 const char * /* O - output-bin or NULL */
559 _pwgGetBin(_pwg_t
*pwg
, /* I - PWG mapping data */
560 const char *output_bin
) /* I - PPD OutputBin string */
562 int i
; /* Looping var */
566 * Range check input...
569 if (!pwg
|| !output_bin
)
573 * Look up the OutputBin string...
577 for (i
= 0; i
< pwg
->num_bins
; i
++)
578 if (!strcasecmp(output_bin
, pwg
->bins
[i
].ppd
))
579 return (pwg
->bins
[i
].pwg
);
586 * '_pwgGetInputSlot()' - Get the PPD InputSlot associated with the job
587 * attributes or a keyword string.
590 const char * /* O - PPD InputSlot or NULL */
591 _pwgGetInputSlot(_pwg_t
*pwg
, /* I - PWG mapping data */
592 ipp_t
*job
, /* I - Job attributes or NULL */
593 const char *keyword
) /* I - Keyword string or NULL */
596 * Range check input...
599 if (!pwg
|| pwg
->num_sources
== 0 || (!job
&& !keyword
))
605 * Lookup the media-col attribute and any media-source found there...
608 ipp_attribute_t
*media_col
, /* media-col attribute */
609 *media_source
; /* media-source attribute */
611 media_col
= ippFindAttribute(job
, "media-col", IPP_TAG_BEGIN_COLLECTION
);
613 (media_source
= ippFindAttribute(media_col
->values
[0].collection
,
615 IPP_TAG_KEYWORD
)) != NULL
)
616 keyword
= media_source
->values
[0].string
.text
;
621 int i
; /* Looping var */
623 for (i
= 0; i
< pwg
->num_sources
; i
++)
624 if (!strcasecmp(keyword
, pwg
->sources
[i
].pwg
))
625 return (pwg
->sources
[i
].ppd
);
633 * '_pwgGetMediaType()' - Get the PPD MediaType associated with the job
634 * attributes or a keyword string.
637 const char * /* O - PPD MediaType or NULL */
638 _pwgGetMediaType(_pwg_t
*pwg
, /* I - PWG mapping data */
639 ipp_t
*job
, /* I - Job attributes or NULL */
640 const char *keyword
) /* I - Keyword string or NULL */
643 * Range check input...
646 if (!pwg
|| pwg
->num_types
== 0 || (!job
&& !keyword
))
652 * Lookup the media-col attribute and any media-source found there...
655 ipp_attribute_t
*media_col
, /* media-col attribute */
656 *media_type
; /* media-type attribute */
658 media_col
= ippFindAttribute(job
, "media-col", IPP_TAG_BEGIN_COLLECTION
);
661 if ((media_type
= ippFindAttribute(media_col
->values
[0].collection
,
663 IPP_TAG_KEYWORD
)) == NULL
)
664 media_type
= ippFindAttribute(media_col
->values
[0].collection
,
665 "media-type", IPP_TAG_NAME
);
668 keyword
= media_type
->values
[0].string
.text
;
674 int i
; /* Looping var */
676 for (i
= 0; i
< pwg
->num_types
; i
++)
677 if (!strcasecmp(keyword
, pwg
->types
[i
].pwg
))
678 return (pwg
->types
[i
].ppd
);
686 * '_pwgGetOutputBin()' - Get the PPD OutputBin associated with the keyword
690 const char * /* O - PPD OutputBin or NULL */
691 _pwgGetOutputBin(_pwg_t
*pwg
, /* I - PWG mapping data */
692 const char *output_bin
)/* I - Keyword string */
694 int i
; /* Looping var */
698 * Range check input...
701 if (!pwg
|| !output_bin
)
705 * Look up the OutputBin string...
709 for (i
= 0; i
< pwg
->num_bins
; i
++)
710 if (!strcasecmp(output_bin
, pwg
->bins
[i
].pwg
))
711 return (pwg
->bins
[i
].ppd
);
718 * '_pwgGetPageSize()' - Get the PPD PageSize associated with the job
719 * attributes or a keyword string.
722 const char * /* O - PPD PageSize or NULL */
723 _pwgGetPageSize(_pwg_t
*pwg
, /* I - PWG mapping data */
724 ipp_t
*job
, /* I - Job attributes or NULL */
725 const char *keyword
, /* I - Keyword string or NULL */
726 int *exact
) /* I - 1 if exact match, 0 otherwise */
728 int i
; /* Looping var */
729 _pwg_size_t
*size
, /* Current size */
730 *closest
, /* Closest size */
731 jobsize
; /* Size data from job */
732 int margins_set
, /* Were the margins set? */
733 dwidth
, /* Difference in width */
734 dlength
, /* Difference in length */
735 dleft
, /* Difference in left margins */
736 dright
, /* Difference in right margins */
737 dbottom
, /* Difference in bottom margins */
738 dtop
, /* Difference in top margins */
739 dmin
, /* Minimum difference */
740 dclosest
; /* Closest difference */
744 * Range check input...
747 if (!pwg
|| (!job
&& !keyword
))
756 * Get the size using media-col or media, with the preference being
760 if (!_pwgInitSize(&jobsize
, job
, &margins_set
))
766 * Get the size using a media keyword...
769 _pwg_media_t
*media
; /* Media definition */
772 if ((media
= _pwgMediaForPWG(keyword
)) == NULL
)
773 if ((media
= _pwgMediaForLegacy(keyword
)) == NULL
)
776 jobsize
.width
= media
->width
;
777 jobsize
.length
= media
->length
;
782 * Now that we have the dimensions and possibly the margins, look at the
783 * available sizes and find the match...
787 dclosest
= 999999999;
789 for (i
= pwg
->num_sizes
, size
= pwg
->sizes
; i
> 0; i
--, size
++)
792 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
793 * is just about 176/2540ths...
796 dwidth
= size
->width
- jobsize
.width
;
797 dlength
= size
->length
- jobsize
.length
;
799 if (dwidth
<= -176 || dwidth
>= 176 || dlength
<= -176 || dlength
>= 176)
805 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
808 dleft
= size
->left
- jobsize
.left
;
809 dright
= size
->right
- jobsize
.right
;
810 dtop
= size
->top
- jobsize
.top
;
811 dbottom
= size
->bottom
- jobsize
.bottom
;
813 if (dleft
<= -35 || dleft
>= 35 || dright
<= -35 || dright
>= 35 ||
814 dtop
<= -35 || dtop
>= 35 || dbottom
<= -35 || dbottom
>= 35)
816 dleft
= dleft
< 0 ? -dleft
: dleft
;
817 dright
= dright
< 0 ? -dright
: dright
;
818 dbottom
= dbottom
< 0 ? -dbottom
: dbottom
;
819 dtop
= dtop
< 0 ? -dtop
: dtop
;
820 dmin
= dleft
+ dright
+ dbottom
+ dtop
;
835 return (size
->map
.ppd
);
839 return (closest
->map
.ppd
);
842 * If we get here we need to check for custom page size support...
845 if (jobsize
.width
>= pwg
->custom_min_width
&&
846 jobsize
.width
<= pwg
->custom_max_width
&&
847 jobsize
.length
>= pwg
->custom_min_length
&&
848 jobsize
.length
<= pwg
->custom_max_length
)
851 * In range, format as Custom.WWWWxLLLL (points).
854 snprintf(pwg
->custom_ppd_size
, sizeof(pwg
->custom_ppd_size
), "Custom.%dx%d",
855 (int)_PWG_TOPTS(jobsize
.width
), (int)_PWG_TOPTS(jobsize
.length
));
857 if (margins_set
&& exact
)
859 dleft
= pwg
->custom_size
.left
- jobsize
.left
;
860 dright
= pwg
->custom_size
.right
- jobsize
.right
;
861 dtop
= pwg
->custom_size
.top
- jobsize
.top
;
862 dbottom
= pwg
->custom_size
.bottom
- jobsize
.bottom
;
864 if (dleft
> -35 && dleft
< 35 && dright
> -35 && dright
< 35 &&
865 dtop
> -35 && dtop
< 35 && dbottom
> -35 && dbottom
< 35)
871 return (pwg
->custom_ppd_size
);
875 * No custom page size support or the size is out of range - return NULL.
883 * '_pwgGetSize()' - Get the PWG size associated with a PPD PageSize.
886 _pwg_size_t
* /* O - PWG size or NULL */
887 _pwgGetSize(_pwg_t
*pwg
, /* I - PWG mapping data */
888 const char *page_size
) /* I - PPD PageSize */
891 _pwg_size_t
*size
; /* Current size */
895 * Range check input...
898 if (!pwg
|| !page_size
)
901 if (!strncasecmp(page_size
, "Custom.", 7))
904 * Custom size; size name can be one of the following:
906 * Custom.WIDTHxLENGTHin - Size in inches
907 * Custom.WIDTHxLENGTHft - Size in feet
908 * Custom.WIDTHxLENGTHcm - Size in centimeters
909 * Custom.WIDTHxLENGTHmm - Size in millimeters
910 * Custom.WIDTHxLENGTHm - Size in meters
911 * Custom.WIDTHxLENGTH[pt] - Size in points
914 double w
, l
; /* Width and length of page */
915 char *ptr
; /* Pointer into PageSize */
916 struct lconv
*loc
; /* Locale data */
919 w
= (float)_cupsStrScand(page_size
+ 7, &ptr
, loc
);
920 if (!ptr
|| *ptr
!= 'x')
923 l
= (float)_cupsStrScand(ptr
+ 1, &ptr
, loc
);
927 if (!strcasecmp(ptr
, "in"))
932 else if (!strcasecmp(ptr
, "ft"))
937 else if (!strcasecmp(ptr
, "mm"))
942 else if (!strcasecmp(ptr
, "cm"))
947 else if (!strcasecmp(ptr
, "m"))
958 pwg
->custom_size
.width
= (int)w
;
959 pwg
->custom_size
.length
= (int)l
;
961 return (&(pwg
->custom_size
));
965 * Not a custom size - look it up...
968 for (i
= pwg
->num_sizes
, size
= pwg
->sizes
; i
> 0; i
--, size
++)
969 if (!strcasecmp(page_size
, size
->map
.ppd
))
977 * '_pwgGetSource()' - Get the PWG media-source associated with a PPD InputSlot.
980 const char * /* O - PWG media-source keyword */
981 _pwgGetSource(_pwg_t
*pwg
, /* I - PWG mapping data */
982 const char *input_slot
) /* I - PPD InputSlot */
984 int i
; /* Looping var */
985 _pwg_map_t
*source
; /* Current source */
989 * Range check input...
992 if (!pwg
|| !input_slot
)
995 for (i
= pwg
->num_sources
, source
= pwg
->sources
; i
> 0; i
--, source
++)
996 if (!strcasecmp(input_slot
, source
->ppd
))
997 return (source
->pwg
);
1004 * '_pwgGetType()' - Get the PWG media-type associated with a PPD MediaType.
1007 const char * /* O - PWG media-type keyword */
1008 _pwgGetType(_pwg_t
*pwg
, /* I - PWG mapping data */
1009 const char *media_type
) /* I - PPD MediaType */
1011 int i
; /* Looping var */
1012 _pwg_map_t
*type
; /* Current type */
1016 * Range check input...
1019 if (!pwg
|| !media_type
)
1022 for (i
= pwg
->num_types
, type
= pwg
->types
; i
> 0; i
--, type
++)
1023 if (!strcasecmp(media_type
, type
->ppd
))
1031 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG source.
1034 const char * /* O - InputSlot name */
1035 _pwgInputSlotForSource(
1036 const char *media_source
, /* I - PWG media-source */
1037 char *name
, /* I - Name buffer */
1038 size_t namesize
) /* I - Size of name buffer */
1041 * Range check input...
1044 if (!media_source
|| !name
|| namesize
< PPD_MAX_NAME
)
1047 if (strcasecmp(media_source
, "main"))
1048 strlcpy(name
, "Cassette", namesize
);
1049 else if (strcasecmp(media_source
, "alternate"))
1050 strlcpy(name
, "Multipurpose", namesize
);
1051 else if (strcasecmp(media_source
, "large-capacity"))
1052 strlcpy(name
, "LargeCapacity", namesize
);
1053 else if (strcasecmp(media_source
, "bottom"))
1054 strlcpy(name
, "Lower", namesize
);
1055 else if (strcasecmp(media_source
, "middle"))
1056 strlcpy(name
, "Middle", namesize
);
1057 else if (strcasecmp(media_source
, "top"))
1058 strlcpy(name
, "Upper", namesize
);
1059 else if (strcasecmp(media_source
, "rear"))
1060 strlcpy(name
, "Rear", namesize
);
1061 else if (strcasecmp(media_source
, "side"))
1062 strlcpy(name
, "Side", namesize
);
1063 else if (strcasecmp(media_source
, "envelope"))
1064 strlcpy(name
, "Envelope", namesize
);
1065 else if (strcasecmp(media_source
, "main-roll"))
1066 strlcpy(name
, "Roll", namesize
);
1067 else if (strcasecmp(media_source
, "alternate-roll"))
1068 strlcpy(name
, "Roll2", namesize
);
1070 pwg_ppdize_name(media_source
, name
, namesize
);
1077 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG type.
1080 const char * /* O - MediaType name */
1081 _pwgMediaTypeForType(
1082 const char *media_type
, /* I - PWG media-source */
1083 char *name
, /* I - Name buffer */
1084 size_t namesize
) /* I - Size of name buffer */
1087 * Range check input...
1090 if (!media_type
|| !name
|| namesize
< PPD_MAX_NAME
)
1093 if (strcasecmp(media_type
, "auto"))
1094 strlcpy(name
, "Auto", namesize
);
1095 else if (strcasecmp(media_type
, "cardstock"))
1096 strlcpy(name
, "Cardstock", namesize
);
1097 else if (strcasecmp(media_type
, "envelope"))
1098 strlcpy(name
, "Envelope", namesize
);
1099 else if (strcasecmp(media_type
, "photographic-glossy"))
1100 strlcpy(name
, "Glossy", namesize
);
1101 else if (strcasecmp(media_type
, "photographic-high-gloss"))
1102 strlcpy(name
, "HighGloss", namesize
);
1103 else if (strcasecmp(media_type
, "photographic-matte"))
1104 strlcpy(name
, "Matte", namesize
);
1105 else if (strcasecmp(media_type
, "stationery"))
1106 strlcpy(name
, "Plain", namesize
);
1107 else if (strcasecmp(media_type
, "stationery-coated"))
1108 strlcpy(name
, "Coated", namesize
);
1109 else if (strcasecmp(media_type
, "stationery-inkjet"))
1110 strlcpy(name
, "Inkjet", namesize
);
1111 else if (strcasecmp(media_type
, "stationery-letterhead"))
1112 strlcpy(name
, "Letterhead", namesize
);
1113 else if (strcasecmp(media_type
, "stationery-preprinted"))
1114 strlcpy(name
, "Preprinted", namesize
);
1115 else if (strcasecmp(media_type
, "transparency"))
1116 strlcpy(name
, "Transparency", namesize
);
1118 pwg_ppdize_name(media_type
, name
, namesize
);
1125 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
1128 const char * /* O - PageSize name */
1129 _pwgPageSizeForMedia(
1130 _pwg_media_t
*media
, /* I - Media */
1131 char *name
, /* I - PageSize name buffer */
1132 size_t namesize
) /* I - Size of name buffer */
1134 const char *sizeptr
, /* Pointer to size in PWG name */
1135 *dimptr
; /* Pointer to dimensions in PWG name */
1139 * Range check input...
1142 if (!media
|| !name
|| namesize
< PPD_MAX_NAME
)
1146 * Copy or generate a PageSize name...
1152 * Use a standard Adobe name...
1155 strlcpy(name
, media
->ppd
, namesize
);
1157 else if (!media
->pwg
|| !strncmp(media
->pwg
, "custom_", 7) ||
1158 (sizeptr
= strchr(media
->pwg
, '_')) == NULL
||
1159 (dimptr
= strchr(sizeptr
+ 1, '_')) == NULL
||
1160 (dimptr
- sizeptr
) > namesize
)
1163 * Use a name of the form "wNNNhNNN"...
1166 snprintf(name
, namesize
, "w%dh%d", (int)_PWG_TOPTS(media
->width
),
1167 (int)_PWG_TOPTS(media
->length
));
1172 * Copy the size name from class_sizename_dimensions...
1175 memcpy(name
, sizeptr
+ 1, dimptr
- sizeptr
- 1);
1176 name
[dimptr
- sizeptr
- 1] = '\0';
1184 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
1188 pwg_ppdize_name(const char *ipp
, /* I - IPP keyword */
1189 char *name
, /* I - Name buffer */
1190 size_t namesize
) /* I - Size of name buffer */
1192 char *ptr
, /* Pointer into name buffer */
1193 *end
; /* End of name buffer */
1196 *name
= toupper(*ipp
++);
1198 for (ptr
= name
+ 1, end
= name
+ namesize
- 1; *ipp
&& ptr
< end
;)
1200 if (*ipp
== '-' && isalpha(ipp
[1] & 255))
1203 *ptr
++ = toupper(*ipp
++ & 255);
1214 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
1218 pwg_unppdize_name(const char *ppd
, /* I - PPD keyword */
1219 char *name
, /* I - Name buffer */
1220 size_t namesize
) /* I - Size of name buffer */
1222 char *ptr
, /* Pointer into name buffer */
1223 *end
; /* End of name buffer */
1226 for (ptr
= name
, end
= name
+ namesize
- 1; *ppd
&& ptr
< end
; ppd
++)
1228 if (isalnum(*ppd
& 255) || *ppd
== '-' || *ppd
== '.')
1229 *ptr
++ = tolower(*ppd
& 255);
1230 else if (*ppd
== '_')
1233 if (!isupper(*ppd
& 255) && isalnum(*ppd
& 255) &&
1234 isupper(ppd
[1] & 255) && ptr
< end
)