]> mj.ucw.cz Git - libucw.git/commitdiff
added support for some color conversions; we should be able to load cmyk
authorPavel Charvat <pavel.charvat@netcentrum.cz>
Thu, 2 Nov 2006 23:06:50 +0000 (00:06 +0100)
committerPavel Charvat <pavel.charvat@netcentrum.cz>
Thu, 2 Nov 2006 23:06:50 +0000 (00:06 +0100)
jpegs now...

14 files changed:
images/Makefile
images/alpha.c [deleted file]
images/color.c
images/color.h
images/image-tool.c
images/image-walk.h
images/image.c
images/images.h
images/io-libjpeg.c
images/io-libmagick.c
images/io-libpng.c
images/io-libungif.c
images/io-main.c
images/math.h

index 5953519acf77cf81d017d311690100a5386818fc..db62a9a77bb0517538a118fdcadd952f0f90dac8 100644 (file)
@@ -4,7 +4,7 @@ DIRS+=images
 
 PROGS+=$(o)/images/image-tool $(o)/images/color-tool
 CONFIGS+=images
-LIBIMAGES_MODS=math config context image scale color alpha io-main object
+LIBIMAGES_MODS=math config context image scale color io-main object
 
 ifdef CONFIG_IMAGES_DUP
 PROGS+=$(o)/images/image-dup-test
diff --git a/images/alpha.c b/images/alpha.c
deleted file mode 100644 (file)
index d97207e..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *     Image Library -- Alpha channels
- *
- *     (c) 2006 Pavel Charvat <pchar@ucw.cz>
- *
- *     This software may be freely distributed and used according to the terms
- *     of the GNU Lesser General Public License.
- */
-
-#undef LOCAL_DEBUG
-
-#include "lib/lib.h"
-#include "images/images.h"
-#include "images/color.h"
-
-static inline uns
-merge_func(uns value, uns alpha, uns acoef, uns bcoef)
-{
-  return ((uns)(acoef + (int)alpha * (int)(value - bcoef)) * (0xffffffffU / 255 / 255)) >> 24;
-}
-
-int
-image_apply_background(struct image_context *ctx UNUSED, struct image *dest, struct image *src, struct color *background)
-{
-  DBG("image_apply_background()");
-
-  /* Grayscale */
-  if (src->pixel_size == 2)
-    {
-      ASSERT(dest->pixel_size == 1);
-      byte bg;
-      if (background->color_space)
-        color_put_grayscale(&bg, background);
-      else
-       bg = 0;
-      uns a = 255 * bg, b = bg;
-#     define IMAGE_WALK_PREFIX(x) walk_##x
-#     define IMAGE_WALK_INLINE
-#     define IMAGE_WALK_DOUBLE
-#     define IMAGE_WALK_UNROLL 4
-#     define IMAGE_WALK_IMAGE dest
-#     define IMAGE_WALK_SEC_IMAGE src
-#     define IMAGE_WALK_COL_STEP 1
-#     define IMAGE_WALK_SEC_COL_STEP 2
-#     define IMAGE_WALK_DO_STEP do{ walk_pos[0] = merge_func(walk_sec_pos[0], walk_sec_pos[1], a, b); }while(0)
-#     include "images/image-walk.h"
-    }
-
-  /* RGBA to RGB or aligned RGB */
-  else if (src->pixel_size == 4)
-    {
-      ASSERT((src->flags & IMAGE_ALPHA) && dest->pixel_size >= 3 && !(dest->flags & IMAGE_ALPHA));
-      byte bg[3];
-      if (background->color_space)
-        color_put_rgb(bg, background);
-      else
-       bg[0] = bg[1] = bg[2] = 0;
-      uns a0 = 255 * bg[0], b0 = bg[0];
-      uns a1 = 255 * bg[1], b1 = bg[1];
-      uns a2 = 255 * bg[2], b2 = bg[2];
-#     define IMAGE_WALK_PREFIX(x) walk_##x
-#     define IMAGE_WALK_INLINE
-#     define IMAGE_WALK_DOUBLE
-#     define IMAGE_WALK_UNROLL 2
-#     define IMAGE_WALK_IMAGE dest
-#     define IMAGE_WALK_SEC_IMAGE src
-#     define IMAGE_WALK_SEC_COL_STEP 4
-#     define IMAGE_WALK_DO_STEP do{ \
-         walk_pos[0] = merge_func(walk_sec_pos[0], walk_sec_pos[3], a0, b0); \
-         walk_pos[1] = merge_func(walk_sec_pos[1], walk_sec_pos[3], a1, b1); \
-         walk_pos[2] = merge_func(walk_sec_pos[2], walk_sec_pos[3], a2, b2); \
-       }while(0)
-#     include "images/image-walk.h"
-    }
-  else
-    ASSERT(0);
-  return 1;
-}
index 7dd3773cdf3cfabd92ef7d850f5aaf005d9c9a35..193a0f138477d313734c410901cbc4d2bfc0ff40 100644 (file)
@@ -13,6 +13,8 @@
 #include "lib/math.h"
 #include "images/images.h"
 #include "images/color.h"
+#include "images/error.h"
+#include "images/math.h"
 
 #include <string.h>
 
@@ -57,7 +59,7 @@ uns
 color_space_name_to_id(byte *name)
 {
   for (uns i = 1; i < COLOR_SPACE_MAX; i++)
-    if (!strcasecmp(name, color_space_name[i]))
+    if (color_space_name[i] && !strcasecmp(name, color_space_name[i]))
       return i;
   return 0;
 }
@@ -65,54 +67,571 @@ color_space_name_to_id(byte *name)
 struct color color_black = { .color_space = COLOR_SPACE_GRAYSCALE };
 struct color color_white = { .c = { 255 }, .color_space = COLOR_SPACE_GRAYSCALE };
 
