#undef LOCAL_DEBUG
-#include "lib/lib.h"
-#include "lib/mempool.h"
-#include "lib/fastbuf.h"
+#include "ucw/lib.h"
+#include "ucw/mempool.h"
+#include "ucw/fastbuf.h"
#include "images/images.h"
+#include "images/error.h"
+#include "images/color.h"
+#include "images/io-main.h"
+
#include <png.h>
#include <setjmp.h>
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);
}
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);
}
libpng_read_header(struct image_io *io)
{
DBG("libpng_read_header()");
-
+
/* 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;
}
-
+
/* Setup libpng longjump */
if (unlikely(setjmp(png_jmpbuf(rd->png_ptr))))
{
png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
return 0;
}
-
+
/* 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);
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;
- }
+ }
/* Success */
io->read_cancel = libpng_read_cancel;
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;
}
+ uns 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)
/* 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
/* 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;
}
-
+
/* Setup libpng longjump */
if (unlikely(setjmp(png_jmpbuf(png_ptr))))
{
/* Setup libpng IO */
png_set_write_fn(png_ptr, io->fastbuf, libpng_write_fn, libpng_flush_fn);
-
+
/* Setup PNG parameters */
struct image *img = io->image;
switch (img->flags & IMAGE_PIXEL_FORMAT)
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);