1 /*
2 * PhotoCD routines for CUPS.
3 *
4 * PhotoCD support is currently limited to the 768x512 base image, which
5 * is only YCC encoded. Support for the higher resolution images will
6 * require a lot of extra code...
7 *
8 * Copyright 2007-2011 by Apple Inc.
9 * Copyright 1993-2006 by Easy Software Products.
10 *
11 * These coded instructions, statements, and computer programs are the
12 * property of Apple Inc. and are protected by Federal copyright
13 * law. Distribution and use rights are outlined in the file "COPYING"
14 * which should have been included with this file.
15 *
16 * Contents:
17 *
18 * _cupsImageReadPhotoCD() - Read a PhotoCD image file.
19 */
20
21 /*
22 * Include necessary headers...
23 */
24
25 #include "image-private.h"
26
27
28 /*
29 * '_cupsImageReadPhotoCD()' - Read a PhotoCD image file.
30 */
31
32 int /* O - Read status */
_cupsImageReadPhotoCD(cups_image_t * img,FILE * fp,cups_icspace_t primary,cups_icspace_t secondary,int saturation,int hue,const cups_ib_t * lut)33 _cupsImageReadPhotoCD(
34 cups_image_t *img, /* IO - cupsImage */
35 FILE *fp, /* I - cupsImage file */
36 cups_icspace_t primary, /* I - Primary choice for colorspace */
37 cups_icspace_t secondary, /* I - Secondary choice for colorspace */
38 int saturation, /* I - Color saturation (%) */
39 int hue, /* I - Color hue (degrees) */
40 const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
41 {
42 int x, y; /* Looping vars */
43 int xdir, /* X direction */
44 xstart; /* X starting point */
45 int bpp; /* Bytes per pixel */
46 int pass; /* Pass number */
47 int rotation; /* 0 for 768x512, 1 for 512x768 */
48 int temp, /* Adjusted luminance */
49 temp2, /* Red, green, and blue values */
50 cb, cr; /* Adjusted chroma values */
51 cups_ib_t *in, /* Input (YCC) pixels */
52 *iy, /* Luminance */
53 *icb, /* Blue chroma */
54 *icr, /* Red chroma */
55 *rgb, /* RGB */
56 *rgbptr, /* Pointer into RGB data */
57 *out; /* Output pixels */
58
59
60 (void)secondary;
61
62 /*
63 * Get the image orientation...
64 */
65
66 fseek(fp, 72, SEEK_SET);
67 rotation = (getc(fp) & 63) != 8;
68
69 /*
70 * Seek to the start of the base image...
71 */
72
73 fseek(fp, 0x30000, SEEK_SET);
74
75 /*
76 * Allocate and initialize...
77 */
78
79 img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
80 img->xppi = 200;
81 img->yppi = 200;
82
83 if (rotation)
84 {
85 img->xsize = 512;
86 img->ysize = 768;
87 }
88 else
89 {
90 img->xsize = 768;
91 img->ysize = 512;
92 }
93
94 cupsImageSetMaxTiles(img, 0);
95
96 bpp = cupsImageGetDepth(img);
97
98 if ((in = malloc(768 * 3)) == NULL)
99 {
100 fputs("DEBUG: Unable to allocate memory!\n", stderr);
101 fclose(fp);
102 return (1);
103 }
104
105 if ((out = malloc(768 * bpp)) == NULL)
106 {
107 fputs("DEBUG: Unable to allocate memory!\n", stderr);
108 fclose(fp);
109 free(in);
110 return (1);
111 }
112
113 if (bpp > 1)
114 {
115 if ((rgb = malloc(768 * 3)) == NULL)
116 {
117 fputs("DEBUG: Unable to allocate memory!\n", stderr);
118 fclose(fp);
119 free(in);
120 free(out);
121 return (1);
122 }
123 }
124 else
125 rgb = NULL;
126
127 if (rotation)
128 {
129 xstart = 767 * bpp;
130 xdir = -2 * bpp;
131 }
132 else
133 {
134 xstart = 0;
135 xdir = 0;
136 }
137
138 /*
139 * Read the image file...
140 */
141
142 for (y = 0; y < 512; y += 2)
143 {
144 /*
145 * Grab the next two scanlines:
146 *
147 * YYYYYYYYYYYYYYY...
148 * YYYYYYYYYYYYYYY...
149 * CbCbCb...CrCrCr...
150 */
151
152 if (fread(in, 1, 768 * 3, fp) < (768 * 3))
153 {
154 /*
155 * Couldn't read a row of data - return an error!
156 */
157
158 free(in);
159 free(out);
160
161 if (bpp > 1)
162 free(rgb);
163
164 return (-1);
165 }
166
167 /*
168 * Process the two scanlines...
169 */
170
171 for (pass = 0, iy = in; pass < 2; pass ++)
172 {
173 if (bpp == 1)
174 {
175 /*
176 * Just extract the luminance channel from the line and put it
177 * in the image...
178 */
179
180 if (primary == CUPS_IMAGE_BLACK)
181 {
182 if (rotation)
183 {
184 for (rgbptr = out + xstart, x = 0; x < 768; x ++)
185 *rgbptr-- = 255 - *iy++;
186
187 if (lut)
188 cupsImageLut(out, 768, lut);
189
190 _cupsImagePutCol(img, 511 - y - pass, 0, 768, out);
191 }
192 else
193 {
194 cupsImageWhiteToBlack(iy, out, 768);
195
196 if (lut)
197 cupsImageLut(out, 768, lut);
198
199 _cupsImagePutRow(img, 0, y + pass, 768, out);
200 iy += 768;
201 }
202 }
203 else if (rotation)
204 {
205 for (rgbptr = out + xstart, x = 0; x < 768; x ++)
206 *rgbptr-- = 255 - *iy++;
207
208 if (lut)
209 cupsImageLut(out, 768, lut);
210
211 _cupsImagePutCol(img, 511 - y - pass, 0, 768, out);
212 }
213 else
214 {
215 if (lut)
216 cupsImageLut(iy, 768, lut);
217
218 _cupsImagePutRow(img, 0, y + pass, 768, iy);
219 iy += 768;
220 }
221 }
222 else
223 {
224 /*
225 * Convert YCbCr to RGB... While every pixel gets a luminance
226 * value, adjacent pixels share chroma information.
227 */
228
229 cb = cr = 0.0f;
230
231 for (x = 0, rgbptr = rgb + xstart, icb = in + 1536, icr = in + 1920;
232 x < 768;
233 x ++, iy ++, rgbptr += xdir)
234 {
235 if (!(x & 1))
236 {
237 cb = (float)(*icb - 156);
238 cr = (float)(*icr - 137);
239 }
240
241 temp = 92241 * (*iy);
242
243 temp2 = (temp + 86706 * cr) / 65536;
244 if (temp2 < 0)
245 *rgbptr++ = 0;
246 else if (temp2 > 255)
247 *rgbptr++ = 255;
248 else
249 *rgbptr++ = temp2;
250
251 temp2 = (temp - 25914 * cb - 44166 * cr) / 65536;
252 if (temp2 < 0)
253 *rgbptr++ = 0;
254 else if (temp2 > 255)
255 *rgbptr++ = 255;
256 else
257 *rgbptr++ = temp2;
258
259 temp2 = (temp + 133434 * cb) / 65536;
260 if (temp2 < 0)
261 *rgbptr++ = 0;
262 else if (temp2 > 255)
263 *rgbptr++ = 255;
264 else
265 *rgbptr++ = temp2;
266
267 if (x & 1)
268 {
269 icb ++;
270 icr ++;
271 }
272 }
273
274 /*
275 * Adjust the hue and saturation if needed...
276 */
277
278 if (saturation != 100 || hue != 0)
279 cupsImageRGBAdjust(rgb, 768, saturation, hue);
280
281 /*
282 * Then convert the RGB data to the appropriate colorspace and
283 * put it in the image...
284 */
285
286 switch (img->colorspace)
287 {
288 default :
289 break;
290
291 case CUPS_IMAGE_RGB :
292 cupsImageRGBToRGB(rgb, out, 768);
293 break;
294 case CUPS_IMAGE_CMY :
295 cupsImageRGBToCMY(rgb, out, 768);
296 break;
297 case CUPS_IMAGE_CMYK :
298 cupsImageRGBToCMYK(rgb, out, 768);
299 break;
300 }
301
302 if (lut)
303 cupsImageLut(out, 768 * bpp, lut);
304
305 if (rotation)
306 _cupsImagePutCol(img, 511 - y - pass, 0, 768, out);
307 else
308 _cupsImagePutRow(img, 0, y + pass, 768, out);
309 }
310 }
311 }
312
313 /*
314 * Free memory and return...
315 */
316
317 free(in);
318 free(out);
319 if (bpp > 1)
320 free(rgb);
321
322 return (0);
323 }
324
325