]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/pwg-ppd.c
Merge changes from CUPS 1.5svn-r9136.
[thirdparty/cups.git] / cups / pwg-ppd.c
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.
19 * _pwgGetBin() - Get the PWG output-bin keyword associated with a
20 * PPD OutputBin.
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
26 * keyword string.
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
46 #include "cups-private.h"
47 #include <math.h>
48
49
50 /*
51 * Local functions...
52 */
53
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);
56
57
58 /*
59 * '_pwgCreateWithPPD()' - Create PWG mapping data from a PPD file.
60 */
61
62 _pwg_t * /* O - PWG mapping data */
63 _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
64 {
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 ppd_choice_t *choice; /* Current InputSlot/MediaType */
71 _pwg_map_t *map; /* Current source/type map */
72 ppd_size_t *ppd_size; /* Current PPD size */
73 _pwg_size_t *pwg_size; /* Current PWG size */
74 char pwg_keyword[3 + PPD_MAX_NAME + 1 + 12 + 1 + 12 + 3],
75 /* PWG keyword string */
76 ppd_name[PPD_MAX_NAME]; /* Normalized PPD name */
77 const char *pwg_name; /* Standard PWG media name */
78 _pwg_media_t *pwg_media; /* PWG media data */
79
80
81 DEBUG_printf(("_pwgCreateWithPPD(ppd=%p)", ppd));
82
83 /*
84 * Range check input...
85 */
86
87 if (!ppd)
88 return (NULL);
89
90 /*
91 * Allocate memory...
92 */
93
94 if ((pwg = calloc(1, sizeof(_pwg_t))) == NULL)
95 {
96 DEBUG_puts("_pwgCreateWithPPD: Unable to allocate _pwg_t.");
97 goto create_error;
98 }
99
100 /*
101 * Copy and convert size data...
102 */
103
104 if (ppd->num_sizes == 0)
105 {
106 DEBUG_puts("_pwgCreateWithPPD: No page sizes in PPD.");
107 goto create_error;
108 }
109
110 if ((pwg->sizes = calloc(ppd->num_sizes, sizeof(_pwg_size_t))) == NULL)
111 {
112 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_size_t's.",
113 ppd->num_sizes));
114 goto create_error;
115 }
116
117 for (i = ppd->num_sizes, pwg_size = pwg->sizes, ppd_size = ppd->sizes;
118 i > 0;
119 i --, ppd_size ++)
120 {
121 /*
122 * Don't copy over custom size...
123 */
124
125 if (!strcasecmp(ppd_size->name, "Custom"))
126 continue;
127
128 /*
129 * Convert the PPD size name to the corresponding PWG keyword name.
130 */
131
132 if ((pwg_media = _pwgMediaForPPD(ppd_size->name)) != NULL)
133 {
134 /*
135 * Standard name, do we have conflicts?
136 */
137
138 for (j = 0; j < pwg->num_sizes; j ++)
139 if (!strcmp(pwg->sizes[j].map.pwg, pwg_media->pwg))
140 {
141 pwg_media = NULL;
142 break;
143 }
144 }
145
146 if (pwg_media)
147 {
148 /*
149 * Standard name and no conflicts, use it!
150 */
151
152 pwg_name = pwg_media->pwg;
153 }
154 else
155 {
156 /*
157 * Not a standard name; convert it to a PWG vendor name of the form:
158 *
159 * pp_lowerppd_WIDTHxHEIGHTuu
160 */
161
162 pwg_name = pwg_keyword;
163
164 pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name));
165 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name,
166 _PWG_FROMPTS(ppd_size->width),
167 _PWG_FROMPTS(ppd_size->length));
168 }
169
170 /*
171 * Save this size...
172 */
173
174 pwg_size->map.ppd = _cupsStrAlloc(ppd_size->name);
175 pwg_size->map.pwg = _cupsStrAlloc(pwg_name);
176 pwg_size->width = _PWG_FROMPTS(ppd_size->width);
177 pwg_size->length = _PWG_FROMPTS(ppd_size->length);
178 pwg_size->left = _PWG_FROMPTS(ppd_size->left);
179 pwg_size->bottom = _PWG_FROMPTS(ppd_size->bottom);
180 pwg_size->right = _PWG_FROMPTS(ppd_size->width - ppd_size->right);
181 pwg_size->top = _PWG_FROMPTS(ppd_size->length - ppd_size->top);
182
183 pwg->num_sizes ++;
184 pwg_size ++;
185 }
186
187 if (ppd->variable_sizes)
188 {
189 /*
190 * Generate custom size data...
191 */
192
193 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
194 _PWG_FROMPTS(ppd->custom_max[0]),
195 _PWG_FROMPTS(ppd->custom_max[1]));
196 pwg->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
197 pwg->custom_max_width = _PWG_FROMPTS(ppd->custom_max[0]);
198 pwg->custom_max_length = _PWG_FROMPTS(ppd->custom_max[1]);
199
200 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
201 _PWG_FROMPTS(ppd->custom_min[0]),
202 _PWG_FROMPTS(ppd->custom_min[1]));
203 pwg->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
204 pwg->custom_min_width = _PWG_FROMPTS(ppd->custom_min[0]);
205 pwg->custom_min_length = _PWG_FROMPTS(ppd->custom_min[1]);
206
207 pwg->custom_size.left = _PWG_FROMPTS(ppd->custom_margins[0]);
208 pwg->custom_size.bottom = _PWG_FROMPTS(ppd->custom_margins[1]);
209 pwg->custom_size.right = _PWG_FROMPTS(ppd->custom_margins[2]);
210 pwg->custom_size.top = _PWG_FROMPTS(ppd->custom_margins[3]);
211 }
212
213 /*
214 * Copy and convert InputSlot data...
215 */
216
217 if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
218 {
219 if ((pwg->sources = calloc(input_slot->num_choices,
220 sizeof(_pwg_map_t))) == NULL)
221 {
222 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
223 "for InputSlot.", input_slot->num_choices));
224 goto create_error;
225 }
226
227 pwg->num_sources = input_slot->num_choices;
228
229 for (i = input_slot->num_choices, choice = input_slot->choices,
230 map = pwg->sources;
231 i > 0;
232 i --, choice ++, map ++)
233 {
234 if (!strncasecmp(choice->choice, "Auto", 4) ||
235 !strcasecmp(choice->choice, "Default"))
236 pwg_name = "auto";
237 else if (!strcasecmp(choice->choice, "Cassette"))
238 pwg_name = "main";
239 else if (!strncasecmp(choice->choice, "Multipurpose", 12) ||
240 !strcasecmp(choice->choice, "MP") ||
241 !strcasecmp(choice->choice, "MPTray"))
242 pwg_name = "alternate";
243 else if (!strcasecmp(choice->choice, "LargeCapacity"))
244 pwg_name = "large-capacity";
245 else if (!strncasecmp(choice->choice, "Lower", 5))
246 pwg_name = "bottom";
247 else if (!strncasecmp(choice->choice, "Middle", 6))
248 pwg_name = "middle";
249 else if (!strncasecmp(choice->choice, "Upper", 5))
250 pwg_name = "top";
251 else if (!strncasecmp(choice->choice, "Side", 4))
252 pwg_name = "side";
253 else if (!strcasecmp(choice->choice, "Roll") ||
254 !strcasecmp(choice->choice, "Roll1"))
255 pwg_name = "main-roll";
256 else if (!strcasecmp(choice->choice, "Roll2"))
257 pwg_name = "alternate-roll";
258 else
259 {
260 /*
261 * Convert PPD name to lowercase...
262 */
263
264 pwg_name = pwg_keyword;
265 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
266 }
267
268 map->pwg = _cupsStrAlloc(pwg_name);
269 map->ppd = _cupsStrAlloc(choice->choice);
270 }
271 }
272
273 /*
274 * Copy and convert MediaType data...
275 */
276
277 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
278 {
279 if ((pwg->types = calloc(media_type->num_choices,
280 sizeof(_pwg_map_t))) == NULL)
281 {
282 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
283 "for MediaType.", media_type->num_choices));
284 goto create_error;
285 }
286
287 pwg->num_types = media_type->num_choices;
288
289 for (i = media_type->num_choices, choice = media_type->choices,
290 map = pwg->types;
291 i > 0;
292 i --, choice ++, map ++)
293 {
294 if (!strncasecmp(choice->choice, "Auto", 4) ||
295 !strcasecmp(choice->choice, "Any") ||
296 !strcasecmp(choice->choice, "Default"))
297 pwg_name = "auto";
298 else if (!strncasecmp(choice->choice, "Card", 4))
299 pwg_name = "cardstock";
300 else if (!strncasecmp(choice->choice, "Env", 3))
301 pwg_name = "envelope";
302 else if (!strncasecmp(choice->choice, "Gloss", 5))
303 pwg_name = "photographic-glossy";
304 else if (!strcasecmp(choice->choice, "HighGloss"))
305 pwg_name = "photographic-high-gloss";
306 else if (!strcasecmp(choice->choice, "Matte"))
307 pwg_name = "photographic-matte";
308 else if (!strncasecmp(choice->choice, "Plain", 5))
309 pwg_name = "stationery";
310 else if (!strncasecmp(choice->choice, "Coated", 6))
311 pwg_name = "stationery-coated";
312 else if (!strcasecmp(choice->choice, "Inkjet"))
313 pwg_name = "stationery-inkjet";
314 else if (!strcasecmp(choice->choice, "Letterhead"))
315 pwg_name = "stationery-letterhead";
316 else if (!strncasecmp(choice->choice, "Preprint", 8))
317 pwg_name = "stationery-preprinted";
318 else if (!strncasecmp(choice->choice, "Transparen", 10))
319 pwg_name = "transparency";
320 else
321 {
322 /*
323 * Convert PPD name to lowercase...
324 */
325
326 pwg_name = pwg_keyword;
327 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
328 }
329
330 map->pwg = _cupsStrAlloc(pwg_name);
331 map->ppd = _cupsStrAlloc(choice->choice);
332 }
333 }
334
335
336 /*
337 * Copy and convert OutputBin data...
338 */
339
340 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
341 {
342 if ((pwg->bins = calloc(output_bin->num_choices,
343 sizeof(_pwg_map_t))) == NULL)
344 {
345 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
346 "for OutputBin.", output_bin->num_choices));
347 goto create_error;
348 }
349
350 pwg->num_bins = output_bin->num_choices;
351
352 for (i = output_bin->num_choices, choice = output_bin->choices,
353 map = pwg->bins;
354 i > 0;
355 i --, choice ++, map ++)
356 {
357 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
358
359 map->pwg = _cupsStrAlloc(pwg_keyword);
360 map->ppd = _cupsStrAlloc(choice->choice);
361 }
362 }
363
364 return (pwg);
365
366 /*
367 * If we get here we need to destroy the PWG mapping data and return NULL...
368 */
369
370 create_error:
371
372 _cupsSetError(IPP_INTERNAL_ERROR, _("Out of memory."), 1);
373 _pwgDestroy(pwg);
374
375 return (NULL);
376 }
377
378
379 /*
380 * '_pwgGetBin()' - Get the PWG output-bin keyword associated with a PPD
381 * OutputBin.
382 */
383
384 const char * /* O - output-bin or NULL */
385 _pwgGetBin(_pwg_t *pwg, /* I - PWG mapping data */
386 const char *output_bin) /* I - PPD OutputBin string */
387 {
388 int i; /* Looping var */
389
390
391 /*
392 * Range check input...
393 */
394
395 if (!pwg || !output_bin)
396 return (NULL);
397
398 /*
399 * Look up the OutputBin string...
400 */
401
402
403 for (i = 0; i < pwg->num_bins; i ++)
404 if (!strcasecmp(output_bin, pwg->bins[i].ppd))
405 return (pwg->bins[i].pwg);
406
407 return (NULL);
408 }
409
410
411 /*
412 * '_pwgGetInputSlot()' - Get the PPD InputSlot associated with the job
413 * attributes or a keyword string.
414 */
415
416 const char * /* O - PPD InputSlot or NULL */
417 _pwgGetInputSlot(_pwg_t *pwg, /* I - PWG mapping data */
418 ipp_t *job, /* I - Job attributes or NULL */
419 const char *keyword) /* I - Keyword string or NULL */
420 {
421 /*
422 * Range check input...
423 */
424
425 if (!pwg || pwg->num_sources == 0 || (!job && !keyword))
426 return (NULL);
427
428 if (job && !keyword)
429 {
430 /*
431 * Lookup the media-col attribute and any media-source found there...
432 */
433
434 ipp_attribute_t *media_col, /* media-col attribute */
435 *media_source; /* media-source attribute */
436
437 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
438 if (media_col &&
439 (media_source = ippFindAttribute(media_col->values[0].collection,
440 "media-source",
441 IPP_TAG_KEYWORD)) != NULL)
442 keyword = media_source->values[0].string.text;
443 }
444
445 if (keyword)
446 {
447 int i; /* Looping var */
448
449 for (i = 0; i < pwg->num_sources; i ++)
450 if (!strcasecmp(keyword, pwg->sources[i].pwg))
451 return (pwg->sources[i].ppd);
452 }
453
454 return (NULL);
455 }
456
457
458 /*
459 * '_pwgGetMediaType()' - Get the PPD MediaType associated with the job
460 * attributes or a keyword string.
461 */
462
463 const char * /* O - PPD MediaType or NULL */
464 _pwgGetMediaType(_pwg_t *pwg, /* I - PWG mapping data */
465 ipp_t *job, /* I - Job attributes or NULL */
466 const char *keyword) /* I - Keyword string or NULL */
467 {
468 /*
469 * Range check input...
470 */
471
472 if (!pwg || pwg->num_types == 0 || (!job && !keyword))
473 return (NULL);
474
475 if (job && !keyword)
476 {
477 /*
478 * Lookup the media-col attribute and any media-source found there...
479 */
480
481 ipp_attribute_t *media_col, /* media-col attribute */
482 *media_type; /* media-type attribute */
483
484 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
485 if (media_col)
486 {
487 if ((media_type = ippFindAttribute(media_col->values[0].collection,
488 "media-type",
489 IPP_TAG_KEYWORD)) == NULL)
490 media_type = ippFindAttribute(media_col->values[0].collection,
491 "media-type", IPP_TAG_NAME);
492
493 if (media_type)
494 keyword = media_type->values[0].string.text;
495 }
496 }
497
498 if (keyword)
499 {
500 int i; /* Looping var */
501
502 for (i = 0; i < pwg->num_types; i ++)
503 if (!strcasecmp(keyword, pwg->types[i].pwg))
504 return (pwg->types[i].ppd);
505 }
506
507 return (NULL);
508 }
509
510
511 /*
512 * '_pwgGetOutputBin()' - Get the PPD OutputBin associated with the keyword
513 * string.
514 */
515
516 const char * /* O - PPD OutputBin or NULL */
517 _pwgGetOutputBin(_pwg_t *pwg, /* I - PWG mapping data */
518 const char *output_bin)/* I - Keyword string */
519 {
520 int i; /* Looping var */
521
522
523 /*
524 * Range check input...
525 */
526
527 if (!pwg || !output_bin)
528 return (NULL);
529
530 /*
531 * Look up the OutputBin string...
532 */
533
534
535 for (i = 0; i < pwg->num_bins; i ++)
536 if (!strcasecmp(output_bin, pwg->bins[i].pwg))
537 return (pwg->bins[i].ppd);
538
539 return (NULL);
540 }
541
542
543 /*
544 * '_pwgGetPageSize()' - Get the PPD PageSize associated with the job
545 * attributes or a keyword string.
546 */
547
548 const char * /* O - PPD PageSize or NULL */
549 _pwgGetPageSize(_pwg_t *pwg, /* I - PWG mapping data */
550 ipp_t *job, /* I - Job attributes or NULL */
551 const char *keyword, /* I - Keyword string or NULL */
552 int *exact) /* I - 1 if exact match, 0 otherwise */
553 {
554 int i; /* Looping var */
555 _pwg_size_t *size, /* Current size */
556 *closest, /* Closest size */
557 jobsize; /* Size data from job */
558 int margins_set, /* Were the margins set? */
559 dwidth, /* Difference in width */
560 dlength, /* Difference in length */
561 dleft, /* Difference in left margins */
562 dright, /* Difference in right margins */
563 dbottom, /* Difference in bottom margins */
564 dtop, /* Difference in top margins */
565 dmin, /* Minimum difference */
566 dclosest; /* Closest difference */
567
568
569 /*
570 * Range check input...
571 */
572
573 if (!pwg || (!job && !keyword))
574 return (NULL);
575
576 if (exact)
577 *exact = 0;
578
579 if (job && !keyword)
580 {
581 /*
582 * Get the size using media-col or media, with the preference being
583 * media-col.
584 */
585
586 if (!_pwgInitSize(&jobsize, job, &margins_set))
587 return (NULL);
588 }
589 else
590 {
591 /*
592 * Get the size using a media keyword...
593 */
594
595 _pwg_media_t *media; /* Media definition */
596
597
598 if ((media = _pwgMediaForPWG(keyword)) == NULL)
599 if ((media = _pwgMediaForLegacy(keyword)) == NULL)
600 return (NULL);
601
602 jobsize.width = media->width;
603 jobsize.length = media->length;
604 margins_set = 0;
605 }
606
607 /*
608 * Now that we have the dimensions and possibly the margins, look at the
609 * available sizes and find the match...
610 */
611
612 closest = NULL;
613 dclosest = 999999999;
614
615 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
616 {
617 /*
618 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
619 * is just about 176/2540ths...
620 */
621
622 dwidth = size->width - jobsize.width;
623 dlength = size->length - jobsize.length;
624
625 if (dwidth <= -176 || dwidth >= 176 || dlength <= -176 || dlength >= 176)
626 continue;
627
628 if (margins_set)
629 {
630 /*
631 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
632 */
633
634 dleft = size->left - jobsize.left;
635 dright = size->right - jobsize.right;
636 dtop = size->top - jobsize.top;
637 dbottom = size->bottom - jobsize.bottom;
638
639 if (dleft <= -35 || dleft >= 35 || dright <= -35 || dright >= 35 ||
640 dtop <= -35 || dtop >= 35 || dbottom <= -35 || dbottom >= 35)
641 {
642 dleft = dleft < 0 ? -dleft : dleft;
643 dright = dright < 0 ? -dright : dright;
644 dbottom = dbottom < 0 ? -dbottom : dbottom;
645 dtop = dtop < 0 ? -dtop : dtop;
646 dmin = dleft + dright + dbottom + dtop;
647
648 if (dmin < dclosest)
649 {
650 dclosest = dmin;
651 closest = size;
652 }
653
654 continue;
655 }
656 }
657
658 if (exact)
659 *exact = 1;
660
661 return (size->map.ppd);
662 }
663
664 if (closest)
665 return (closest->map.ppd);
666
667 /*
668 * If we get here we need to check for custom page size support...
669 */
670
671 if (jobsize.width >= pwg->custom_min_width &&
672 jobsize.width <= pwg->custom_max_width &&
673 jobsize.length >= pwg->custom_min_length &&
674 jobsize.length <= pwg->custom_max_length)
675 {
676 /*
677 * In range, format as Custom.WWWWxLLLL (points).
678 */
679
680 snprintf(pwg->custom_ppd_size, sizeof(pwg->custom_ppd_size), "Custom.%dx%d",
681 (int)_PWG_TOPTS(jobsize.width), (int)_PWG_TOPTS(jobsize.length));
682
683 if (margins_set && exact)
684 {
685 dleft = pwg->custom_size.left - jobsize.left;
686 dright = pwg->custom_size.right - jobsize.right;
687 dtop = pwg->custom_size.top - jobsize.top;
688 dbottom = pwg->custom_size.bottom - jobsize.bottom;
689
690 if (dleft > -35 && dleft < 35 && dright > -35 && dright < 35 &&
691 dtop > -35 && dtop < 35 && dbottom > -35 && dbottom < 35)
692 *exact = 1;
693 }
694 else if (exact)
695 *exact = 1;
696
697 return (pwg->custom_ppd_size);
698 }
699
700 /*
701 * No custom page size support or the size is out of range - return NULL.
702 */
703
704 return (NULL);
705 }
706
707
708 /*
709 * '_pwgGetSize()' - Get the PWG size associated with a PPD PageSize.
710 */
711
712 _pwg_size_t * /* O - PWG size or NULL */
713 _pwgGetSize(_pwg_t *pwg, /* I - PWG mapping data */
714 const char *page_size) /* I - PPD PageSize */
715 {
716 int i;
717 _pwg_size_t *size; /* Current size */
718
719
720 /*
721 * Range check input...
722 */
723
724 if (!pwg || !page_size)
725 return (NULL);
726
727 if (!strncasecmp(page_size, "Custom.", 7))
728 {
729 /*
730 * Custom size; size name can be one of the following:
731 *
732 * Custom.WIDTHxLENGTHin - Size in inches
733 * Custom.WIDTHxLENGTHft - Size in feet
734 * Custom.WIDTHxLENGTHcm - Size in centimeters
735 * Custom.WIDTHxLENGTHmm - Size in millimeters
736 * Custom.WIDTHxLENGTHm - Size in meters
737 * Custom.WIDTHxLENGTH[pt] - Size in points
738 */
739
740 double w, l; /* Width and length of page */
741 char *ptr; /* Pointer into PageSize */
742 struct lconv *loc; /* Locale data */
743
744 loc = localeconv();
745 w = (float)_cupsStrScand(page_size + 7, &ptr, loc);
746 if (!ptr || *ptr != 'x')
747 return (NULL);
748
749 l = (float)_cupsStrScand(ptr + 1, &ptr, loc);
750 if (!ptr)
751 return (NULL);
752
753 if (!strcasecmp(ptr, "in"))
754 {
755 w *= 2540.0;
756 l *= 2540.0;
757 }
758 else if (!strcasecmp(ptr, "ft"))
759 {
760 w *= 12.0 * 2540.0;
761 l *= 12.0 * 2540.0;
762 }
763 else if (!strcasecmp(ptr, "mm"))
764 {
765 w *= 100.0;
766 l *= 100.0;
767 }
768 else if (!strcasecmp(ptr, "cm"))
769 {
770 w *= 1000.0;
771 l *= 1000.0;
772 }
773 else if (!strcasecmp(ptr, "m"))
774 {
775 w *= 100000.0;
776 l *= 100000.0;
777 }
778 else
779 {
780 w *= 2540.0 / 72.0;
781 l *= 2540.0 / 72.0;
782 }
783
784 pwg->custom_size.width = (int)w;
785 pwg->custom_size.length = (int)l;
786
787 return (&(pwg->custom_size));
788 }
789
790 /*
791 * Not a custom size - look it up...
792 */
793
794 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
795 if (!strcasecmp(page_size, size->map.ppd))
796 return (size);
797
798 return (NULL);
799 }
800
801
802 /*
803 * '_pwgGetSource()' - Get the PWG media-source associated with a PPD InputSlot.
804 */
805
806 const char * /* O - PWG media-source keyword */
807 _pwgGetSource(_pwg_t *pwg, /* I - PWG mapping data */
808 const char *input_slot) /* I - PPD InputSlot */
809 {
810 int i; /* Looping var */
811 _pwg_map_t *source; /* Current source */
812
813
814 /*
815 * Range check input...
816 */
817
818 if (!pwg || !input_slot)
819 return (NULL);
820
821 for (i = pwg->num_sources, source = pwg->sources; i > 0; i --, source ++)
822 if (!strcasecmp(input_slot, source->ppd))
823 return (source->pwg);
824
825 return (NULL);
826 }
827
828
829 /*
830 * '_pwgGetType()' - Get the PWG media-type associated with a PPD MediaType.
831 */
832
833 const char * /* O - PWG media-type keyword */
834 _pwgGetType(_pwg_t *pwg, /* I - PWG mapping data */
835 const char *media_type) /* I - PPD MediaType */
836 {
837 int i; /* Looping var */
838 _pwg_map_t *type; /* Current type */
839
840
841 /*
842 * Range check input...
843 */
844
845 if (!pwg || !media_type)
846 return (NULL);
847
848 for (i = pwg->num_types, type = pwg->types; i > 0; i --, type ++)
849 if (!strcasecmp(media_type, type->ppd))
850 return (type->pwg);
851
852 return (NULL);
853 }
854
855
856 /*
857 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG source.
858 */
859
860 const char * /* O - InputSlot name */
861 _pwgInputSlotForSource(
862 const char *media_source, /* I - PWG media-source */
863 char *name, /* I - Name buffer */
864 size_t namesize) /* I - Size of name buffer */
865 {
866 /*
867 * Range check input...
868 */
869
870 if (!media_source || !name || namesize < PPD_MAX_NAME)
871 return (NULL);
872
873 if (strcasecmp(media_source, "main"))
874 strlcpy(name, "Cassette", namesize);
875 else if (strcasecmp(media_source, "alternate"))
876 strlcpy(name, "Multipurpose", namesize);
877 else if (strcasecmp(media_source, "large-capacity"))
878 strlcpy(name, "LargeCapacity", namesize);
879 else if (strcasecmp(media_source, "bottom"))
880 strlcpy(name, "Lower", namesize);
881 else if (strcasecmp(media_source, "middle"))
882 strlcpy(name, "Middle", namesize);
883 else if (strcasecmp(media_source, "top"))
884 strlcpy(name, "Upper", namesize);
885 else if (strcasecmp(media_source, "rear"))
886 strlcpy(name, "Rear", namesize);
887 else if (strcasecmp(media_source, "side"))
888 strlcpy(name, "Side", namesize);
889 else if (strcasecmp(media_source, "envelope"))
890 strlcpy(name, "Envelope", namesize);
891 else if (strcasecmp(media_source, "main-roll"))
892 strlcpy(name, "Roll", namesize);
893 else if (strcasecmp(media_source, "alternate-roll"))
894 strlcpy(name, "Roll2", namesize);
895 else
896 pwg_ppdize_name(media_source, name, namesize);
897
898 return (name);
899 }
900
901
902 /*
903 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG type.
904 */
905
906 const char * /* O - MediaType name */
907 _pwgMediaTypeForType(
908 const char *media_type, /* I - PWG media-source */
909 char *name, /* I - Name buffer */
910 size_t namesize) /* I - Size of name buffer */
911 {
912 /*
913 * Range check input...
914 */
915
916 if (!media_type || !name || namesize < PPD_MAX_NAME)
917 return (NULL);
918
919 if (strcasecmp(media_type, "auto"))
920 strlcpy(name, "Auto", namesize);
921 else if (strcasecmp(media_type, "cardstock"))
922 strlcpy(name, "Cardstock", namesize);
923 else if (strcasecmp(media_type, "envelope"))
924 strlcpy(name, "Envelope", namesize);
925 else if (strcasecmp(media_type, "photographic-glossy"))
926 strlcpy(name, "Glossy", namesize);
927 else if (strcasecmp(media_type, "photographic-high-gloss"))
928 strlcpy(name, "HighGloss", namesize);
929 else if (strcasecmp(media_type, "photographic-matte"))
930 strlcpy(name, "Matte", namesize);
931 else if (strcasecmp(media_type, "stationery"))
932 strlcpy(name, "Plain", namesize);
933 else if (strcasecmp(media_type, "stationery-coated"))
934 strlcpy(name, "Coated", namesize);
935 else if (strcasecmp(media_type, "stationery-inkjet"))
936 strlcpy(name, "Inkjet", namesize);
937 else if (strcasecmp(media_type, "stationery-letterhead"))
938 strlcpy(name, "Letterhead", namesize);
939 else if (strcasecmp(media_type, "stationery-preprinted"))
940 strlcpy(name, "Preprinted", namesize);
941 else if (strcasecmp(media_type, "transparency"))
942 strlcpy(name, "Transparency", namesize);
943 else
944 pwg_ppdize_name(media_type, name, namesize);
945
946 return (name);
947 }
948
949
950 /*
951 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
952 */
953
954 const char * /* O - PageSize name */
955 _pwgPageSizeForMedia(
956 _pwg_media_t *media, /* I - Media */
957 char *name, /* I - PageSize name buffer */
958 size_t namesize) /* I - Size of name buffer */
959 {
960 const char *sizeptr, /* Pointer to size in PWG name */
961 *dimptr; /* Pointer to dimensions in PWG name */
962
963
964 /*
965 * Range check input...
966 */
967
968 if (!media || !name || namesize < PPD_MAX_NAME)
969 return (NULL);
970
971 /*
972 * Copy or generate a PageSize name...
973 */
974
975 if (media->ppd)
976 {
977 /*
978 * Use a standard Adobe name...
979 */
980
981 strlcpy(name, media->ppd, namesize);
982 }
983 else if (!media->pwg || !strncmp(media->pwg, "custom_", 7) ||
984 (sizeptr = strchr(media->pwg, '_')) == NULL ||
985 (dimptr = strchr(sizeptr + 1, '_')) == NULL ||
986 (dimptr - sizeptr) > namesize)
987 {
988 /*
989 * Use a name of the form "wNNNhNNN"...
990 */
991
992 snprintf(name, namesize, "w%dh%d", (int)_PWG_TOPTS(media->width),
993 (int)_PWG_TOPTS(media->length));
994 }
995 else
996 {
997 /*
998 * Copy the size name from class_sizename_dimensions...
999 */
1000
1001 memcpy(name, sizeptr + 1, dimptr - sizeptr - 1);
1002 name[dimptr - sizeptr - 1] = '\0';
1003 }
1004
1005 return (name);
1006 }
1007
1008
1009 /*
1010 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
1011 */
1012
1013 static void
1014 pwg_ppdize_name(const char *ipp, /* I - IPP keyword */
1015 char *name, /* I - Name buffer */
1016 size_t namesize) /* I - Size of name buffer */
1017 {
1018 char *ptr, /* Pointer into name buffer */
1019 *end; /* End of name buffer */
1020
1021
1022 *name = toupper(*ipp++);
1023
1024 for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
1025 {
1026 if (*ipp == '-' && isalpha(ipp[1] & 255))
1027 {
1028 ipp ++;
1029 *ptr++ = toupper(*ipp++ & 255);
1030 }
1031 else
1032 *ptr++ = *ipp++;
1033 }
1034
1035 *ptr = '\0';
1036 }
1037
1038
1039 /*
1040 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
1041 */
1042
1043 static void
1044 pwg_unppdize_name(const char *ppd, /* I - PPD keyword */
1045 char *name, /* I - Name buffer */
1046 size_t namesize) /* I - Size of name buffer */
1047 {
1048 char *ptr, /* Pointer into name buffer */
1049 *end; /* End of name buffer */
1050
1051
1052 for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++)
1053 {
1054 if (isalnum(*ppd & 255) || *ppd == '-' || *ppd == '.')
1055 *ptr++ = tolower(*ppd & 255);
1056 else if (*ppd == '_')
1057 *ptr++ = '-';
1058
1059 if (!isupper(*ppd & 255) && isalnum(*ppd & 255) &&
1060 isupper(ppd[1] & 255) && ptr < end)
1061 *ptr++ = '-';
1062 }
1063
1064 *ptr = '\0';
1065 }
1066
1067
1068 /*
1069 * End of "$Id$".
1070 */