]> mj.ucw.cz Git - libucw.git/blobdiff - images/io-libpng.c
Released as 6.5.16.
[libucw.git] / images / io-libpng.c
index f15955a64cf83c045bd953cb1afa33fd96908b96..e39c8b7efd112128daadadae5cc2d31397705462 100644 (file)
@@ -9,11 +9,14 @@
 
 #undef LOCAL_DEBUG
 
-#include "lib/lib.h"
-#include "lib/mempool.h"
-#include "lib/fastbuf.h"
-#include "images/images.h"
-#include "images/io-main.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>
 
@@ -30,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);
 }
 
@@ -44,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);
 }
 
@@ -52,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);
 }
 
@@ -65,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");
 }
@@ -73,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);
 }
 
@@ -100,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;
     }
@@ -132,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);
@@ -169,7 +172,7 @@ libpng_read_header(struct image_io *io)
         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,18 +188,6 @@ 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;
-    }
-
   struct image_io_read_data_internals rdi;
   rdi.image = NULL;
 
@@ -209,29 +200,32 @@ libpng_read_data(struct image_io *io)
       return 0;
     }
 
-  uns read_flags = io->flags;
-  
+  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))
+         {
+           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_ALPHA) & IMAGE_CHANNELS_FORMAT;
+               read_flags = (read_flags & IMAGE_CHANNELS_FORMAT) | IMAGE_ALPHA;
              }
-           else if ((io->flags & IMAGE_PIXEL_FORMAT) == (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
+           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);
@@ -240,35 +234,45 @@ libpng_read_data(struct image_io *io)
           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))
+       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_ALPHA) & IMAGE_CHANNELS_FORMAT;
+             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))
+       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_ALPHA) & IMAGE_CHANNELS_FORMAT;
-         else if ((io->flags & IMAGE_PIXEL_FORMAT) != (COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED))
+           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:
@@ -287,7 +291,7 @@ libpng_read_data(struct image_io *io)
   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);
@@ -306,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;
     }
@@ -358,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);