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 */
21 # define PDFTOPS CUPS_SERVERBIN "/filter/cgpdftops"
23 # define PDFTOPS CUPS_SERVERBIN "/filter/pdftops"
24 #endif /* __APPLE__ */
32 static ppd_file_t
*ppd
= NULL
; /* PPD file data */
33 static _ppd_cache_t
*ppd_cache
= NULL
;
34 /* IPP to PPD cache data */
35 #endif /* !CUPS_LITE */
42 static void ascii85(const unsigned char *data
, int length
, int eod
);
43 static void dsc_header(int num_pages
);
44 static void dsc_page(int page
);
45 static void dsc_trailer(int num_pages
);
46 static int get_options(cups_option_t
**options
);
47 static int jpeg_to_ps(const char *filename
, int copies
);
48 static int pdf_to_ps(const char *filename
, int copies
, int num_options
, cups_option_t
*options
);
49 static int ps_to_ps(const char *filename
, int copies
);
50 static int raster_to_ps(const char *filename
);
54 * 'main()' - Main entry for PostScript printer command.
57 int /* O - Exit status */
58 main(int argc
, /* I - Number of command-line arguments */
59 char *argv
[]) /* I - Command-line arguments */
61 const char *content_type
, /* Content type to print */
62 *ipp_copies
; /* IPP_COPIES value */
63 int copies
; /* Number of copies */
64 int num_options
; /* Number of options */
65 cups_option_t
*options
; /* Options */
69 * Get print options...
72 num_options
= get_options(&options
);
73 if ((ipp_copies
= getenv("IPP_COPIES")) != NULL
)
74 copies
= atoi(ipp_copies
);
84 fputs("ERROR: Too many arguments supplied, aborting.\n", stderr
);
87 else if ((content_type
= getenv("CONTENT_TYPE")) == NULL
)
89 fputs("ERROR: CONTENT_TYPE environment variable not set, aborting.\n", stderr
);
92 else if (!strcasecmp(content_type
, "application/pdf"))
94 return (pdf_to_ps(argv
[1], copies
, num_options
, options
));
96 else if (!strcasecmp(content_type
, "application/postscript"))
98 return (ps_to_ps(argv
[1], copies
));
100 else if (!strcasecmp(content_type
, "image/jpeg"))
102 return (jpeg_to_ps(argv
[1], copies
));
104 else if (!strcasecmp(content_type
, "image/pwg-raster") || !strcasecmp(content_type
, "image/urf"))
106 return (raster_to_ps(argv
[1]));
110 fprintf(stderr
, "ERROR: CONTENT_TYPE %s not supported.\n", content_type
);
117 * 'ascii85()' - Write binary data using a Base85 encoding...
121 ascii85(const unsigned char *data
, /* I - Data to write */
122 int length
, /* I - Number of bytes to write */
123 int eod
) /* I - 1 if this is the end, 0 otherwise */
125 unsigned b
= 0; /* Current 32-bit word */
126 unsigned char c
[5]; /* Base-85 encoded characters */
127 static int col
= 0; /* Column */
128 static unsigned char leftdata
[4]; /* Leftover data at the end */
129 static int leftcount
= 0; /* Size of leftover data */
139 b
= (unsigned)((((((data
[0] << 8) | data
[1]) << 8) | data
[2]) << 8) | data
[3]);
142 b
= (unsigned)((((((leftdata
[0] << 8) | data
[0]) << 8) | data
[1]) << 8) | data
[2]);
145 b
= (unsigned)((((((leftdata
[0] << 8) | leftdata
[1]) << 8) | data
[0]) << 8) | data
[1]);
148 b
= (unsigned)((((((leftdata
[0] << 8) | leftdata
[1]) << 8) | leftdata
[2]) << 8) | data
[0]);
165 c
[4] = (b
% 85) + '!';
167 c
[3] = (b
% 85) + '!';
169 c
[2] = (b
% 85) + '!';
171 c
[1] = (b
% 85) + '!';
173 c
[0] = (unsigned char)(b
+ '!');
175 fwrite(c
, 1, 5, stdout
);
179 data
+= 4 - leftcount
;
180 length
-= 4 - leftcount
;
186 // Copy any remainder into the leftdata array...
187 if ((length
- leftcount
) > 0)
188 memcpy(leftdata
+ leftcount
, data
, (size_t)(length
- leftcount
));
190 memset(leftdata
+ length
, 0, (size_t)(4 - length
));
197 // Do the end-of-data dance...
206 // Write the remaining bytes as needed...
207 b
= (unsigned)((((((leftdata
[0] << 8) | leftdata
[1]) << 8) | leftdata
[2]) << 8) | leftdata
[3]);
209 c
[4] = (b
% 85) + '!';
211 c
[3] = (b
% 85) + '!';
213 c
[2] = (b
% 85) + '!';
215 c
[1] = (b
% 85) + '!';
217 c
[0] = (unsigned char)(b
+ '!');
219 fwrite(c
, (size_t)(leftcount
+ 1), 1, stdout
);
231 * 'dsc_header()' - Write out a standard Document Structuring Conventions
236 dsc_header(int num_pages
) /* I - Number of pages or 0 if not known */
238 const char *job_name
= getenv("IPP_JOB_NAME");
243 const char *job_id
= getenv("IPP_JOB_ID");
246 ppdEmitJCL(ppd
, stdout
, job_id
? atoi(job_id
) : 0, cupsUser(), job_name
? job_name
: "Unknown");
247 #endif /* !CUPS_LITE */
249 puts("%!PS-Adobe-3.0");
250 puts("%%LanguageLevel: 2");
251 printf("%%%%Creator: ippeveps/%d.%d.%d\n", CUPS_VERSION_MAJOR
, CUPS_VERSION_MINOR
, CUPS_VERSION_PATCH
);
254 fputs("%%Title: ", stdout
);
257 if (*job_name
>= 0x20 && *job_name
< 0x7f)
267 printf("%%%%Pages: %d\n", num_pages
);
269 puts("%%Pages: (atend)");
270 puts("%%EndComments");
275 puts("%%BeginProlog");
278 puts("%%BeginFeature: *JobPatchFile 1");
280 puts("%%EndFeature");
282 ppdEmit(ppd
, stdout
, PPD_ORDER_PROLOG
);
285 puts("%%BeginSetup");
286 ppdEmit(ppd
, stdout
, PPD_ORDER_DOCUMENT
);
287 ppdEmit(ppd
, stdout
, PPD_ORDER_ANY
);
290 #endif /* !CUPS_LITE */
295 * 'dsc_page()' - Mark the start of a page.
299 dsc_page(int page
) /* I - Page numebr (1-based) */
301 printf("%%%%Page: (%d) %d\n", page
, page
);
303 fprintf(stderr
, "ATTR: job-impressions-completed=%d\n", page
);
308 puts("%%BeginPageSetup");
309 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
310 puts("%%EndPageSetup");
312 #endif /* !CUPS_LITE */
317 * 'dsc_trailer()' - Mark the end of the document.
321 dsc_trailer(int num_pages
) /* I - Number of pages */
326 printf("%%%%Pages: %d\n", num_pages
);
331 if (ppd
&& ppd
->jcl_end
)
332 ppdEmitJCLEnd(ppd
, stdout
);
334 #endif /* !CUPS_LITE */
340 * 'get_options()' - Get the PPD options corresponding to the IPP Job Template
344 static int /* O - Number of options */
345 get_options(cups_option_t
**options
) /* O - Options */
347 int num_options
= 0; /* Number of options */
348 const char *value
; /* Option value */
349 pwg_media_t
*media
= NULL
; /* Media mapping */
350 int num_media_col
= 0; /* Number of media-col values */
351 cups_option_t
*media_col
= NULL
; /* media-col values */
353 const char *choice
; /* PPD choice */
354 #endif /* !CUPS_LITE */
358 * No options to start...
367 if ((value
= getenv("IPP_MEDIA")) == NULL
)
368 if ((value
= getenv("IPP_MEDIA_COL")) == NULL
)
369 if ((value
= getenv("IPP_MEDIA_DEFAULT")) == NULL
)
370 value
= getenv("IPP_MEDIA_COL_DEFAULT");
380 num_media_col
= cupsParseOptions(value
, 0, &media_col
);
385 * media value - map to media-col.media-size-name...
388 num_media_col
= cupsAddOption("media-size-name", value
, 0, &media_col
);
392 if ((value
= cupsGetOption("media-size-name", num_media_col
, media_col
)) != NULL
)
394 media
= pwgMediaForPWG(value
);
396 else if ((value
= cupsGetOption("media-size", num_media_col
, media_col
)) != NULL
)
398 int num_media_size
; /* Number of media-size values */
399 cups_option_t
*media_size
; /* media-size values */
400 const char *x_dimension
, /* x-dimension value */
401 *y_dimension
; /* y-dimension value */
403 num_media_size
= cupsParseOptions(value
, 0, &media_size
);
405 if ((x_dimension
= cupsGetOption("x-dimension", num_media_size
, media_size
)) != NULL
&& (y_dimension
= cupsGetOption("y-dimension", num_media_size
, media_size
)) != NULL
)
406 media
= pwgMediaForSize(atoi(x_dimension
), atoi(y_dimension
));
408 cupsFreeOptions(num_media_size
, media_size
);
412 num_options
= cupsAddOption("PageSize", media
->ppd
, num_options
, options
);
416 * Load PPD file and the corresponding IPP <-> PPD cache data...
419 if ((ppd
= ppdOpenFile(getenv("PPD"))) != NULL
)
421 ppd_cache
= _ppdCacheCreateWithPPD(ppd
);
423 if ((value
= getenv("IPP_FINISHINGS")) == NULL
)
424 value
= getenv("IPP_FINISHINGS_DEFAULT");
428 char *ptr
; /* Pointer into value */
429 int fin
; /* Current value */
431 for (fin
= strtol(value
, &ptr
, 10); fin
> 0; fin
= strtol(ptr
+ 1, &ptr
, 10))
433 num_options
= _ppdCacheGetFinishingOptions(ppd_cache
, NULL
, (ipp_finishings_t
)fin
, num_options
, options
);
440 if ((value
= cupsGetOption("media-source", num_media_col
, media_col
)) != NULL
)
442 if ((choice
= _ppdCacheGetInputSlot(ppd_cache
, NULL
, value
)) != NULL
)
443 num_options
= cupsAddOption("InputSlot", choice
, num_options
, options
);
446 if ((value
= cupsGetOption("media-type", num_media_col
, media_col
)) != NULL
)
448 if ((choice
= _ppdCacheGetMediaType(ppd_cache
, NULL
, value
)) != NULL
)
449 num_options
= cupsAddOption("MediaType", choice
, num_options
, options
);
452 if ((value
= getenv("IPP_OUTPUT_BIN")) == NULL
)
453 value
= getenv("IPP_OUTPUT_BIN_DEFAULT");
457 if ((choice
= _ppdCacheGetOutputBin(ppd_cache
, value
)) != NULL
)
458 num_options
= cupsAddOption("OutputBin", choice
, num_options
, options
);
461 if ((value
= getenv("IPP_SIDES")) == NULL
)
462 value
= getenv("IPP_SIDES_DEFAULT");
464 if (value
&& ppd_cache
->sides_option
)
466 if (!strcmp(value
, "one-sided") && ppd_cache
->sides_1sided
)
467 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_1sided
, num_options
, options
);
468 else if (!strcmp(value
, "two-sided-long-edge") && ppd_cache
->sides_2sided_long
)
469 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_2sided_long
, num_options
, options
);
470 else if (!strcmp(value
, "two-sided-short-edge") && ppd_cache
->sides_2sided_short
)
471 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_2sided_short
, num_options
, options
);
474 if ((value
= getenv("IPP_PRINT_QUALITY")) == NULL
)
475 value
= getenv("IPP_PRINT_QUALITY_DEFAULT");
479 int i
; /* Looping var */
480 int pq
; /* Print quality (0-2) */
481 int pcm
= 1; /* Print color model (0 = mono, 1 = color) */
482 int num_presets
; /* Number of presets */
483 cups_option_t
*presets
; /* Presets */
485 if ((pq
= atoi(value
) - 3) < 0)
490 if ((value
= getenv("IPP_PRINT_COLOR_MODE")) == NULL
)
491 value
= getenv("IPP_PRINT_COLOR_MODE_DEFAULT");
493 if (value
&& !strcmp(value
, "monochrome"))
496 num_presets
= ppd_cache
->num_presets
[pcm
][pq
];
497 presets
= ppd_cache
->presets
[pcm
][pq
];
499 for (i
= 0; i
< num_presets
; i
++)
500 num_options
= cupsAddOption(presets
[i
].name
, presets
[i
].value
, num_options
, options
);
504 * Mark the PPD with the options...
507 ppdMarkDefaults(ppd
);
508 cupsMarkOptions(ppd
, num_options
, *options
);
510 #endif /* !CUPS_LITE */
512 cupsFreeOptions(num_media_col
, media_col
);
514 return (num_options
);
519 * 'jpeg_to_ps()' - Convert a JPEG file to PostScript.
522 static int /* O - Exit status */
523 jpeg_to_ps(const char *filename
, /* I - Filename */
524 int copies
) /* I - Number of copies */
526 int fd
; /* JPEG file descriptor */
527 int copy
; /* Current copy */
528 int width
= 0, /* Width */
529 height
= 0, /* Height */
530 depth
= 0, /* Number of colors */
531 length
; /* Length of marker */
532 unsigned char buffer
[65536], /* Copy buffer */
533 *bufptr
, /* Pointer info buffer */
534 *bufend
; /* End of buffer */
535 ssize_t bytes
; /* Bytes in buffer */
536 const char *decode
; /* Decode array */
537 float page_left
, /* Left margin */
538 page_top
, /* Top margin */
539 page_width
, /* Page width in points */
540 page_height
, /* Page heigth in points */
541 x_factor
, /* X image scaling factor */
542 y_factor
, /* Y image scaling factor */
543 page_scaling
; /* Image scaling factor */
545 ppd_size_t
*page_size
; /* Current page size */
546 #endif /* !CUPS_LITE */
550 * Open the input file...
555 if ((fd
= open(filename
, O_RDONLY
)) < 0)
557 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
568 * Read the JPEG dimensions...
571 bytes
= read(fd
, buffer
, sizeof(buffer
));
573 if (bytes
< 3 || memcmp(buffer
, "\377\330\377", 3))
575 fputs("ERROR: Not a JPEG image.\n", stderr
);
583 for (bufptr
= buffer
+ 2, bufend
= buffer
+ bytes
; bufptr
< bufend
;)
586 * Scan the file for a SOFn marker, then we can get the dimensions...
593 if (bufptr
>= bufend
)
596 * If we are at the end of the current buffer, re-fill and continue...
599 if ((bytes
= read(fd
, buffer
, sizeof(buffer
))) <= 0)
603 bufend
= buffer
+ bytes
;
609 if ((bufptr
+ 16) >= bufend
)
612 * Read more of the marker...
615 bytes
= bufend
- bufptr
;
617 memmove(buffer
, bufptr
, (size_t)bytes
);
619 bufend
= buffer
+ bytes
;
621 if ((bytes
= read(fd
, bufend
, sizeof(buffer
) - (size_t)bytes
)) <= 0)
627 length
= (size_t)((bufptr
[1] << 8) | bufptr
[2]);
629 if ((*bufptr
>= 0xc0 && *bufptr
<= 0xc3) || (*bufptr
>= 0xc5 && *bufptr
<= 0xc7) || (*bufptr
>= 0xc9 && *bufptr
<= 0xcb) || (*bufptr
>= 0xcd && *bufptr
<= 0xcf))
632 * SOFn marker, look for dimensions...
635 width
= (bufptr
[6] << 8) | bufptr
[7];
636 height
= (bufptr
[4] << 8) | bufptr
[5];
642 * Skip past this marker...
646 bytes
= bufend
- bufptr
;
648 while (length
>= bytes
)
652 if ((bytes
= read(fd
, buffer
, sizeof(buffer
))) <= 0)
656 bufend
= buffer
+ bytes
;
666 fprintf(stderr
, "DEBUG: JPEG dimensions are %dx%dx%d\n", width
, height
, depth
);
668 if (width
<= 0 || height
<= 0 || depth
<= 0)
670 fputs("ERROR: No valid image data in JPEG file.\n", stderr
);
678 fputs("ATTR: job-impressions=1\n", stderr
);
681 * Figure out the dimensions/scaling of the final image...
688 page_height
= 720.0f
;
691 if ((page_size
= ppdPageSize(ppd
, NULL
)) != NULL
)
693 page_left
= page_size
->left
;
694 page_top
= page_size
->top
;
695 page_width
= page_size
->right
- page_left
;
696 page_height
= page_top
- page_size
->bottom
;
703 page_height
= 720.0f
;
705 #endif /* CUPS_LITE */
707 fprintf(stderr
, "DEBUG: page_left=%.2f, page_top=%.2f, page_width=%.2f, page_height=%.2f\n", page_left
, page_top
, page_width
, page_height
);
709 /* TODO: Support orientation/rotation, different print-scaling modes */
710 x_factor
= page_width
/ width
;
711 y_factor
= page_height
/ height
;
713 if (x_factor
> y_factor
&& (height
* x_factor
) <= page_height
)
714 page_scaling
= x_factor
;
716 page_scaling
= y_factor
;
718 fprintf(stderr
, "DEBUG: Scaled dimensions are %.2fx%.2f\n", width
* page_scaling
, height
* page_scaling
);
726 for (copy
= 1; copy
<= copies
; copy
++)
732 puts("/DeviceGray setcolorspace");
737 puts("/DeviceRGB setcolorspace");
738 decode
= "0 1 0 1 0 1";
742 puts("/DeviceCMYK setcolorspace");
743 decode
= "0 1 0 1 0 1 0 1";
746 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
);
747 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
);
750 lseek(fd
, 0, SEEK_SET
);
752 while ((bytes
= read(fd
, buffer
, sizeof(buffer
))) > 0)
753 ascii85(buffer
, (int)bytes
, 0);
755 ascii85(buffer
, 0, 1);
757 puts("grestore showpage");
767 * 'pdf_to_ps()' - Convert a PDF file to PostScript.
770 static int /* O - Exit status */
771 pdf_to_ps(const char *filename
, /* I - Filename */
772 int copies
, /* I - Number of copies */
773 int num_options
, /* I - Number of options */
774 cups_option_t
*options
) /* I - options */
776 int status
; /* Exit status */
777 char tempfile
[1024]; /* Temporary file */
778 int tempfd
; /* Temporary file descriptor */
779 int pid
; /* Process ID */
780 const char *pdf_argv
[8]; /* Command-line arguments */
781 char pdf_options
[1024]; /* Options */
782 const char *value
; /* Option value */
783 const char *job_id
, /* job-id value */
784 *job_name
; /* job-name value */
788 * Create a temporary file for the PostScript version...
791 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
793 fprintf(stderr
, "ERROR: Unable to create temporary file: %s\n", strerror(errno
));
798 * Run cgpdftops or pdftops in the filter directory...
801 if ((value
= cupsGetOption("PageSize", num_options
, options
)) != NULL
)
802 snprintf(pdf_options
, sizeof(pdf_options
), "PageSize=%s", value
);
804 pdf_options
[0] = '\0';
806 if ((job_id
= getenv("IPP_JOB_ID")) == NULL
)
808 if ((job_name
= getenv("IPP_JOB_NAME")) == NULL
)
809 job_name
= "untitled";
811 pdf_argv
[0] = "printer";
812 pdf_argv
[1] = job_id
;
813 pdf_argv
[2] = cupsUser();
814 pdf_argv
[3] = job_name
;
816 pdf_argv
[5] = pdf_options
;
817 pdf_argv
[6] = filename
;
820 if ((pid
= fork()) == 0)
823 * Child comes here...
830 execv(PDFTOPS
, (char * const *)pdf_argv
);
836 * Unable to fork process...
839 perror("ERROR: Unable to start PDF filter");
849 * Wait for the filter to complete...
855 while (waitpid(pid
, &status
, 0) < 0);
857 while (wait(&status
) < 0);
858 # endif /* HAVE_WAITPID */
862 if (WIFEXITED(status
))
863 fprintf(stderr
, "ERROR: " PDFTOPS
" exited with status %d.\n", WEXITSTATUS(status
));
865 fprintf(stderr
, "ERROR: " PDFTOPS
" terminated with signal %d.\n", WTERMSIG(status
));
873 * Copy the PostScript output from the command...
876 status
= ps_to_ps(tempfile
, copies
);
885 * 'ps_to_ps()' - Copy PostScript to the standard output.
888 static int /* O - Exit status */
889 ps_to_ps(const char *filename
, /* I - Filename */
890 int copies
) /* I - Number of copies */
892 FILE *fp
; /* File to read from */
893 int copy
, /* Current copy */
894 page
, /* Current page number */
895 num_pages
= 0, /* Total number of pages */
896 first_page
, /* First page */
897 last_page
; /* Last page */
898 const char *page_ranges
; /* page-ranges option */
899 long first_pos
= -1; /* Offset for first page */
900 char line
[1024]; /* Line from file */
904 * Open the print file...
909 if ((fp
= fopen(filename
, "rb")) == NULL
)
911 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
922 * Check page ranges...
925 if ((page_ranges
= getenv("IPP_PAGE_RANGES")) != NULL
)
927 if (sscanf(page_ranges
, "%d-%d", &first_page
, &last_page
) != 2)
940 * Write the PostScript header for the document...
947 while (fgets(line
, sizeof(line
), fp
))
949 if (!strncmp(line
, "%%Page:", 7))
952 first_pos
= ftell(fp
);
958 if (!strncmp(line
, "%%Page:", 7))
960 for (copy
= 0; copy
< copies
; copy
++)
962 int copy_page
= 0; /* Do we copy the page data? */
965 fseek(fp
, first_pos
, SEEK_SET
);
968 while (fgets(line
, sizeof(line
), fp
))
970 if (!strncmp(line
, "%%Page:", 7))
973 copy_page
= page
>= first_page
&& page
<= last_page
;
987 dsc_trailer(num_pages
);
989 fprintf(stderr
, "ATTR: job-impressions=%d\n", num_pages
/ copies
);
999 * 'raster_to_ps()' - Convert PWG Raster/Apple Raster to PostScript.
1001 * The current implementation locally-decodes the raster data and then writes
1002 * whole, non-blank lines as 1-line high images with base-85 encoding, resulting
1003 * in between 10 and 20 times larger output. A alternate implementation (if it
1004 * is deemed necessary) would be to implement a PostScript decode procedure that
1005 * handles the modified packbits decompression so that we just have the base-85
1006 * encoding overhead (25%). Furthermore, Level 3 PostScript printers also
1007 * support Flate compression.
1009 * That said, the most efficient path with the highest quality is for Clients
1010 * to supply PDF files and us to use the existing PDF to PostScript conversion
1014 static int /* O - Exit status */
1015 raster_to_ps(const char *filename
) /* I - Filename */
1017 int fd
; /* Input file */
1018 cups_raster_t
*ras
; /* Raster stream */
1019 cups_page_header2_t header
; /* Page header */
1020 int page
= 0; /* Current page */
1021 unsigned y
; /* Current line */
1022 unsigned char *line
; /* Line buffer */
1023 unsigned char white
; /* White color */
1024 const char *decode
; /* Image decode array */
1028 * Open the input file...
1033 if ((fd
= open(filename
, O_RDONLY
)) < 0)
1035 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
1045 * Open the raster stream and send pages...
1048 if ((ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
)) == NULL
)
1050 fputs("ERROR: Unable to read raster data, aborting.\n", stderr
);
1056 while (cupsRasterReadHeader2(ras
, &header
))
1060 fprintf(stderr
, "DEBUG: Page %d: %ux%ux%u\n", page
, header
.cupsWidth
, header
.cupsHeight
, header
.cupsBitsPerPixel
);
1062 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
)
1064 fputs("ERROR: Unsupported color space, aborting.\n", stderr
);
1067 else if (header
.cupsBitsPerColor
!= 1 && header
.cupsBitsPerColor
!= 8)
1069 fputs("ERROR: Unsupported bit depth, aborting.\n", stderr
);
1073 line
= malloc(header
.cupsBytesPerLine
);
1078 printf("%.6f %.6f scale\n", 72.0f
/ header
.HWResolution
[0], 72.0f
/ header
.HWResolution
[1]);
1080 switch (header
.cupsColorSpace
)
1082 case CUPS_CSPACE_W
:
1083 case CUPS_CSPACE_SW
:
1085 puts("/DeviceGray setcolorspace");
1089 case CUPS_CSPACE_K
:
1091 puts("/DeviceGray setcolorspace");
1096 decode
= "0 1 0 1 0 1";
1097 puts("/DeviceRGB setcolorspace");
1102 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
);
1104 for (y
= header
.cupsHeight
; y
> 0; y
--)
1106 if (cupsRasterReadPixels(ras
, line
, header
.cupsBytesPerLine
))
1108 if (line
[0] != white
|| memcmp(line
, line
+ 1, header
.cupsBytesPerLine
- 1))
1110 printf("%d L\n", y
- 1);
1111 ascii85(line
, (int)header
.cupsBytesPerLine
, 1);
1118 fprintf(stderr
, "DEBUG: y=%d at end...\n", y
);
1120 puts("grestore grestore");
1126 cupsRasterClose(ras
);
1130 fprintf(stderr
, "ATTR: job-impressions=%d\n", page
);