1 /*
2 * imageio.c - This file deals with reading/writing image files
3 *
4 * $Id: imageio.c,v 1.25 2009/05/16 18:37:52 johns Exp $
5 */
6
7 /* For our puposes, we're interested only in the 3 byte per pixel 24 bit
8 * truecolor sort of file..
9 */
10
11 #include <stdio.h>
12 #include "machine.h"
13 #include "types.h"
14 #include "util.h"
15 #include "imageio.h"
16 #include "ppm.h" /* 24-bit and 48-bit PPM files */
17 #include "psd.h" /* 24-bit and 48-bit Photoshop files */
18 #include "tgafile.h" /* 24-bit Truevision Targa files */
19 #include "jpeg.h" /* JPEG files */
20 #include "pngfile.h" /* PNG files */
21 #include "sgirgb.h" /* 24-bit SGI RGB files */
22 #include "winbmp.h" /* 24-bit Windows Bitmap files */
23 #include "ui.h" /* UI error messages */
24
25 static
fakeimage(char * name,int * xres,int * yres,unsigned char ** imgdata)26 int fakeimage(char * name, int * xres, int * yres, unsigned char ** imgdata) {
27 int i, imgsize;
28 char msgtxt[2048];
29 sprintf(msgtxt, "Error loading image %s. Faking it using solid gray.", name);
30 rt_ui_message(MSG_0, msgtxt);
31
32 *xres = 4;
33 *yres = 4;
34 imgsize = 3 * (*xres) * (*yres);
35 *imgdata = malloc(imgsize);
36 for (i=0; i<imgsize; i++) {
37 (*imgdata)[i] = 255;
38 }
39
40 return IMAGENOERR;
41 }
42
43
readimage(rawimage * img)44 int readimage(rawimage * img) {
45 int rc;
46 int xres, yres, zres;
47 unsigned char * imgdata;
48 char * name = img->name;
49 char msgtxt[2048];
50
51 xres=1;
52 yres=1;
53 zres=1;
54
55 if (strstr(name, ".ppm")) {
56 rc = readppm(name, &xres, &yres, &imgdata);
57 } else if (strstr(name, ".tga")) {
58 rc = readtga(name, &xres, &yres, &imgdata);
59 } else if (strstr(name, ".jpg")) {
60 rc = readjpeg(name, &xres, &yres, &imgdata);
61 } else if (strstr(name, ".png")) {
62 rc = readpng(name, &xres, &yres, &imgdata);
63 } else if (strstr(name, ".gif")) {
64 rc = IMAGEUNSUP;
65 } else if (strstr(name, ".tiff")) {
66 rc = IMAGEUNSUP;
67 } else if (strstr(name, ".rgb")) {
68 rc = IMAGEUNSUP;
69 } else if (strstr(name, ".xpm")) {
70 rc = IMAGEUNSUP;
71 } else {
72 rc = readppm(name, &xres, &yres, &imgdata);
73 }
74
75 switch (rc) {
76 case IMAGEREADERR:
77 sprintf(msgtxt, "Short read encountered while loading image %s", name);
78 rt_ui_message(MSG_0, msgtxt);
79 rc = IMAGENOERR; /* remap to non-fatal error */
80 break;
81
82 case IMAGEUNSUP:
83 sprintf(msgtxt, "Cannot read unsupported format for image %s", name);
84 rt_ui_message(MSG_0, msgtxt);
85 break;
86 }
87
88 /* If the image load failed, create a tiny white colored image to fake it */
89 /* this allows a scene to render even when a file can't be loaded */
90 if (rc != IMAGENOERR) {
91 rc = fakeimage(name, &xres, &yres, &imgdata);
92 }
93
94 /* If we succeeded in loading the image, return it. */
95 if (rc == IMAGENOERR) {
96 img->xres = xres;
97 img->yres = yres;
98 img->zres = zres;
99 img->bpp = 3;
100 img->data = imgdata;
101 }
102
103 return rc;
104 }
105
106
minmax_rgb96f(int xres,int yres,const float * fimg,float * min,float * max)107 void minmax_rgb96f(int xres, int yres, const float *fimg,
108 float *min, float *max) {
109 int i, sz;
110 float minval, maxval;
111
112 minval=maxval=fimg[0];
113
114 sz = xres * yres * 3;
115 for (i=0; i<sz; i++) {
116 if (fimg[i] > maxval)
117 maxval=fimg[i];
118 if (fimg[i] < minval)
119 minval=fimg[i];
120 }
121
122 if (min != NULL)
123 *min = minval;
124
125 if (max != NULL)
126 *max = maxval;
127 }
128
129
normalize_rgb96f(int xres,int yres,float * fimg)130 void normalize_rgb96f(int xres, int yres, float *fimg) {
131 int i, sz;
132 float min, max, scale;
133 sz = xres * yres * 3;
134 minmax_rgb96f(xres, yres, fimg, &min, &max);
135 scale = 1.0 / (max-min);
136 for (i=0; i<sz; i++)
137 fimg[i] = (fimg[i]-min) * scale;
138 }
139
140
gamma_rgb96f(int xres,int yres,float * fimg,float gamma)141 void gamma_rgb96f(int xres, int yres, float *fimg, float gamma) {
142 float invgamma = 1.0 / gamma;
143 int i, sz;
144 sz = xres * yres * 3;
145 for (i=0; i<sz; i++)
146 fimg[i] = pow(fimg[i], invgamma);
147 }
148
149
image_rgb24_from_rgb96f(int xres,int yres,float * fimg)150 unsigned char * image_rgb24_from_rgb96f(int xres, int yres, float *fimg) {
151 unsigned char *img;
152 int x, y, R, G, B;
153 img = (unsigned char *) malloc(xres * yres * 3);
154
155 for (y=0; y<yres; y++) {
156 for (x=0; x<xres; x++) {
157 int addr = (xres * y + x) * 3;
158 R = (int) (fimg[addr ] * 255.0f); /* quantize float to integer */
159 G = (int) (fimg[addr + 1] * 255.0f); /* quantize float to integer */
160 B = (int) (fimg[addr + 2] * 255.0f); /* quantize float to integer */
161
162 if (R > 255) R = 255; /* clamp pixel value to range 0-255 */
163 if (R < 0) R = 0;
164 img[addr ] = (byte) R; /* Store final pixel to the image buffer */
165
166 if (G > 255) G = 255; /* clamp pixel value to range 0-255 */
167 if (G < 0) G = 0;
168 img[addr + 1] = (byte) G; /* Store final pixel to the image buffer */
169
170 if (B > 255) B = 255; /* clamp pixel value to range 0-255 */
171 if (B < 0) B = 0;
172 img[addr + 2] = (byte) B; /* Store final pixel to the image buffer */
173 }
174 }
175
176 return img;
177 }
178
179
image_crop_rgb96f(int xres,int yres,float * fimg,int szx,int szy,int sx,int sy)180 float * image_crop_rgb96f(int xres, int yres, float *fimg,
181 int szx, int szy, int sx, int sy) {
182 float *cropped;
183 int x, y;
184
185 cropped = (float *) malloc(szx * szy * 3 * sizeof(float));
186 memset(cropped, 0, szx * szy * 3 * sizeof(float));
187
188 for (y=0; y<szy; y++) {
189 int oaddr = ((y+sy) * xres + sx) * 3;
190 if ((y+sy >= 0) && (y+sy < yres)) {
191 for (x=0; x<szx; x++) {
192 if ((x+sx >= 0) && (x+sx < xres)) {
193 int addr = (szx * y + x) * 3;
194 cropped[addr ] = fimg[oaddr + (x*3) ];
195 cropped[addr + 1] = fimg[oaddr + (x*3) + 1];
196 cropped[addr + 2] = fimg[oaddr + (x*3) + 2];
197 }
198 }
199 }
200 }
201
202 return cropped;
203 }
204
205
image_crop_rgb24(int xres,int yres,unsigned char * img,int szx,int szy,int sx,int sy)206 unsigned char * image_crop_rgb24(int xres, int yres, unsigned char *img,
207 int szx, int szy, int sx, int sy) {
208 unsigned char *cropped;
209 int x, y;
210
211 cropped = (unsigned char *) malloc(szx * szy * 3 * sizeof(unsigned char));
212 memset(cropped, 0, szx * szy * 3 * sizeof(unsigned char));
213
214 for (y=0; y<szy; y++) {
215 int oaddr = ((y+sy) * xres + sx) * 3;
216 if ((y+sy >= 0) && (y+sy < yres)) {
217 for (x=0; x<szx; x++) {
218 if ((x+sx >= 0) && (x+sx < xres)) {
219 int addr = (szx * y + x) * 3;
220 cropped[addr ] = img[oaddr + (x*3) ];
221 cropped[addr + 1] = img[oaddr + (x*3) + 1];
222 cropped[addr + 2] = img[oaddr + (x*3) + 2];
223 }
224 }
225 }
226 }
227
228 return cropped;
229 }
230
231
image_rgb48be_from_rgb96f(int xres,int yres,float * fimg)232 unsigned char * image_rgb48be_from_rgb96f(int xres, int yres, float *fimg) {
233 int x, y, R, G, B;
234 unsigned char *img = (unsigned char *) malloc(xres * yres * 6);
235
236 for (y=0; y<yres; y++) {
237 for (x=0; x<xres; x++) {
238 int faddr = (xres * y + x) * 3;
239 int iaddr = faddr * 2;
240
241 R = (int) (fimg[faddr ] * 65535.0f); /* quantize float to integer */
242 G = (int) (fimg[faddr + 1] * 65535.0f); /* quantize float to integer */
243 B = (int) (fimg[faddr + 2] * 65535.0f); /* quantize float to integer */
244
245 if (R > 65535) R = 65535; /* clamp pixel value to range 0-65535 */
246 if (R < 0) R = 0;
247 img[iaddr ] = (byte) ((R >> 8) & 0xff);
248 img[iaddr + 1] = (byte) (R & 0xff);
249
250 if (G > 65535) G = 65535; /* clamp pixel value to range 0-65535 */
251 if (G < 0) G = 0;
252 img[iaddr + 2] = (byte) ((G >> 8) & 0xff);
253 img[iaddr + 3] = (byte) (G & 0xff);
254
255 if (B > 65535) B = 65535; /* clamp pixel value to range 0-65535 */
256 if (B < 0) B = 0;
257 img[iaddr + 4] = (byte) ((B >> 8) & 0xff);
258 img[iaddr + 5] = (byte) (B & 0xff);
259 }
260 }
261
262 return img;
263 }
264
265
image_rgb48bepl_from_rgb96f(int xres,int yres,float * fimg)266 unsigned char * image_rgb48bepl_from_rgb96f(int xres, int yres, float *fimg) {
267 int x, y, R, G, B, sz;
268 unsigned char *img = (unsigned char *) malloc(xres * yres * 6);
269
270 sz = xres * yres * 2;
271 for (y=0; y<yres; y++) {
272 for (x=0; x<xres; x++) {
273 int addr = xres * y + x;
274 int faddr = addr * 3;
275 int iaddr = addr * 2;
276 int raddr = iaddr;
277 int gaddr = iaddr + sz;
278 int baddr = iaddr + (sz * 2);
279
280 R = (int) (fimg[faddr ] * 65535.0f); /* quantize float to integer */
281 G = (int) (fimg[faddr + 1] * 65535.0f); /* quantize float to integer */
282 B = (int) (fimg[faddr + 2] * 65535.0f); /* quantize float to integer */
283
284 if (R > 65535) R = 65535; /* clamp pixel value to range 0-65535 */
285 if (R < 0) R = 0;
286 img[raddr ] = (byte) ((R >> 8) & 0xff);
287 img[raddr + 1] = (byte) (R & 0xff);
288
289 if (G > 65535) G = 65535; /* clamp pixel value to range 0-65535 */
290 if (G < 0) G = 0;
291 img[gaddr ] = (byte) ((G >> 8) & 0xff);
292 img[gaddr + 1] = (byte) (G & 0xff);
293
294 if (B > 65535) B = 65535; /* clamp pixel value to range 0-65535 */
295 if (B < 0) B = 0;
296 img[baddr ] = (byte) ((B >> 8) & 0xff);
297 img[baddr + 1] = (byte) (B & 0xff);
298 }
299 }
300
301 return img;
302 }
303
304
writeimage(char * name,int xres,int yres,void * img,int imgbufferformat,int fileformat)305 int writeimage(char * name, int xres, int yres, void *img,
306 int imgbufferformat, int fileformat) {
307 if (img == NULL)
308 return IMAGENULLDATA;
309
310 if (imgbufferformat == RT_IMAGE_BUFFER_RGB24) {
311 unsigned char *imgbuf = (unsigned char *) img;
312
313 switch (fileformat) {
314 case RT_FORMAT_PPM:
315 return writeppm(name, xres, yres, imgbuf);
316
317 case RT_FORMAT_SGIRGB:
318 return writergb(name, xres, yres, imgbuf);
319
320 case RT_FORMAT_JPEG:
321 return writejpeg(name, xres, yres, imgbuf);
322
323 case RT_FORMAT_PNG:
324 return writepng(name, xres, yres, imgbuf);
325
326 case RT_FORMAT_WINBMP:
327 return writebmp(name, xres, yres, imgbuf);
328
329 case RT_FORMAT_TARGA:
330 return writetga(name, xres, yres, imgbuf);
331
332 default:
333 printf("Unsupported image format combination\n");
334 return IMAGEUNSUP;
335 }
336 } else {
337 unsigned char *imgbuf = (unsigned char *) img;
338 int rc;
339
340 switch (fileformat) {
341 case RT_FORMAT_PPM:
342 imgbuf = image_rgb24_from_rgb96f(xres, yres, img);
343 rc = writeppm(name, xres, yres, imgbuf);
344 free(imgbuf);
345 return rc;
346
347 case RT_FORMAT_SGIRGB:
348 imgbuf = image_rgb24_from_rgb96f(xres, yres, img);
349 rc = writergb(name, xres, yres, imgbuf);
350 free(imgbuf);
351 return rc;
352
353 case RT_FORMAT_JPEG:
354 imgbuf = image_rgb24_from_rgb96f(xres, yres, img);
355 rc = writejpeg(name, xres, yres, imgbuf);
356 free(imgbuf);
357 return rc;
358
359 case RT_FORMAT_PNG:
360 imgbuf = image_rgb24_from_rgb96f(xres, yres, img);
361 rc = writepng(name, xres, yres, imgbuf);
362 free(imgbuf);
363 return rc;
364
365 case RT_FORMAT_WINBMP:
366 imgbuf = image_rgb24_from_rgb96f(xres, yres, img);
367 rc = writebmp(name, xres, yres, imgbuf);
368 free(imgbuf);
369 return rc;
370
371 case RT_FORMAT_TARGA:
372 imgbuf = image_rgb24_from_rgb96f(xres, yres, img);
373 rc = writetga(name, xres, yres, imgbuf);
374 free(imgbuf);
375 return rc;
376
377 case RT_FORMAT_PPM48:
378 imgbuf = image_rgb48be_from_rgb96f(xres, yres, img);
379 rc = writeppm48(name, xres, yres, imgbuf);
380 free(imgbuf);
381 return rc;
382
383 case RT_FORMAT_PSD48:
384 imgbuf = image_rgb48bepl_from_rgb96f(xres, yres, img);
385 rc = writepsd48(name, xres, yres, imgbuf);
386 free(imgbuf);
387 return rc;
388
389 default:
390 printf("Unsupported image format combination\n");
391 return IMAGEUNSUP;
392 }
393 }
394 }
395
396
397