• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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