2 * Image Library -- libpng
4 * (c) 2006 Pavel Charvat <pchar@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
13 #include "lib/mempool.h"
14 #include "lib/fastbuf.h"
15 #include "images/images.h"
19 struct libpng_read_data {
30 libpng_malloc(png_structp png_ptr, png_size_t size)
32 DBG("libpng_malloc(size=%u)", (uns)size);
33 return mp_alloc(png_get_mem_ptr(png_ptr), size);
37 libpng_free(png_structp png_ptr UNUSED, png_voidp ptr UNUSED)
43 libpng_read_error(png_structp png_ptr, png_const_charp msg)
45 DBG("libpng_read_error()");
46 image_thread_err_dup(png_get_error_ptr(png_ptr), IMAGE_ERR_READ_FAILED, (byte *)msg);
47 longjmp(png_jmpbuf(png_ptr), 1);
51 libpng_write_error(png_structp png_ptr, png_const_charp msg)
53 DBG("libpng_write_error()");
54 image_thread_err_dup(png_get_error_ptr(png_ptr), IMAGE_ERR_WRITE_FAILED, (byte *)msg);
55 longjmp(png_jmpbuf(png_ptr), 1);
59 libpng_warning(png_structp png_ptr UNUSED, png_const_charp msg UNUSED)
61 DBG("libpng_warning(): %s", (byte *)msg);
65 libpng_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
67 DBG("libpng_read_fn(len=%u)", (uns)length);
68 if (unlikely(bread((struct fastbuf *)png_get_io_ptr(png_ptr), (byte *)data, length) < length))
69 png_error(png_ptr, "Incomplete data");
73 libpng_write_fn(png_structp png_ptr, png_bytep data, png_size_t length)
75 DBG("libpng_write_fn(len=%u)", (uns)length);
76 bwrite((struct fastbuf *)png_get_io_ptr(png_ptr), (byte *)data, length);
80 libpng_flush_fn(png_structp png_ptr UNUSED)
82 DBG("libpng_flush_fn()");
86 libpng_read_cancel(struct image_io *io)
88 DBG("libpng_read_cancel()");
90 struct libpng_read_data *rd = io->read_data;
91 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
95 libpng_read_header(struct image_io *io)
97 DBG("libpng_read_header()");
99 /* Create libpng structures */
100 struct libpng_read_data *rd = io->read_data = mp_alloc(io->internal_pool, sizeof(*rd));
101 rd->png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
102 io->thread, libpng_read_error, libpng_warning,
103 io->internal_pool, libpng_malloc, libpng_free);
104 if (unlikely(!rd->png_ptr))
106 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libpng read structure.");
109 rd->info_ptr = png_create_info_struct(rd->png_ptr);
110 if (unlikely(!rd->info_ptr))
112 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libpng info structure.");
113 png_destroy_read_struct(&rd->png_ptr, NULL, NULL);
116 rd->end_ptr = png_create_info_struct(rd->png_ptr);
117 if (unlikely(!rd->end_ptr))
119 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libpng info structure.");
120 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, NULL);
124 /* Setup libpng longjump */
125 if (unlikely(setjmp(png_jmpbuf(rd->png_ptr))))
127 DBG("Libpng failed to read the image, longjump saved us");
128 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
132 /* Setup libpng IO */
133 png_set_read_fn(rd->png_ptr, io->fastbuf, libpng_read_fn);
134 png_set_user_limits(rd->png_ptr, IMAGE_MAX_SIZE, IMAGE_MAX_SIZE);
137 png_read_info(rd->png_ptr, rd->info_ptr);
138 png_get_IHDR(rd->png_ptr, rd->info_ptr, &rd->cols, &rd->rows, &rd->bit_depth, &rd->color_type, NULL, NULL, NULL);
140 /* Fill image_io values */
143 switch (rd->color_type)
145 case PNG_COLOR_TYPE_GRAY:
146 io->flags |= COLOR_SPACE_GRAYSCALE;
147 io->number_of_colors = 1 << 8;
149 case PNG_COLOR_TYPE_GRAY_ALPHA:
150 io->flags |= COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
151 io->number_of_colors = 1 << 8;
153 case PNG_COLOR_TYPE_RGB:
154 io->flags |= COLOR_SPACE_RGB;
155 io->number_of_colors = 1 << 24;
157 case PNG_COLOR_TYPE_RGB_ALPHA:
158 io->number_of_colors = 1 << 24;
159 io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA;
161 case PNG_COLOR_TYPE_PALETTE:
162 io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA;
164 if (png_get_PLTE(rd->png_ptr, rd->info_ptr, NULL, &num_palette))
165 io->number_of_colors = num_palette;
167 io->number_of_colors = 1 << rd->bit_depth;
171 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
172 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Unknown color type");
177 io->read_cancel = libpng_read_cancel;
182 libpng_read_data(struct image_io *io)
184 DBG("libpng_read_data()");
186 struct libpng_read_data *rd = io->read_data;
188 /* Test supported pixel formats */
189 switch (io->flags & IMAGE_COLOR_SPACE)
191 case COLOR_SPACE_GRAYSCALE:
192 case COLOR_SPACE_RGB:
195 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
196 image_thread_err(io->thread, IMAGE_ERR_INVALID_PIXEL_FORMAT, "Unsupported color space.");
200 volatile int need_scale = io->cols != rd->cols || io->rows != rd->rows;
201 struct image * volatile img = need_scale ?
202 image_new(io->thread, rd->cols, rd->rows, io->flags & IMAGE_PIXEL_FORMAT, NULL) :
203 image_new(io->thread, rd->cols, rd->rows, io->flags, io->pool);
206 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
210 if (setjmp(png_jmpbuf(rd->png_ptr)))
212 DBG("Libpng failed to read the image, longjump saved us");
213 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
214 if (need_scale || !io->pool)
219 /* Apply transformations */
220 if (rd->bit_depth == 16)
221 png_set_strip_16(rd->png_ptr);
222 switch (rd->color_type)
224 case PNG_COLOR_TYPE_PALETTE:
225 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
227 png_set_palette_to_rgb(rd->png_ptr);
228 png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514);
231 png_set_palette_to_rgb(rd->png_ptr);
232 if ((io->flags & IMAGE_ALPHA) || (io->flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
233 png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER);
235 png_set_strip_alpha(rd->png_ptr);
237 case PNG_COLOR_TYPE_GRAY:
238 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_RGB)
239 png_set_gray_to_rgb(rd->png_ptr);
240 if (io->flags & IMAGE_ALPHA)
241 png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER);
243 case PNG_COLOR_TYPE_GRAY_ALPHA:
244 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_RGB)
245 png_set_gray_to_rgb(rd->png_ptr);
246 if (!(io->flags & IMAGE_ALPHA))
247 png_set_strip_alpha(rd->png_ptr);
249 case PNG_COLOR_TYPE_RGB:
250 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
251 png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514);
252 if ((io->flags & IMAGE_ALPHA) || (io->flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
253 png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER);
255 case PNG_COLOR_TYPE_RGB_ALPHA:
256 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
257 png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514);
258 if (!(io->flags & IMAGE_ALPHA) && (io->flags & IMAGE_PIXEL_FORMAT) != (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
259 png_set_strip_alpha(rd->png_ptr);
264 png_read_update_info(rd->png_ptr, rd->info_ptr);
266 /* Read image data */
267 DBG("Reading image data");
268 byte *pixels = img->pixels;
269 png_bytep rows[img->rows];
270 for (uns r = 0; r < img->rows; r++, pixels += img->row_size)
271 rows[r] = (png_bytep)pixels;
272 png_read_image(rd->png_ptr, rows);
273 png_read_end(rd->png_ptr, rd->end_ptr);
275 /* Destroy libpng read structure */
276 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
278 /* Scale and store the resulting image */
281 struct image *dest = image_new(io->thread, io->cols, io->rows, io->flags, io->pool);
287 if (!image_scale(io->thread, dest, img))
298 io->image_destroy = !io->pool;
304 libpng_write(struct image_io *io)
306 DBG("libpng_write()");
308 /* Create libpng structures */
309 png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
310 io->thread, libpng_write_error, libpng_warning,
311 io->internal_pool, libpng_malloc, libpng_free);
312 if (unlikely(!png_ptr))
314 image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "Cannot create libpng write structure.");
317 png_infop info_ptr = png_create_info_struct(png_ptr);
318 if (unlikely(!info_ptr))
320 image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "Cannot create libpng info structure.");
321 png_destroy_write_struct(&png_ptr, NULL);
325 /* Setup libpng longjump */
326 if (unlikely(setjmp(png_jmpbuf(png_ptr))))
328 DBG("Libpng failed to write the image, longjump saved us.");
329 png_destroy_write_struct(&png_ptr, &info_ptr);
333 /* Setup libpng IO */
334 png_set_write_fn(png_ptr, io->fastbuf, libpng_write_fn, libpng_flush_fn);
336 /* Setup PNG parameters */
337 struct image *img = io->image;
338 switch (img->flags & IMAGE_PIXEL_FORMAT)
340 case COLOR_SPACE_GRAYSCALE | IMAGE_PIXELS_ALIGNED:
341 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_GRAY,
342 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
344 case COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA | IMAGE_PIXELS_ALIGNED:
345 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_GRAY_ALPHA,
346 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
348 case COLOR_SPACE_RGB:
349 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB,
350 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
352 case COLOR_SPACE_RGB | IMAGE_ALPHA | IMAGE_PIXELS_ALIGNED:
353 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB_ALPHA,
354 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
356 case COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED:
357 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB,
358 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
359 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
364 png_write_info(png_ptr, info_ptr);
367 byte *pixels = img->pixels;
368 png_bytep rows[img->rows];
369 for (uns r = 0; r < img->rows; r++, pixels += img->row_size)
370 rows[r] = (png_bytep)pixels;
371 png_write_image(png_ptr, rows);
372 png_write_end(png_ptr, info_ptr);
374 /* Free libpng structure */
375 png_destroy_write_struct(&png_ptr, &info_ptr);