-inline void
-color_put_grayscale(byte *dest, struct color *color)
+int
+color_get(struct color *color, byte *src, uns src_space)
+{
+  color->color_space = src_space;
+  memcpy(color->c, src, color_space_channels[src_space]);
+  return 1;
+}
+
+int
+color_put(struct image_context *ctx, struct color *color, byte *dest, uns dest_space)
 {
-  switch (color->color_space)
+  switch (dest_space)
     {
       case COLOR_SPACE_GRAYSCALE:
-       dest[0] = color->c[0];
+       switch (color->color_space)
+         {
+            case COLOR_SPACE_GRAYSCALE:
+             dest[0] = color->c[0];
+             return 1;
+            case COLOR_SPACE_RGB:
+             dest[0] = rgb_to_gray_func(color->c[0], color->c[1], color->c[2]);
+             return 1;
+         }
        break;
       case COLOR_SPACE_RGB:
-       dest[0] = rgb_to_gray_func(color->c[0], color->c[1], color->c[2]);
+        switch (color->color_space)
+          {
+            case COLOR_SPACE_GRAYSCALE:
+             dest[0] = dest[1] = dest[2] = color->c[0];
+             return 1;
+            case COLOR_SPACE_RGB:
+             dest[0] = color->c[0];
+             dest[1] = color->c[1];
+             dest[2] = color->c[2];
+             return 1;
+           case COLOR_SPACE_CMYK:
+             {
+               double rgb[3], cmyk[4];
+               for (uns i = 0; i < 4; i++)
+                 cmyk[i] = color->c[i] * (1.0 / 255);
+               cmyk_to_rgb_exact(rgb, cmyk);
+               for (uns i = 0; i < 3; i++)
+                 dest[i] = CLAMP(rgb[i] * 255, 0, 255);
+             }
+             return 1;
+          }
+       break;
+      case COLOR_SPACE_CMYK:
+       switch (color->color_space)
+         {
+           case COLOR_SPACE_GRAYSCALE:
+             dest[0] = dest[1] = dest[2] = 0;
+             dest[3] = 255 - color->c[0];
+             return 1;
+           case COLOR_SPACE_RGB:
+             {
+               double rgb[3], cmyk[4];
+               for (uns i = 0; i < 3; i++)
+                 rgb[i] = color->c[i] * (1.0 / 255);
+               rgb_to_cmyk_exact(cmyk, rgb);
+               for (uns i = 0; i < 4; i++)
+                 dest[i] = CLAMP(cmyk[i] * 255, 0, 255);
+             }
+             return 1;
+         }
        break;
-      default:
-       ASSERT(0);
     }
+  if (dest_space != COLOR_SPACE_RGB )
+    {
+      /* Try to convert the color via RGB */
+      struct color rgb;
+      if (!color_put(ctx, color, rgb.c, COLOR_SPACE_RGB))
+       return 0;
+      rgb.color_space = COLOR_SPACE_RGB;
+      return color_put(ctx, &rgb, dest, dest_space);
+    }
+  IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Conversion from %s to %s is not supported",
+      color_space_id_to_name(color->color_space), color_space_id_to_name(color->color_space));
+  return 0;
 }
 
-inline void
-color_put_rgb(byte *dest, struct color *color)
+
+/********************* IMAGE CONVERSION ROUTINES **********************/
+
+struct image_conv_options image_conv_defaults = {
+  .flags = IMAGE_CONV_COPY_ALPHA | IMAGE_CONV_FILL_ALPHA | IMAGE_CONV_APPLY_ALPHA,
+  .background = { .color_space = COLOR_SPACE_GRAYSCALE } };
+  
+/* Grayscale <-> RGB */
+
+#define IMAGE_WALK_PREFIX(x) walk_##x
+#define IMAGE_WALK_FUNC_NAME image_conv_gray_1_to_rgb_n
+#define IMAGE_WALK_DOUBLE
+#define IMAGE_WALK_SEC_COL_STEP 1
+#define IMAGE_WALK_UNROLL 4
+#define IMAGE_WALK_DO_STEP do{ walk_pos[0] = walk_pos[1] = walk_pos[2] = walk_sec_pos[0]; }while(0)
+#include "images/image-walk.h"
+
+#define IMAGE_WALK_PREFIX(x) walk_##x
+#define IMAGE_WALK_FUNC_NAME image_conv_rgb_n_to_gray_1
+#define IMAGE_WALK_DOUBLE
+#define IMAGE_WALK_COL_STEP 1
+#define IMAGE_WALK_UNROLL 2
+#define IMAGE_WALK_DO_STEP do{ walk_pos[0] = rgb_to_gray_func(walk_sec_pos[0], walk_sec_pos[1], walk_sec_pos[2]); }while(0)
+#include "images/image-walk.h"
+
+/* YCbCr <-> RGB */
+
+static inline void
+pixel_conv_ycbcr_to_rgb(byte *dest, byte *src)
+{
+  /* R = Y                + 1.40200 * Cr
+   * G = Y - 0.34414 * Cb - 0.71414 * Cr
+   * B = Y + 1.77200 * Cb */
+  int y = src[0], cb = src[1] - 128, cr = src[2] - 128;
+  dest[0] = CLAMP(y + (91881 * cr) / 0x10000, 0, 255);
+  dest[1] = CLAMP(y - (22553 * cb + 46801 * cr) / 0x10000, 0, 255);
+  dest[2] = CLAMP(y + (116129 * cb) / 0x10000, 0, 255);
+}
+
+#define IMAGE_WALK_PREFIX(x) walk_##x
+#define IMAGE_WALK_FUNC_NAME image_conv_ycbcr_n_to_rgb_n
+#define IMAGE_WALK_DOUBLE
+#define IMAGE_WALK_DO_STEP do{ pixel_conv_ycbcr_to_rgb(walk_pos, walk_sec_pos); }while(0)
+#include "images/image-walk.h"
+
+static inline void
+pixel_conv_rgb_to_ycbcr(byte *dest, byte *src)
+{
+  /* Y  =  0.29900 * R + 0.58700 * G + 0.11400 * B
+   * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTER
+   * Cr =  0.50000 * R - 0.41869 * G - 0.08131 * B + CENTER */
+  uns r = src[0], g = src[1], b = src[2];
+  dest[0] = (19595 * r + 38470 * g + 7471 * b) / 0x10000;
+  dest[1] = (0x800000 + 0x8000 * b - 11058 * r - 21710 * g) / 0x10000;
+  dest[2] = (0x800000 + 0x8000 * r - 27439 * g - 5329 * b) / 0x10000;
+}
+
+#define IMAGE_WALK_PREFIX(x) walk_##x
+#define IMAGE_WALK_FUNC_NAME image_conv_rgb_n_to_ycbcr_n
+#define IMAGE_WALK_DOUBLE
+#define IMAGE_WALK_DO_STEP do{ pixel_conv_rgb_to_ycbcr(walk_pos, walk_sec_pos); }while(0)
+#include "images/image-walk.h"
+
+/* CMYK <-> RGB */
+
+static inline void
+pixel_conv_cmyk_to_rgb(byte *dest, byte *src)
 {
-  switch (color->color_space)
+  uns d = (255 - src[3]) * (0xffffffffU / 255 /255);
+  dest[0] = d * (255 - src[0]) >> 24;
+  dest[1] = d * (255 - src[1]) >> 24;
+  dest[2] = d * (255 - src[2]) >> 24;
+}
+
+#define IMAGE_WALK_PREFIX(x) walk_##x
+#define IMAGE_WALK_FUNC_NAME image_conv_cmyk_4_to_rgb_n
+#define IMAGE_WALK_DOUBLE
+#define IMAGE_WALK_SEC_COL_STEP 4
+#define IMAGE_WALK_DO_STEP do{ pixel_conv_cmyk_to_rgb(walk_pos, walk_sec_pos); }while(0)
+#include "images/image-walk.h"
+
+static inline void
+pixel_conv_rgb_to_cmyk(byte *dest, byte *src)
+{
+  uns k = MAX(src[0], src[1]);
+  k = MAX(k, src[2]);
+  uns d = fast_div_u32_u8(0x7fffffffU, k); /* == 0 for zero K */
+  dest[0] = (d * (k - src[0])) >> 23;
+  dest[1] = (d * (k - src[1])) >> 23;
+  dest[2] = (d * (k - src[2])) >> 23;
+  dest[3] = 255 - k;
+}
+
+#define IMAGE_WALK_PREFIX(x) walk_##x
+#define IMAGE_WALK_FUNC_NAME image_conv_rgb_n_to_cmyk_4
+#define IMAGE_WALK_DOUBLE
+#define IMAGE_WALK_COL_STEP 4
+#define IMAGE_WALK_DO_STEP do{ pixel_conv_rgb_to_cmyk(walk_pos, walk_sec_pos); }while(0)
+#include "images/image-walk.h"
+
+/* Main functions */
+
+static int
+image_conv_color_space(struct image_context *ctx UNUSED, struct image *dest, struct image *src, struct image_conv_options *opt UNUSED)
+{
+  switch (dest->flags & IMAGE_COLOR_SPACE)
     {
       case COLOR_SPACE_GRAYSCALE:
-       dest[0] = dest[1] = dest[2] = color->c[0];
+        switch (src->flags & IMAGE_COLOR_SPACE)
+          {
+           case COLOR_SPACE_RGB:
+             if (dest->pixel_size == 1)
+               {
+                 image_conv_rgb_n_to_gray_1(dest, src);
+                 return 1;
+               }
+             break;
+         }
        break;
       case COLOR_SPACE_RGB:
-       dest[0] = color->c[0];
-       dest[1] = color->c[1];
-       dest[2] = color->c[2];
+       switch (src->flags & IMAGE_CHANNELS_FORMAT)
+         {
+           case COLOR_SPACE_GRAYSCALE:
+             if (src->pixel_size == 1)
+               {
+                 image_conv_gray_1_to_rgb_n(dest, src);
+                 return 1;
+               }
+             break;
+           case COLOR_SPACE_YCBCR:
+             image_conv_ycbcr_n_to_rgb_n(dest, src);
+             return 1;
+           case COLOR_SPACE_CMYK:
+             if (src->pixel_size == 4)
+               {
+                 image_conv_cmyk_4_to_rgb_n(dest, src);
+                 return 1;
+               }
+             break;
+       }
        break;
-      default:
-       ASSERT(0);
+      case COLOR_SPACE_YCBCR:
+        switch (src->flags & IMAGE_CHANNELS_FORMAT)
+         {
+           case COLOR_SPACE_RGB:
+             image_conv_rgb_n_to_ycbcr_n(dest, src);
+             return 1;
+         }
+       break;
+      case COLOR_SPACE_CMYK:
+        switch (src->flags & IMAGE_CHANNELS_FORMAT)
+          {
+           case COLOR_SPACE_RGB:
+             if (dest->pixel_size == 4)
+               {
+                 image_conv_rgb_n_to_cmyk_4(dest, src);
+                 return 1;
+               }
+             break;
+          }
+        break;
     }
+  return 0;
 }
 
