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