1 /*
2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * @brief Convert PWG Raster to a PostScript file
16 * @file rastertops.c
17 * @author Pranjal Bhor <bhor.pranjal@gmail.com> (C) 2016
18 * @author Neil 'Superna' Armstrong <superna9999@gmail.com> (C) 2010
19 * @author Tobias Hoffmann <smilingthax@gmail.com> (c) 2012
20 * @author Till Kamppeter <till.kamppeter@gmail.com> (c) 2014
21 */
22
23 #include <config.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <math.h>
34 #include <signal.h>
35 #include <cups/cups.h>
36 #include <cups/raster.h>
37 #include <cupsfilters/colormanager.h>
38 #include <cupsfilters/image.h>
39 #include <assert.h>
40 #include <zlib.h>
41
42 /*
43 * 'write_prolog()' - Writing the PostScript prolog for the file
44 */
45
46 void
writeProlog(int width,int height)47 writeProlog(int width, /* I - width of the image in points */
48 int height) /* I - height of the image in points */
49 {
50 /* Document header... */
51 printf("%%!PS-Adobe-3.0\n");
52 printf("%%%%BoundingBox: %d %d %d %d\n", 0, 0, width, height);
53 printf("%%%%Creator: cups-filters\n");
54 printf("%%%%LanguageLevel: 2\n");
55 printf("%%%%DocumentData: Clean7Bit\n");
56 printf("%%%%Pages: (atend)\n");
57 printf("%%%%EndComments\n");
58 printf("%%%%BeginProlog\n");
59 printf("%%%%EndProlog\n");
60 }
61
62 /*
63 * 'writeStartPage()' - Write the basic page setup
64 */
65
66 void
writeStartPage(int page,int width,int length)67 writeStartPage(int page, /* I - Page to write */
68 int width, /* I - Page width in points */
69 int length) /* I - Page length in points */
70 {
71 printf("%%%%Page: %d %d\n", page, page);
72 printf("%%%%BeginPageSetup\n");
73 printf("<< /PageSize[%d %d] >> setpagedevice\n", width, length);
74 printf("%%%%EndPageSetup\n");
75 }
76
77 /*
78 * 'find_bits()' - Finding the number of bits per color
79 */
80
81 int /* O - Exit status */
find_bits(cups_cspace_t mode,int bpc)82 find_bits(cups_cspace_t mode, /* I - Color space of data */
83 int bpc) /* I - Original bits per color of data */
84 {
85 if (bpc == 1 &&
86 (mode == CUPS_CSPACE_RGB ||
87 mode == CUPS_CSPACE_ADOBERGB ||
88 mode == CUPS_CSPACE_SRGB ||
89 mode == CUPS_CSPACE_CMY))
90 return 8;
91
92 if (bpc == 16)
93 return 8;
94
95 return bpc;
96 }
97
98 /*
99 * 'writeImage()' - Write the information regarding the image
100 */
101
102 void /* O - Exit status */
writeImage(int pagewidth,int pageheight,int bpc,int pixwidth,int pixheight,cups_cspace_t mode)103 writeImage(int pagewidth, /* I - width of page in points */
104 int pageheight, /* I - height of page in points */
105 int bpc, /* I - bits per color */
106 int pixwidth, /* I - width of image in pixels */
107 int pixheight, /* I - height of image in pixels */
108 cups_cspace_t mode) /* I - color model of image */
109 {
110 printf("gsave\n");
111
112 switch (mode)
113 {
114 case CUPS_CSPACE_RGB:
115 case CUPS_CSPACE_CMY:
116 case CUPS_CSPACE_SRGB:
117 case CUPS_CSPACE_ADOBERGB:
118 printf("/DeviceRGB setcolorspace\n");
119 break;
120
121 case CUPS_CSPACE_CMYK:
122 printf("/DeviceCMYK setcolorspace\n");
123 break;
124
125 default:
126 case CUPS_CSPACE_K:
127 case CUPS_CSPACE_W:
128 case CUPS_CSPACE_SW:
129 printf("/DeviceGray setcolorspace\n");
130 break;
131 }
132
133 if (bpc == 16)
134 printf("/Input currentfile /FlateDecode filter def\n");
135 printf("%d %d scale\n", pagewidth, pageheight);
136 printf("<< \n"
137 "/ImageType 1\n"
138 "/Width %d\n"
139 "/Height %d\n"
140 "/BitsPerComponent %d\n", pixwidth, pixheight, find_bits(mode, bpc));
141
142 switch (mode)
143 {
144 case CUPS_CSPACE_RGB:
145 case CUPS_CSPACE_CMY:
146 case CUPS_CSPACE_SRGB:
147 case CUPS_CSPACE_ADOBERGB:
148 printf("/Decode [0 1 0 1 0 1]\n");
149 break;
150
151 case CUPS_CSPACE_CMYK:
152 printf("/Decode [0 1 0 1 0 1 0 1]\n");
153 break;
154
155 case CUPS_CSPACE_SW:
156 printf("/Decode [0 1]\n");
157 break;
158
159 default:
160 case CUPS_CSPACE_K:
161 case CUPS_CSPACE_W:
162 printf("/Decode [1 0]\n");
163 break;
164 }
165
166 if(bpc==16)
167 printf("/DataSource {3 string 0 1 2 {1 index exch Input read {pop}"
168 "if Input read pop put } for} bind\n");
169 else
170 printf("/DataSource currentfile /FlateDecode filter\n");
171
172 printf("/ImageMatrix [%d 0 0 %d 0 %d]\n", pixwidth, -1*pixheight, pixheight);
173 printf(">> image\n");
174 }
175
176 /*
177 * 'convert_pixels()'- Convert 1 bpc to 8 bpc
178 */
179
180 void
convert_pixels(unsigned char * pixdata,unsigned char * convertedpix,int width)181 convert_pixels(unsigned char *pixdata, /* I - Original pixel data */
182 unsigned char *convertedpix, /* I - Buffer for converted data */
183 int width) /* I - Width of data */
184 {
185 int j, k = 0; /* Variables for iteration */
186 unsigned int mask; /* Variable for per byte iteration */
187 unsigned char temp; /* temporary character */
188
189 for(j = 0; j < width; ++j)
190 {
191 temp = *(pixdata + j);
192 for (mask = 0x80; mask != 0; mask >>= 1)
193 {
194 if (mask!=0x80 && mask != 0x08)
195 {
196 if (temp & mask)
197 convertedpix[k] = 0xFF;
198 else
199 convertedpix[k] = 0;
200 ++k;
201 }
202 }
203 }
204 }
205
206 /*
207 * 'write_flate()' - Write the image data in flate encoded format
208 */
209
210 int /* O - Error value */
write_flate(cups_raster_t * ras,cups_page_header2_t header)211 write_flate(cups_raster_t *ras, /* I - Image data */
212 cups_page_header2_t header) /* I - Bytes Per Line */
213 {
214 int ret, /* Return value of this
215 function */
216 flush, /* Check the end of image
217 data */
218 curr_line=1, /* Maitining the working
219 line of pixels */
220 alloc,
221 flag = 0;
222 unsigned have; /* Bytes available in
223 output buffer */
224 z_stream strm; /* Structure required
225 by deflate */
226 unsigned char *pixdata,
227 *convertedpix;
228 unsigned char in[header.cupsBytesPerLine * 6], /* Input data buffer */
229 out[header.cupsBytesPerLine * 6]; /* Output data buffer */
230
231 /* allocate deflate state */
232 strm.zalloc = Z_NULL;
233 strm.zfree = Z_NULL;
234 strm.opaque = Z_NULL;
235 ret = deflateInit(&strm, -1);
236 if (ret != Z_OK)
237 return ret;
238
239 if(header.cupsBitsPerColor == 1 &&
240 (header.cupsColorSpace == CUPS_CSPACE_RGB ||
241 header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ||
242 header.cupsColorSpace == CUPS_CSPACE_SRGB))
243 flag = 1;
244
245 /* compress until end of file */
246 do {
247 pixdata = malloc(header.cupsBytesPerLine);
248 cupsRasterReadPixels(ras, pixdata, header.cupsBytesPerLine);
249 if (flag)
250 {
251 convertedpix = malloc(header.cupsBytesPerLine * 6);
252 convert_pixels(pixdata,convertedpix, header.cupsBytesPerLine);
253 alloc = header.cupsBytesPerLine * 6;
254 }
255 else
256 {
257 convertedpix = malloc(header.cupsBytesPerLine);
258 memcpy(convertedpix, pixdata, header.cupsBytesPerLine);
259 alloc = header.cupsBytesPerLine;
260 }
261
262 if(curr_line == header.cupsHeight)
263 flush = Z_FINISH;
264 else
265 flush = Z_NO_FLUSH;
266 curr_line++;
267 memcpy(in, convertedpix, alloc);
268 strm.avail_in = alloc;
269 strm.next_in = in;
270
271 /* run deflate() on input until output buffer not full, finish
272 * compression if all of source has been read in */
273 do {
274 strm.avail_out = alloc;
275 strm.next_out = out;
276
277 /* Run the deflate algorithm on the data */
278 ret = deflate(&strm, flush);
279
280 /* check whether state is not clobbered */
281 assert(ret != Z_STREAM_ERROR);
282 have = alloc - strm.avail_out;
283 if (fwrite(out, 1, have, stdout) != have)
284 {
285 (void)deflateEnd(&strm);
286 if (convertedpix != NULL)
287 free(convertedpix);
288 return Z_ERRNO;
289 }
290 } while (strm.avail_out == 0);
291
292 /* all input will be used */
293 assert(strm.avail_in == 0);
294
295 /* done when last data in file processed */
296 free(pixdata);
297 free(convertedpix);
298 } while (flush != Z_FINISH);
299
300 /* stream will be complete */
301 assert(ret == Z_STREAM_END);
302
303 /* clean up and return */
304 (void)deflateEnd(&strm);
305 return Z_OK;
306 }
307
308 /*
309 * Report a zlib or i/o error
310 */
311
312 void
zerr(int ret)313 zerr(int ret) /* I - Return status of deflate */
314 {
315 fputs("zpipe: ", stderr);
316 switch (ret) {
317 case Z_ERRNO:
318 fputs("error in source data or output file\n", stderr);
319 break;
320 case Z_STREAM_ERROR:
321 fputs("invalid compression level\n", stderr);
322 break;
323 case Z_DATA_ERROR:
324 fputs("invalid or incomplete deflate data\n", stderr);
325 break;
326 case Z_MEM_ERROR:
327 fputs("out of memory\n", stderr);
328 break;
329 case Z_VERSION_ERROR:
330 fputs("zlib version mismatch!\n", stderr);
331 }
332 }
333
334 /*
335 * 'writeEndPage()' - Show the current page.
336 */
337
338 void
writeEndPage()339 writeEndPage()
340 {
341 printf("\ngrestore\n");
342 printf("showpage\n");
343 printf("%%%%PageTrailer\n");
344 }
345
346 /*
347 * 'writeTrailer()' - Write the PostScript trailer.
348 */
349
350 void
writeTrailer(int pages)351 writeTrailer(int pages) /* I - Number of pages */
352 {
353 printf("%%%%Trailer\n");
354 printf("%%%%Pages: %d\n", pages);
355 printf("%%%%EOF\n");
356 }
357
358 /*
359 * 'main()' - Main entry and processing of driver.
360 */
361
362 int /* O - Exit status */
main(int argc,char * argv[])363 main(int argc, /* I - Number of command-line arguments */
364 char *argv[]) /* I - Command-line arguments */
365 {
366 FILE *input = NULL; /* File pointer to raster document */
367 int fd, /* File descriptor for raster document */
368 num_options, /* Number of options */
369 Canceled = 0, /* variable for job cancellation */
370 empty, /* Is the input empty? */
371 Page = 0, /* variable for counting the pages */
372 ret; /* Return value of deflate compression */
373 ppd_file_t *ppd; /* PPD file */
374 cups_raster_t *ras; /* Raster stream for printing */
375 cups_page_header2_t header; /* Page header from file */
376 cups_option_t *options; /* Options */
377
378 /*
379 * Make sure status messages are not buffered...
380 */
381 setbuf(stderr, NULL);
382
383 /*
384 * Check command-line...
385 */
386 if (argc < 6 || argc > 7)
387 {
388 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
389 "rastertops");
390 return (1);
391 }
392
393 num_options = cupsParseOptions(argv[5], 0, &options);
394
395 /*
396 * Open the PPD file...
397 */
398 ppd = ppdOpenFile(getenv("PPD"));
399
400 if (ppd)
401 {
402 ppdMarkDefaults(ppd);
403 cupsMarkOptions(ppd, num_options, options);
404 }
405 else
406 {
407 ppd_status_t status; /* PPD error */
408 int linenum; /* Line number */
409
410 fprintf(stderr, "DEBUG: The PPD file could not be opened.\n");
411 status = ppdLastError(&linenum);
412 fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
413 }
414
415 /*
416 * Open the page stream...
417 */
418 if (argc == 7)
419 {
420 input = fopen(argv[6], "rb");
421 if (input == NULL) {
422 fprintf(stderr, "Unable to open PWG Raster file\n");
423 exit(1);
424 }
425 }
426 else
427 input = stdin;
428
429 /*
430 * Get fd from file
431 */
432 fd = fileno(input);
433
434 /*
435 * Transform
436 */
437 ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
438
439 /*
440 * Register a signal handler to eject the current page if the
441 * job is cancelled.
442 */
443 Canceled = 0;
444
445
446 /*
447 * Process pages as needed...
448 */
449 Page = 0;
450 empty = 1;
451
452 while (cupsRasterReadHeader2(ras, &header))
453 {
454 /*
455 * Write the prolog for PS only once
456 */
457 if (empty)
458 {
459 empty = 0;
460 writeProlog(header.PageSize[0], header.PageSize[1]);
461 }
462
463 /*
464 * Write a status message with the page number and number of copies.
465 */
466 if (Canceled)
467 break;
468
469 Page ++;
470
471 fprintf(stderr, "INFO: Starting page %d.\n", Page);
472
473 /*
474 * Write the starting of the page
475 */
476 writeStartPage(Page, header.PageSize[0], header.PageSize[1]);
477
478 /*
479 * write the information regarding the image
480 */
481 writeImage(header.PageSize[0], header.PageSize[1],
482 header.cupsBitsPerColor,
483 header.cupsWidth, header.cupsHeight,
484 header.cupsColorSpace);
485
486 /* Write the compressed image data*/
487 ret = write_flate(ras, header);
488 if (ret != Z_OK)
489 zerr(ret);
490 writeEndPage();
491 }
492
493 if (empty)
494 {
495 fprintf(stderr, "DEBUG: Input is empty, outputting empty file.\n");
496 cupsRasterClose(ras);
497 return 0;
498 }
499
500 writeTrailer(Page);
501
502 cupsRasterClose(ras);
503
504 return 0;
505 }
506