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_internals {
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_error(png_structp png_ptr, png_const_charp msg)
45 DBG("libpng_error()");
46 image_thread_err(png_get_error_ptr(png_ptr), IMAGE_ERR_READ_FAILED, (byte *)msg);
47 longjmp(png_jmpbuf(png_ptr), 1);
51 libpng_warning(png_structp png_ptr UNUSED, png_const_charp msg UNUSED)
53 DBG("libpng_warning(): %s", (byte *)msg);
57 libpng_read(png_structp png_ptr, png_bytep data, png_size_t length)
59 DBG("libpng_read(): len=%d", (uns)length);
60 if (unlikely(bread(png_get_io_ptr(png_ptr), data, length) < length))
61 png_error(png_ptr, "Incomplete data");
65 libpng_read_cancel(struct image_io *io)
67 DBG("libpng_read_cancel()");
68 struct libpng_internals *i = io->read_data;
69 png_destroy_read_struct(&i->png_ptr, &i->info_ptr, &i->end_ptr);
73 libpng_read_header(struct image_io *io)
75 DBG("libpng_read_header()");
76 struct libpng_internals *i = io->read_data = mp_alloc(io->internal_pool, sizeof(*i));
77 i->png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
78 io->thread, libpng_error, libpng_warning,
79 io->internal_pool, libpng_malloc, libpng_free);
80 if (unlikely(!i->png_ptr))
82 i->info_ptr = png_create_info_struct(i->png_ptr);
83 if (unlikely(!i->info_ptr))
85 png_destroy_read_struct(&i->png_ptr, NULL, NULL);
88 i->end_ptr = png_create_info_struct(i->png_ptr);
89 if (unlikely(!i->end_ptr))
91 png_destroy_read_struct(&i->png_ptr, &i->info_ptr, NULL);
94 if (setjmp(png_jmpbuf(i->png_ptr)))
96 DBG("Libpng failed to read the image, longjump saved us");
97 png_destroy_read_struct(&i->png_ptr, &i->info_ptr, &i->end_ptr);
100 png_set_read_fn(i->png_ptr, io->fastbuf, libpng_read);
101 png_set_user_limits(i->png_ptr, 0xffff, 0xffff);
103 DBG("Reading image info");
104 png_read_info(i->png_ptr, i->info_ptr);
105 png_get_IHDR(i->png_ptr, i->info_ptr, &i->cols, &i->rows, &i->bit_depth, &i->color_type, NULL, NULL, NULL);
111 if (!(io->flags & IMAGE_CHANNELS_FORMAT))
112 switch (i->color_type)
114 case PNG_COLOR_TYPE_GRAY:
115 io->flags |= COLOR_SPACE_GRAYSCALE;
117 case PNG_COLOR_TYPE_GRAY_ALPHA:
118 io->flags |= COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
120 case PNG_COLOR_TYPE_RGB:
121 io->flags |= COLOR_SPACE_RGB;
123 case PNG_COLOR_TYPE_RGB_ALPHA:
124 case PNG_COLOR_TYPE_PALETTE:
125 io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA;
128 png_destroy_read_struct(&i->png_ptr, &i->info_ptr, &i->end_ptr);
129 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Unknown color type");
133 io->read_cancel = libpng_read_cancel;
137 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libpng read structure.");
142 libpng_read_data(struct image_io *io)
144 DBG("libpng_read_data()");
146 struct libpng_internals *i = io->read_data;
148 /* Test supported pixel formats */
149 switch (io->flags & IMAGE_COLOR_SPACE)
151 case COLOR_SPACE_GRAYSCALE:
152 case COLOR_SPACE_RGB:
155 png_destroy_read_struct(&i->png_ptr, &i->info_ptr, &i->end_ptr);
156 image_thread_err(io->thread, IMAGE_ERR_INVALID_PIXEL_FORMAT, "Unsupported color space.");
160 volatile int need_scale = io->cols != i->cols || io->rows != i->rows;
161 struct image * volatile img = need_scale ?
162 image_new(io->thread, i->cols, i->rows, io->flags & IMAGE_PIXEL_FORMAT, NULL) :
163 image_new(io->thread, i->cols, i->rows, io->flags, io->pool);
166 png_destroy_read_struct(&i->png_ptr, &i->info_ptr, &i->end_ptr);
170 if (setjmp(png_jmpbuf(i->png_ptr)))
172 DBG("Libpng failed to read the image, longjump saved us");
173 png_destroy_read_struct(&i->png_ptr, &i->info_ptr, &i->end_ptr);
174 if (need_scale || !io->pool)
175 image_destroy(io->thread, img);
179 /* Apply transformations */
180 if (i->bit_depth == 16)
181 png_set_strip_16(i->png_ptr);
182 switch (i->color_type)
184 case PNG_COLOR_TYPE_PALETTE:
185 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
187 png_set_palette_to_rgb(i->png_ptr);
188 png_set_rgb_to_gray_fixed(i->png_ptr, 1, 21267, 71514);
191 png_set_palette_to_rgb(i->png_ptr);
192 if ((io->flags & IMAGE_ALPHA) || (io->flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
193 png_set_add_alpha(i->png_ptr, 255, PNG_FILLER_AFTER);
195 png_set_strip_alpha(i->png_ptr);
197 case PNG_COLOR_TYPE_GRAY:
198 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_RGB)
199 png_set_gray_to_rgb(i->png_ptr);
200 if (io->flags & IMAGE_ALPHA)
201 png_set_add_alpha(i->png_ptr, 255, PNG_FILLER_AFTER);
203 case PNG_COLOR_TYPE_GRAY_ALPHA:
204 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_RGB)
205 png_set_gray_to_rgb(i->png_ptr);
206 if (!(io->flags & IMAGE_ALPHA))
207 png_set_strip_alpha(i->png_ptr);
209 case PNG_COLOR_TYPE_RGB:
210 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
211 png_set_rgb_to_gray_fixed(i->png_ptr, 1, 21267, 71514);
212 if ((io->flags & IMAGE_ALPHA) || (io->flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
213 png_set_add_alpha(i->png_ptr, 255, PNG_FILLER_AFTER);
215 case PNG_COLOR_TYPE_RGB_ALPHA:
216 if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE)
217 png_set_rgb_to_gray_fixed(i->png_ptr, 1, 21267, 71514);
218 if (!(io->flags & IMAGE_ALPHA) && (io->flags & IMAGE_PIXEL_FORMAT) != (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
219 png_set_strip_alpha(i->png_ptr);
224 png_read_update_info(i->png_ptr, i->info_ptr);
226 /* Read image data */
227 DBG("Reading image data");
228 byte *pixels = img->pixels;
229 png_bytep rows[img->rows];
230 for (uns r = 0; r < img->rows; r++, pixels += img->row_size)
231 rows[r] = (png_bytep)pixels;
232 png_read_image(i->png_ptr, rows);
233 png_read_end(i->png_ptr, i->end_ptr);
235 /* Destroy libpng read structure */
236 png_destroy_read_struct(&i->png_ptr, &i->info_ptr, &i->end_ptr);
238 /* Scale and store the resulting image */
241 struct image *dest = image_new(io->thread, io->cols, io->rows, io->flags, io->pool);
244 image_destroy(io->thread, img);
247 if (!image_scale(io->thread, dest, img))
249 image_destroy(io->thread, img);
251 image_destroy(io->thread, dest);
258 io->image_destroy = !io->pool;
264 libpng_write(struct image_io *io)
266 image_thread_err(io->thread, IMAGE_ERR_NOT_IMPLEMENTED, "Libpng writing not implemented.");