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