1 /*
2  * "$Id: image-sun.c 7223 2008-01-16 23:41:19Z mike $"
3  *
4  *   Sun Raster image file routines for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 2007-2008 by Apple Inc.
7  *   Copyright 1993-2007 by Easy Software Products.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Apple Inc. and are protected by Federal copyright
11  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  *   which should have been included with this file.  If this file is
13  *   file is missing or damaged, see the license at "http://www.cups.org/".
14  *
15  *   This file is subject to the Apple OS-Developed Software exception.
16  *
17  * Contents:
18  *
19  *   _cupsImageReadSunRaster() - Read a SunRaster image file.
20  *   read_unsigned()      - Read a 32-bit unsigned integer.
21  */
22 
23 /*
24  * Include necessary headers...
25  */
26 
27 #include "image-private.h"
28 
29 
30 #define	RAS_MAGIC	0x59a66a95
31 
32 	/* Sun supported ras_type's */
33 #define RT_OLD		0		/* Raw pixrect image in 68000 byte order */
34 #define RT_STANDARD	1		/* Raw pixrect image in 68000 byte order */
35 #define RT_BYTE_ENCODED	2		/* Run-length compression of bytes */
36 #define RT_FORMAT_RGB	3		/* XRGB or RGB instead of XBGR or BGR */
37 #define RT_EXPERIMENTAL	0xffff		/* Reserved for testing */
38 
39 	/* Sun registered ras_maptype's */
40 #define RMT_RAW		2
41 	/* Sun supported ras_maptype's */
42 #define RMT_NONE	0		/* ras_maplength is expected to be 0 */
43 #define RMT_EQUAL_RGB	1		/* red[ras_maplength/3],green[],blue[] */
44 
45 #define RAS_RLE 0x80
46 
47 /*
48  * NOTES:
49  * 	Each line of the image is rounded out to a multiple of 16 bits.
50  *   This corresponds to the rounding convention used by the memory pixrect
51  *   package (/usr/include/pixrect/memvar.h) of the SunWindows system.
52  *	The ras_encoding field (always set to 0 by Sun's supported software)
53  *   was renamed to ras_length in release 2.0.  As a result, rasterfiles
54  *   of type 0 generated by the old software claim to have 0 length; for
55  *   compatibility, code reading rasterfiles must be prepared to compute the
56  *   true length from the width, height, and depth fields.
57  */
58 
59 /*
60  * Local functions...
61  */
62 
63 static unsigned	read_unsigned(FILE *fp);
64 
65 
66 /*
67  * '_cupsImageReadSunRaster()' - Read a SunRaster image file.
68  */
69 
70 int					/* O - Read status */
_cupsImageReadSunRaster(cups_image_t * img,FILE * fp,cups_icspace_t primary,cups_icspace_t secondary,int saturation,int hue,const cups_ib_t * lut)71 _cupsImageReadSunRaster(
72     cups_image_t    *img,		/* IO - cupsImage */
73     FILE            *fp,		/* I - cupsImage file */
74     cups_icspace_t  primary,		/* I - Primary choice for colorspace */
75     cups_icspace_t  secondary,		/* I - Secondary choice for colorspace */
76     int             saturation,		/* I - Color saturation (%) */
77     int             hue,		/* I - Color hue (degrees) */
78     const cups_ib_t *lut)		/* I - Lookup table for gamma/brightness */
79 {
80   int		i, x, y,
81 		bpp,			/* Bytes per pixel */
82 		scanwidth,
83 		run_count,
84 		run_value;
85   cups_ib_t	*in,
86 		*out,
87 		*scanline,
88 		*scanptr,
89 		*p,
90 		bit;
91   unsigned	ras_depth,		/* depth (1, 8, or 24 bits) of pixel */
92 		ras_type,		/* type of file; see RT_* below */
93 		ras_maplength;		/* length (bytes) of following map */
94   unsigned char	cmap[3][256];		/* colormap */
95 
96 
97  /*
98   * Read the header; we already know that this is a raster file (cupsImageOpen
99   * checks this) so we don't need to check the magic number again.
100   */
101 
102   fputs("DEBUG: Reading Sun Raster image...\n", stderr);
103 
104   read_unsigned(fp); /* Skip magic */
105   img->xsize    = read_unsigned(fp);
106   img->ysize    = read_unsigned(fp);
107   ras_depth     = read_unsigned(fp);
108   /* ras_length */read_unsigned(fp);
109   ras_type      = read_unsigned(fp);
110   /* ras_maptype*/read_unsigned(fp);
111   ras_maplength = read_unsigned(fp);
112 
113   fprintf(stderr, "DEBUG: ras_width=%d, ras_height=%d, ras_depth=%d, ras_type=%d, ras_maplength=%d\n",
114           img->xsize, img->ysize, ras_depth, ras_type, ras_maplength);
115 
116   if (ras_maplength > 768 ||
117       img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH ||
118       img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT ||
119       ras_depth == 0 || ras_depth > 32)
120   {
121     fputs("DEBUG: Raster image cannot be loaded!\n", stderr);
122     return (1);
123   }
124 
125   if (ras_maplength > 0)
126   {
127     memset(cmap[0], 255, sizeof(cmap[0]));
128     memset(cmap[1], 0, sizeof(cmap[1]));
129     memset(cmap[2], 0, sizeof(cmap[2]));
130 
131     fread(cmap[0], 1, ras_maplength / 3, fp);
132     fread(cmap[1], 1, ras_maplength / 3, fp);
133     fread(cmap[2], 1, ras_maplength / 3, fp);
134   }
135 
136  /*
137   * Compute the width of each line and allocate memory as needed...
138   */
139 
140   scanwidth = (img->xsize * ras_depth + 7) / 8;
141   if (scanwidth & 1)
142     scanwidth ++;
143 
144   if (ras_depth < 24 && ras_maplength == 0)
145   {
146     img->colorspace = secondary;
147     in = malloc(img->xsize + 1);
148   }
149   else
150   {
151     img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
152     in = malloc(img->xsize * 3 + 1);
153   }
154 
155   if (!in)
156   {
157     fputs("DEBUG: Unable to allocate memory!\n", stderr);
158     fclose(fp);
159     return (1);
160   }
161 
162   bpp = cupsImageGetDepth(img);
163 
164   if ((out = malloc(img->xsize * bpp)) == NULL)
165   {
166     fputs("DEBUG: Unable to allocate memory!\n", stderr);
167     fclose(fp);
168     free(in);
169     return (1);
170   }
171 
172   if ((scanline = malloc(scanwidth)) == NULL)
173   {
174     fputs("DEBUG: Unable to allocate memory!\n", stderr);
175     fclose(fp);
176     free(in);
177     free(out);
178     return (1);
179   }
180 
181   run_count = 0;
182   run_value = 0;
183 
184   fprintf(stderr, "DEBUG: bpp=%d, scanwidth=%d\n", bpp, scanwidth);
185 
186   for (y = 0; y < img->ysize; y ++)
187   {
188     if ((ras_depth != 8 && ras_depth != 24) || ras_maplength > 0)
189       p = scanline;
190     else
191       p = in;
192 
193     if (ras_type != RT_BYTE_ENCODED)
194       fread(p, scanwidth, 1, fp);
195     else
196     {
197       for (i = scanwidth; i > 0; i --, p ++)
198       {
199         if (run_count > 0)
200         {
201           *p = run_value;
202           run_count --;
203         }
204         else
205         {
206           run_value = getc(fp);
207 
208           if (run_value == RAS_RLE)
209           {
210             run_count = getc(fp);
211             if (run_count == 0)
212               *p = RAS_RLE;
213             else
214               run_value = *p = getc(fp);
215           }
216           else
217             *p = run_value;
218         }
219       }
220     }
221 
222     if (ras_depth == 1 && ras_maplength == 0)
223     {
224      /*
225       * 1-bit B&W image...
226       */
227 
228       for (x = img->xsize, bit = 128, scanptr = scanline, p = in;
229            x > 0;
230            x --, p ++)
231       {
232 	if (*scanptr & bit)
233           *p = 255;
234         else
235           *p = 0;
236 
237 	if (bit > 1)
238           bit >>= 1;
239 	else
240 	{
241           bit = 128;
242           scanptr ++;
243 	}
244       }
245     }
246     else if (ras_depth == 1)
247     {
248      /*
249       * 1-bit colormapped image...
250       */
251 
252       for (x = img->xsize, bit = 128, scanptr = scanline, p = in;
253            x > 0;
254            x --)
255       {
256 	if (*scanptr & bit)
257 	{
258           *p++ = cmap[0][1];
259           *p++ = cmap[1][1];
260           *p++ = cmap[2][1];
261 	}
262         else
263 	{
264           *p++ = cmap[0][0];
265           *p++ = cmap[1][0];
266           *p++ = cmap[2][0];
267 	}
268 
269 	if (bit > 1)
270           bit >>= 1;
271 	else
272 	{
273           bit = 128;
274           scanptr ++;
275 	}
276       }
277     }
278     else if (ras_depth == 8 && ras_maplength > 0)
279     {
280      /*
281       * 8-bit colormapped image.
282       */
283 
284       for (x = img->xsize, scanptr = scanline, p = in;
285            x > 0;
286            x --)
287       {
288         *p++ = cmap[0][*scanptr];
289         *p++ = cmap[1][*scanptr];
290         *p++ = cmap[2][*scanptr++];
291       }
292     }
293     else if (ras_depth == 24 && ras_type != RT_FORMAT_RGB)
294     {
295      /*
296       * Convert BGR to RGB...
297       */
298 
299       for (x = img->xsize, scanptr = scanline, p = in;
300            x > 0;
301            x --, scanptr += 3)
302       {
303         *p++ = scanptr[2];
304         *p++ = scanptr[1];
305         *p++ = scanptr[0];
306       }
307     }
308 
309     if (ras_depth <= 8 && ras_maplength == 0)
310     {
311       if (img->colorspace == CUPS_IMAGE_WHITE)
312       {
313         if (lut)
314 	  cupsImageLut(in, img->xsize, lut);
315 
316         _cupsImagePutRow(img, 0, y, img->xsize, in);
317       }
318       else
319       {
320 	switch (img->colorspace)
321 	{
322 	  default :
323 	      break;
324 
325 	  case CUPS_IMAGE_RGB :
326 	      cupsImageWhiteToRGB(in, out, img->xsize);
327 	      break;
328 	  case CUPS_IMAGE_BLACK :
329 	      cupsImageWhiteToBlack(in, out, img->xsize);
330 	      break;
331 	  case CUPS_IMAGE_CMY :
332 	      cupsImageWhiteToCMY(in, out, img->xsize);
333 	      break;
334 	  case CUPS_IMAGE_CMYK :
335 	      cupsImageWhiteToCMYK(in, out, img->xsize);
336 	      break;
337 	}
338 
339         if (lut)
340 	  cupsImageLut(out, img->xsize * bpp, lut);
341 
342         _cupsImagePutRow(img, 0, y, img->xsize, out);
343       }
344     }
345     else
346     {
347       if ((saturation != 100 || hue != 0) && bpp > 1)
348 	cupsImageRGBAdjust(in, img->xsize, saturation, hue);
349 
350       switch (img->colorspace)
351       {
352 	default :
353 	    break;
354 
355 	case CUPS_IMAGE_WHITE :
356 	    cupsImageRGBToWhite(in, out, img->xsize);
357 	    break;
358 	case CUPS_IMAGE_BLACK :
359 	    cupsImageRGBToBlack(in, out, img->xsize);
360 	    break;
361 	case CUPS_IMAGE_CMY :
362 	    cupsImageRGBToCMY(in, out, img->xsize);
363 	    break;
364 	case CUPS_IMAGE_CMYK :
365 	    cupsImageRGBToCMYK(in, out, img->xsize);
366 	    break;
367       }
368 
369       if (lut)
370 	cupsImageLut(out, img->xsize * bpp, lut);
371 
372       _cupsImagePutRow(img, 0, y, img->xsize, out);
373     }
374   }
375 
376   free(scanline);
377   free(in);
378   free(out);
379 
380   fclose(fp);
381 
382   return (0);
383 }
384 
385 
386 /*
387  * 'read_unsigned()' - Read a 32-bit unsigned integer.
388  */
389 
390 static unsigned				/* O - Integer from file */
read_unsigned(FILE * fp)391 read_unsigned(FILE *fp)			/* I - File to read from */
392 {
393   unsigned	v;			/* Integer from file */
394 
395 
396   v = getc(fp);
397   v = (v << 8) | getc(fp);
398   v = (v << 8) | getc(fp);
399   v = (v << 8) | getc(fp);
400 
401   return (v);
402 }
403 
404 
405 /*
406  * End of "$Id: image-sun.c 7223 2008-01-16 23:41:19Z mike $".
407  */
408