-void
-color_put_color_space(byte *dest, struct color *color, uns color_space)
+static void
+image_conv_copy(struct image *dest, struct image *src)
+{
+  if (dest->pixels == src->pixels)
+    return;
+  else if (dest->pixel_size != src->pixel_size)
+    {
+      uns channels = MIN(dest->channels, src->channels);
+      switch (channels)
+        {
+         case 1:
+           {
+#            define IMAGE_WALK_PREFIX(x) walk_##x
+#            define IMAGE_WALK_INLINE
+#            define IMAGE_WALK_DOUBLE
+#             define IMAGE_WALK_IMAGE dest
+#             define IMAGE_WALK_SEC_IMAGE src
+#            define IMAGE_WALK_UNROLL 4
+#            define IMAGE_WALK_DO_STEP do{ walk_pos[0] = walk_sec_pos[0]; }while(0)
+#            include "images/image-walk.h"
+            }
+           return;
+         case 2:
+#            define IMAGE_WALK_PREFIX(x) walk_##x
+#            define IMAGE_WALK_INLINE
+#            define IMAGE_WALK_DOUBLE
+#             define IMAGE_WALK_IMAGE dest
+#             define IMAGE_WALK_SEC_IMAGE src
+#            define IMAGE_WALK_UNROLL 4
+#            define IMAGE_WALK_DO_STEP do{ walk_pos[0] = walk_sec_pos[0]; walk_pos[1] = walk_sec_pos[1]; }while(0)
+#            include "images/image-walk.h"
+           return;
+         case 3:
+#            define IMAGE_WALK_PREFIX(x) walk_##x
+#            define IMAGE_WALK_INLINE
+#            define IMAGE_WALK_DOUBLE
+#             define IMAGE_WALK_IMAGE dest
+#             define IMAGE_WALK_SEC_IMAGE src
+#            define IMAGE_WALK_UNROLL 2
+#            define IMAGE_WALK_DO_STEP do{ walk_pos[0] = walk_sec_pos[0]; walk_pos[1] = walk_sec_pos[1]; walk_pos[2] = walk_sec_pos[2]; }while(0)
+#            include "images/image-walk.h"
+           return;
+         case 4:
+#            define IMAGE_WALK_PREFIX(x) walk_##x
+#            define IMAGE_WALK_INLINE
+#            define IMAGE_WALK_DOUBLE
+#             define IMAGE_WALK_IMAGE dest
+#             define IMAGE_WALK_SEC_IMAGE src
+#            define IMAGE_WALK_UNROLL 2
+#            define IMAGE_WALK_DO_STEP do{ walk_pos[0] = walk_sec_pos[0]; walk_pos[1] = walk_sec_pos[1]; walk_pos[2] = walk_sec_pos[2]; walk_pos[3] = walk_sec_pos[3]; }while(0)
+#            include "images/image-walk.h"
+           return;
+         default:
+#            define IMAGE_WALK_PREFIX(x) walk_##x
+#            define IMAGE_WALK_INLINE
+#            define IMAGE_WALK_DOUBLE
+#             define IMAGE_WALK_IMAGE dest
+#             define IMAGE_WALK_SEC_IMAGE src
+#            define IMAGE_WALK_DO_STEP do{ for (uns i = 0; i < channels; i++) walk_pos[i] = walk_sec_pos[i]; }while(0)
+#             include "images/image-walk.h"
+           return;
+       }
+    }
+  else if (dest->row_size != src->row_size || ((dest->flags | src->flags) & IMAGE_GAPS_PROTECTED))
+    {
+      byte *s = src->pixels;
+      byte *d = dest->pixels;
+      for (uns row = src->rows; row--; )
+        {
+          memcpy(d, s, src->row_pixels_size);
+          d += dest->row_size;
+          s += src->row_size;
+        }
+    }
+  else if (dest->pixels != src->pixels)
+    memcpy(dest->pixels, src->pixels, src->image_size);
+}
+
+static void
+image_conv_fill_alpha(struct image *dest)
 {
-  switch (color_space)
+  switch (dest->channels)
     {
-      case COLOR_SPACE_GRAYSCALE:
-       color_put_grayscale(dest, color);
+      case 2:
+       if (dest->pixel_size == 2)
+         {
+#           define IMAGE_WALK_PREFIX(x) walk_##x
+#           define IMAGE_WALK_INLINE
+#           define IMAGE_WALK_IMAGE dest
+#           define IMAGE_WALK_COL_STEP 2
+#           define IMAGE_WALK_UNROLL 4
+#           define IMAGE_WALK_DO_STEP do{ walk_pos[1] = 255; }while(0)
+#           include "images/image-walk.h"
+           return;
+         }
        break;
-      case COLOR_SPACE_RGB:
-       color_put_rgb(dest, color);
+      case 4:
+       if (dest->pixel_size == 4)
+         {
+#           define IMAGE_WALK_PREFIX(x) walk_##x
+#           define IMAGE_WALK_INLINE
+#           define IMAGE_WALK_IMAGE dest
+#           define IMAGE_WALK_COL_STEP 4
+#           define IMAGE_WALK_UNROLL 4
+#           define IMAGE_WALK_DO_STEP do{ walk_pos[3] = 255; }while(0)
+#           include "images/image-walk.h"
+           return;
+         }
        break;
-      default:
-       ASSERT(0);
     }
+  {
+#   define IMAGE_WALK_PREFIX(x) walk_##x
+#   define IMAGE_WALK_INLINE
+#   define IMAGE_WALK_IMAGE dest
+#   define IMAGE_WALK_UNROLL 4
+#   define IMAGE_WALK_DO_STEP do{ walk_pos[dest->channels - 1] = 255; }while(0)
+#   include "images/image-walk.h"
+  }
+}
+
+static void
+image_conv_copy_alpha(struct image *dest, struct image *src)
+{
+  if (dest->pixels != src->pixels || dest->channels != src->channels)
+    {
+#     define IMAGE_WALK_PREFIX(x) walk_##x
+#     define IMAGE_WALK_INLINE
+#     define IMAGE_WALK_DOUBLE
+#     define IMAGE_WALK_IMAGE dest
+#     define IMAGE_WALK_SEC_IMAGE src
+#     define IMAGE_WALK_UNROLL 4
+#     define IMAGE_WALK_DO_STEP do{ walk_pos[dest->channels - 1] = walk_sec_pos[src->channels - 1]; }while(0)
+#     include "images/image-walk.h"
+    }
+}
+
+static inline uns
+image_conv_alpha_func(uns value, uns alpha, uns acoef, uns bcoef)
+{
+  return ((uns)(acoef + (int)alpha * (int)(value - bcoef)) * (0xffffffffU / 255 / 255)) >> 24;
+}
+
+static int
+image_conv_apply_alpha_from(struct image_context *ctx, struct image *dest, struct image *src, struct image_conv_options *opt)
+{
+  if (!opt->background.color_space)
+    return 1;
+  byte background[IMAGE_MAX_CHANNELS];
+  if (unlikely(!color_put(ctx, &opt->background, background, dest->flags & IMAGE_COLOR_SPACE)))
+    return 0;
+  uns a[IMAGE_MAX_CHANNELS], b[IMAGE_MAX_CHANNELS];
+  for (uns i = 0; i < dest->channels; i++)
+    a[i] = 255 * (b[i] = background[i]);
+  switch (dest->channels)
+    {
+      case 1:
+       {
+#         define IMAGE_WALK_PREFIX(x) walk_##x
+#         define IMAGE_WALK_INLINE
+#         define IMAGE_WALK_IMAGE dest
+#         define IMAGE_WALK_SEC_IMAGE src
+#         define IMAGE_WALK_DOUBLE
+#        define IMAGE_WALK_UNROLL 2
+#         define IMAGE_WALK_DO_STEP do{ \
+              walk_pos[0] = image_conv_alpha_func(walk_pos[0], walk_sec_pos[src->channels - 1], a[0], b[0]); }while(0)
+#         include "images/image-walk.h"
+       }
+       return 1;
+      case 3:
+       {
+#         define IMAGE_WALK_PREFIX(x) walk_##x
+#         define IMAGE_WALK_INLINE
+#         define IMAGE_WALK_IMAGE dest
+#         define IMAGE_WALK_SEC_IMAGE src
+#         define IMAGE_WALK_DOUBLE
+#         define IMAGE_WALK_DO_STEP do{ \
+              walk_pos[0] = image_conv_alpha_func(walk_pos[0], walk_sec_pos[src->channels - 1], a[0], b[0]); \
+              walk_pos[1] = image_conv_alpha_func(walk_pos[1], walk_sec_pos[src->channels - 1], a[1], b[1]); \
+              walk_pos[2] = image_conv_alpha_func(walk_pos[2], walk_sec_pos[src->channels - 1], a[2], b[2]); }while(0)
+#         include "images/image-walk.h"
+       }
+       return 1;
+    }
+  {
+#   define IMAGE_WALK_PREFIX(x) walk_##x
+#   define IMAGE_WALK_INLINE
+#   define IMAGE_WALK_IMAGE dest
+#   define IMAGE_WALK_SEC_IMAGE src
+#   define IMAGE_WALK_DOUBLE
+#   define IMAGE_WALK_DO_STEP do{ for (uns i = 0; i < dest->channels; i++) \
+        walk_pos[i] = image_conv_alpha_func(walk_pos[i], walk_sec_pos[src->channels - 1], a[i], b[i]); }while(0)
+#   include "images/image-walk.h"
+  }
+  return 1;
+}
+
+static int
+image_conv_apply_alpha_to(struct image_context *ctx, struct image *dest, struct image *src, struct image_conv_options *opt)
+{
+  if (!opt->background.color_space)
+    {
+      image_conv_copy(dest, src);
+      return 1;
+    }
+  byte background[IMAGE_MAX_CHANNELS];
+  if (unlikely(!color_put(ctx, &opt->background, background, dest->flags & IMAGE_COLOR_SPACE)))
+    return 0;
+  uns a[IMAGE_MAX_CHANNELS], b[IMAGE_MAX_CHANNELS];
+  for (uns i = 0; i < dest->channels; i++)
+    a[i] = 255 * (b[i] = background[i]);
+  switch (dest->channels)
+    {
+      case 1:
+       {
+#         define IMAGE_WALK_PREFIX(x) walk_##x
+#         define IMAGE_WALK_INLINE
+#         define IMAGE_WALK_IMAGE dest
+#         define IMAGE_WALK_SEC_IMAGE src
+#         define IMAGE_WALK_DOUBLE
+#        define IMAGE_WALK_UNROLL 2
+#         define IMAGE_WALK_DO_STEP do{ \
+              walk_pos[0] = image_conv_alpha_func(walk_sec_pos[0], walk_sec_pos[src->channels - 1], a[0], b[0]); }while(0)
+#         include "images/image-walk.h"
+       }
+       return 1;
+      case 3:
+       {
+#         define IMAGE_WALK_PREFIX(x) walk_##x
+#         define IMAGE_WALK_INLINE
+#         define IMAGE_WALK_IMAGE dest
+#         define IMAGE_WALK_SEC_IMAGE src
+#         define IMAGE_WALK_DOUBLE
+#         define IMAGE_WALK_DO_STEP do{ \
+              walk_pos[0] = image_conv_alpha_func(walk_sec_pos[0], walk_sec_pos[src->channels - 1], a[0], b[0]); \
+              walk_pos[1] = image_conv_alpha_func(walk_sec_pos[1], walk_sec_pos[src->channels - 1], a[1], b[1]); \
+              walk_pos[2] = image_conv_alpha_func(walk_sec_pos[2], walk_sec_pos[src->channels - 1], a[2], b[2]); }while(0)
+#         include "images/image-walk.h"
+       }
+       return 1;
+    }
+  {
+#   define IMAGE_WALK_PREFIX(x) walk_##x
+#   define IMAGE_WALK_INLINE
+#   define IMAGE_WALK_IMAGE dest
+#   define IMAGE_WALK_SEC_IMAGE src
+#   define IMAGE_WALK_DOUBLE
+#   define IMAGE_WALK_DO_STEP do{ for (uns i = 0; i < dest->channels; i++) \
+        walk_pos[i] = image_conv_alpha_func(walk_sec_pos[i], walk_sec_pos[src->channels - 1], a[i], b[i]); }while(0)
+#   include "images/image-walk.h"
+  }
+  return 1;
+}
+
+int
+image_conv(struct image_context *ctx, struct image *dest, struct image *src, struct image_conv_options *opt)
+{
+  ASSERT(dest->cols == src->cols && dest->rows == src->rows);
+  if (!((dest->flags ^ src->flags) & IMAGE_COLOR_SPACE))
+    {
+      if (!(src->flags & IMAGE_ALPHA) || (dest->flags & IMAGE_ALPHA))
+       image_conv_copy(dest, src);
+      else if (unlikely(!image_conv_apply_alpha_to(ctx, dest, src, opt)))
+       return 0;
+    }
+  else
+    {
+      if (!(src->flags & IMAGE_ALPHA))
+        {
+         if (unlikely(!image_conv_color_space(ctx, dest, src, opt)))
+           goto error;
+         if ((dest->flags & IMAGE_ALPHA) && (opt->flags & IMAGE_CONV_FILL_ALPHA))
+           image_conv_fill_alpha(dest);
+       }
+      else
+        {
+         if (dest->flags & IMAGE_ALPHA)
+           {
+             if (dest->channels <= src->channels)
+               {
+                 if (unlikely(!image_conv_color_space(ctx, dest, src, opt)))
+                   goto error;
+                 if (opt->flags & IMAGE_CONV_COPY_ALPHA)
+                   image_conv_copy_alpha(dest, src);
+                 else if (opt->flags & IMAGE_CONV_FILL_ALPHA)
+                   image_conv_fill_alpha(dest);
+               }
+             else
+               {
+                 if (opt->flags & IMAGE_CONV_COPY_ALPHA)
+                   image_conv_copy_alpha(dest, src);
+                 else
+                   image_conv_fill_alpha(dest);
+                 if (unlikely(!image_conv_color_space(ctx, dest, src, opt)))
+                   goto error;
+               }
+           }
+         else
+           {
+             if (dest->channels <= src->channels)
+               {
+                 if (unlikely(!image_conv_color_space(ctx, dest, src, opt)))
+                   goto error;
+                 if (unlikely(!image_conv_apply_alpha_from(ctx, dest, src, opt)))
+                   return 0;
+               }
+             else
+               {
+                 if (unlikely(!image_conv_apply_alpha_to(ctx, dest, src, opt)))
+                   return 0;
+                 if (unlikely(!image_conv_color_space(ctx, dest, dest, opt)))
+                   goto error;
+               }
+           }
+       }
+    }
+  return 1;
+error:
+  IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Image conversion not supported for such pixel formats");
+  return 0;
 }
 
 /********************* EXACT CONVERSION ROUTINES **********************/
