2 * Generic Adobe PostScript printer command for ippeveprinter/CUPS.
4 * Copyright © 2019 by Apple Inc.
6 * Licensed under Apache License v2.0. See the file "LICENSE" for more
11 * Include necessary headers...
14 #include "ippevecommon.h"
16 # include <cups/ppd-private.h>
17 #endif /* !CUPS_LITE */
22 # define PDFTOPS CUPS_SERVERBIN "/filter/cgpdftops"
24 # define PDFTOPS CUPS_SERVERBIN "/filter/pdftops"
25 #endif /* __APPLE__ */
33 static ppd_file_t
*ppd
= NULL
; /* PPD file data */
34 static _ppd_cache_t
*ppd_cache
= NULL
;
35 /* IPP to PPD cache data */
36 #endif /* !CUPS_LITE */
43 static void ascii85(const unsigned char *data
, int length
, int eod
);
44 static void dsc_header(int num_pages
);
45 static void dsc_page(int page
);
46 static void dsc_trailer(int num_pages
);
47 static int get_options(cups_option_t
**options
);
48 static int jpeg_to_ps(const char *filename
, int copies
);
49 static int pdf_to_ps(const char *filename
, int copies
, int num_options
, cups_option_t
*options
);
50 static int ps_to_ps(const char *filename
, int copies
);
51 static int raster_to_ps(const char *filename
);
55 * 'main()' - Main entry for PostScript printer command.
58 int /* O - Exit status */
59 main(int argc
, /* I - Number of command-line arguments */
60 char *argv
[]) /* I - Command-line arguments */
62 const char *content_type
, /* Content type to print */
63 *ipp_copies
; /* IPP_COPIES value */
64 int copies
; /* Number of copies */
65 int num_options
; /* Number of options */
66 cups_option_t
*options
; /* Options */
70 * Get print options...
73 num_options
= get_options(&options
);
74 if ((ipp_copies
= getenv("IPP_COPIES")) != NULL
)
75 copies
= atoi(ipp_copies
);
85 fputs("ERROR: Too many arguments supplied, aborting.\n", stderr
);
88 else if ((content_type
= getenv("CONTENT_TYPE")) == NULL
)
90 fputs("ERROR: CONTENT_TYPE environment variable not set, aborting.\n", stderr
);
93 else if (!strcasecmp(content_type
, "application/pdf"))
95 return (pdf_to_ps(argv
[1], copies
, num_options
, options
));
97 else if (!strcasecmp(content_type
, "application/postscript"))
99 return (ps_to_ps(argv
[1], copies
));
101 else if (!strcasecmp(content_type
, "image/jpeg"))
103 return (jpeg_to_ps(argv
[1], copies
));
105 else if (!strcasecmp(content_type
, "image/pwg-raster") || !strcasecmp(content_type
, "image/urf"))
107 return (raster_to_ps(argv
[1]));
111 fprintf(stderr
, "ERROR: CONTENT_TYPE %s not supported.\n", content_type
);
118 * 'ascii85()' - Write binary data using a Base85 encoding...
122 ascii85(const unsigned char *data
, /* I - Data to write */
123 int length
, /* I - Number of bytes to write */
124 int eod
) /* I - 1 if this is the end, 0 otherwise */
126 unsigned b
= 0; /* Current 32-bit word */
127 unsigned char c
[5]; /* Base-85 encoded characters */
128 static int col
= 0; /* Column */
129 static unsigned char leftdata
[4]; /* Leftover data at the end */
130 static int leftcount
= 0; /* Size of leftover data */
140 b
= (unsigned)((((((data
[0] << 8) | data
[1]) << 8) | data
[2]) << 8) | data
[3]);
143 b
= (unsigned)((((((leftdata
[0] << 8) | data
[0]) << 8) | data
[1]) << 8) | data
[2]);
146 b
= (unsigned)((((((leftdata
[0] << 8) | leftdata
[1]) << 8) | data
[0]) << 8) | data
[1]);
149 b
= (unsigned)((((((leftdata
[0] << 8) | leftdata
[1]) << 8) | leftdata
[2]) << 8) | data
[0]);
166 c
[4] = (b
% 85) + '!';
168 c
[3] = (b
% 85) + '!';
170 c
[2] = (b
% 85) + '!';
172 c
[1] = (b
% 85) + '!';
174 c
[0] = (unsigned char)(b
+ '!');
176 fwrite(c
, 1, 5, stdout
);
180 data
+= 4 - leftcount
;
181 length
-= 4 - leftcount
;
187 // Copy any remainder into the leftdata array...
188 if ((length
- leftcount
) > 0)
189 memcpy(leftdata
+ leftcount
, data
, (size_t)(length
- leftcount
));
191 memset(leftdata
+ length
, 0, (size_t)(4 - length
));
198 // Do the end-of-data dance...
207 // Write the remaining bytes as needed...
208 b
= (unsigned)((((((leftdata
[0] << 8) | leftdata
[1]) << 8) | leftdata
[2]) << 8) | leftdata
[3]);
210 c
[4] = (b
% 85) + '!';
212 c
[3] = (b
% 85) + '!';
214 c
[2] = (b
% 85) + '!';
216 c
[1] = (b
% 85) + '!';
218 c
[0] = (unsigned char)(b
+ '!');
220 fwrite(c
, (size_t)(leftcount
+ 1), 1, stdout
);
232 * 'dsc_header()' - Write out a standard Document Structuring Conventions
237 dsc_header(int num_pages
) /* I - Number of pages or 0 if not known */
239 const char *job_name
= getenv("IPP_JOB_NAME");
244 const char *job_id
= getenv("IPP_JOB_ID");
247 ppdEmitJCL(ppd
, stdout
, job_id
? atoi(job_id
) : 0, cupsUser(), job_name
? job_name
: "Unknown");
248 #endif /* !CUPS_LITE */
250 puts("%!PS-Adobe-3.0");
251 puts("%%LanguageLevel: 2");
252 printf("%%%%Creator: ippeveps/%d.%d.%d\n", CUPS_VERSION_MAJOR
, CUPS_VERSION_MINOR
, CUPS_VERSION_PATCH
);
255 fputs("%%Title: ", stdout
);
258 if (*job_name
>= 0x20 && *job_name
< 0x7f)
268 printf("%%%%Pages: %d\n", num_pages
);
270 puts("%%Pages: (atend)");
271 puts("%%EndComments");
276 puts("%%BeginProlog");
279 puts("%%BeginFeature: *JobPatchFile 1");
281 puts("%%EndFeature");
283 ppdEmit(ppd
, stdout
, PPD_ORDER_PROLOG
);
286 puts("%%BeginSetup");
287 ppdEmit(ppd
, stdout
, PPD_ORDER_DOCUMENT
);
288 ppdEmit(ppd
, stdout
, PPD_ORDER_ANY
);
291 #endif /* !CUPS_LITE */
296 * 'dsc_page()' - Mark the start of a page.
300 dsc_page(int page
) /* I - Page numebr (1-based) */
302 printf("%%%%Page: (%d) %d\n", page
, page
);
304 fprintf(stderr
, "ATTR: job-impressions-completed=%d\n", page
);
309 puts("%%BeginPageSetup");
310 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
311 puts("%%EndPageSetup");
313 #endif /* !CUPS_LITE */
318 * 'dsc_trailer()' - Mark the end of the document.
322 dsc_trailer(int num_pages
) /* I - Number of pages */
327 printf("%%%%Pages: %d\n", num_pages
);
332 if (ppd
&& ppd
->jcl_end
)
333 ppdEmitJCLEnd(ppd
, stdout
);
335 #endif /* !CUPS_LITE */
341 * 'get_options()' - Get the PPD options corresponding to the IPP Job Template
345 static int /* O - Number of options */
346 get_options(cups_option_t
**options
) /* O - Options */
348 int num_options
= 0; /* Number of options */
349 const char *value
; /* Option value */
350 pwg_media_t
*media
= NULL
; /* Media mapping */
351 int num_media_col
= 0; /* Number of media-col values */
352 cups_option_t
*media_col
= NULL
; /* media-col values */
354 const char *choice
; /* PPD choice */
355 #endif /* !CUPS_LITE */
359 * No options to start...
368 if ((value
= getenv("IPP_MEDIA")) == NULL
)
369 if ((value
= getenv("IPP_MEDIA_COL")) == NULL
)
370 if ((value
= getenv("IPP_MEDIA_DEFAULT")) == NULL
)
371 value
= getenv("IPP_MEDIA_COL_DEFAULT");
381 num_media_col
= cupsParseOptions(value
, 0, &media_col
);
386 * media value - map to media-col.media-size-name...
389 num_media_col
= cupsAddOption("media-size-name", value
, 0, &media_col
);
393 if ((value
= cupsGetOption("media-size-name", num_media_col
, media_col
)) != NULL
)
395 media
= pwgMediaForPWG(value
);
397 else if ((value
= cupsGetOption("media-size", num_media_col
, media_col
)) != NULL
)
399 int num_media_size
; /* Number of media-size values */
400 cups_option_t
*media_size
; /* media-size values */
401 const char *x_dimension
, /* x-dimension value */
402 *y_dimension
; /* y-dimension value */
404 num_media_size
= cupsParseOptions(value
, 0, &media_size
);
406 if ((x_dimension
= cupsGetOption("x-dimension", num_media_size
, media_size
)) != NULL
&& (y_dimension
= cupsGetOption("y-dimension", num_media_size
, media_size
)) != NULL
)
407 media
= pwgMediaForSize(atoi(x_dimension
), atoi(y_dimension
));
409 cupsFreeOptions(num_media_size
, media_size
);
413 num_options
= cupsAddOption("PageSize", media
->ppd
, num_options
, options
);
417 * Load PPD file and the corresponding IPP <-> PPD cache data...
420 if ((ppd
= ppdOpenFile(getenv("PPD"))) != NULL
)
422 ppd_cache
= _ppdCacheCreateWithPPD(ppd
);
424 /* TODO: Fix me - values are names, not numbers... Also need to support finishings-col */
425 if ((value
= getenv("IPP_FINISHINGS")) == NULL
)
426 value
= getenv("IPP_FINISHINGS_DEFAULT");
430 char *ptr
; /* Pointer into value */
431 int fin
; /* Current value */
433 for (fin
= strtol(value
, &ptr
, 10); fin
> 0; fin
= strtol(ptr
+ 1, &ptr
, 10))
435 num_options
= _ppdCacheGetFinishingOptions(ppd_cache
, NULL
, (ipp_finishings_t
)fin
, num_options
, options
);
442 if ((value
= cupsGetOption("media-source", num_media_col
, media_col
)) != NULL
)
444 if ((choice
= _ppdCacheGetInputSlot(ppd_cache
, NULL
, value
)) != NULL
)
445 num_options
= cupsAddOption("InputSlot", choice
, num_options
, options
);
448 if ((value
= cupsGetOption("media-type", num_media_col
, media_col
)) != NULL
)
450 if ((choice
= _ppdCacheGetMediaType(ppd_cache
, NULL
, value
)) != NULL
)
451 num_options
= cupsAddOption("MediaType", choice
, num_options
, options
);
454 if ((value
= getenv("IPP_OUTPUT_BIN")) == NULL
)
455 value
= getenv("IPP_OUTPUT_BIN_DEFAULT");
459 if ((choice
= _ppdCacheGetOutputBin(ppd_cache
, value
)) != NULL
)
460 num_options
= cupsAddOption("OutputBin", choice
, num_options
, options
);
463 if ((value
= getenv("IPP_SIDES")) == NULL
)
464 value
= getenv("IPP_SIDES_DEFAULT");
466 if (value
&& ppd_cache
->sides_option
)
468 if (!strcmp(value
, "one-sided") && ppd_cache
->sides_1sided
)
469 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_1sided
, num_options
, options
);
470 else if (!strcmp(value
, "two-sided-long-edge") && ppd_cache
->sides_2sided_long
)
471 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_2sided_long
, num_options
, options
);
472 else if (!strcmp(value
, "two-sided-short-edge") && ppd_cache
->sides_2sided_short
)
473 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_2sided_short
, num_options
, options
);
476 if ((value
= getenv("IPP_PRINT_QUALITY")) == NULL
)
477 value
= getenv("IPP_PRINT_QUALITY_DEFAULT");
481 int i
; /* Looping var */
482 int pq
; /* Print quality (0-2) */
483 int pcm
= 1; /* Print color model (0 = mono, 1 = color) */
484 int num_presets
; /* Number of presets */
485 cups_option_t
*presets
; /* Presets */
487 if (!strcmp(value
, "draft"))
489 else if (!strcmp(value
, "high"))
494 if ((value
= getenv("IPP_PRINT_COLOR_MODE")) == NULL
)
495 value
= getenv("IPP_PRINT_COLOR_MODE_DEFAULT");
497 if (value
&& !strcmp(value
, "monochrome"))
500 num_presets
= ppd_cache
->num_presets
[pcm
][pq
];
501 presets
= ppd_cache
->presets
[pcm
][pq
];
503 for (i
= 0; i
< num_presets
; i
++)
504 num_options
= cupsAddOption(presets
[i
].name
, presets
[i
].value
, num_options
, options
);
508 * Mark the PPD with the options...
511 ppdMarkDefaults(ppd
);
512 cupsMarkOptions(ppd
, num_options
, *options
);
514 #endif /* !CUPS_LITE */
516 cupsFreeOptions(num_media_col
, media_col
);
518 return (num_options
);
523 * 'jpeg_to_ps()' - Convert a JPEG file to PostScript.
526 static int /* O - Exit status */
527 jpeg_to_ps(const char *filename
, /* I - Filename */
528 int copies
) /* I - Number of copies */
530 int fd
; /* JPEG file descriptor */
531 int copy
; /* Current copy */
532 int width
= 0, /* Width */
533 height
= 0, /* Height */
534 depth
= 0, /* Number of colors */
535 length
; /* Length of marker */
536 unsigned char buffer
[65536], /* Copy buffer */
537 *bufptr
, /* Pointer info buffer */
538 *bufend
; /* End of buffer */
539 ssize_t bytes
; /* Bytes in buffer */
540 const char *decode
; /* Decode array */
541 float page_left
, /* Left margin */
542 page_top
, /* Top margin */
543 page_width
, /* Page width in points */
544 page_height
, /* Page heigth in points */
545 x_factor
, /* X image scaling factor */
546 y_factor
, /* Y image scaling factor */
547 page_scaling
; /* Image scaling factor */
549 ppd_size_t
*page_size
; /* Current page size */
550 #endif /* !CUPS_LITE */
554 * Open the input file...
559 if ((fd
= open(filename
, O_RDONLY
)) < 0)
561 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
572 * Read the JPEG dimensions...
575 bytes
= read(fd
, buffer
, sizeof(buffer
));
577 if (bytes
< 3 || memcmp(buffer
, "\377\330\377", 3))
579 fputs("ERROR: Not a JPEG image.\n", stderr
);
587 for (bufptr
= buffer
+ 2, bufend
= buffer
+ bytes
; bufptr
< bufend
;)
590 * Scan the file for a SOFn marker, then we can get the dimensions...
597 if (bufptr
>= bufend
)
600 * If we are at the end of the current buffer, re-fill and continue...
603 if ((bytes
= read(fd
, buffer
, sizeof(buffer
))) <= 0)
607 bufend
= buffer
+ bytes
;
613 if ((bufptr
+ 16) >= bufend
)
616 * Read more of the marker...
619 bytes
= bufend
- bufptr
;
621 memmove(buffer
, bufptr
, (size_t)bytes
);
623 bufend
= buffer
+ bytes
;
625 if ((bytes
= read(fd
, bufend
, sizeof(buffer
) - (size_t)bytes
)) <= 0)
631 length
= (size_t)((bufptr
[1] << 8) | bufptr
[2]);
633 if ((*bufptr
>= 0xc0 && *bufptr
<= 0xc3) || (*bufptr
>= 0xc5 && *bufptr
<= 0xc7) || (*bufptr
>= 0xc9 && *bufptr
<= 0xcb) || (*bufptr
>= 0xcd && *bufptr
<= 0xcf))
636 * SOFn marker, look for dimensions...
639 width
= (bufptr
[6] << 8) | bufptr
[7];
640 height
= (bufptr
[4] << 8) | bufptr
[5];
646 * Skip past this marker...
650 bytes
= bufend
- bufptr
;
652 while (length
>= bytes
)
656 if ((bytes
= read(fd
, buffer
, sizeof(buffer
))) <= 0)
660 bufend
= buffer
+ bytes
;
670 fprintf(stderr
, "DEBUG: JPEG dimensions are %dx%dx%d\n", width
, height
, depth
);
672 if (width
<= 0 || height
<= 0 || depth
<= 0)
674 fputs("ERROR: No valid image data in JPEG file.\n", stderr
);
682 fputs("ATTR: job-impressions=1\n", stderr
);
685 * Figure out the dimensions/scaling of the final image...
692 page_height
= 720.0f
;
695 if ((page_size
= ppdPageSize(ppd
, NULL
)) != NULL
)
697 page_left
= page_size
->left
;
698 page_top
= page_size
->top
;
699 page_width
= page_size
->right
- page_left
;
700 page_height
= page_top
- page_size
->bottom
;
707 page_height
= 720.0f
;
709 #endif /* CUPS_LITE */
711 fprintf(stderr
, "DEBUG: page_left=%.2f, page_top=%.2f, page_width=%.2f, page_height=%.2f\n", page_left
, page_top
, page_width
, page_height
);
713 /* TODO: Support orientation/rotation, different print-scaling modes */
714 x_factor
= page_width
/ width
;
715 y_factor
= page_height
/ height
;
717 if (x_factor
> y_factor
&& (height
* x_factor
) <= page_height
)
718 page_scaling
= x_factor
;
720 page_scaling
= y_factor
;
722 fprintf(stderr
, "DEBUG: Scaled dimensions are %.2fx%.2f\n", width
* page_scaling
, height
* page_scaling
);
730 for (copy
= 1; copy
<= copies
; copy
++)
736 puts("/DeviceGray setcolorspace");
741 puts("/DeviceRGB setcolorspace");
742 decode
= "0 1 0 1 0 1";
746 puts("/DeviceCMYK setcolorspace");
747 decode
= "0 1 0 1 0 1 0 1";
750 printf("gsave %.3f %.3f translate %.3f %.3f scale\n", page_left
+ 0.5f
* (page_width
- width
* page_scaling
), page_top
- 0.5f
* (page_height
- height
* page_scaling
), page_scaling
, page_scaling
);
751 printf("<</ImageType 1/Width %d/Height %d/BitsPerComponent 8/ImageMatrix[1 0 0 -1 0 1]/Decode[%s]/DataSource currentfile/ASCII85Decode filter/DCTDecode filter/Interpolate true>>image\n", width
, height
, decode
);
754 lseek(fd
, 0, SEEK_SET
);
756 while ((bytes
= read(fd
, buffer
, sizeof(buffer
))) > 0)
757 ascii85(buffer
, (int)bytes
, 0);
759 ascii85(buffer
, 0, 1);
761 puts("grestore showpage");
771 * 'pdf_to_ps()' - Convert a PDF file to PostScript.
774 static int /* O - Exit status */
775 pdf_to_ps(const char *filename
, /* I - Filename */
776 int copies
, /* I - Number of copies */
777 int num_options
, /* I - Number of options */
778 cups_option_t
*options
) /* I - options */
780 int status
; /* Exit status */
781 char tempfile
[1024]; /* Temporary file */
782 int tempfd
; /* Temporary file descriptor */
783 int pid
; /* Process ID */
784 const char *pdf_argv
[8]; /* Command-line arguments */
785 char pdf_options
[1024]; /* Options */
786 const char *value
; /* Option value */
787 const char *job_id
, /* job-id value */
788 *job_name
; /* job-name value */
792 * Create a temporary file for the PostScript version...
795 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
797 fprintf(stderr
, "ERROR: Unable to create temporary file: %s\n", strerror(errno
));
802 * Run cgpdftops or pdftops in the filter directory...
805 if ((value
= cupsGetOption("PageSize", num_options
, options
)) != NULL
)
806 snprintf(pdf_options
, sizeof(pdf_options
), "PageSize=%s", value
);
808 pdf_options
[0] = '\0';
810 if ((job_id
= getenv("IPP_JOB_ID")) == NULL
)
812 if ((job_name
= getenv("IPP_JOB_NAME")) == NULL
)
813 job_name
= "untitled";
815 pdf_argv
[0] = "printer";
816 pdf_argv
[1] = job_id
;
817 pdf_argv
[2] = cupsUser();
818 pdf_argv
[3] = job_name
;
820 pdf_argv
[5] = pdf_options
;
821 pdf_argv
[6] = filename
;
824 if ((pid
= fork()) == 0)
827 * Child comes here...
834 execv(PDFTOPS
, (char * const *)pdf_argv
);
840 * Unable to fork process...
843 perror("ERROR: Unable to start PDF filter");
853 * Wait for the filter to complete...
859 while (waitpid(pid
, &status
, 0) < 0);
861 while (wait(&status
) < 0);
862 # endif /* HAVE_WAITPID */
866 if (WIFEXITED(status
))
867 fprintf(stderr
, "ERROR: " PDFTOPS
" exited with status %d.\n", WEXITSTATUS(status
));
869 fprintf(stderr
, "ERROR: " PDFTOPS
" terminated with signal %d.\n", WTERMSIG(status
));
877 * Copy the PostScript output from the command...
880 status
= ps_to_ps(tempfile
, copies
);
889 * 'ps_to_ps()' - Copy PostScript to the standard output.
892 static int /* O - Exit status */
893 ps_to_ps(const char *filename
, /* I - Filename */
894 int copies
) /* I - Number of copies */
896 FILE *fp
; /* File to read from */
897 int copy
, /* Current copy */
898 page
, /* Current page number */
899 num_pages
= 0, /* Total number of pages */
900 first_page
, /* First page */
901 last_page
; /* Last page */
902 const char *page_ranges
; /* page-ranges option */
903 long first_pos
= -1; /* Offset for first page */
904 char line
[1024]; /* Line from file */
908 * Open the print file...
913 if ((fp
= fopen(filename
, "rb")) == NULL
)
915 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
926 * Check page ranges...
929 if ((page_ranges
= getenv("IPP_PAGE_RANGES")) != NULL
)
931 if (sscanf(page_ranges
, "%d-%d", &first_page
, &last_page
) != 2)
944 * Write the PostScript header for the document...
951 while (fgets(line
, sizeof(line
), fp
))
953 if (!strncmp(line
, "%%Page:", 7))
956 first_pos
= ftell(fp
);
962 if (!strncmp(line
, "%%Page:", 7))
964 for (copy
= 0; copy
< copies
; copy
++)
966 int copy_page
= 0; /* Do we copy the page data? */
969 fseek(fp
, first_pos
, SEEK_SET
);
972 while (fgets(line
, sizeof(line
), fp
))
974 if (!strncmp(line
, "%%Page:", 7))
977 copy_page
= page
>= first_page
&& page
<= last_page
;
991 dsc_trailer(num_pages
);
993 fprintf(stderr
, "ATTR: job-impressions=%d\n", num_pages
/ copies
);
1003 * 'raster_to_ps()' - Convert PWG Raster/Apple Raster to PostScript.
1005 * The current implementation locally-decodes the raster data and then writes
1006 * whole, non-blank lines as 1-line high images with base-85 encoding, resulting
1007 * in between 10 and 20 times larger output. A alternate implementation (if it
1008 * is deemed necessary) would be to implement a PostScript decode procedure that
1009 * handles the modified packbits decompression so that we just have the base-85
1010 * encoding overhead (25%). Furthermore, Level 3 PostScript printers also
1011 * support Flate compression.
1013 * That said, the most efficient path with the highest quality is for Clients
1014 * to supply PDF files and us to use the existing PDF to PostScript conversion
1018 static int /* O - Exit status */
1019 raster_to_ps(const char *filename
) /* I - Filename */
1021 int fd
; /* Input file */
1022 cups_raster_t
*ras
; /* Raster stream */
1023 cups_page_header2_t header
; /* Page header */
1024 int page
= 0; /* Current page */
1025 unsigned y
; /* Current line */
1026 unsigned char *line
; /* Line buffer */
1027 unsigned char white
; /* White color */
1028 const char *decode
; /* Image decode array */
1032 * Open the input file...
1037 if ((fd
= open(filename
, O_RDONLY
)) < 0)
1039 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
1049 * Open the raster stream and send pages...
1052 if ((ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
)) == NULL
)
1054 fputs("ERROR: Unable to read raster data, aborting.\n", stderr
);
1060 while (cupsRasterReadHeader2(ras
, &header
))
1064 fprintf(stderr
, "DEBUG: Page %d: %ux%ux%u\n", page
, header
.cupsWidth
, header
.cupsHeight
, header
.cupsBitsPerPixel
);
1066 if (header
.cupsColorSpace
!= CUPS_CSPACE_W
&& header
.cupsColorSpace
!= CUPS_CSPACE_SW
&& header
.cupsColorSpace
!= CUPS_CSPACE_K
&& header
.cupsColorSpace
!= CUPS_CSPACE_RGB
&& header
.cupsColorSpace
!= CUPS_CSPACE_SRGB
)
1068 fputs("ERROR: Unsupported color space, aborting.\n", stderr
);
1071 else if (header
.cupsBitsPerColor
!= 1 && header
.cupsBitsPerColor
!= 8)
1073 fputs("ERROR: Unsupported bit depth, aborting.\n", stderr
);
1077 line
= malloc(header
.cupsBytesPerLine
);
1082 printf("%.6f %.6f scale\n", 72.0f
/ header
.HWResolution
[0], 72.0f
/ header
.HWResolution
[1]);
1084 switch (header
.cupsColorSpace
)
1086 case CUPS_CSPACE_W
:
1087 case CUPS_CSPACE_SW
:
1089 puts("/DeviceGray setcolorspace");
1093 case CUPS_CSPACE_K
:
1095 puts("/DeviceGray setcolorspace");
1100 decode
= "0 1 0 1 0 1";
1101 puts("/DeviceRGB setcolorspace");
1106 printf("gsave /L{grestore gsave 0 exch translate <</ImageType 1/Width %u/Height 1/BitsPerComponent %u/ImageMatrix[1 0 0 -1 0 1]/DataSource currentfile/ASCII85Decode filter/Decode[%s]>>image}bind def\n", header
.cupsWidth
, header
.cupsBitsPerColor
, decode
);
1108 for (y
= header
.cupsHeight
; y
> 0; y
--)
1110 if (cupsRasterReadPixels(ras
, line
, header
.cupsBytesPerLine
))
1112 if (line
[0] != white
|| memcmp(line
, line
+ 1, header
.cupsBytesPerLine
- 1))
1114 printf("%d L\n", y
- 1);
1115 ascii85(line
, (int)header
.cupsBytesPerLine
, 1);
1122 fprintf(stderr
, "DEBUG: y=%d at end...\n", y
);
1124 puts("grestore grestore");
1130 cupsRasterClose(ras
);
1134 fprintf(stderr
, "ATTR: job-impressions=%d\n", page
);