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 <ucw/mempool.h>
14 #include <ucw/fastbuf.h>
15 #include <images/images.h>
16 #include <images/error.h>
17 #include <images/color.h>
18 #include <images/io-main.h>
23 struct libpng_read_data {
34 libpng_malloc(png_structp png_ptr, png_size_t size)
36 DBG("libpng_malloc(size=%u)", (uint)size);
37 return mp_alloc(png_get_mem_ptr(png_ptr), size);
41 libpng_free(png_structp png_ptr UNUSED, png_voidp ptr UNUSED)
47 libpng_read_error(png_structp png_ptr, png_const_charp msg)
49 DBG("libpng_read_error()");
50 IMAGE_ERROR(png_get_error_ptr(png_ptr), IMAGE_ERROR_READ_FAILED, "%s", msg);
51 longjmp(png_jmpbuf(png_ptr), 1);
55 libpng_write_error(png_structp png_ptr, png_const_charp msg)
57 DBG("libpng_write_error()");
58 IMAGE_ERROR(png_get_error_ptr(png_ptr), IMAGE_ERROR_WRITE_FAILED, "%s", msg);
59 longjmp(png_jmpbuf(png_ptr), 1);
63 libpng_warning(png_structp png_ptr UNUSED, png_const_charp msg UNUSED)
65 DBG("libpng_warning(): %s", (byte *)msg);
69 libpng_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
71 DBG("libpng_read_fn(len=%u)", (uint)length);
72 if (unlikely(bread((struct fastbuf *)png_get_io_ptr(png_ptr), (byte *)data, length) < length))
73 png_error(png_ptr, "Incomplete data");
77 libpng_write_fn(png_structp png_ptr, png_bytep data, png_size_t length)
79 DBG("libpng_write_fn(len=%u)", (uint)length);
80 bwrite((struct fastbuf *)png_get_io_ptr(png_ptr), (byte *)data, length);
84 libpng_flush_fn(png_structp png_ptr UNUSED)
86 DBG("libpng_flush_fn()");
90 libpng_read_cancel(struct image_io *io)
92 DBG("libpng_read_cancel()");
94 struct libpng_read_data *rd = io->read_data;
95 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
99 libpng_read_header(struct image_io *io)
101 DBG("libpng_read_header()");
103 /* Create libpng structures */
104 struct libpng_read_data *rd = io->read_data = mp_alloc(io->internal_pool, sizeof(*rd));
105 rd->png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
106 io->context, libpng_read_error, libpng_warning,
107 io->internal_pool, libpng_malloc, libpng_free);
108 if (unlikely(!rd->png_ptr))
110 IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Cannot create libpng read structure.");
113 rd->info_ptr = png_create_info_struct(rd->png_ptr);
114 if (unlikely(!rd->info_ptr))
116 IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Cannot create libpng info structure.");
117 png_destroy_read_struct(&rd->png_ptr, NULL, NULL);
120 rd->end_ptr = png_create_info_struct(rd->png_ptr);
121 if (unlikely(!rd->end_ptr))
123 IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Cannot create libpng info structure.");
124 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, NULL);
128 /* Setup libpng longjump */
129 if (unlikely(setjmp(png_jmpbuf(rd->png_ptr))))
131 DBG("Libpng failed to read the image, longjump saved us");
132 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
136 /* Setup libpng IO */
137 png_set_read_fn(rd->png_ptr, io->fastbuf, libpng_read_fn);
138 png_set_user_limits(rd->png_ptr, image_max_dim, image_max_dim);
141 png_read_info(rd->png_ptr, rd->info_ptr);
142 png_get_IHDR(rd->png_ptr, rd->info_ptr, &rd->cols, &rd->rows, &rd->bit_depth, &rd->color_type, NULL, NULL, NULL);
144 /* Fill image_io values */
147 switch (rd->color_type)
149 case PNG_COLOR_TYPE_GRAY:
150 io->flags = COLOR_SPACE_GRAYSCALE;
151 io->number_of_colors = 1 << 8;
153 case PNG_COLOR_TYPE_GRAY_ALPHA:
154 io->flags = COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
155 io->number_of_colors = 1 << 8;
157 case PNG_COLOR_TYPE_RGB:
158 io->flags = COLOR_SPACE_RGB;
159 io->number_of_colors = 1 << 24;
161 case PNG_COLOR_TYPE_RGB_ALPHA:
162 io->number_of_colors = 1 << 24;
163 io->flags = COLOR_SPACE_RGB | IMAGE_ALPHA;
165 case PNG_COLOR_TYPE_PALETTE:
166 io->flags = COLOR_SPACE_RGB | IMAGE_ALPHA | IMAGE_IO_HAS_PALETTE;
168 if (png_get_PLTE(rd->png_ptr, rd->info_ptr, NULL, &num_palette))
169 io->number_of_colors = num_palette;
171 io->number_of_colors = 1 << rd->bit_depth;
174 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
175 IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Unknown color type");
180 io->read_cancel = libpng_read_cancel;
185 libpng_read_data(struct image_io *io)
187 DBG("libpng_read_data()");
189 struct libpng_read_data *rd = io->read_data;
191 struct image_io_read_data_internals rdi;
194 if (setjmp(png_jmpbuf(rd->png_ptr)))
196 DBG("Libpng failed to read the image, longjump saved us");
197 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
199 image_io_read_data_break(&rdi, io);
203 uint read_flags = io->flags;
205 /* Apply transformations */
206 if (rd->bit_depth == 16)
207 png_set_strip_16(rd->png_ptr);
208 switch (rd->color_type)
210 case PNG_COLOR_TYPE_PALETTE:
211 if ((read_flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
213 png_set_palette_to_rgb(rd->png_ptr);
214 png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514);
218 png_set_palette_to_rgb(rd->png_ptr);
219 read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB;
221 if (!(read_flags & IMAGE_ALPHA))
223 if (io->flags & IMAGE_IO_USE_BACKGROUND)
225 png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER);
226 read_flags = (read_flags & IMAGE_CHANNELS_FORMAT) | IMAGE_ALPHA;
228 else if ((read_flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
229 png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER);
231 png_set_strip_alpha(rd->png_ptr);
234 png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER);
236 case PNG_COLOR_TYPE_GRAY:
237 if ((read_flags & IMAGE_COLOR_SPACE) != COLOR_SPACE_GRAYSCALE)
239 png_set_gray_to_rgb(rd->png_ptr);
240 read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB;
242 if (read_flags & IMAGE_ALPHA)
243 png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER);
245 case PNG_COLOR_TYPE_GRAY_ALPHA:
246 if ((read_flags & IMAGE_COLOR_SPACE) != COLOR_SPACE_GRAYSCALE)
248 png_set_gray_to_rgb(rd->png_ptr);
249 read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB;
251 if (!(read_flags & IMAGE_ALPHA))
253 if (io->flags & IMAGE_IO_USE_BACKGROUND)
254 read_flags = (read_flags & IMAGE_CHANNELS_FORMAT) | IMAGE_ALPHA;
256 png_set_strip_alpha(rd->png_ptr);
259 case PNG_COLOR_TYPE_RGB:
260 if ((read_flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
261 png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514);
263 read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB;
264 if ((read_flags & IMAGE_ALPHA) || (read_flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
265 png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER);
267 case PNG_COLOR_TYPE_RGB_ALPHA:
268 if ((read_flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
269 png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514);
271 read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB;
272 if (!(read_flags & IMAGE_ALPHA))
273 if (io->flags & IMAGE_IO_USE_BACKGROUND)
274 read_flags = (read_flags & IMAGE_CHANNELS_FORMAT) | IMAGE_ALPHA;
275 else if ((read_flags & IMAGE_PIXEL_FORMAT) != (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
276 png_set_strip_alpha(rd->png_ptr);
281 png_read_update_info(rd->png_ptr, rd->info_ptr);
283 /* Prepare the image */
284 if (unlikely(!image_io_read_data_prepare(&rdi, io, rd->cols, rd->rows, read_flags)))
286 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
289 /* Read image data */
290 DBG("Reading image data");
291 struct image *img = rdi.image;
292 byte *pixels = img->pixels;
293 png_bytep rows[img->rows];
294 for (uint r = 0; r < img->rows; r++, pixels += img->row_size)
295 rows[r] = (png_bytep)pixels;
296 png_read_image(rd->png_ptr, rows);
297 png_read_end(rd->png_ptr, rd->end_ptr);
299 /* Destroy libpng read structure */
300 png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
302 /* Finish the image */
303 return image_io_read_data_finish(&rdi, io);
307 libpng_write(struct image_io *io)
309 DBG("libpng_write()");
311 /* Create libpng structures */
312 png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
313 io->context, libpng_write_error, libpng_warning,
314 io->internal_pool, libpng_malloc, libpng_free);
315 if (unlikely(!png_ptr))
317 IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Cannot create libpng write structure.");
320 png_infop info_ptr = png_create_info_struct(png_ptr);
321 if (unlikely(!info_ptr))
323 IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Cannot create libpng info structure.");
324 png_destroy_write_struct(&png_ptr, NULL);
328 /* Setup libpng longjump */
329 if (unlikely(setjmp(png_jmpbuf(png_ptr))))
331 DBG("Libpng failed to write the image, longjump saved us.");
332 png_destroy_write_struct(&png_ptr, &info_ptr);
336 /* Setup libpng IO */
337 png_set_write_fn(png_ptr, io->fastbuf, libpng_write_fn, libpng_flush_fn);
339 /* Setup PNG parameters */
340 struct image *img = io->image;
341 switch (img->flags & IMAGE_PIXEL_FORMAT)
343 case COLOR_SPACE_GRAYSCALE | IMAGE_PIXELS_ALIGNED:
344 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_GRAY,
345 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
347 case COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA | IMAGE_PIXELS_ALIGNED:
348 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_GRAY_ALPHA,
349 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
351 case COLOR_SPACE_RGB:
352 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB,
353 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
355 case COLOR_SPACE_RGB | IMAGE_ALPHA | IMAGE_PIXELS_ALIGNED:
356 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB_ALPHA,
357 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
359 case COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED:
360 png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB,
361 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
362 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
365 IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Libpng does not support this pixel format (0x%x)", img->flags & IMAGE_PIXEL_FORMAT);
366 png_destroy_write_struct(&png_ptr, &info_ptr);
369 png_write_info(png_ptr, info_ptr);
372 byte *pixels = img->pixels;
373 png_bytep rows[img->rows];
374 for (uint r = 0; r < img->rows; r++, pixels += img->row_size)
375 rows[r] = (png_bytep)pixels;
376 png_write_image(png_ptr, rows);
377 png_write_end(png_ptr, info_ptr);
379 /* Free libpng structure */
380 png_destroy_write_struct(&png_ptr, &info_ptr);