Tachyon (current)  Current Main Branch
pngfile.c
Go to the documentation of this file.
1 /*
2  * pngfile.c - This file deals with PNG format image files (reading/writing)
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: pngfile.c,v 1.16 2022/02/18 17:55:28 johns Exp $
8  *
9  */
10 
11 /*
12  * This code requires support from libpng, and libz.
13  * For our purposes, we're interested only in the 3 byte per pixel 24 bit
14  * RGB input/output. Probably won't implement any decent checking at this
15  * point.
16  */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <math.h>
21 
22 #define TACHYON_INTERNAL 1
23 #include "tachyon.h"
24 #include "util.h"
25 #include "imageio.h" /* error codes etc */
26 #include "pngfile.h" /* the protos for this file */
27 
28 #if !defined(USEPNG)
29 
30 int readpng(const char *name, int *xres, int *yres, unsigned char **imgdata) {
31  return IMAGEUNSUP;
32 }
33 
34 int writepng(const char *name, int xres, int yres, unsigned char *imgdata) {
35  return IMAGEUNSUP;
36 }
37 
38 #else
39 
40 #include "png.h" /* the libpng library headers */
41 
42 /* The png_jmpbuf() macro, used in error handling, became available in
43  * libpng version 1.0.6. If you want to be able to run your code with older
44  * versions of libpng, you must define the macro yourself (but only if it
45  * is not already defined by libpng!).
46  */
47 #ifndef png_jmpbuf
48 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
49 #endif
50 
51 int readpng(const char *name, int *xres, int *yres, unsigned char **imgdata) {
52  FILE * ifp;
53  png_structp png_ptr;
54  png_infop info_ptr;
55  png_bytep *row_pointers;
56  int x, y;
57 
58  /* Create and initialize the png_struct with the default error handlers */
59  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
60  if (png_ptr == NULL) {
61  return IMAGEALLOCERR; /* Could not initialize PNG library, return error */
62  }
63 
64  /* Allocate/initialize the memory for image information. REQUIRED. */
65  info_ptr = png_create_info_struct(png_ptr);
66  if (info_ptr == NULL) {
67  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
68  return IMAGEALLOCERR; /* Could not initialize PNG library, return error */
69  }
70 
71  /* open input file before doing any more PNG decompression setup */
72  if ((ifp = fopen(name, "rb")) == NULL)
73  return IMAGEBADFILE; /* Could not open image, return error */
74 
75  /* Set error handling for setjmp/longjmp method of libpng error handling */
76  if (setjmp(png_jmpbuf(png_ptr))) {
77  /* Free all of the memory associated with the png_ptr and info_ptr */
78  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
79  /* If we get here, we had a problem reading the file */
80  fclose(ifp);
81  return IMAGEBADFILE; /* Could not open image, return error */
82  }
83 
84  /* Set up the input control if you are using standard C streams */
85  png_init_io(png_ptr, ifp);
86 
87  /* one-shot call to read the whole PNG file into memory */
88  png_read_png(png_ptr, info_ptr,
89  PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA,
90  NULL);
91  *xres = png_get_image_width(png_ptr, info_ptr);
92  *yres = png_get_image_height(png_ptr, info_ptr);
93 
94  /* copy pixel data into our own data structures */
95  row_pointers = png_get_rows(png_ptr, info_ptr);
96 
97  *imgdata = (unsigned char *) malloc(3 * (*xres) * (*yres));
98  if ((*imgdata) == NULL) {
99  return IMAGEALLOCERR;
100  }
101 
102  for (y=0; y<(*yres); y++) {
103  unsigned char *img = &(*imgdata)[(y * (*xres) * 3)];
104  for (x=0; x<(*xres); x++) {
105  img[(x*3) ] = row_pointers[(*yres) - y - 1][x ];
106  img[(x*3) + 1] = row_pointers[(*yres) - y - 1][x + 1];
107  img[(x*3) + 2] = row_pointers[(*yres) - y - 1][x + 2];
108  }
109  }
110 
111  /* clean up after the read, and free any memory allocated - REQUIRED */
112  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
113 
114  fclose(ifp); /* Close the input file */
115 
116  return IMAGENOERR; /* No fatal errors */
117 }
118 
119 
120 
121 int writepng(const char *name, int xres, int yres, unsigned char *imgdata) {
122  FILE *ofp;
123  png_structp png_ptr;
124  png_infop info_ptr;
125  png_bytep *row_pointers;
126  png_textp text_ptr;
127  int y;
128 
129  /* Create and initialize the png_struct with the default error handlers */
130  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
131  if (png_ptr == NULL) {
132  return IMAGEALLOCERR; /* Could not initialize PNG library, return error */
133  }
134 
135  /* Allocate/initialize the memory for image information. REQUIRED. */
136  info_ptr = png_create_info_struct(png_ptr);
137  if (info_ptr == NULL) {
138  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
139  return IMAGEALLOCERR; /* Could not initialize PNG library, return error */
140  }
141 
142  /* open output file before doing any more PNG compression setup */
143  if ((ofp = fopen(name, "wb")) == NULL) {
144  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
145  return IMAGEBADFILE;
146  }
147 
148  /* Set error handling for setjmp/longjmp method of libpng error handling */
149  if (setjmp(png_jmpbuf(png_ptr))) {
150  /* Free all of the memory associated with the png_ptr and info_ptr */
151  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
152  /* If we get here, we had a problem writing the file */
153  fclose(ofp);
154  return IMAGEBADFILE; /* Could not open image, return error */
155  }
156 
157  /* Set up the input control if you are using standard C streams */
158  png_init_io(png_ptr, ofp);
159 
160  png_set_IHDR(png_ptr, info_ptr, xres, yres,
161  8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
162  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
163 
164  png_set_gAMA(png_ptr, info_ptr, 1.0);
165 
166  text_ptr = (png_textp) png_malloc(png_ptr, (png_uint_32)sizeof(png_text) * 2);
167 
168  text_ptr[0].key = "Description";
169  text_ptr[0].text = "A scene rendered by the Tachyon ray tracer";
170  text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
171 #ifdef PNG_iTXt_SUPPORTED
172  text_ptr[0].lang = NULL;
173 #endif
174 
175  text_ptr[1].key = "Software";
176  text_ptr[1].text = "Tachyon Parallel/Multiprocessor Ray Tracer";
177  text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
178 #ifdef PNG_iTXt_SUPPORTED
179  text_ptr[1].lang = NULL;
180 #endif
181  png_set_text(png_ptr, info_ptr, text_ptr, 1);
182 
183  row_pointers = png_malloc(png_ptr, yres*sizeof(png_bytep));
184  for (y=0; y<yres; y++) {
185  row_pointers[yres - y - 1] = (png_bytep) &imgdata[y * xres * 3];
186  }
187 
188  png_set_rows(png_ptr, info_ptr, row_pointers);
189 
190  /* one-shot call to write the whole PNG file into memory */
191  png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
192 
193  png_free(png_ptr, row_pointers);
194  png_free(png_ptr, text_ptr);
195 
196  /* clean up after the write and free any memory allocated - REQUIRED */
197  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
198 
199  fclose(ofp); /* close the output file */
200 
201  return IMAGENOERR; /* No fatal errors */
202 }
203 
204 
205 
206 int writepng_alpha(const char *name, int xres, int yres, unsigned char *imgdata) {
207  FILE *ofp;
208  png_structp png_ptr;
209  png_infop info_ptr;
210  png_bytep *row_pointers;
211  png_textp text_ptr;
212  int y;
213 
214  /* Create and initialize the png_struct with the default error handlers */
215  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
216  if (png_ptr == NULL) {
217  return IMAGEALLOCERR; /* Could not initialize PNG library, return error */
218  }
219 
220  /* Allocate/initialize the memory for image information. REQUIRED. */
221  info_ptr = png_create_info_struct(png_ptr);
222  if (info_ptr == NULL) {
223  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
224  return IMAGEALLOCERR; /* Could not initialize PNG library, return error */
225  }
226 
227  /* open output file before doing any more PNG compression setup */
228  if ((ofp = fopen(name, "wb")) == NULL) {
229  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
230  return IMAGEBADFILE;
231  }
232 
233  /* Set error handling for setjmp/longjmp method of libpng error handling */
234  if (setjmp(png_jmpbuf(png_ptr))) {
235  /* Free all of the memory associated with the png_ptr and info_ptr */
236  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
237  /* If we get here, we had a problem writing the file */
238  fclose(ofp);
239  return IMAGEBADFILE; /* Could not open image, return error */
240  }
241 
242  /* Set up the input control if you are using standard C streams */
243  png_init_io(png_ptr, ofp);
244 
245 #if 0
246  /* this API apparently doesn't exist on all revs of libpng */
247  /* png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); */
248 
249  /* optional significant bit chunk */
250  png_color_8 sig_bit;
251  memset(&sig_bit, 0, sizeof(sig_bit));
252 
253  sig_bit.red = 8;
254  sig_bit.green = 8;
255  sig_bit.blue = 8;
256  sig_bit.alpha = 8;
257 
258  png_set_sBIT(png_ptr, info_ptr, &sig_bit);
259 #endif
260 
261  png_set_IHDR(png_ptr, info_ptr, xres, yres,
262  8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
263  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
264 
265  png_set_gAMA(png_ptr, info_ptr, 1.0);
266 
267  text_ptr = (png_textp) png_malloc(png_ptr, (png_uint_32)sizeof(png_text) * 2);
268 
269  text_ptr[0].key = "Description";
270  text_ptr[0].text = "A scene rendered by the Tachyon ray tracer";
271  text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
272 #ifdef PNG_iTXt_SUPPORTED
273  text_ptr[0].lang = NULL;
274 #endif
275 
276  text_ptr[1].key = "Software";
277  text_ptr[1].text = "Tachyon Parallel/Multiprocessor Ray Tracer";
278  text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
279 #ifdef PNG_iTXt_SUPPORTED
280  text_ptr[1].lang = NULL;
281 #endif
282  png_set_text(png_ptr, info_ptr, text_ptr, 1);
283 
284  row_pointers = png_malloc(png_ptr, yres*sizeof(png_bytep));
285  for (y=0; y<yres; y++) {
286  row_pointers[yres - y - 1] = (png_bytep) &imgdata[y * xres * 4];
287  }
288 
289  png_set_rows(png_ptr, info_ptr, row_pointers);
290 
291  /* write out metadata first */
292  /* png_write_info(png_ptr, info_ptr); */
293 
294  /* one-shot call to write the whole PNG file into memory */
295  png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
296 
297  png_free(png_ptr, row_pointers);
298  png_free(png_ptr, text_ptr);
299 
300  /* clean up after the write and free any memory allocated - REQUIRED */
301  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
302 
303  fclose(ofp); /* close the output file */
304 
305  return IMAGENOERR; /* No fatal errors */
306 }
307 
308 
309 #endif
int readpng(const char *name, int *xres, int *yres, unsigned char **imgdata)
Definition: pngfile.c:30
#define IMAGEUNSUP
the image file is an unsupported format
Definition: imageio.h:18
int writepng(const char *name, int xres, int yres, unsigned char *imgdata)
Definition: pngfile.c:34
int writepng_alpha(const char *name, int xres, int yres, unsigned char *imgdata)
#define IMAGEALLOCERR
not enough remaining memory to load this image
Definition: imageio.h:19
Tachyon cross-platform timers, special math function wrappers, and RNGs.
#define IMAGENOERR
no error
Definition: imageio.h:16
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
#define IMAGEBADFILE
can&#39;t find or can&#39;t open the file
Definition: imageio.h:17