@@ -365,6 +884,36 @@ luv_to_xyz_exact(double xyz[3], double luv[3])
   xyz[2] = (9 * xyz[1] - 15 * var_v * xyz[1] - var_v * xyz[0]) / (3 * var_v);
 }
 
+/* RGB to CMYK - a very simple version, not too accureate  */
+void
+rgb_to_cmyk_exact(double cmyk[4], double rgb[3])
+{
+  cmyk[0] = 1 - rgb[0];
+  cmyk[1] = 1 - rgb[1];
+  cmyk[2] = 1 - rgb[2];
+  cmyk[3] = MIN(cmyk[0], cmyk[1]);
+  cmyk[3] = MIN(cmyk[3], cmyk[2]);
+  if (cmyk[3] > 0.9999)
+    {
+      cmyk[3] = 1;
+      cmyk[0] = cmyk[1] = cmyk[2] = 0;
+    }
+  else
+    {
+      double d = 1 / (1 - cmyk[3]);
+      for (uns i = 0; i < 3; i++)
+        cmyk[i] = d * (cmyk[i] - cmyk[3]);
+    }
+}
+
+/* CMYK to RGB */
+void
+cmyk_to_rgb_exact(double rgb[3], double cmyk[4])
+{
+  double d = 1 - cmyk[1];
+  for (uns i = 0; i < 3; i++)
+    rgb[i] = d * (1 - cmyk[i]);
+}
 
 /***************** OPTIMIZED SRGB -> LUV CONVERSION *********************/
 
