X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=images%2Fio-libpng.c;h=e39c8b7efd112128daadadae5cc2d31397705462;hb=1481eca416a467e9952dbc5e4852afe66eaf1256;hp=dbf33d511dd359f97b32dda431782f3e244f0855;hpb=993d8284c9b643b7a0ddc27a67a3f324b3d77aaf;p=libucw.git diff --git a/images/io-libpng.c b/images/io-libpng.c index dbf33d51..e39c8b7e 100644 --- a/images/io-libpng.c +++ b/images/io-libpng.c @@ -9,10 +9,14 @@ #undef LOCAL_DEBUG -#include "lib/lib.h" -#include "lib/mempool.h" -#include "lib/fastbuf.h" -#include "images/images.h" +#include +#include +#include +#include +#include +#include +#include + #include #include @@ -29,7 +33,7 @@ struct libpng_read_data { static png_voidp libpng_malloc(png_structp png_ptr, png_size_t size) { - DBG("libpng_malloc(size=%u)", (uns)size); + DBG("libpng_malloc(size=%u)", (uint)size); return mp_alloc(png_get_mem_ptr(png_ptr), size); } @@ -43,7 +47,7 @@ static void NONRET libpng_read_error(png_structp png_ptr, png_const_charp msg) { DBG("libpng_read_error()"); - image_thread_err_dup(png_get_error_ptr(png_ptr), IMAGE_ERR_READ_FAILED, (byte *)msg); + IMAGE_ERROR(png_get_error_ptr(png_ptr), IMAGE_ERROR_READ_FAILED, "%s", msg); longjmp(png_jmpbuf(png_ptr), 1); } @@ -51,7 +55,7 @@ static void NONRET libpng_write_error(png_structp png_ptr, png_const_charp msg) { DBG("libpng_write_error()"); - image_thread_err_dup(png_get_error_ptr(png_ptr), IMAGE_ERR_WRITE_FAILED, (byte *)msg); + IMAGE_ERROR(png_get_error_ptr(png_ptr), IMAGE_ERROR_WRITE_FAILED, "%s", msg); longjmp(png_jmpbuf(png_ptr), 1); } @@ -64,7 +68,7 @@ libpng_warning(png_structp png_ptr UNUSED, png_const_charp msg UNUSED) static void libpng_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { - DBG("libpng_read_fn(len=%u)", (uns)length); + DBG("libpng_read_fn(len=%u)", (uint)length); if (unlikely(bread((struct fastbuf *)png_get_io_ptr(png_ptr), (byte *)data, length) < length)) png_error(png_ptr, "Incomplete data"); } @@ -72,7 +76,7 @@ libpng_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) static void libpng_write_fn(png_structp png_ptr, png_bytep data, png_size_t length) { - DBG("libpng_write_fn(len=%u)", (uns)length); + DBG("libpng_write_fn(len=%u)", (uint)length); bwrite((struct fastbuf *)png_get_io_ptr(png_ptr), (byte *)data, length); } @@ -99,24 +103,24 @@ libpng_read_header(struct image_io *io) /* Create libpng structures */ struct libpng_read_data *rd = io->read_data = mp_alloc(io->internal_pool, sizeof(*rd)); rd->png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, - io->thread, libpng_read_error, libpng_warning, + io->context, libpng_read_error, libpng_warning, io->internal_pool, libpng_malloc, libpng_free); if (unlikely(!rd->png_ptr)) { - image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libpng read structure."); + IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Cannot create libpng read structure."); return 0; } rd->info_ptr = png_create_info_struct(rd->png_ptr); if (unlikely(!rd->info_ptr)) { - image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libpng info structure."); + IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Cannot create libpng info structure."); png_destroy_read_struct(&rd->png_ptr, NULL, NULL); return 0; } rd->end_ptr = png_create_info_struct(rd->png_ptr); if (unlikely(!rd->end_ptr)) { - image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libpng info structure."); + IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Cannot create libpng info structure."); png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, NULL); return 0; } @@ -131,7 +135,7 @@ libpng_read_header(struct image_io *io) /* Setup libpng IO */ png_set_read_fn(rd->png_ptr, io->fastbuf, libpng_read_fn); - png_set_user_limits(rd->png_ptr, IMAGE_MAX_SIZE, IMAGE_MAX_SIZE); + png_set_user_limits(rd->png_ptr, image_max_dim, image_max_dim); /* Read header */ png_read_info(rd->png_ptr, rd->info_ptr); @@ -143,33 +147,32 @@ libpng_read_header(struct image_io *io) switch (rd->color_type) { case PNG_COLOR_TYPE_GRAY: - io->flags |= COLOR_SPACE_GRAYSCALE; + io->flags = COLOR_SPACE_GRAYSCALE; io->number_of_colors = 1 << 8; break; case PNG_COLOR_TYPE_GRAY_ALPHA: - io->flags |= COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA; + io->flags = COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA; io->number_of_colors = 1 << 8; break; case PNG_COLOR_TYPE_RGB: - io->flags |= COLOR_SPACE_RGB; + io->flags = COLOR_SPACE_RGB; io->number_of_colors = 1 << 24; break; case PNG_COLOR_TYPE_RGB_ALPHA: io->number_of_colors = 1 << 24; - io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA; + io->flags = COLOR_SPACE_RGB | IMAGE_ALPHA; break; case PNG_COLOR_TYPE_PALETTE: - io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA; + io->flags = COLOR_SPACE_RGB | IMAGE_ALPHA | IMAGE_IO_HAS_PALETTE; int num_palette; if (png_get_PLTE(rd->png_ptr, rd->info_ptr, NULL, &num_palette)) io->number_of_colors = num_palette; else io->number_of_colors = 1 << rd->bit_depth; - io->has_palette = 1; break; default: png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr); - image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Unknown color type"); + IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Unknown color type"); break; } @@ -185,89 +188,110 @@ libpng_read_data(struct image_io *io) struct libpng_read_data *rd = io->read_data; - /* Test supported pixel formats */ - switch (io->flags & IMAGE_COLOR_SPACE) - { - case COLOR_SPACE_GRAYSCALE: - case COLOR_SPACE_RGB: - break; - default: - png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr); - image_thread_err(io->thread, IMAGE_ERR_INVALID_PIXEL_FORMAT, "Unsupported color space."); - return 0; - } - - volatile int need_scale = io->cols != rd->cols || io->rows != rd->rows; - struct image * volatile img = need_scale ? - image_new(io->thread, rd->cols, rd->rows, io->flags & IMAGE_PIXEL_FORMAT, NULL) : - image_new(io->thread, rd->cols, rd->rows, io->flags, io->pool); - if (!img) - { - png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr); - return 0; - } + struct image_io_read_data_internals rdi; + rdi.image = NULL; if (setjmp(png_jmpbuf(rd->png_ptr))) { DBG("Libpng failed to read the image, longjump saved us"); png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr); - if (need_scale || !io->pool) - image_destroy(img); + if (rdi.image) + image_io_read_data_break(&rdi, io); return 0; } + uint read_flags = io->flags; + /* Apply transformations */ if (rd->bit_depth == 16) png_set_strip_16(rd->png_ptr); switch (rd->color_type) { case PNG_COLOR_TYPE_PALETTE: - if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE) + if ((read_flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE) { png_set_palette_to_rgb(rd->png_ptr); png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514); } else - png_set_palette_to_rgb(rd->png_ptr); - if ((io->flags & IMAGE_ALPHA) || (io->flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED)) - png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER); + { + png_set_palette_to_rgb(rd->png_ptr); + read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB; + } + if (!(read_flags & IMAGE_ALPHA)) + { + if (io->flags & IMAGE_IO_USE_BACKGROUND) + { + png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER); + read_flags = (read_flags & IMAGE_CHANNELS_FORMAT) | IMAGE_ALPHA; + } + else if ((read_flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED)) + png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER); + else + png_set_strip_alpha(rd->png_ptr); + } else - png_set_strip_alpha(rd->png_ptr); + png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_GRAY: - if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_RGB) - png_set_gray_to_rgb(rd->png_ptr); - if (io->flags & IMAGE_ALPHA) + if ((read_flags & IMAGE_COLOR_SPACE) != COLOR_SPACE_GRAYSCALE) + { + png_set_gray_to_rgb(rd->png_ptr); + read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB; + } + if (read_flags & IMAGE_ALPHA) png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_GRAY_ALPHA: - if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_RGB) - png_set_gray_to_rgb(rd->png_ptr); - if (!(io->flags & IMAGE_ALPHA)) - png_set_strip_alpha(rd->png_ptr); + if ((read_flags & IMAGE_COLOR_SPACE) != COLOR_SPACE_GRAYSCALE) + { + png_set_gray_to_rgb(rd->png_ptr); + read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB; + } + if (!(read_flags & IMAGE_ALPHA)) + { + if (io->flags & IMAGE_IO_USE_BACKGROUND) + read_flags = (read_flags & IMAGE_CHANNELS_FORMAT) | IMAGE_ALPHA; + else + png_set_strip_alpha(rd->png_ptr); + } break; case PNG_COLOR_TYPE_RGB: - if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE) + if ((read_flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE) png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514); - if ((io->flags & IMAGE_ALPHA) || (io->flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED)) + else + read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB; + if ((read_flags & IMAGE_ALPHA) || (read_flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED)) png_set_add_alpha(rd->png_ptr, 255, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_RGB_ALPHA: - if ((io->flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE) + if ((read_flags & IMAGE_COLOR_SPACE) == COLOR_SPACE_GRAYSCALE) png_set_rgb_to_gray_fixed(rd->png_ptr, 1, 21267, 71514); - if (!(io->flags & IMAGE_ALPHA) && (io->flags & IMAGE_PIXEL_FORMAT) != (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED)) - png_set_strip_alpha(rd->png_ptr); + else + read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB; + if (!(read_flags & IMAGE_ALPHA)) + if (io->flags & IMAGE_IO_USE_BACKGROUND) + read_flags = (read_flags & IMAGE_CHANNELS_FORMAT) | IMAGE_ALPHA; + else if ((read_flags & IMAGE_PIXEL_FORMAT) != (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED)) + png_set_strip_alpha(rd->png_ptr); break; default: ASSERT(0); } png_read_update_info(rd->png_ptr, rd->info_ptr); + /* Prepare the image */ + if (unlikely(!image_io_read_data_prepare(&rdi, io, rd->cols, rd->rows, read_flags))) + { + png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr); + return 0; + } /* Read image data */ DBG("Reading image data"); + struct image *img = rdi.image; byte *pixels = img->pixels; png_bytep rows[img->rows]; - for (uns r = 0; r < img->rows; r++, pixels += img->row_size) + for (uint r = 0; r < img->rows; r++, pixels += img->row_size) rows[r] = (png_bytep)pixels; png_read_image(rd->png_ptr, rows); png_read_end(rd->png_ptr, rd->end_ptr); @@ -275,29 +299,8 @@ libpng_read_data(struct image_io *io) /* Destroy libpng read structure */ png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr); - /* Scale and store the resulting image */ - if (need_scale) - { - struct image *dest = image_new(io->thread, io->cols, io->rows, io->flags, io->pool); - if (!dest) - { - image_destroy(img); - return 0; - } - if (!image_scale(io->thread, dest, img)) - { - image_destroy(img); - if (!io->pool) - image_destroy(dest); - return 0; - } - io->image = dest; - } - else - io->image = img; - io->image_destroy = !io->pool; - - return 1; + /* Finish the image */ + return image_io_read_data_finish(&rdi, io); } int @@ -307,17 +310,17 @@ libpng_write(struct image_io *io) /* Create libpng structures */ png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, - io->thread, libpng_write_error, libpng_warning, + io->context, libpng_write_error, libpng_warning, io->internal_pool, libpng_malloc, libpng_free); if (unlikely(!png_ptr)) { - image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "Cannot create libpng write structure."); + IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Cannot create libpng write structure."); return 0; } png_infop info_ptr = png_create_info_struct(png_ptr); if (unlikely(!info_ptr)) { - image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "Cannot create libpng info structure."); + IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Cannot create libpng info structure."); png_destroy_write_struct(&png_ptr, NULL); return 0; } @@ -359,14 +362,16 @@ libpng_write(struct image_io *io) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); break; default: - ASSERT(0); + IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Libpng does not support this pixel format (0x%x)", img->flags & IMAGE_PIXEL_FORMAT); + png_destroy_write_struct(&png_ptr, &info_ptr); + return 0; } png_write_info(png_ptr, info_ptr); /* Write pixels */ byte *pixels = img->pixels; png_bytep rows[img->rows]; - for (uns r = 0; r < img->rows; r++, pixels += img->row_size) + for (uint r = 0; r < img->rows; r++, pixels += img->row_size) rows[r] = (png_bytep)pixels; png_write_image(png_ptr, rows); png_write_end(png_ptr, info_ptr);