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 /* TODO: Fix me - values are names, not numbers... Also need to support finishings-col */
424 if ((value
= getenv("IPP_FINISHINGS")) == NULL
)
425 value
= getenv("IPP_FINISHINGS_DEFAULT");
429 char *ptr
; /* Pointer into value */
430 int fin
; /* Current value */
432 for (fin
= strtol(value
, &ptr
, 10); fin
> 0; fin
= strtol(ptr
+ 1, &ptr
, 10))
434 num_options
= _ppdCacheGetFinishingOptions(ppd_cache
, NULL
, (ipp_finishings_t
)fin
, num_options
, options
);
441 if ((value
= cupsGetOption("media-source", num_media_col
, media_col
)) != NULL
)
443 if ((choice
= _ppdCacheGetInputSlot(ppd_cache
, NULL
, value
)) != NULL
)
444 num_options
= cupsAddOption("InputSlot", choice
, num_options
, options
);
447 if ((value
= cupsGetOption("media-type", num_media_col
, media_col
)) != NULL
)
449 if ((choice
= _ppdCacheGetMediaType(ppd_cache
, NULL
, value
)) != NULL
)
450 num_options
= cupsAddOption("MediaType", choice
, num_options
, options
);
453 if ((value
= getenv("IPP_OUTPUT_BIN")) == NULL
)
454 value
= getenv("IPP_OUTPUT_BIN_DEFAULT");
458 if ((choice
= _ppdCacheGetOutputBin(ppd_cache
, value
)) != NULL
)
459 num_options
= cupsAddOption("OutputBin", choice
, num_options
, options
);
462 if ((value
= getenv("IPP_SIDES")) == NULL
)
463 value
= getenv("IPP_SIDES_DEFAULT");
465 if (value
&& ppd_cache
->sides_option
)
467 if (!strcmp(value
, "one-sided") && ppd_cache
->sides_1sided
)
468 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_1sided
, num_options
, options
);
469 else if (!strcmp(value
, "two-sided-long-edge") && ppd_cache
->sides_2sided_long
)
470 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_2sided_long
, num_options
, options
);
471 else if (!strcmp(value
, "two-sided-short-edge") && ppd_cache
->sides_2sided_short
)
472 num_options
= cupsAddOption(ppd_cache
->sides_option
, ppd_cache
->sides_2sided_short
, num_options
, options
);
475 if ((value
= getenv("IPP_PRINT_QUALITY")) == NULL
)
476 value
= getenv("IPP_PRINT_QUALITY_DEFAULT");
480 int i
; /* Looping var */
481 int pq
; /* Print quality (0-2) */
482 int pcm
= 1; /* Print color model (0 = mono, 1 = color) */
483 int num_presets
; /* Number of presets */
484 cups_option_t
*presets
; /* Presets */
486 if (!strcmp(value
, "draft"))
488 else if (!strcmp(value
, "high"))
493 if ((value
= getenv("IPP_PRINT_COLOR_MODE")) == NULL
)
494 value
= getenv("IPP_PRINT_COLOR_MODE_DEFAULT");
496 if (value
&& !strcmp(value
, "monochrome"))
499 num_presets
= ppd_cache
->num_presets
[pcm
][pq
];
500 presets
= ppd_cache
->presets
[pcm
][pq
];
502 for (i
= 0; i
< num_presets
; i
++)
503 num_options
= cupsAddOption(presets
[i
].name
, presets
[i
].value
, num_options
, options
);
507 * Mark the PPD with the options...
510 ppdMarkDefaults(ppd
);
511 cupsMarkOptions(ppd
, num_options
, *options
);
513 #endif /* !CUPS_LITE */
515 cupsFreeOptions(num_media_col
, media_col
);
517 return (num_options
);
522 * 'jpeg_to_ps()' - Convert a JPEG file to PostScript.
525 static int /* O - Exit status */
526 jpeg_to_ps(const char *filename
, /* I - Filename */
527 int copies
) /* I - Number of copies */
529 int fd
; /* JPEG file descriptor */
530 int copy
; /* Current copy */
531 int width
= 0, /* Width */
532 height
= 0, /* Height */
533 depth
= 0, /* Number of colors */
534 length
; /* Length of marker */
535 unsigned char buffer
[65536], /* Copy buffer */
536 *bufptr
, /* Pointer info buffer */
537 *bufend
; /* End of buffer */
538 ssize_t bytes
; /* Bytes in buffer */
539 const char *decode
; /* Decode array */
540 float page_left
, /* Left margin */
541 page_top
, /* Top margin */
542 page_width
, /* Page width in points */
543 page_height
, /* Page heigth in points */
544 x_factor
, /* X image scaling factor */
545 y_factor
, /* Y image scaling factor */
546 page_scaling
; /* Image scaling factor */
548 ppd_size_t
*page_size
; /* Current page size */
549 #endif /* !CUPS_LITE */
553 * Open the input file...
558 if ((fd
= open(filename
, O_RDONLY
)) < 0)
560 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
571 * Read the JPEG dimensions...
574 bytes
= read(fd
, buffer
, sizeof(buffer
));
576 if (bytes
< 3 || memcmp(buffer
, "\377\330\377", 3))
578 fputs("ERROR: Not a JPEG image.\n", stderr
);
586 for (bufptr
= buffer
+ 2, bufend
= buffer
+ bytes
; bufptr
< bufend
;)
589 * Scan the file for a SOFn marker, then we can get the dimensions...
596 if (bufptr
>= bufend
)
599 * If we are at the end of the current buffer, re-fill and continue...
602 if ((bytes
= read(fd
, buffer
, sizeof(buffer
))) <= 0)
606 bufend
= buffer
+ bytes
;
612 if ((bufptr
+ 16) >= bufend
)
615 * Read more of the marker...
618 bytes
= bufend
- bufptr
;
620 memmove(buffer
, bufptr
, (size_t)bytes
);
622 bufend
= buffer
+ bytes
;
624 if ((bytes
= read(fd
, bufend
, sizeof(buffer
) - (size_t)bytes
)) <= 0)
630 length
= (size_t)((bufptr
[1] << 8) | bufptr
[2]);
632 if ((*bufptr
>= 0xc0 && *bufptr
<= 0xc3) || (*bufptr
>= 0xc5 && *bufptr
<= 0xc7) || (*bufptr
>= 0xc9 && *bufptr
<= 0xcb) || (*bufptr
>= 0xcd && *bufptr
<= 0xcf))
635 * SOFn marker, look for dimensions...
638 width
= (bufptr
[6] << 8) | bufptr
[7];
639 height
= (bufptr
[4] << 8) | bufptr
[5];
645 * Skip past this marker...
649 bytes
= bufend
- bufptr
;
651 while (length
>= bytes
)
655 if ((bytes
= read(fd
, buffer
, sizeof(buffer
))) <= 0)
659 bufend
= buffer
+ bytes
;
669 fprintf(stderr
, "DEBUG: JPEG dimensions are %dx%dx%d\n", width
, height
, depth
);
671 if (width
<= 0 || height
<= 0 || depth
<= 0)
673 fputs("ERROR: No valid image data in JPEG file.\n", stderr
);
681 fputs("ATTR: job-impressions=1\n", stderr
);
684 * Figure out the dimensions/scaling of the final image...
691 page_height
= 720.0f
;
694 if ((page_size
= ppdPageSize(ppd
, NULL
)) != NULL
)
696 page_left
= page_size
->left
;
697 page_top
= page_size
->top
;
698 page_width
= page_size
->right
- page_left
;
699 page_height
= page_top
- page_size
->bottom
;
706 page_height
= 720.0f
;
708 #endif /* CUPS_LITE */
710 fprintf(stderr
, "DEBUG: page_left=%.2f, page_top=%.2f, page_width=%.2f, page_height=%.2f\n", page_left
, page_top
, page_width
, page_height
);
712 /* TODO: Support orientation/rotation, different print-scaling modes */
713 x_factor
= page_width
/ width
;
714 y_factor
= page_height
/ height
;
716 if (x_factor
> y_factor
&& (height
* x_factor
) <= page_height
)
717 page_scaling
= x_factor
;
719 page_scaling
= y_factor
;
721 fprintf(stderr
, "DEBUG: Scaled dimensions are %.2fx%.2f\n", width
* page_scaling
, height
* page_scaling
);
729 for (copy
= 1; copy
<= copies
; copy
++)
735 puts("/DeviceGray setcolorspace");
740 puts("/DeviceRGB setcolorspace");
741 decode
= "0 1 0 1 0 1";
745 puts("/DeviceCMYK setcolorspace");
746 decode
= "0 1 0 1 0 1 0 1";
749 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
);
750 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
);
753 lseek(fd
, 0, SEEK_SET
);
755 while ((bytes
= read(fd
, buffer
, sizeof(buffer
))) > 0)
756 ascii85(buffer
, (int)bytes
, 0);
758 ascii85(buffer
, 0, 1);
760 puts("grestore showpage");
770 * 'pdf_to_ps()' - Convert a PDF file to PostScript.
773 static int /* O - Exit status */
774 pdf_to_ps(const char *filename
, /* I - Filename */
775 int copies
, /* I - Number of copies */
776 int num_options
, /* I - Number of options */
777 cups_option_t
*options
) /* I - options */
779 int status
; /* Exit status */
780 char tempfile
[1024]; /* Temporary file */
781 int tempfd
; /* Temporary file descriptor */
782 int pid
; /* Process ID */
783 const char *pdf_argv
[8]; /* Command-line arguments */
784 char pdf_options
[1024]; /* Options */
785 const char *value
; /* Option value */
786 const char *job_id
, /* job-id value */
787 *job_name
; /* job-name value */
791 * Create a temporary file for the PostScript version...
794 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
796 fprintf(stderr
, "ERROR: Unable to create temporary file: %s\n", strerror(errno
));
801 * Run cgpdftops or pdftops in the filter directory...
804 if ((value
= cupsGetOption("PageSize", num_options
, options
)) != NULL
)
805 snprintf(pdf_options
, sizeof(pdf_options
), "PageSize=%s", value
);
807 pdf_options
[0] = '\0';
809 if ((job_id
= getenv("IPP_JOB_ID")) == NULL
)
811 if ((job_name
= getenv("IPP_JOB_NAME")) == NULL
)
812 job_name
= "untitled";
814 pdf_argv
[0] = "printer";
815 pdf_argv
[1] = job_id
;
816 pdf_argv
[2] = cupsUser();
817 pdf_argv
[3] = job_name
;
819 pdf_argv
[5] = pdf_options
;
820 pdf_argv
[6] = filename
;
823 if ((pid
= fork()) == 0)
826 * Child comes here...
833 execv(PDFTOPS
, (char * const *)pdf_argv
);
839 * Unable to fork process...
842 perror("ERROR: Unable to start PDF filter");
852 * Wait for the filter to complete...
858 while (waitpid(pid
, &status
, 0) < 0);
860 while (wait(&status
) < 0);
861 # endif /* HAVE_WAITPID */
865 if (WIFEXITED(status
))
866 fprintf(stderr
, "ERROR: " PDFTOPS
" exited with status %d.\n", WEXITSTATUS(status
));
868 fprintf(stderr
, "ERROR: " PDFTOPS
" terminated with signal %d.\n", WTERMSIG(status
));
876 * Copy the PostScript output from the command...
879 status
= ps_to_ps(tempfile
, copies
);
888 * 'ps_to_ps()' - Copy PostScript to the standard output.
891 static int /* O - Exit status */
892 ps_to_ps(const char *filename
, /* I - Filename */
893 int copies
) /* I - Number of copies */
895 FILE *fp
; /* File to read from */
896 int copy
, /* Current copy */
897 page
, /* Current page number */
898 num_pages
= 0, /* Total number of pages */
899 first_page
, /* First page */
900 last_page
; /* Last page */
901 const char *page_ranges
; /* page-ranges option */
902 long first_pos
= -1; /* Offset for first page */
903 char line
[1024]; /* Line from file */
907 * Open the print file...
912 if ((fp
= fopen(filename
, "rb")) == NULL
)
914 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
925 * Check page ranges...
928 if ((page_ranges
= getenv("IPP_PAGE_RANGES")) != NULL
)
930 if (sscanf(page_ranges
, "%d-%d", &first_page
, &last_page
) != 2)
943 * Write the PostScript header for the document...
950 while (fgets(line
, sizeof(line
), fp
))
952 if (!strncmp(line
, "%%Page:", 7))
955 first_pos
= ftell(fp
);
961 if (!strncmp(line
, "%%Page:", 7))
963 for (copy
= 0; copy
< copies
; copy
++)
965 int copy_page
= 0; /* Do we copy the page data? */
968 fseek(fp
, first_pos
, SEEK_SET
);
971 while (fgets(line
, sizeof(line
), fp
))
973 if (!strncmp(line
, "%%Page:", 7))
976 copy_page
= page
>= first_page
&& page
<= last_page
;
990 dsc_trailer(num_pages
);
992 fprintf(stderr
, "ATTR: job-impressions=%d\n", num_pages
/ copies
);
1002 * 'raster_to_ps()' - Convert PWG Raster/Apple Raster to PostScript.
1004 * The current implementation locally-decodes the raster data and then writes
1005 * whole, non-blank lines as 1-line high images with base-85 encoding, resulting
1006 * in between 10 and 20 times larger output. A alternate implementation (if it
1007 * is deemed necessary) would be to implement a PostScript decode procedure that
1008 * handles the modified packbits decompression so that we just have the base-85
1009 * encoding overhead (25%). Furthermore, Level 3 PostScript printers also
1010 * support Flate compression.
1012 * That said, the most efficient path with the highest quality is for Clients
1013 * to supply PDF files and us to use the existing PDF to PostScript conversion
1017 static int /* O - Exit status */
1018 raster_to_ps(const char *filename
) /* I - Filename */
1020 int fd
; /* Input file */
1021 cups_raster_t
*ras
; /* Raster stream */
1022 cups_page_header2_t header
; /* Page header */
1023 int page
= 0; /* Current page */
1024 unsigned y
; /* Current line */
1025 unsigned char *line
; /* Line buffer */
1026 unsigned char white
; /* White color */
1027 const char *decode
; /* Image decode array */
1031 * Open the input file...
1036 if ((fd
= open(filename
, O_RDONLY
)) < 0)
1038 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", filename
, strerror(errno
));
1048 * Open the raster stream and send pages...
1051 if ((ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
)) == NULL
)
1053 fputs("ERROR: Unable to read raster data, aborting.\n", stderr
);
1059 while (cupsRasterReadHeader2(ras
, &header
))
1063 fprintf(stderr
, "DEBUG: Page %d: %ux%ux%u\n", page
, header
.cupsWidth
, header
.cupsHeight
, header
.cupsBitsPerPixel
);
1065 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
)
1067 fputs("ERROR: Unsupported color space, aborting.\n", stderr
);
1070 else if (header
.cupsBitsPerColor
!= 1 && header
.cupsBitsPerColor
!= 8)
1072 fputs("ERROR: Unsupported bit depth, aborting.\n", stderr
);
1076 line
= malloc(header
.cupsBytesPerLine
);
1081 printf("%.6f %.6f scale\n", 72.0f
/ header
.HWResolution
[0], 72.0f
/ header
.HWResolution
[1]);
1083 switch (header
.cupsColorSpace
)
1085 case CUPS_CSPACE_W
:
1086 case CUPS_CSPACE_SW
:
1088 puts("/DeviceGray setcolorspace");
1092 case CUPS_CSPACE_K
:
1094 puts("/DeviceGray setcolorspace");
1099 decode
= "0 1 0 1 0 1";
1100 puts("/DeviceRGB setcolorspace");
1105 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
);
1107 for (y
= header
.cupsHeight
; y
> 0; y
--)
1109 if (cupsRasterReadPixels(ras
, line
, header
.cupsBytesPerLine
))
1111 if (line
[0] != white
|| memcmp(line
, line
+ 1, header
.cupsBytesPerLine
- 1))
1113 printf("%d L\n", y
- 1);
1114 ascii85(line
, (int)header
.cupsBytesPerLine
, 1);
1121 fprintf(stderr
, "DEBUG: y=%d at end...\n", y
);
1123 puts("grestore grestore");
1129 cupsRasterClose(ras
);
1133 fprintf(stderr
, "ATTR: job-impressions=%d\n", page
);