index 7ec32acc87cdfc5563194f22783b8d5f7c9766c3..a148e6c3c062b38e1e4ec5159fc133ec6ef7e167 100644 (file)
 
 #include "images/images.h"
 
+/* Basic color spaces */
 enum {
   COLOR_SPACE_UNKNOWN = 0,
-  COLOR_SPACE_UNKNOWN_1 = 1,
-  COLOR_SPACE_UNKNOWN_2 = 2,
-  COLOR_SPACE_UNKNOWN_3 = 3,
-  COLOR_SPACE_UNKNOWN_4 = 4,
+  COLOR_SPACE_UNKNOWN_1 = 1,   /* unknown 1-channel color space */
+  COLOR_SPACE_UNKNOWN_2 = 2,   /* unknown 2-channels color space */
+  COLOR_SPACE_UNKNOWN_3 = 3,   /* unknown 3-channels color space */
+  COLOR_SPACE_UNKNOWN_4 = 4,   /* unknown 4-channels color space */
   COLOR_SPACE_UNKNOWN_MAX = 4,
   COLOR_SPACE_GRAYSCALE,
   COLOR_SPACE_RGB,
@@ -48,9 +49,49 @@ enum {
 extern uns color_space_channels[COLOR_SPACE_MAX];
 extern byte *color_space_name[COLOR_SPACE_MAX];
 
+/* Color space ID <-> name conversions */
 byte *color_space_id_to_name(uns id);
 uns color_space_name_to_id(byte *name);
 
+/* Struct color manipulation */
+int color_get(struct color *color, byte *src, uns src_space);
+int color_put(struct image_context *ctx, struct color *color, byte *dest, uns dest_space);
+
+static inline void
+color_make_gray(struct color *color, uns gray)
+{
+  color->c[0] = gray;
+  color->color_space = COLOR_SPACE_GRAYSCALE;
+}
+
+static inline void
+color_make_rgb(struct color *color, uns r, uns g, uns b)
+{
+  color->c[0] = r;
+  color->c[1] = g;
+  color->c[2] = b;
+  color->color_space = COLOR_SPACE_RGB;
+}
+
+extern struct color color_black, color_white;
+
+/* Conversion between various pixel formats */
+
+enum {
+  IMAGE_CONV_FILL_ALPHA = 1,
+  IMAGE_CONV_COPY_ALPHA = 2,
+  IMAGE_CONV_APPLY_ALPHA = 4,
+};
+
+struct image_conv_options {
+  uns flags;
+  struct color background;
+};
+
+extern struct image_conv_options image_conv_defaults;
+
+int image_conv(struct image_context *ctx, struct image *dest, struct image *src, struct image_conv_options *opt);
+
 /* Color spaces in the CIE 1931 chromacity diagram */
 
 struct color_space_chromacity_info {
@@ -98,33 +139,13 @@ rgb_to_gray_func(uns r, uns g, uns b)
   return (r * 19660 + g * 38666 + b * 7210) >> 16;
 }
 
-extern struct color color_black, color_white;
-
-static inline void
-color_make_gray(struct color *color, uns gray)
-{
-  color->c[0] = gray;
-  color->color_space = COLOR_SPACE_GRAYSCALE;
-}
-
-static inline void
-color_make_rgb(struct color *color, uns r, uns g, uns b)
-{
-  color->c[0] = r;
-  color->c[1] = g;
-  color->c[2] = b;
-  color->color_space = COLOR_SPACE_RGB;
-}
-
-void color_put_color_space(byte *dest, struct color *color, uns color_space);
-void color_put_grayscale(byte *dest, struct color *color);
-void color_put_rgb(byte *dest, struct color *color);
-
 /* Exact slow conversion routines */
 void srgb_to_xyz_exact(double dest[3], double src[3]);
 void xyz_to_srgb_exact(double dest[3], double src[3]);
 void xyz_to_luv_exact(double dest[3], double src[3]);
 void luv_to_xyz_exact(double dest[3], double src[3]);
+void rgb_to_cmyk_exact(double dest[4], double src[3]);
+void cmyk_to_rgb_exact(double dest[3], double src[4]);
 
 /* Reference white */
 #define REF_WHITE_X 0.96422
index 5063d9b65382bf484d6e51b60aac6ff33764e257..e1717569f86ef165331c2856442fc452ac07be13 100644 (file)
@@ -184,7 +184,7 @@ main(int argc, char **argv)
       if (io.background_color.color_space)
         {
          byte rgb[3];
-         color_put_rgb(rgb, &io.background_color);
+         TRY(color_put(&ctx, &io.background_color, rgb, COLOR_SPACE_RGB));
           printf("Background:  %02x%02x%02x\n", rgb[0], rgb[1], rgb[2]);
        }
       if (io.exif_size)
index dfc72a1926a33b741ca825b40eb798856416c223..96bfd5cbaced84b054694e65859128fbe229d834 100644 (file)
 #endif
 
 #ifndef IMAGE_WALK_INLINE
-static void P(walk)
+static void
+#ifdef IMAGE_WALK_FUNC_NAME
+IMAGE_WALK_FUNC_NAME
+#else
+P(walk)
+#endif
     (struct image *P(img)
 #   ifdef IMAGE_WALK_DOUBLE
     , struct image *P(sec_img)
@@ -143,6 +148,7 @@ static void P(walk)
 }
 
 #undef IMAGE_WALK_PREFIX
+#undef IMAGE_WALK_FUNC_NAME
 #undef IMAGE_WALK_INLINE
 #undef IMAGE_WALK_UNROLL
 #undef IMAGE_WALK_DOUBLE
index 26445aa34835934fa73545f980fb4b6d28b92f0e..058b173e9abf192261ae8ef5d800fa833c2ba361 100644 (file)
@@ -41,7 +41,7 @@ image_new(struct image_context *ctx, uns cols, uns rows, uns flags, struct mempo
   pixel_size = channels = flags_to_pixel_size(flags);
   if (!channels || channels > 4)
     {
-      IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Invalid number of color channels");
+      IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Invalid number of color channels (%u)", channels);
       return NULL;
     }
   switch (channels)
index f35caf59156623e9729952575c445c64264265de..5449519c172b5abc4dd9816a5c55c7f708ca1ec4 100644 (file)
@@ -68,12 +68,22 @@ enum image_flag {
   IMAGE_INTERNAL_FLAGS = IMAGE_NEED_DESTROY | IMAGE_GAPS_PROTECTED,
 };
 
+#define IMAGE_MAX_CHANNELS 4
+#define IMAGE_CHANNELS_FORMAT_MAX_SIZE 128
+byte *image_channels_format_to_name(uns format, byte *buf);
+uns image_name_to_channels_format(byte *name);
+
+struct color {
+  byte c[IMAGE_MAX_CHANNELS];
+  byte color_space;
+};
+
 struct image {
   byte *pixels;                        /* aligned top left pixel, there are at least sizeof(uns)
                                   unused bytes after the buffer (possible optimizations) */
   uns cols;                    /* number of columns */
   uns rows;                    /* number of rows */
-  uns channels;                        /* number of color channels */
+  uns channels;                        /* number of color channels including the alpha channel */
   uns pixel_size;              /* size of pixel in bytes (1, 2, 3 or 4) */
   uns row_size;                        /* scanline size in bytes */
   uns row_pixels_size;         /* scanline size in bytes excluding rows gaps */
@@ -93,25 +103,11 @@ image_dimensions_valid(uns cols, uns rows)
 {
   return cols && rows && cols <= image_max_dim && rows <= image_max_dim;
 }
-
-#define IMAGE_CHANNELS_FORMAT_MAX_SIZE 128
-byte *image_channels_format_to_name(uns format, byte *buf);
-uns image_name_to_channels_format(byte *name);
-
-struct color {
-  byte c[3];
-  byte color_space;
-} PACKED;
-
 /* scale.c */
 
 int image_scale(struct image_context *ctx, struct image *dest, struct image *src);
 void image_dimensions_fit_to_box(uns *cols, uns *rows, uns max_cols, uns max_rows, uns upsample);
 
-/* alpha.c */
-
-int image_apply_background(struct image_context *ctx, struct image *dest, struct image *src, struct color *background);
-
 /* image-io.c */
 
 enum image_format {
index f4a72e29a70228afb7d98681e246347d531605b2..03952519ee8542a0af5f49f97e8726592e3d5d1e 100644 (file)
@@ -7,7 +7,7 @@
  *     of the GNU Lesser General Public License.
  */
 
-#define LOCAL_DEBUG
+#undef LOCAL_DEBUG
 
 #include "lib/lib.h"
 #include "lib/mempool.h"
@@ -52,7 +52,7 @@ libjpeg_read_error_exit(j_common_ptr cinfo)
   struct libjpeg_err *e = (struct libjpeg_err *)cinfo->err;
   byte buf[JMSG_LENGTH_MAX];
   e->pub.format_message(cinfo, buf);
-  IMAGE_ERROR(e->io->context, IMAGE_ERROR_READ_FAILED, "%s", buf);
+  IMAGE_ERROR(e->io->context, IMAGE_ERROR_READ_FAILED, "libjpeg: %s", buf);
   longjmp(e->setjmp_buf, 1);
 }
 
@@ -63,7 +63,7 @@ libjpeg_write_error_exit(j_common_ptr cinfo)
   struct libjpeg_err *e = (struct libjpeg_err *)cinfo->err;
   byte buf[JMSG_LENGTH_MAX];
   e->pub.format_message(cinfo, buf);
-  IMAGE_ERROR(e->io->context, IMAGE_ERROR_WRITE_FAILED, "%s", buf);
+  IMAGE_ERROR(e->io->context, IMAGE_ERROR_WRITE_FAILED, "libjpeg: %s", buf);
   longjmp(e->setjmp_buf, 1);
 }
 
@@ -336,16 +336,14 @@ libjpeg_read_data(struct image_io *io)
   DBG("libjpeg_read_data()");
 
   struct libjpeg_read_internals *i = io->read_data;
+  uns read_flags = io->flags;
 
   /* Select color space */
-  switch (io->flags & IMAGE_COLOR_SPACE)
+  switch (read_flags & IMAGE_COLOR_SPACE)
     {
       case COLOR_SPACE_GRAYSCALE:
        i->cinfo.out_color_space = JCS_GRAYSCALE;
        break;
-      case COLOR_SPACE_RGB:
-       i->cinfo.out_color_space = JCS_RGB;
-       break;
       case COLOR_SPACE_YCBCR:
        i->cinfo.out_color_space = JCS_YCbCr;
        break;
@@ -356,9 +354,18 @@ libjpeg_read_data(struct image_io *io)
        i->cinfo.out_color_space = JCS_YCCK;
        break;
       default:
-       jpeg_destroy_decompress(&i->cinfo);
-       IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Unsupported color space.");
-       return 0;
+       switch (i->cinfo.jpeg_color_space)
+         {
+           case JCS_CMYK:
+             read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_CMYK; 
+             i->cinfo.out_color_space = JCS_YCbCr;
+             break;
+           default:
+             read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB; 
+             i->cinfo.out_color_space = JCS_RGB;
+             break;
+         }
+       break;
     }
 
   /* Prepare the image  */
@@ -383,7 +390,7 @@ libjpeg_read_data(struct image_io *io)
     }
   jpeg_calc_output_dimensions(&i->cinfo);
   DBG("Output dimensions %ux%u", (uns)i->cinfo.output_width, (uns)i->cinfo.output_height);
-  if (unlikely(!image_io_read_data_prepare(&rdi, io, i->cinfo.output_width, i->cinfo.output_height, io->flags)))
+  if (unlikely(!image_io_read_data_prepare(&rdi, io, i->cinfo.output_width, i->cinfo.output_height, read_flags)))
     {
       jpeg_destroy_decompress(&i->cinfo);
       return 0;
@@ -401,7 +408,7 @@ libjpeg_read_data(struct image_io *io)
   /* Decompress the image */
   struct image *img = rdi.image;
   jpeg_start_decompress(&i->cinfo);
-  if ((int)img->pixel_size == i->cinfo.num_components)
+  if ((int)img->pixel_size == i->cinfo.output_components)
     {
       byte *pixels = img->pixels;
       for (uns r = img->rows; r--; )
@@ -416,7 +423,7 @@ libjpeg_read_data(struct image_io *io)
         {
          case 2: /* Grayscale -> Grayscale+Alpha */
            {
-             ASSERT(i->cinfo.num_components == 1);
+             ASSERT(i->cinfo.output_components == 1);
              byte buf[img->cols], *src;
 #            define IMAGE_WALK_PREFIX(x) walk_##x
 #             define IMAGE_WALK_INLINE
@@ -430,7 +437,7 @@ libjpeg_read_data(struct image_io *io)
            break;
          case 4: /* * -> *+Alpha or aligned * */
            {
-             ASSERT(i->cinfo.num_components == 3);
+             ASSERT(i->cinfo.output_components == 3);
              byte buf[img->cols * 3], *src;
 #            define IMAGE_WALK_PREFIX(x) walk_##x
 #             define IMAGE_WALK_INLINE
index cdf58048ced1d69946e6ce3d11dc28b3c15cb3da..60d3615941c0330fa7fa833670ea394f5ef54026 100644 (file)
@@ -170,8 +170,11 @@ libmagick_read_data(struct image_io *io)
   /* Prepare the image */
   struct image_io_read_data_internals rdi;
   uns read_flags = io->flags;
+  uns cs = read_flags & IMAGE_COLOR_SPACE;
+  if (cs != COLOR_SPACE_GRAYSCALE && cs != COLOR_SPACE_RGB)
+    read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_PIXEL_FORMAT) | COLOR_SPACE_RGB;
   if ((read_flags & IMAGE_IO_USE_BACKGROUND) && !(read_flags & IMAGE_ALPHA))
-    read_flags = (read_flags | IMAGE_ALPHA) & IMAGE_CHANNELS_FORMAT;
+    read_flags = (read_flags & IMAGE_CHANNELS_FORMAT) | IMAGE_ALPHA;
   if (unlikely(!image_io_read_data_prepare(&rdi, io, rd->image->columns, rd->image->rows, read_flags)))
     {
       libmagick_destroy_read_data(rd);
@@ -279,7 +282,8 @@ libmagick_write(struct image_io *io)
         info->colorspace = RGBColorspace;
         break;
       default:
-        ASSERT(0);
+        IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Unsupported color space.");
+        goto err;
     }
   switch (io->format)
     {
index 76b2d2478fc290401842b7dbac350ac4cd3d201b..2095065f189a9c4a198697b3c90081d230a627b2 100644 (file)
@@ -188,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_ERROR(io->context, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Unsupported color space.");
-        return 0;
-    }
-
   struct image_io_read_data_internals rdi;
   rdi.image = NULL;
 
@@ -220,21 +208,24 @@ libpng_read_data(struct image_io *io)
   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);
@@ -243,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:
@@ -361,7 +362,9 @@ 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);
 
index c46484311cbe980a86b6a5032a57972ee56d4e1a..9e19de266d2e1343f5a49623e9d5340bdfe213b7 100644 (file)
@@ -147,7 +147,11 @@ libungif_read_data(struct image_io *io)
 
   /* Prepare image */
   struct image_io_read_data_internals rdi;
-  if (unlikely(!image_io_read_data_prepare(&rdi, io, image->ImageDesc.Width, image->ImageDesc.Height, io->flags)))
+  uns read_flags = io->flags;
+  uns cs = read_flags & IMAGE_COLOR_SPACE;
+  if (cs != COLOR_SPACE_GRAYSCALE && cs != COLOR_SPACE_RGB)
+    read_flags = (read_flags & ~IMAGE_COLOR_SPACE & IMAGE_CHANNELS_FORMAT) | COLOR_SPACE_RGB;
+  if (unlikely(!image_io_read_data_prepare(&rdi, io, image->ImageDesc.Width, image->ImageDesc.Height, read_flags)))
     {
       DGifCloseFile(gif);
       return 0;
@@ -180,7 +184,11 @@ libungif_read_data(struct image_io *io)
          if (pal_pos != pal_end)
            bzero(pal_pos, pal_end - pal_pos);
          if (rd->transparent_index >= 0 && (io->flags & IMAGE_IO_USE_BACKGROUND))
-           color_put_grayscale(pal + rd->transparent_index, &io->background_color);
+           if (!color_put(io->context, &io->background_color, pal + rd->transparent_index, COLOR_SPACE_GRAYSCALE))
+             {
+               DGifCloseFile(gif);
+               return 0;
+             }
 #        define DO_ROW_END do{ \
              walk_row_start += dein_step; \
              if (walk_row_start >= img_end) \
@@ -232,7 +240,11 @@ libungif_read_data(struct image_io *io)
          if (pal_pos != pal_end)
            bzero(pal_pos, pal_end - pal_pos);
          if (rd->transparent_index >= 0 && (io->flags & IMAGE_IO_USE_BACKGROUND))
-           color_put_rgb(pal + 4 * rd->transparent_index, &io->background_color);
+           if (!color_put(io->context, &io->background_color, pal + 4 * rd->transparent_index, COLOR_SPACE_RGB))
+             {
+               DGifCloseFile(gif);
+               return 0;
+             }
 #        define IMAGE_WALK_PREFIX(x) walk_##x
 #        define IMAGE_WALK_INLINE
 #        define IMAGE_WALK_IMAGE (rdi.image)
index 7b176b70a187e4944bfa8af6966e4a3a3f6b96a3..3d02a9e5e8aecee0f0f27616f794666216f6ef24 100644 (file)
@@ -14,6 +14,7 @@
 #include "images/images.h"
 #include "images/error.h"
 #include "images/io-main.h"
+#include "images/color.h"
 
 #include <string.h>
 
@@ -341,20 +342,18 @@ image_io_read_data_finish(struct image_io_read_data_internals *rdi, struct image
          rdi->image = img;
        }
 
-      /* Merge with background */
-      if ((io->flags ^ rdi->image->flags) & IMAGE_ALPHA)
+      /* Convert pixel format */
+      if (io->flags != rdi->image->flags)
         {
-         DBG("Applying background");
-         uns flags = rdi->image->flags & ~IMAGE_ALPHA;
-         if (!(rdi->need_transformations = (flags ^ io->flags) & (IMAGE_NEW_FLAGS & ~IMAGE_PIXELS_ALIGNED)))
-           flags = io->flags;
-         struct image *img = image_new(io->context, io->cols, io->rows, flags, rdi->need_transformations ? NULL : io->pool);
+         struct image *img = image_new(io->context, io->cols, io->rows, io->flags, io->pool);
          if (unlikely(!img))
            {
              image_destroy(rdi->image);
              return 0;
            }
-          if (unlikely(!image_apply_background(io->context, img, rdi->image, &io->background_color)))
+         struct image_conv_options opt = image_conv_defaults;
+         opt.background = io->background_color;
+          if (unlikely(!image_conv(io->context, img, rdi->image, &opt)))
             {
               image_destroy(rdi->image);
              image_destroy(img);
@@ -363,10 +362,6 @@ image_io_read_data_finish(struct image_io_read_data_internals *rdi, struct image
          image_destroy(rdi->image);
          rdi->image = img;
        }
-
-      // FIXME: support for various color spaces
-
-      ASSERT(!rdi->need_transformations);
     }
 
   /* Success */
index 1824c95bb42a7a05361defc282487e32aa7574a3..a4d561670274f7a282eebd350b1acce85d604ba1 100644 (file)
@@ -13,17 +13,7 @@ isqr(int x)
 static inline uns
 fast_div_u32_u8(uns x, uns y)
 {
-#ifdef CPU_I386
-  int ret, dmy;
-  asm volatile (
-    "mull %3"
-    :"=d"(ret),"=a"(dmy)
-    :"1"(x),"g"(fast_div_tab[y])
-  );
-  return ret;
-#else
   return ((u64)(x) * fast_div_tab[y]) >> 32;
-#endif
 }
 
 static inline uns