]> mj.ucw.cz Git - libucw.git/commitdiff
revising & testing image library
authorPavel Charvat <pavel.charvat@netcentrum.cz>
Wed, 20 Sep 2006 09:43:24 +0000 (11:43 +0200)
committerPavel Charvat <pavel.charvat@netcentrum.cz>
Wed, 20 Sep 2006 09:43:24 +0000 (11:43 +0200)
* struct image_thread renamed to struct image_context;
  changed its messaging iface
* added simple automatic tests for thread safety
* added some global ImageLib.* configuration variables
* playing with color spaces... not important but interesting :-)

- to be continue -

24 files changed:
cf/images
images/Makefile
images/alpha.c
images/color-tool.c [new file with mode: 0644]
images/color.c
images/color.h
images/config.c
images/context.c [new file with mode: 0644]
images/dup-init.c
images/duplicates.h
images/error.h [new file with mode: 0644]
images/image-dup-test.c
images/image-sim-test.c
images/image-test.c
images/image-tool.c
images/image.c
images/images.h
images/io-libjpeg.c
images/io-libpng.c
images/io-libungif.c
images/io-main.c
images/scale.c
images/sig-init.c
images/signature.h

index 6f36620e7457643d54aebb308e4a9c28c2e14fae..c4087583a3461718e1615e5e507871d7c38f12d8 100644 (file)
--- a/cf/images
+++ b/cf/images
@@ -2,7 +2,15 @@
 
 ######## General parameters #####################################################
 
-Images {
+ImageLib {
+
+# Default tracing level (0 to disable)
+Trace          0
+
+# Limits for image allocation. ImageMaxDim must be less than 1<<16.
+ImageMaxDim    0xffff
+ImageMaxBytes  256M
+
 }
 
 ######## Image signatures #######################################################
index 8b7efbdd5c8842da108cb3cc3aa7be29b14ffad0..a4a2fb2687c2f332ae506c00c8cb56f8cf6ad5af 100644 (file)
@@ -2,9 +2,9 @@
 
 DIRS+=images
 
-PROGS+=$(o)/images/image-tool
+PROGS+=$(o)/images/image-tool $(o)/images/color-tool
 CONFIGS+=images
-LIBIMAGES_MODS=math config image scale color alpha io-main object
+LIBIMAGES_MODS=math config context image scale color alpha io-main object
 
 ifdef CONFIG_IMAGES_DUP
 PROGS+=$(o)/images/image-dup-test
@@ -54,6 +54,9 @@ $(o)/images/libimages.so: $(addsuffix .oo,$(addprefix $(o)/images/,$(LIBIMAGES_M
 $(o)/images/image-tool: $(o)/images/image-tool.o $(LIBIMAGES) $(LIBUCW)
 $(o)/images/image-tool: LIBS+=$(LIBIMAGES_LIBS)
 
+$(o)/images/color-tool: $(o)/images/color-tool.o $(LIBIMAGES) $(LIBUCW)
+$(o)/images/color-tool: LIBS+=$(LIBIMAGES_LIBS)
+
 $(o)/images/image-dup-test: $(o)/images/image-dup-test.o $(LIBIMAGES) $(LIBUCW)
 $(o)/images/image-dup-test: LIBS+=$(LIBIMAGES_LIBS)
 
@@ -62,7 +65,7 @@ $(o)/images/image-sim-test: LIBS+=$(LIBIMAGES_LIBS)
 
 TESTS+=$(o)/images/image-test.test
 $(o)/images/image-test: $(o)/images/image-test.o $(LIBIMAGES) $(LIBUCW)
-$(o)/images/image-test: LIBS+=$(LIBIMAGES_LIBS)
+$(o)/images/image-test: LIBS+=$(LIBIMAGES_LIBS) -lpthread
 $(o)/images/image-test.test: $(o)/images/image-test
 
 TESTS+=$(o)/images/hilbert-test.test
index 9f6dfd14ff64bef46879263f127ae394d023e3f8..d97207e8cb4c54589a37186ae94f595624684e58 100644 (file)
@@ -20,7 +20,7 @@ merge_func(uns value, uns alpha, uns acoef, uns bcoef)
 }
 
 int
-image_apply_background(struct image_thread *thread UNUSED, struct image *dest, struct image *src, struct color *background)
+image_apply_background(struct image_context *ctx UNUSED, struct image *dest, struct image *src, struct color *background)
 {
   DBG("image_apply_background()");
 
diff --git a/images/color-tool.c b/images/color-tool.c
new file mode 100644 (file)
index 0000000..112f738
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *     Color spaces tool
+ *
+ *     (c) 2006 Pavel Charvat <pchar@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU General Public License.
+ */
+
+#include "lib/lib.h"
+#include "images/images.h"
+#include "images/color.h"
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+static void NONRET
+usage(void)
+{
+  fputs("\
+Usage: color-tool input-color-space output-color-space\n\
+", stderr);
+  exit(1);
+}
+
+static char *shortopts = "";
+static struct option longopts[] =
+{
+  { NULL,                      0, 0, 0 }
+};
+
+static const struct color_space_info *
+parse_color_space(byte *s)
+{
+  if (!strcasecmp(s, "sRGB"))
+    return &color_srgb_info;
+  else if (!strcasecmp(s, "AdobeRGB") || !strcasecmp(s, "Adobe RGB"))
+    return &color_adobe_rgb_info;
+  else if (!strcasecmp(s, "CIERGB") || strcasecmp(s, "CIE RGB"))
+    return &color_cie_rgb_info;
+  else
+    die("Unknown color space");
+}
+
+static void
+print_matrix(double m[9])
+{
+  for (uns j = 0; j < 3; j++)
+    {
+      for (uns i = 0; i < 3; i++)
+       printf(" %12.8f", m[i + j * 3]);
+      printf("\n");
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+  log_init(argv[0]);
+  int opt;
+  while ((opt = getopt_long(argc, argv, shortopts, longopts, NULL)) >= 0)
+    switch (opt)
+      {
+       default:
+         usage();
+      }
+
+  if (argc == optind + 1)
+    {
+      const struct color_space_info *a = parse_color_space(argv[optind]);
+      double a_to_xyz[9], xyz_to_a[9];
+      color_compute_color_space_to_xyz_matrix(a_to_xyz, &a->chromacity);
+      color_invert_matrix(xyz_to_a, a_to_xyz);
+      printf("linear %s -> XYZ:\n", a->name);
+      print_matrix(a_to_xyz);
+      printf("XYZ -> linear %s:\n", a->name);
+      print_matrix(xyz_to_a);
+      printf("Simple gamma: %.8f\n", a->gamma.simple_gamma);
+      printf("Detailed gamma: g=%.8f o=%.8f t=%.8f s=%.8f\n", a->gamma.detailed_gamma, a->gamma.offset, a->gamma.transition, a->gamma.slope);
+    }
+  else if (argc == optind + 2)
+    {
+      const struct color_space_info *a = parse_color_space(argv[optind++]);
+      const struct color_space_info *b = parse_color_space(argv[optind]);
+      double a_to_b[9];
+      color_compute_color_spaces_conversion_matrix(a_to_b, &a->chromacity, &b->chromacity);
+      printf("linear %s -> linear %s:\n", a->name, b->name);
+      print_matrix(a_to_b);
+    }
+  else
+    usage();
+
+  return 0;
+}
index 80f48294c86c0db14d7d5fe925a365c6469208ef..43d4847a5df833edcd38837e06d151f10fc7a433 100644 (file)
@@ -7,7 +7,7 @@
  *     of the GNU Lesser General Public License.
  */
 
-#undef LOCAL_DEBUG
+#define LOCAL_DEBUG
 
 #include "sherlock/sherlock.h"
 #include "lib/math.h"
@@ -29,7 +29,7 @@ color_put_grayscale(byte *dest, struct color *color)
        dest[0] = rgb_to_gray_func(color->c[0], color->c[1], color->c[2]);
        break;
       default:
-       ASSERT(0);      
+       ASSERT(0);
     }
 }
 
@@ -47,61 +47,241 @@ color_put_rgb(byte *dest, struct color *color)
        dest[2] = color->c[2];
        break;
       default:
-       ASSERT(0);      
+       ASSERT(0);
     }
 }
 
 void
-color_put_color_space(byte *dest, struct color *color, enum color_space color_space)
+color_put_color_space(byte *dest, struct color *color, uns color_space)
 {
   switch (color_space)
     {
       case COLOR_SPACE_GRAYSCALE:
        color_put_grayscale(dest, color);
-       break;  
+       break;
       case COLOR_SPACE_RGB:
-       color_put_rgb(dest, color);     
+       color_put_rgb(dest, color);
        break;
       default:
-       ASSERT(0);      
+       ASSERT(0);
     }
 }
 
 /********************* EXACT CONVERSION ROUTINES **********************/
 
-/* sRGB to XYZ */
-void
-srgb_to_xyz_slow(double xyz[3], double srgb[3])
+/* Reference whites */
+#define COLOR_ILLUMINANT_A     0.44757, 0.40744
+#define COLOR_ILLUMINANT_B     0.34840, 0.35160
+#define COLOR_ILLUMINANT_C     0.31006, 0.31615
+#define COLOR_ILLUMINANT_D50    0.34567, 0.35850
+#define COLOR_ILLUMINANT_D55   0.33242, 0.34743
+#define COLOR_ILLUMINANT_D65    0.31273, 0.32902
+#define COLOR_ILLUMINANT_D75   0.29902, 0.31485
+#define COLOR_ILLUMINANT_9300K 0.28480, 0.29320
+#define COLOR_ILLUMINANT_E      (1./3.), (1./3.)
+#define COLOR_ILLUMINANT_F2    0.37207, 0.37512
+#define COLOR_ILLUMINANT_F7    0.31285, 0.32918
+#define COLOR_ILLUMINANT_F11   0.38054, 0.37691
+
+const double
+  color_illuminant_d50[2] = {COLOR_ILLUMINANT_D50},
+  color_illuminant_d65[2] = {COLOR_ILLUMINANT_D65},
+  color_illuminant_e[2] = {COLOR_ILLUMINANT_E};
+
+/* RGB profiles (many missing) */
+const struct color_space_info
+  color_adobe_rgb_info = {"Adobe RGB", {{0.6400, 0.3300}, {0.2100, 0.7100}, {0.1500, 0.0600}, {COLOR_ILLUMINANT_D65}}, {0.45, 0.45, 0, 0, 0}},
+  color_apple_rgb_info = {"Apple RGB", {{0.6250, 0.3400}, {0.2800, 0.5950}, {0.1550, 0.0700}, {COLOR_ILLUMINANT_D65}}, {0.56, 0.56, 0, 0, 0}},
+  color_cie_rgb_info = {"CIE RGB", {{0.7350, 0.2650}, {0.2740, 0.7170}, {0.1670, 0.0090}, {COLOR_ILLUMINANT_E}}, {0.45, 0.45, 0, 0, 0}},
+  color_color_match_rgb_info = {"ColorMatch RGB", {{0.6300, 0.3400}, {0.2950, 0.6050}, {0.1500, 0.0750}, {COLOR_ILLUMINANT_D50}}, {0.56, 0.56, 0, 0, 0}},
+  color_srgb_info = {"sRGB", {{0.6400, 0.3300}, {0.3000, 0.6000}, {0.1500, 0.0600}, {COLOR_ILLUMINANT_D65}}, {0.45, 0.42, 0.055, 0.003, 12.92}};
+
+#define CLIP(x, min, max) (((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x))
+
+static inline void
+clip(double a[3])
+{
+  a[0] = CLIP(a[0], 0, 1);
+  a[1] = CLIP(a[1], 0, 1);
+  a[2] = CLIP(a[2], 0, 1);
+}
+
+static inline void
+correct_gamma_simple(double dest[3], double src[3], const struct color_space_gamma_info *info)
+{
+  dest[0] = pow(src[0], info->simple_gamma);
+  dest[1] = pow(src[1], info->simple_gamma);
+  dest[2] = pow(src[2], info->simple_gamma);
+}
+
+static inline void
+invert_gamma_simple(double dest[3], double src[3], const struct color_space_gamma_info *info)
+{
+  dest[0] = pow(src[0], 1 / info->simple_gamma);
+  dest[1] = pow(src[1], 1 / info->simple_gamma);
+  dest[2] = pow(src[2], 1 / info->simple_gamma);
+}
+
+static inline void
+correct_gamma_detailed(double dest[3], double src[3], const struct color_space_gamma_info *info)
 {
-  double a[3];
   for (uns i = 0; i < 3; i++)
-    if (srgb[i] > 0.04045)
-      a[i] = pow((srgb[i] + 0.055) * (1 / 1.055), 2.4);
+    if (src[i] > info->transition)
+      dest[i] = (1 + info->offset) * pow(src[i], info->detailed_gamma) - info->offset;
     else
-      a[i] = srgb[i] * (1 / 12.92);
-  xyz[0] = SRGB_XYZ_XR * a[0] + SRGB_XYZ_XG * a[1] + SRGB_XYZ_XB * a[2];
-  xyz[1] = SRGB_XYZ_YR * a[0] + SRGB_XYZ_YG * a[1] + SRGB_XYZ_YB * a[2];
-  xyz[2] = SRGB_XYZ_ZR * a[0] + SRGB_XYZ_ZG * a[1] + SRGB_XYZ_ZB * a[2];
+      dest[i] = info->slope * src[i];
 }
 
-/* XYZ to sRGB */
-void
-xyz_to_srgb_slow(double srgb[3], double xyz[3])
+static inline void
+invert_gamma_detailed(double dest[3], double src[3], const struct color_space_gamma_info *info)
 {
-  double a[3];
-  a[0] =  3.2406 * xyz[0] + -1.5372 * xyz[1] + -0.4986 * xyz[2];
-  a[1] = -0.9689 * xyz[0] +  1.8758 * xyz[1] +  0.0415 * xyz[2];
-  a[2] =  0.0557 * xyz[0] + -0.2040 * xyz[1] +  1.0570 * xyz[2];
   for (uns i = 0; i < 3; i++)
-    if (a[i] > 0.0031308)
-      srgb[i] = 1.055 * pow(a[i], 1 / 2.4) - 0.055;
+    if (src[i] > info->transition * info->slope)
+      dest[i] = pow((src[i] + info->offset) / (1 + info->offset), 1 / info->detailed_gamma);
     else
-      srgb[i] = 12.92 * a[i];
+      dest[i] = src[i] / info->slope;
+}
+
+static inline void
+apply_matrix(double dest[3], double src[3], double matrix[9])
+{
+  dest[0] = src[0] * matrix[0] + src[1] * matrix[1] + src[2] * matrix[2];
+  dest[1] = src[0] * matrix[3] + src[1] * matrix[4] + src[2] * matrix[5];
+  dest[2] = src[0] * matrix[6] + src[1] * matrix[7] + src[2] * matrix[8];
+}
+
+void
+color_invert_matrix(double dest[9], double matrix[9])
+{
+  double *i = dest, *m = matrix;
+  double a0 = m[4] * m[8] - m[5] * m[7];
+  double a1 = m[3] * m[8] - m[5] * m[6];
+  double a2 = m[3] * m[7] - m[4] * m[6];
+  double d = 1 / (m[0] * a0 - m[1] * a1 + m[2] * a2);
+  i[0] = d * a0;
+  i[3] = -d * a1;
+  i[6] = d * a2;
+  i[1] = -d * (m[1] * m[8] - m[2] * m[7]);
+  i[4] = d * (m[0] * m[8] - m[2] * m[6]);
+  i[7] = -d * (m[0] * m[7] - m[1] * m[6]);
+  i[2] = d * (m[1] * m[5] - m[2] * m[4]);
+  i[5] = -d * (m[0] * m[5] - m[2] * m[3]);
+  i[8] = d * (m[0] * m[4] - m[1] * m[3]);
+}
+
+static void
+mul_matrices(double r[9], double a[9], double b[9])
+{
+  r[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6];
+  r[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7];
+  r[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8];
+  r[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6];
+  r[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7];
+  r[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8];
+  r[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6];
+  r[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7];
+  r[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8];
+}
+
+/* computes conversion matrix from a given color space to CIE XYZ */
+void
+color_compute_color_space_to_xyz_matrix(double matrix[9], const struct color_space_chromacity_info *space)
+{
+  double wX = space->white[0] / space->white[1];
+  double wZ = (1 - space->white[0] - space->white[1]) / space->white[1];
+  double a[9], b[9];
+  a[0] = space->prim1[0]; a[3] = space->prim1[1]; a[6] = 1 - a[0] - a[3];
+  a[1] = space->prim2[0]; a[4] = space->prim2[1]; a[7] = 1 - a[1] - a[4];
+  a[2] = space->prim3[0]; a[5] = space->prim3[1]; a[8] = 1 - a[2] - a[5];
+  color_invert_matrix(b, a);
+  double ra = wX * b[0] + b[1] + wZ * b[2];
+  double rb = wX * b[3] + b[4] + wZ * b[5];
+  double rc = wX * b[6] + b[7] + wZ * b[8];
+  matrix[0] = a[0] * ra;
+  matrix[1] = a[1] * rb;
+  matrix[2] = a[2] * rc;
+  matrix[3] = a[3] * ra;
+  matrix[4] = a[4] * rb;
+  matrix[5] = a[5] * rc;
+  matrix[6] = a[6] * ra;
+  matrix[7] = a[7] * rb;
+  matrix[8] = a[8] * rc;
+}
+
+/* computes matrix to join transofmations with different reference whites */
+void
+color_compute_bradford_matrix(double matrix[9], const double source[2], const double dest[2])
+{
+  /* cone response matrix and its inversion */
+  static double r[9] = {
+    0.8951, 0.2664, -0.1614,
+    -0.7502, 1.7135, 0.0367,
+    0.0389, -0.0685, 1.0296};
+  //static double i[9] = {0.9870, -0.1471, 0.1600, 0.4323, 0.5184, 0.0493, -0.0085, 0.0400, 0.9685};
+  double i[9];
+  color_invert_matrix(i, r);
+  double aX = source[0] / source[1];
+  double aZ = (1 - source[0] - source[1]) / source[1];
+  double bX = dest[0] / dest[1];
+  double bZ = (1 - dest[0] - dest[1]) / dest[1];
+  double x = (r[0] * bX + r[1] + r[2] * bZ) / (r[0] * aX + r[1] + r[2] * aZ);
+  double y = (r[3] * bX + r[4] + r[5] * bZ) / (r[3] * aX + r[4] + r[5] * aZ);
+  double z = (r[6] * bX + r[7] + r[8] * bZ) / (r[6] * aX + r[7] + r[8] * aZ);
+  double m[9];
+  m[0] = i[0] * x; m[1] = i[1] * y; m[2] = i[2] * z;
+  m[3] = i[3] * x; m[4] = i[4] * y; m[5] = i[5] * z;
+  m[6] = i[6] * x; m[7] = i[7] * y; m[8] = i[8] * z;
+  mul_matrices(matrix, m, r);
+}
+
+void
+color_compute_color_spaces_conversion_matrix(double matrix[9], const struct color_space_chromacity_info *src, const struct color_space_chromacity_info *dest)
+{
+  double a_to_xyz[9], b_to_xyz[9], xyz_to_b[9], bradford[9], m[9];
+  color_compute_color_space_to_xyz_matrix(a_to_xyz, src);
+  color_compute_color_space_to_xyz_matrix(b_to_xyz, dest);
+  color_invert_matrix(xyz_to_b, b_to_xyz);
+  if (src->white[0] == dest->white[0] && src->white[1] == dest->white[1])
+    mul_matrices(matrix, a_to_xyz, xyz_to_b);
+  else
+    {
+      color_compute_bradford_matrix(bradford, src->white, dest->white);
+      mul_matrices(m, a_to_xyz, bradford);
+      mul_matrices(matrix, m, xyz_to_b);
+    }
+}
+
+/* sRGB to XYZ */
+void
+srgb_to_xyz_exact(double xyz[3], double srgb[3])
+{
+  static double matrix[9] = {
+    0.41248031, 0.35756952, 0.18043951,
+    0.21268516, 0.71513904, 0.07217580,
+    0.01933501, 0.11918984, 0.95031473};
+  double srgb_lin[3];
+  invert_gamma_detailed(srgb_lin, srgb, &color_srgb_info.gamma);
+  apply_matrix(xyz, srgb_lin, matrix);
+  xyz_to_srgb_exact(srgb_lin, xyz);
+}
+
+/* XYZ to sRGB */
+void
+xyz_to_srgb_exact(double srgb[3], double xyz[3])
+{
+  static double matrix[9] = {
+     3.24026666, -1.53704957, -0.49850256,
+    -0.96928381,  1.87604525,  0.04155678,
+     0.05564281, -0.20402363,  1.05721334};
+  double srgb_lin[3];
+  apply_matrix(srgb_lin, xyz, matrix);
+  clip(srgb_lin);
+  correct_gamma_detailed(srgb, srgb_lin, &color_srgb_info.gamma);
 }
 
 /* XYZ to CIE-Luv */
 void
-xyz_to_luv_slow(double luv[3], double xyz[3])
+xyz_to_luv_exact(double luv[3], double xyz[3])
 {
   double sum = xyz[0] + 15 * xyz[1] + 3 * xyz[2];
   if (sum < 0.000001)
@@ -122,7 +302,7 @@ xyz_to_luv_slow(double luv[3], double xyz[3])
 
 /* CIE-Luv to XYZ */
 void
-luv_to_xyz_slow(double xyz[3], double luv[3])
+luv_to_xyz_exact(double xyz[3], double luv[3])
 {
   double var_u = luv[1] / (13 * luv[0]) + (4 * REF_WHITE_X / (REF_WHITE_X + 15 * REF_WHITE_Y + 3 * REF_WHITE_Z));
   double var_v = luv[2] / (13 * luv[0]) + (9 * REF_WHITE_Y / (REF_WHITE_X + 15 * REF_WHITE_Y + 3 * REF_WHITE_Z));
@@ -305,8 +485,8 @@ srgb_to_luv_func(double dest[3], double src[3])
   srgb[0] = src[0] / 255.;
   srgb[1] = src[1] / 255.;
   srgb[2] = src[2] / 255.;
-  srgb_to_xyz_slow(xyz, srgb);
-  xyz_to_luv_slow(luv, xyz);
+  srgb_to_xyz_exact(xyz, srgb);
+  xyz_to_luv_exact(luv, xyz);
   dest[0] = luv[0] * 2.55;
   dest[1] = luv[1] * (2.55 / 4) + 128;
   dest[2] = luv[2] * (2.55 / 4) + 128;
index d8cee26b497b5efb1137c83939b06a2ccd6331c0..8c87e87c5414500d89a77bdb603e9a21dd5943c3 100644 (file)
@@ -8,6 +8,8 @@
  *
  *
  *     References:
+ *     - A Review of RGB Color Spaces, Danny Pascale (2003)
+ *     - http://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
  *     - http://www.tecgraf.puc-rio.br/~mgattass/color/ColorIndex.html
  *
  *     FIXME:
 
 #include "images/images.h"
 
+// A comparison of four multimedia RGB spaces, Danny Pascale
+
+enum {
+  COLOR_SPACE_UNKNOWN = 0,
+  COLOR_SPACE_GRAYSCALE,
+  COLOR_SPACE_RGB,
+  COLOR_SPACE_XYZ,
+  COLOR_SPACE_LAB,
+  COLOR_SPACE_LUV,
+  COLOR_SPACE_YCBCR,
+  COLOR_SPACE_MAX
+};
+
+/* Color spaces in the CIE 1931 chromacity diagram */
+
+struct color_space_chromacity_info {
+  double prim1[2];
+  double prim2[2];
+  double prim3[2];
+  double white[2];
+};
+
+struct color_space_gamma_info {
+  double simple_gamma;
+  double detailed_gamma;
+  double offset;
+  double transition;
+  double slope;
+};
+
+struct color_space_info {
+  byte *name;
+  struct color_space_chromacity_info chromacity;
+  struct color_space_gamma_info gamma;
+};
+
+extern const double
+  color_illuminant_d50[2],
+  color_illuminant_d65[2],
+  color_illuminant_e[2];
+
+extern const struct color_space_info
+  color_adobe_rgb_info,                /* Adobe RGB (1998) */
+  color_apple_rgb_info,                /* Apple RGB */
+  color_cie_rgb_info,          /* CIE RGB */
+  color_color_match_rgb_info,  /* ColorMatch RGB */
+  color_srgb_info;             /* sRGB */
+
+/* These routines do not check numeric errors! */
+void color_compute_color_space_to_xyz_matrix(double matrix[9], const struct color_space_chromacity_info *space);
+void color_compute_bradford_matrix(double matrix[9], const double src[2], const double dest[2]);
+void color_compute_color_spaces_conversion_matrix(double matrix[9], const struct color_space_chromacity_info *src, const struct color_space_chromacity_info *dest);
+void color_invert_matrix(double dest[9], double matrix[9]);
+
 static inline uns
 rgb_to_gray_func(uns r, uns g, uns b)
 {
@@ -49,15 +105,15 @@ color_make_rgb(struct color *color, uns r, uns g, uns b)
   color->color_space = COLOR_SPACE_RGB;
 }
 
-void color_put_color_space(byte *dest, struct color *color, enum color_space color_space);
+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_slow(double dest[3], double src[3]);
-void xyz_to_srgb_slow(double dest[3], double src[3]);
-void xyz_to_luv_slow(double dest[3], double src[3]);
-void luv_to_xyz_slow(double dest[3], double src[3]);
+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]);
 
 /* Reference white */
 #define REF_WHITE_X 0.96422
index 11c93787e764fde5ce2d5f51bc25af7ecd952f2f..a268525e6c919adf75b6b24df83dd642103ff39a 100644 (file)
 
 #include <string.h>
 
+/* ImageLib section */
+uns image_trace;
+uns image_max_dim = 0xffff;
+uns image_max_bytes = ~0U;
+
+/* ImageSig section */
 uns image_sig_min_width;
 uns image_sig_min_height;
 uns *image_sig_prequant_thresholds;
@@ -26,7 +32,16 @@ double image_sig_textured_threshold;
 int image_sig_compare_method;
 uns image_sig_cmp_features_weights[IMAGE_REG_F + IMAGE_REG_H];
 
-static struct cf_section sig_config = {
+static struct cf_section image_lib_config = {
+  CF_ITEMS{
+    CF_UNS("Trace", &image_trace),
+    CF_UNS("ImageMaxDim", &image_max_dim),
+    CF_UNS("ImageMaxBytes", &image_max_bytes),
+    CF_END
+  }
+};
+
+static struct cf_section image_sig_config = {
   CF_ITEMS{
     CF_UNS("MinWidth", &image_sig_min_width),
     CF_UNS("MinHeight", &image_sig_min_height),
@@ -47,5 +62,6 @@ static struct cf_section sig_config = {
 static void CONSTRUCTOR
 images_init_config(void)
 {
-  cf_declare_section("ImageSig", &sig_config, 0);
+  cf_declare_section("ImageLib", &image_lib_config, 0);
+  cf_declare_section("ImageSig", &image_sig_config, 0);
 }
diff --git a/images/context.c b/images/context.c
new file mode 100644 (file)
index 0000000..bcabc52
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *     Image Library -- Image contexts
+ *
+ *     (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 "lib/bbuf.h"
+#include "images/images.h"
+#include "images/error.h"
+
+#include <string.h>
+
+void
+image_context_init(struct image_context *ctx)
+{
+  bzero(ctx, sizeof(*ctx));
+  bb_init(&ctx->msg_buf);
+  ctx->tracing_level = image_trace;
+  ctx->msg_callback = image_context_msg_default;
+}
+
+void
+image_context_cleanup(struct image_context *ctx)
+{
+  IMAGE_TRACE(ctx, 10, "Destroying image thread");
+  bb_done(&ctx->msg_buf);
+}
+
+void
+image_context_msg_default(struct image_context *ctx)
+{
+  log(ctx->msg_code >> 24, "%s", ctx->msg);
+}
+
+void
+image_context_msg_silent(struct image_context *ctx UNUSED)
+{
+}
+
+void
+image_context_msg(struct image_context *ctx, uns code, char *msg, ...)
+{
+  ctx->msg_code = code;
+  va_list args;
+  va_start(args, msg);
+  ctx->msg = bb_vprintf(&ctx->msg_buf, msg, args);
+  va_end(args);
+  ctx->msg_callback(ctx);
+}
+
+void
+image_context_vmsg(struct image_context *ctx, uns code, char *msg, va_list args)
+{
+  ctx->msg_code = code;
+  ctx->msg = bb_vprintf(&ctx->msg_buf, msg, args);
+  ctx->msg_callback(ctx);
+}
index da4b2be4d743114364a62f7f2a4fb4996a770712..1dda196c30a9a90463bcab01355837ccdb616f0b 100644 (file)
@@ -13,6 +13,7 @@
 #include "lib/mempool.h"
 #include "lib/fastbuf.h"
 #include "images/images.h"
+#include "images/color.h"
 #include "images/duplicates.h"
 
 #include <fcntl.h>
@@ -20,9 +21,9 @@
 static uns image_dup_tab_limit = 8;
 
 static inline struct image *
-image_dup_subimage(struct image_thread *thread, struct image_dup *dup, struct image *block, uns tab_col, uns tab_row)
+image_dup_subimage(struct image_context *ctx, struct image_dup *dup, struct image *block, uns tab_col, uns tab_row)
 {
-  return image_init_matrix(thread, block, image_dup_block(dup, tab_col, tab_row),
+  return image_init_matrix(ctx, block, image_dup_block(dup, tab_col, tab_row),
       1 << tab_col, 1 << tab_row, 3 << tab_col, COLOR_SPACE_RGB);
 }
 
@@ -44,7 +45,7 @@ image_dup_estimate_size(uns cols, uns rows)
 }
 
 uns
-image_dup_init(struct image_thread *thread, struct image_dup *dup, struct image *img, struct mempool *pool)
+image_dup_init(struct image_context *ctx, struct image_dup *dup, struct image *img, struct mempool *pool)
 {
   DBG("image_dup_init()");
 
@@ -59,9 +60,9 @@ image_dup_init(struct image_thread *thread, struct image_dup *dup, struct image
   /* Scale original image to right bottom block */
   {
     struct image block;
-    if (!image_dup_subimage(thread, dup, &block, dup->tab_cols, dup->tab_rows))
+    if (!image_dup_subimage(ctx, dup, &block, dup->tab_cols, dup->tab_rows))
       return 0;
-    if (!image_scale(thread, &block, img))
+    if (!image_scale(ctx, &block, img))
       return 0;
   }
 
index 07db2afe70911ef6e608100d8020d06994b482df..dd07b763cc6c4679817b2998b9db31a521cedd65 100644 (file)
@@ -24,7 +24,7 @@ struct image_dup {
 
 /* dup-init.c */
 
-uns image_dup_init(struct image_thread *thread, struct image_dup *dup, struct image *image, struct mempool *pool);
+uns image_dup_init(struct image_context *ctx, struct image_dup *dup, struct image *image, struct mempool *pool);
 uns image_dup_estimate_size(uns cols, uns rows);
 
 /* dup-cmp.c */
diff --git a/images/error.h b/images/error.h
new file mode 100644 (file)
index 0000000..92f3766
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _IMAGES_ERROR_H
+#define _IMAGES_ERROR_H
+
+extern uns image_trace; /* ImageLib.Trace */ 
+
+/* Error codes */
+
+enum image_msg_code {
+  IMAGE_MSG_TYPE = 0xff000000,
+  IMAGE_MSG_TRACE = (L_DEBUG << 24),
+  IMAGE_MSG_WARN = (L_WARN << 24),
+  IMAGE_MSG_ERROR = (L_ERROR << 24),
+  IMAGE_TRACE_LEVEL = 0x0000ffff,
+  IMAGE_WARN_TYPE = 0x0000ffff,
+  IMAGE_WARN_SUBTYPE = 0x00ff0000,
+  IMAGE_ERROR_TYPE = 0x0000ffff,
+  IMAGE_ERROR_SUBTYPE = 0x00ff0000,
+  IMAGE_ERROR_NOT_IMPLEMENTED = 1,
+  IMAGE_ERROR_INVALID_DIMENSIONS = 2,
+  IMAGE_ERROR_INVALID_FILE_FORMAT = 3,
+  IMAGE_ERROR_INVALID_PIXEL_FORMAT = 4,
+  IMAGE_ERROR_READ_FAILED = 5,
+  IMAGE_ERROR_WRITE_FAILED = 6,
+};
+
+/* Useful macros */
+
+#define IMAGE_WARN(ctx, type, msg...) image_context_msg((ctx), IMAGE_MSG_WARN | (type), msg)
+#define IMAGE_ERROR(ctx, type, msg...) image_context_msg((ctx), IMAGE_MSG_ERROR | (type), msg)
+
+#define IMAGE_TRACE(ctx, level, msg...) do { \
+       struct image_context *_ctx = (ctx); uns _level = (level); \
+       if (_level < _ctx->tracing_level) image_context_msg(_ctx, IMAGE_MSG_TRACE | _level, msg); } while (0)
+
+#endif
index ecfa5500f1fb22266bd15acf7d479327efe64101..cbd37e5a89e5b00eaff3c62a546f8614fa54a73c 100644 (file)
@@ -10,6 +10,7 @@
 #include "lib/lib.h"
 #include "lib/getopt.h"
 #include "lib/fastbuf.h"
+#include "lib/mempool.h"
 #include "images/images.h"
 #include "images/color.h"
 #include "images/duplicates.h"
@@ -106,16 +107,15 @@ main(int argc, char **argv)
   file_name_1 = argv[optind++];
   file_name_2 = argv[optind];
   
-#define TRY(x) do{ if (!(x)) die("Error: %s", it.err_msg); }while(0)
+#define TRY(x) do{ if (!(x)) exit(1); }while(0)
   MSG("Initializing image library");
-  struct image_thread it;
+  struct image_context ctx;
   struct image_io io;
-  image_thread_init(&it);
+  image_context_init(&ctx);
 
   struct image *img1, *img2;
 
-  if (!image_io_init(&it, &io))
-    die("Cannot initialize image I/O (%s)", it.err_msg);
+  TRY(image_io_init(&ctx, &io));
   MSG("Reading %s", file_name_1);
   io.fastbuf = bopen(file_name_1, O_RDONLY, 1 << 18);
   io.format = format_1 ? : image_file_name_to_format(file_name_1);
@@ -149,8 +149,8 @@ main(int argc, char **argv)
   struct image_dup dup1, dup2;
   struct mempool *pool = mp_new(1 << 18);
   MSG("Creating internal structures");
-  TRY(image_dup_init(&it, &dup1, img1, pool));
-  TRY(image_dup_init(&it, &dup2, img2, pool));
+  TRY(image_dup_init(&ctx, &dup1, img1, pool));
+  TRY(image_dup_init(&ctx, &dup2, img2, pool));
 
   MSG("Similarity bitmap %02x", image_dup_compare(&dup1, &dup2, transformations | IMAGE_DUP_SCALE | IMAGE_DUP_WANT_ALL));
 
@@ -158,7 +158,7 @@ main(int argc, char **argv)
   
   image_destroy(img1);
   image_destroy(img2);
-  image_thread_cleanup(&it);
+  image_context_cleanup(&ctx);
   MSG("Done.");
   return 0;
 }
index bac384ec28a673113effe453b46621e08fda9664..22f3951cc7348d95ef3b952045b2714212ece442 100644 (file)
@@ -13,6 +13,7 @@
 #include "images/images.h"
 #include "images/color.h"
 #include "images/signature.h"
+
 #include <stdlib.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -60,7 +61,7 @@ static byte *segmentation_name_1;
 static byte *segmentation_name_2;
 
 #define MSG(x...) do{ if (verbose) log(L_INFO, ##x); }while(0)
-#define TRY(x) do{ if (!(x)) die("Error: %s", it.err_msg); }while(0)
+#define TRY(x) do{ if (!(x)) exit(1); }while(0)
 
 static void
 msg_str(byte *s, void *param UNUSED)
@@ -81,7 +82,7 @@ dump_signature(struct image_signature *sig)
     }
 }
 
-static struct image_thread it;
+static struct image_context ctx;
 static struct image_io io;
 
 static void
@@ -91,8 +92,8 @@ write_segmentation(struct image_sig_data *data, byte *fn)
   
   struct fastbuf *fb = bopen(fn, O_WRONLY | O_CREAT | O_TRUNC, 4096);
   struct image *img;
-  TRY(img = image_new(&it, data->image->cols, data->image->rows, COLOR_SPACE_RGB, NULL));
-  image_clear(&it, img);
+  TRY(img = image_new(&ctx, data->image->cols, data->image->rows, COLOR_SPACE_RGB, NULL));
+  image_clear(&ctx, img);
 
   for (uns i = 0; i < data->regions_count; i++)
     {
@@ -101,8 +102,8 @@ write_segmentation(struct image_sig_data *data, byte *fn)
       luv[0] = data->regions[i].a[0] * (4 / 2.55);
       luv[1] = ((int)data->regions[i].a[1] - 128) * (4 / 2.55);
       luv[2] = ((int)data->regions[i].a[2] - 128) * (4 / 2.55);
-      luv_to_xyz_slow(xyz, luv);
-      xyz_to_srgb_slow(srgb, xyz);
+      luv_to_xyz_exact(xyz, luv);
+      xyz_to_srgb_exact(srgb, xyz);
       c[0] = CLAMP(srgb[0] * 255, 0, 255); 
       c[1] = CLAMP(srgb[1] * 255, 0, 255); 
       c[2] = CLAMP(srgb[2] * 255, 0, 255); 
@@ -186,12 +187,11 @@ main(int argc, char **argv)
   MSG("Initializing image library");
   srandom(time(NULL) ^ getpid());
   srgb_to_luv_init();
-  image_thread_init(&it);
+  image_context_init(&ctx);
 
   struct image *img1, *img2;
 
-  if (!image_io_init(&it, &io))
-    die("Cannot initialize image I/O (%s)", it.err_msg);
+  TRY(image_io_init(&ctx, &io));
 
   if (file_name_1)
     {
@@ -238,7 +238,7 @@ main(int argc, char **argv)
   if (img1)
     {
       struct image_sig_data data;
-      TRY(image_sig_init(&it, &data, img1));
+      TRY(image_sig_init(&ctx, &data, img1));
       image_sig_preprocess(&data);
       if (data.valid)
         {
@@ -254,7 +254,7 @@ main(int argc, char **argv)
   if (img2)
     {
       struct image_sig_data data;
-      TRY(image_sig_init(&it, &data, img2));
+      TRY(image_sig_init(&ctx, &data, img2));
       image_sig_preprocess(&data);
       if (data.valid)
         {
@@ -288,7 +288,7 @@ main(int argc, char **argv)
     image_destroy(img2);
 
   image_io_cleanup(&io);
-  image_thread_cleanup(&it);
+  image_context_cleanup(&ctx);
   MSG("Done.");
   return 0;
 }
index 1e49d284dd1b66d68044aff9bcf397bc9de9b440..c751e8a0225ccd3c0bc0f3ed7407784c3d056976 100644 (file)
@@ -2,41 +2,54 @@
 
 #include "lib/lib.h"
 #include "lib/mempool.h"
+#include "lib/fastbuf.h"
 #include "images/images.h"
+#include "images/color.h"
+
+#include <stdlib.h>
 #include <string.h>
+#include <pthread.h>
+#include <time.h>
+#include <unistd.h>
 
 static uns want_image_iface;
+static uns want_threads;
+
+#define TRY(x) do { if (!(x)) ASSERT(0); } while (0)
 
 static void
 test_image_iface(void)
 {
   struct mempool *pool;
-  struct image_thread it;
+  struct image_context ctx;
   struct image *i1, *i2;
   struct image s1;
-  int i;
 
   pool = mp_new(1024);
-  image_thread_init(&it);
+  image_context_init(&ctx);
 
-  i1 = image_new(&it, 731, 327, COLOR_SPACE_RGB, NULL);
+  /* Image allocation */
+  i1 = image_new(&ctx, 731, 327, COLOR_SPACE_RGB, NULL);
   ASSERT(i1);
   ASSERT(i1->pixel_size == 3);
   image_destroy(i1);
 
-  i1 = image_new(&it, 2214, 0, COLOR_SPACE_RGB, NULL);
+  /* Test invalid image size  */
+  ctx.msg_callback = image_context_msg_silent;
+  i1 = image_new(&ctx, 2214, 0, COLOR_SPACE_RGB, NULL);
   ASSERT(!i1);
-
-  i1 = image_new(&it, 0xffffff, 0xffffff, COLOR_SPACE_RGB, NULL);
+  i1 = image_new(&ctx, 0xffffff, 0xffffff, COLOR_SPACE_RGB, NULL);
   ASSERT(!i1);
+  ctx.msg_callback = image_context_msg_default;
 
-  i1 = image_new(&it, 370, 100, COLOR_SPACE_GRAYSCALE, pool);
+  /* Various image allocatio parameters */
+  i1 = image_new(&ctx, 370, 100, COLOR_SPACE_GRAYSCALE, pool);
   ASSERT(i1);
   ASSERT(i1->pixel_size == 1);
   image_destroy(i1);
   mp_flush(pool);
 
-  i1 = image_new(&it, 373, 101, COLOR_SPACE_RGB | IMAGE_ALIGNED, NULL);
+  i1 = image_new(&ctx, 373, 101, COLOR_SPACE_RGB | IMAGE_ALIGNED, NULL);
   ASSERT(i1);
   ASSERT(i1->pixel_size == 4);
   ASSERT(IMAGE_SSE_ALIGN_SIZE >= 16);
@@ -44,38 +57,158 @@ test_image_iface(void)
   ASSERT(!((addr_int_t)i1->pixels & (IMAGE_SSE_ALIGN_SIZE - 1)));
   image_destroy(i1);
 
-  i1 = image_new(&it, 283, 329, COLOR_SPACE_RGB, NULL);
+  i1 = image_new(&ctx, 283, 329, COLOR_SPACE_RGB, NULL);
   ASSERT(i1);
   ASSERT(i1->pixel_size == 3);
 
-  i2 = image_clone(&it, i1, COLOR_SPACE_RGB, NULL);
+  /* Image structures cloning */
+  i2 = image_clone(&ctx, i1, COLOR_SPACE_RGB, NULL);
   ASSERT(i2);
   ASSERT(i2->pixel_size == 3);
   image_destroy(i2);
 
-  i2 = image_clone(&it, i1, COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED, NULL);
+  i2 = image_clone(&ctx, i1, COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED, NULL);
   ASSERT(i2);
   ASSERT(i2->pixel_size == 4);
   image_destroy(i2);
 
-  i = image_init_subimage(&it, &s1, i1, 29, 39, 283 - 29, 100);
-  ASSERT(i);
+  /* Subimages */
+  i2 = image_init_subimage(&ctx, &s1, i1, 29, 39, 283 - 29, 100);
+  ASSERT(i2);
   image_destroy(&s1);
 
   image_destroy(i1);
 
-  image_thread_cleanup(&it);
+  image_context_cleanup(&ctx);
   mp_delete(pool);
 }
 
+#define TEST_THREADS_COUNT 4
+
+static void *
+test_threads_thread(void *param UNUSED)
+{
+  DBG("Starting thread");
+  struct image_context ctx;
+  struct image_io io;
+  image_context_init(&ctx);
+  TRY(image_io_init(&ctx, &io));
+
+  for (uns num = 0; num < 200; num++)
+    {
+      int r0 = random_max(100);
+
+      /* realloc context */
+      if ((r0 -= 2) < 0)
+        {
+         image_io_cleanup(&io);
+         image_context_cleanup(&ctx);
+         image_context_init(&ctx);
+         TRY(image_io_init(&ctx, &io));
+       }
+
+      /* realloc I/O */
+      else if ((r0 -= 2) < 0)
+        {
+         image_io_cleanup(&io);
+         TRY(image_io_init(&ctx, &io));
+       }
+
+      /* encode and decode random image */
+      else
+        {
+          struct image *img;
+
+          TRY(img = image_new(&ctx, 10 + random_max(140), 10 + random_max(140), COLOR_SPACE_RGB, NULL));
+         image_clear(&ctx, img);
+
+#if defined(CONFIG_IMAGES_LIBJPEG) || defined(CONFIG_IMAGES_LIBPNG) || defined(CONFIG_IMAGES_LIBMAGICK)
+
+         struct fastbuf *wfb = fbmem_create(10000);
+         struct fastbuf *rfb;
+         uns format = 0;
+         while (!format)
+           {
+             switch (random_max(2))
+               {
+                 case 0:
+#if defined(CONFIG_IMAGES_LIBJPEG) || defined(CONFIG_IMAGES_LIBMAGICK)
+                   format = IMAGE_FORMAT_JPEG;
+#endif
+                   break;
+                 case 1:
+#if defined(CONFIG_IMAGES_LIBPNG) || defined(CONFIG_IMAGES_LIBMAGICK)
+                   format = IMAGE_FORMAT_PNG;
+#endif
+                   break;
+                 default:
+                   ASSERT(0);
+               }
+           }
+
+         io.format = format;
+         io.fastbuf = wfb;
+         io.image = img;
+         TRY(image_io_write(&io));
+         image_io_reset(&io);
+
+         rfb = fbmem_clone_read(wfb);
+         io.format = format;
+         io.fastbuf = rfb;
+         TRY(image_io_read(&io, 0));
+         image_io_reset(&io);
+
+         bclose(rfb);
+         bclose(wfb);
+
+#endif
+          image_destroy(img);
+       }
+    }
+
+  image_io_cleanup(&io);
+  image_context_cleanup(&ctx);
+  DBG("Stopping thread");
+  return NULL;
+}
+
+static void
+test_threads(void)
+{
+  pthread_t threads[TEST_THREADS_COUNT - 1];
+  pthread_attr_t attr;
+  if (pthread_attr_init(&attr) < 0 ||
+      pthread_attr_setstacksize(&attr, 1 << 20) < 0)
+    ASSERT(0);
+  for (uns i = 0; i < TEST_THREADS_COUNT - 1; i++)
+    {
+      if (pthread_create(threads + i, &attr, test_threads_thread, NULL) < 0)
+        die("Unable to create thread: %m");
+    }
+  test_threads_thread(NULL);
+  for (uns i = 0; i < TEST_THREADS_COUNT - 1; i++)
+    if (pthread_join(threads[i], NULL) < 0)
+      die("Cannot join thread: %m");
+}
+
 int
 main(int argc, char **argv)
 {
-  for (int i = 0; i < argc; i++)
+  for (int i = 1; i < argc; i++)
     if (!strcmp(argv[i], "image-iface"))
-      want_image_iface = 1;
+      want_image_iface++;
+    else if (!strcmp(argv[i], "threads"))
+      want_threads++;
+    else
+      die("Invalid parameter");
+
+  srandom(time(NULL) ^ getpid());
+  
   if (want_image_iface)
     test_image_iface();
+  if (want_threads)
+    test_threads();
+  
   return 0;
 }
 
index 1d4f68a0e45416e37c4ee8d510319b28655fe40f..e37f44969ce3b5c3645805e00ce3f36a28da90d0 100644 (file)
@@ -166,13 +166,14 @@ main(int argc, char **argv)
   if (argc > optind)
     output_file_name = argv[optind];
 
-#define TRY(x) do{ if (!(x)) die("Error: %s", it.err_msg); }while(0)
+#define TRY(x) do{ if (!(x)) exit(1); }while(0)
   MSG("Initializing image library");
-  struct image_thread it;
+  struct image_context ctx;
   struct image_io io;
-  image_thread_init(&it);
-  if (!image_io_init(&it, &io))
-    die("Cannot initialize image I/O (%s)", it.err_msg);
+  image_context_init(&ctx);
+  ctx.tracing_level = ~0U;
+  if (!image_io_init(&ctx, &io))
+    die("Cannot initialize image I/O");
 
   MSG("Reading %s", input_file_name);
   io.fastbuf = bopen(input_file_name, O_RDONLY, 1 << 18);
@@ -238,7 +239,7 @@ main(int argc, char **argv)
     }
 
   image_io_cleanup(&io);
-  image_thread_cleanup(&it);
+  image_context_cleanup(&ctx);
   MSG("Done.");
   return 0;
 }
index deb8f9f81141f81b4d53425ad2e6074c5a9b8b7c..48d5d6b9b116f7c12ae490d0e0fc77b37f587a94 100644 (file)
 #include "lib/lib.h"
 #include "lib/mempool.h"
 #include "images/images.h"
-#include <string.h>
-
-#define MAX_IMAGE_BYTES (1 << 30)
-
-void
-image_thread_init(struct image_thread *it)
-{
-  DBG("image_thread_init()");
-  bzero(it, sizeof(*it));
-  it->pool = mp_new(1024);
-}
-
-void
-image_thread_cleanup(struct image_thread *it)
-{
-  DBG("image_thread_cleanup()");
-  mp_delete(it->pool);
-}
+#include "images/error.h"
+#include "images/color.h"
 
-void
-image_thread_err_format(struct image_thread *it, uns code, char *msg, ...)
-{
-  va_list args;
-  va_start(args, msg);
-  it->err_code = code;
-  it->err_msg = mp_vprintf(it->pool, msg, args);
-  va_end(args);
-}
+#include <string.h>
 
 static inline uns
 flags_to_pixel_size(uns flags)
@@ -62,13 +38,13 @@ flags_to_pixel_size(uns flags)
 }
 
 struct image *
-image_new(struct image_thread *it, uns cols, uns rows, uns flags, struct mempool *pool)
+image_new(struct image_context *ctx, uns cols, uns rows, uns flags, struct mempool *pool)
 {
   DBG("image_new(cols=%u rows=%u flags=0x%x pool=%p)", cols, rows, flags, pool);
   flags &= IMAGE_NEW_FLAGS;
   if (unlikely(!image_dimensions_valid(cols, rows)))
     {
-      image_thread_err_format(it, IMAGE_ERR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows);
+      IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows);
       return NULL;
     }
   struct image *img;
@@ -98,9 +74,9 @@ image_new(struct image_thread *it, uns cols, uns rows, uns flags, struct mempool
   row_size = ALIGN(row_size, align);
   u64 image_size_64 = (u64)row_size * rows;
   u64 bytes_64 = image_size_64 + (sizeof(struct image) + IMAGE_SSE_ALIGN_SIZE - 1 + sizeof(uns));
-  if (unlikely(bytes_64 > MAX_IMAGE_BYTES))
+  if (unlikely(bytes_64 > image_max_bytes))
     {
-      image_thread_err(it, IMAGE_ERR_INVALID_DIMENSIONS, "Image does not fit in memory");
+      IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Image does not fit in memory");
       return NULL;
     }
   if (pool)
@@ -125,13 +101,13 @@ image_new(struct image_thread *it, uns cols, uns rows, uns flags, struct mempool
 }
 
 struct image *
-image_clone(struct image_thread *it, struct image *src, uns flags, struct mempool *pool)
+image_clone(struct image_context *ctx, struct image *src, uns flags, struct mempool *pool)
 {
   DBG("image_clone(src=%p flags=0x%x pool=%p)", src, src->flags, pool);
   struct image *img;
   flags &= IMAGE_NEW_FLAGS & ~IMAGE_CHANNELS_FORMAT;
   flags |= src->flags & IMAGE_CHANNELS_FORMAT;
-  if (!(img = image_new(it, src->cols, src->rows, flags, pool)))
+  if (!(img = image_new(ctx, src->cols, src->rows, flags, pool)))
     return NULL;
   if (img->image_size)
     {
@@ -172,7 +148,7 @@ image_destroy(struct image *img)
 }
 
 void
-image_clear(struct image_thread *it UNUSED, struct image *img)
+image_clear(struct image_context *ctx UNUSED, struct image *img)
 {
   DBG("image_clear(img=%p)", img);
   if (img->image_size)
@@ -188,12 +164,12 @@ image_clear(struct image_thread *it UNUSED, struct image *img)
 }
 
 struct image *
-image_init_matrix(struct image_thread *it, struct image *img, byte *pixels, uns cols, uns rows, uns row_size, uns flags)
+image_init_matrix(struct image_context *ctx, struct image *img, byte *pixels, uns cols, uns rows, uns row_size, uns flags)
 {
   DBG("image_init_matrix(img=%p pixels=%p cols=%u rows=%u row_size=%u flags=0x%x)", img, pixels, cols, rows, row_size, flags);
   if (unlikely(!image_dimensions_valid(cols, rows)))
     {
-      image_thread_err_format(it, IMAGE_ERR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows);
+      IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows);
       return NULL;
     }
   img->pixels = pixels;
@@ -207,7 +183,7 @@ image_init_matrix(struct image_thread *it, struct image *img, byte *pixels, uns
 }
 
 struct image *
-image_init_subimage(struct image_thread *it UNUSED, struct image *img, struct image *src, uns left, uns top, uns cols, uns rows)
+image_init_subimage(struct image_context *ctx UNUSED, struct image *img, struct image *src, uns left, uns top, uns cols, uns rows)
 {
   DBG("image_init_subimage(img=%p src=%p left=%u top=%u cols=%u rows=%u)", img, src, left, top, cols, rows);
   ASSERT(left + cols <= src->cols && top + rows <= src->rows);
@@ -223,7 +199,7 @@ image_init_subimage(struct image_thread *it UNUSED, struct image *img, struct im
 }
 
 byte *
-color_space_to_name(enum color_space cs)
+color_space_to_name(uns cs)
 {
   return image_channels_format_to_name(cs);
 }
index 460f5881c9fa4e5f698fa927a044af6bd9d723f9..2b698dc96c1c23f848ae63ca8f35b05bc758d78b 100644 (file)
@@ -1,76 +1,66 @@
+/*
+ *     Image Library -- Main hearer file
+ *
+ *     (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.
+ */
+
 #ifndef _IMAGES_IMAGES_H
 #define _IMAGES_IMAGES_H
 
-#include "lib/mempool.h"
+#include "lib/bbuf.h"
 
-/* image.c */
+struct mempool;
+struct fastbuf;
 
-/* error handling */
 
-enum image_error {
-  IMAGE_ERR_OK = 0,
-  IMAGE_ERR_UNSPECIFIED,
-  IMAGE_ERR_NOT_IMPLEMENTED,
-  IMAGE_ERR_INVALID_DIMENSIONS,
-  IMAGE_ERR_INVALID_FILE_FORMAT,
-  IMAGE_ERR_INVALID_PIXEL_FORMAT,
-  IMAGE_ERR_READ_FAILED,
-  IMAGE_ERR_WRITE_FAILED,
-  IMAGE_ERR_MAX
-};
+/* context.c
+ * - contexts with error/message handling
+ * - imagelib is thread-safe until each context is bounded to a single thread */
 
-struct image_thread {
-  byte *err_msg;
-  enum image_error err_code;
-  struct mempool *pool;
+struct image_context {
+  byte *msg;                           /* last message */
+  uns msg_code;                                /* last message code (see images/error.h for details) */
+  bb_t msg_buf;                                /* message buffer */
+  void (*msg_callback)(struct image_context *ctx); /* called for each message (in msg_{str,code}) */
+  uns tracing_level;                   /* tracing level (zero to disable) */
 };
 
-void image_thread_init(struct image_thread *thread);
-void image_thread_cleanup(struct image_thread *thread);
+/* initialization/cleanup */
+void image_context_init(struct image_context *ctx);
+void image_context_cleanup(struct image_context *ctx);
 
-static inline void
-image_thread_flush(struct image_thread *thread)
-{
-  thread->err_code = 0;
-  thread->err_msg = NULL;
-  mp_flush(thread->pool);
-}
+/* message handling, see images/error.h for useful macros */
+void image_context_msg(struct image_context *ctx, uns code, char *msg, ...);
+void image_context_vmsg(struct image_context *ctx, uns code, char *msg, va_list args);
 
-static inline void
-image_thread_err(struct image_thread *thread, uns code, char *msg)
-{
-  thread->err_code = code;
-  thread->err_msg = (byte *)msg;
-}
+/* default callback, displays messages with standard libucw's log() routine */
+void image_context_msg_default(struct image_context *ctx);
 
-static inline void
-image_thread_err_dup(struct image_thread *thread, uns code, char *msg)
-{
-  thread->err_code = code;
-  thread->err_msg = mp_strdup(thread->pool, msg);
-}
+/* empty callback */
+void image_context_msg_silent(struct image_context *ctx);
 
-void image_thread_err_format(struct image_thread *thread, uns code, char *msg, ...);
 
-/* basic image manupulation */
+/* image.c
+ * - basic manipulation with images
+ * - image structure is not directly connected to a single context
+ *   but manipulation routines are (user must synchronize the access himself)! */
 
-#define IMAGE_MAX_SIZE         0xffffU /* maximum number of cols/rows, must be <(1<<16) */
-#define IMAGE_SSE_ALIGN_SIZE   (MAX(16, sizeof(uns)))
+extern uns image_max_dim;              /* ImageLib.ImageMaxDim */
+extern uns image_max_bytes;            /* ImageLib.ImageMaxBytes */
 
-enum color_space {
-  COLOR_SPACE_UNKNOWN,
-  COLOR_SPACE_GRAYSCALE,
-  COLOR_SPACE_RGB,
-  COLOR_SPACE_MAX
-};
+/* SSE aligning size, see IMAGE_SSE_ALIGNED */
+#define IMAGE_SSE_ALIGN_SIZE (MAX(16, sizeof(uns)))
 
 enum image_flag {
-  IMAGE_COLOR_SPACE = 0x7,     /* mask for enum color_space */
-  IMAGE_ALPHA = 0x8,           /* alpha channel */
-  IMAGE_PIXELS_ALIGNED = 0x10, /* align pixel size to the nearest power of two  */
-  IMAGE_SSE_ALIGNED = 0x20,    /* align scanlines to multiples of 16 bytes (both start and size) */
-  IMAGE_NEED_DESTROY = 0x40,   /* image is allocated with xmalloc */
-  IMAGE_GAPS_PROTECTED = 0x80, /* cannot access gaps between rows */
+  IMAGE_COLOR_SPACE = 0x7,             /* mask for enum color_space */
+  IMAGE_ALPHA = 0x8,                   /* alpha channel */
+  IMAGE_PIXELS_ALIGNED = 0x10,         /* align pixel size to the nearest power of two  */
+  IMAGE_SSE_ALIGNED = 0x20,            /* align scanlines to multiples of 16 bytes (both start and size) */
+  IMAGE_NEED_DESTROY = 0x40,           /* image is allocated with xmalloc */
+  IMAGE_GAPS_PROTECTED = 0x80,         /* cannot access gaps between rows */
   IMAGE_CHANNELS_FORMAT = IMAGE_COLOR_SPACE | IMAGE_ALPHA,
   IMAGE_PIXEL_FORMAT = IMAGE_CHANNELS_FORMAT | IMAGE_PIXELS_ALIGNED,
   IMAGE_ALIGNED = IMAGE_PIXELS_ALIGNED | IMAGE_SSE_ALIGNED,
@@ -79,7 +69,7 @@ enum image_flag {
 };
 
 struct image {
-  byte *pixels;                        /* left top pixel, there are at least sizeof(uns)
+  byte *pixels;                        /* aligned top left pixel, there are at least sizeof(uns)
                                   unsed bytes after the buffer (possible optimizations) */
   u32 cols;                    /* number of columns */
   u32 rows;                    /* number of rows */
@@ -89,20 +79,20 @@ struct image {
   u32 flags;                   /* enum image_flag */
 };
 
-struct image *image_new(struct image_thread *it, uns cols, uns rows, uns flags, struct mempool *pool);
-struct image *image_clone(struct image_thread *it, struct image *src, uns flags, struct mempool *pool);
+struct image *image_new(struct image_context *ctx, uns cols, uns rows, uns flags, struct mempool *pool);
+struct image *image_clone(struct image_context *ctx, struct image *src, uns flags, struct mempool *pool);
 void image_destroy(struct image *img);
-void image_clear(struct image_thread *it, struct image *img);
-struct image *image_init_matrix(struct image_thread *it, struct image *img, byte *pixels, uns cols, uns rows, uns row_size, uns flags);
-struct image *image_init_subimage(struct image_thread *it, struct image *img, struct image *src, uns left, uns top, uns cols, uns rows);
+void image_clear(struct image_context *ctx, struct image *img);
+struct image *image_init_matrix(struct image_context *ctx, struct image *img, byte *pixels, uns cols, uns rows, uns row_size, uns flags);
+struct image *image_init_subimage(struct image_context *ctx, struct image *img, struct image *src, uns left, uns top, uns cols, uns rows);
 
 static inline int
 image_dimensions_valid(uns cols, uns rows)
 {
-  return cols && rows && cols <= IMAGE_MAX_SIZE && rows <= IMAGE_MAX_SIZE;
+  return cols && rows && cols <= image_max_dim && rows <= image_max_dim;
 }
 
-byte *color_space_to_name(enum color_space cs);
+byte *color_space_to_name(uns cs);
 byte *image_channels_format_to_name(uns format);
 uns image_name_to_channels_format(byte *name);
 
@@ -113,12 +103,12 @@ struct color {
 
 /* scale.c */
 
-int image_scale(struct image_thread *thread, struct image *dest, struct image *src);
+int image_scale(struct image_context *ctx, struct image *dest, struct image *src);
 void image_dimensions_fit_to_box(u32 *cols, u32 *rows, u32 max_cols, u32 max_rows, uns upsample);
 
 /* alpha.c */
 
-int image_apply_background(struct image_thread *thread, struct image *dest, struct image *src, struct color *background);
+int image_apply_background(struct image_context *ctx, struct image *dest, struct image *src, struct color *background);
 
 /* image-io.c */
 
@@ -153,7 +143,7 @@ struct image_io {
 #endif
 
   /* internals */
-  struct image_thread *thread;
+  struct image_context *context;
   struct mempool *internal_pool;
   void *read_data;
   void (*read_cancel)(struct image_io *io);
@@ -169,7 +159,7 @@ enum image_io_flags {
 #endif
 };
 
-int image_io_init(struct image_thread *it, struct image_io *io);
+int image_io_init(struct image_context *ctx, struct image_io *io);
 void image_io_cleanup(struct image_io *io);
 void image_io_reset(struct image_io *io);
 
index 10c49d7d91d1b256eb7683de3cac9d5cb7f47600..30bd0fff4b90061f16a135a275e7bbd2c9a73634 100644 (file)
 #include "lib/mempool.h"
 #include "lib/fastbuf.h"
 #include "images/images.h"
+#include "images/error.h"
+#include "images/color.h"
 #include "images/io-main.h"
+
 #include <stdio.h>
 #include <sys/types.h>
 #include <jpeglib.h>
@@ -49,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_thread_err_dup(e->io->thread, IMAGE_ERR_READ_FAILED, buf);
+  IMAGE_ERROR(e->io->context, IMAGE_ERROR_READ_FAILED, "%s", buf);
   longjmp(e->setjmp_buf, 1);
 }
 
@@ -60,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_thread_err_dup(e->io->thread, IMAGE_ERR_WRITE_FAILED,  buf);
+  IMAGE_ERROR(e->io->context, IMAGE_ERROR_WRITE_FAILED, "%s", buf);
   longjmp(e->setjmp_buf, 1);
 }
 
@@ -148,7 +151,7 @@ libjpeg_fastbuf_write_prepare(struct libjpeg_write_internals *i)
   i->dest.free_in_buffer = len;
   if (!len)
     {
-      image_thread_err(i->err.io->thread, IMAGE_ERR_WRITE_FAILED, "Unexpected end of stream");
+      IMAGE_ERROR(i->err.io->context, IMAGE_ERROR_WRITE_FAILED, "Unexpected end of stream");
       longjmp(i->err.setjmp_buf, 1);
     }
 }
@@ -324,7 +327,7 @@ libjpeg_read_data(struct image_io *io)
        break;
       default:
        jpeg_destroy_decompress(&i->cinfo);
-       image_thread_err(io->thread, IMAGE_ERR_INVALID_PIXEL_FORMAT, "Unsupported color space.");
+       IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Unsupported color space.");
        return 0;
     }
 
@@ -466,7 +469,7 @@ libjpeg_write(struct image_io *io)
        break;
       default:
        jpeg_destroy_compress(&i.cinfo);
-       image_thread_err(io->thread, IMAGE_ERR_INVALID_PIXEL_FORMAT, "Unsupported pixel format.");
+       IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Unsupported pixel format.");
        return 0;
     }
   jpeg_set_defaults(&i.cinfo);
index f15955a64cf83c045bd953cb1afa33fd96908b96..76b2d2478fc290401842b7dbac350ac4cd3d201b 100644 (file)
 #include "lib/mempool.h"
 #include "lib/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>
 
@@ -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);
 }
 
@@ -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;
     }
 
@@ -193,7 +196,7 @@ libpng_read_data(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_INVALID_PIXEL_FORMAT, "Unsupported color space.");
+       IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Unsupported color space.");
         return 0;
     }
 
@@ -306,17 +309,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;
     }
index 45940edee2f052f9f5d4edd0f937717c50d0bc86..c46484311cbe980a86b6a5032a57972ee56d4e1a 100644 (file)
 #include "lib/mempool.h"
 #include "lib/fastbuf.h"
 #include "images/images.h"
+#include "images/error.h"
 #include "images/color.h"
 #include "images/io-main.h"
+
 #include <gif_lib.h>
 
 struct libungif_read_data {
@@ -47,7 +49,7 @@ libungif_read_header(struct image_io *io)
   GifFileType *gif;
   if (unlikely(!(gif = DGifOpen(io->fastbuf, libungif_read_func))))
     {
-      image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libungif structure.");
+      IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Cannot create libungif structure.");
       return 0;
     }
 
@@ -57,7 +59,7 @@ libungif_read_header(struct image_io *io)
   DBG("executing DGifSlurp()");
   if (unlikely(DGifSlurp(gif) != GIF_OK))
     {
-      image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Gif read failed.");
+      IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Gif read failed.");
       DGifCloseFile(gif);
       return 0;
     }
@@ -65,7 +67,7 @@ libungif_read_header(struct image_io *io)
   DBG("ImageCount=%d ColorResolution=%d SBackGroundColor=%d SColorMap=%p", gif->ImageCount, gif->SColorResolution, gif->SBackGroundColor, gif->SColorMap);
   if (unlikely(!gif->ImageCount))
     {
-      image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "There are no images in gif file.");
+      IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "There are no images in gif file.");
       DGifCloseFile(gif);
       return 0;
     }
@@ -73,16 +75,16 @@ libungif_read_header(struct image_io *io)
   /* Read image parameters */
   SavedImage *image = gif->SavedImages;
   if (unlikely(image->ImageDesc.Width <= 0 || image->ImageDesc.Height <= 0 ||
-      image->ImageDesc.Width > (int)IMAGE_MAX_SIZE || image->ImageDesc.Height > (int)IMAGE_MAX_SIZE))
+      image->ImageDesc.Width > (int)image_max_dim || image->ImageDesc.Height > (int)image_max_dim))
     {
-      image_thread_err(io->thread, IMAGE_ERR_INVALID_DIMENSIONS, "Invalid gif dimensions.");
+      IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid gif dimensions.");
       DGifCloseFile(gif);
       return 0;
     }
   ColorMapObject *color_map = image->ImageDesc.ColorMap ? : gif->SColorMap;
   if (unlikely(!color_map))
     {
-      image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Missing palette.");
+      IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Missing palette.");
       DGifCloseFile(gif);
       return 0;
     }
@@ -90,7 +92,7 @@ libungif_read_header(struct image_io *io)
   io->rows = image->ImageDesc.Height;
   if (unlikely((io->number_of_colors = color_map->ColorCount) > 256))
     {
-      image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Too many gif colors.");
+      IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Too many gif colors.");
       DGifCloseFile(gif);
       return 0;
     }
@@ -106,7 +108,7 @@ libungif_read_header(struct image_io *io)
          DBG("Found graphics control extension");
          if (unlikely(e->ByteCount != 4))
            {
-              image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Invalid graphics control extension.");
+              IMAGE_ERROR(io->context, IMAGE_ERROR_READ_FAILED, "Invalid graphics control extension.");
               DGifCloseFile(gif);
               return 0;
            }
index aca3a8ae9d35e6718a79cbc5aba3f0aeea032033..230a7cfd8f025f73db7b498bcfdbea899f4514eb 100644 (file)
 #undef LOCAL_DEBUG
 
 #include "lib/lib.h"
+#include "lib/mempool.h"
 #include "images/images.h"
+#include "images/error.h"
 #include "images/io-main.h"
+
 #include <string.h>
 
 int
-image_io_init(struct image_thread *it, struct image_io *io)
+image_io_init(struct image_context *ctx, struct image_io *io)
 {
   DBG("image_io_init()");
   bzero(io, sizeof(*io));
-  io->thread = it;
+  io->context = ctx;
 #ifdef CONFIG_IMAGES_LIBJPEG
   if (!libjpeg_init(io))
     goto libjpeg_failed;
@@ -106,11 +109,11 @@ image_io_reset(struct image_io *io)
   image_io_read_cancel(io);
   image_io_image_destroy(io);
   struct mempool *pool = io->internal_pool;
-  struct image_thread *thread = io->thread;
+  struct image_context *ctx = io->context;
   mp_flush(pool);
   bzero(io, sizeof(*io));
   io->internal_pool = pool;
-  io->thread = thread;
+  io->context = ctx;
 }
 
 int
@@ -153,7 +156,7 @@ image_io_read_header(struct image_io *io)
     default:
       ASSERT(0);
   }
-  image_thread_err(io->thread, IMAGE_ERR_INVALID_FILE_FORMAT, "Image format not supported.");
+  IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_FILE_FORMAT, "Image format not supported.");
   return 0;
 }
 
@@ -257,7 +260,7 @@ image_io_write(struct image_io *io)
     default:
       break;
   }
-  image_thread_err(io->thread, IMAGE_ERR_INVALID_FILE_FORMAT, "Output format not supported.");
+  IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_FILE_FORMAT, "Output format not supported.");
   return 0;
 }
 
@@ -304,9 +307,9 @@ image_io_read_data_prepare(struct image_io_read_data_internals *rdi, struct imag
   DBG("image_io_read_data_prepare()");
   if (rdi->need_transformations = io->cols != cols || io->rows != rows ||
       ((io->flags ^ flags) & IMAGE_NEW_FLAGS))
-    return rdi->image = image_new(io->thread, cols, rows, flags & IMAGE_IO_IMAGE_FLAGS, NULL);
+    return rdi->image = image_new(io->context, cols, rows, flags & IMAGE_IO_IMAGE_FLAGS, NULL);
   else
-    return rdi->image = image_new(io->thread, io->cols, io->rows, io->flags & IMAGE_IO_IMAGE_FLAGS, io->pool);
+    return rdi->image = image_new(io->context, io->cols, io->rows, io->flags & IMAGE_IO_IMAGE_FLAGS, io->pool);
 }
 
 int
@@ -322,13 +325,13 @@ image_io_read_data_finish(struct image_io_read_data_internals *rdi, struct image
          uns flags = rdi->image->flags;
          if (!(rdi->need_transformations = ((io->flags ^ rdi->image->flags) & (IMAGE_NEW_FLAGS & ~IMAGE_PIXELS_ALIGNED))))
            flags = io->flags;
-         struct image *img = image_new(io->thread, io->cols, io->rows, flags, rdi->need_transformations ? NULL : io->pool);
+         struct image *img = image_new(io->context, io->cols, io->rows, flags, rdi->need_transformations ? NULL : io->pool);
          if (unlikely(!img))
            {
              image_destroy(rdi->image);
              return 0;
            }
-          if (unlikely(!image_scale(io->thread, img, rdi->image)))
+          if (unlikely(!image_scale(io->context, img, rdi->image)))
             {
               image_destroy(rdi->image);
              image_destroy(img);
@@ -345,13 +348,13 @@ image_io_read_data_finish(struct image_io_read_data_internals *rdi, struct image
          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->thread, io->cols, io->rows, flags, rdi->need_transformations ? NULL : io->pool);
+         struct image *img = image_new(io->context, io->cols, io->rows, flags, rdi->need_transformations ? NULL : io->pool);
          if (unlikely(!img))
            {
              image_destroy(rdi->image);
              return 0;
            }
-          if (unlikely(!image_apply_background(io->thread, img, rdi->image, &io->background_color)))
+          if (unlikely(!image_apply_background(io->context, img, rdi->image, &io->background_color)))
             {
               image_destroy(rdi->image);
              image_destroy(img);
index 2c351cbdcb6714d47e4a4f74a69bff680dbea3d3..e987e0f58651663ffaf2433bacf4c5a834a53fe4 100644 (file)
@@ -11,6 +11,8 @@
 
 #include "lib/lib.h"
 #include "images/images.h"
+#include "images/error.h"
+
 #include <string.h>
 
 #define IMAGE_SCALE_PREFIX(x) image_scale_1_##x
 #include "images/scale-gen.h"
 
 int
-image_scale(struct image_thread *it, struct image *dest, struct image *src)
+image_scale(struct image_context *ctx, struct image *dest, struct image *src)
 {
   if (src->cols < dest->cols || src->rows < dest->rows)
     {
-      image_thread_err(it, IMAGE_ERR_INVALID_DIMENSIONS, "Upsampling not supported.");
+      IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Upsampling not supported.");
       return 0;
     }
   if ((src->flags & IMAGE_PIXEL_FORMAT) != (dest->flags & IMAGE_PIXEL_FORMAT))
     {
-      image_thread_err(it, IMAGE_ERR_INVALID_PIXEL_FORMAT, "Different pixel format not supported.");
+      IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Different pixel format not supported.");
       return 0;
     }
   switch (src->pixel_size)
@@ -68,8 +70,8 @@ image_scale(struct image_thread *it, struct image *dest, struct image *src)
 void
 image_dimensions_fit_to_box(u32 *cols, u32 *rows, u32 max_cols, u32 max_rows, uns upsample)
 {
-  ASSERT(*cols && *rows && *cols <= IMAGE_MAX_SIZE && *rows <= IMAGE_MAX_SIZE);
-  ASSERT(max_cols && max_rows && max_cols <= IMAGE_MAX_SIZE && max_rows <= IMAGE_MAX_SIZE);
+  ASSERT(image_dimensions_valid(*cols, *rows));
+  ASSERT(image_dimensions_valid(max_cols, max_rows));
   if (*cols <= max_cols && *rows <= max_rows)
     {
       if (!upsample)
index 061bbfec7ffd7b107d5a978906f6dfa82a494be7..8a3b5ea2ab924861b81142058042fbe0dc9800c7 100644 (file)
 #include "lib/fastbuf.h"
 #include "lib/conf.h"
 #include "lib/math.h"
-#include "images/math.h"
 #include "images/images.h"
+#include "images/math.h"
+#include "images/error.h"
 #include "images/color.h"
 #include "images/signature.h"
 
 #include <alloca.h>
 
 int
-image_sig_init(struct image_thread *thread, struct image_sig_data *data, struct image *image)
+image_sig_init(struct image_context *ctx, struct image_sig_data *data, struct image *image)
 {
   ASSERT((image->flags & IMAGE_PIXEL_FORMAT) == COLOR_SPACE_RGB);
   data->image = image;
@@ -33,7 +34,7 @@ image_sig_init(struct image_thread *thread, struct image_sig_data *data, struct
   data->blocks_count = data->cols * data->rows;
   if (data->blocks_count >= 0x10000)
     {
-      image_thread_err(thread, IMAGE_ERR_INVALID_DIMENSIONS, "Image too large for implemented signature algorithm.");
+      IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Image too large for implemented signature algorithm.");
       return 0;
     }
   data->blocks = xmalloc(data->blocks_count * sizeof(struct image_sig_block));
@@ -306,10 +307,10 @@ image_sig_cleanup(struct image_sig_data *data)
 }
 
 int
-compute_image_signature(struct image_thread *thread, struct image_signature *sig, struct image *image)
+compute_image_signature(struct image_context *ctx, struct image_signature *sig, struct image *image)
 {
   struct image_sig_data data;
-  if (!image_sig_init(thread, &data, image))
+  if (!image_sig_init(ctx, &data, image))
     return 0;
   image_sig_preprocess(&data);
   if (data.valid)
index 5e3647d1d02e24d965cae6170ee8f1fc75cc2232..791acc6819ef78a49aa4f40157c31888b5dbeb01 100644 (file)
@@ -107,9 +107,9 @@ struct image_sig_data {
 
 /* sig-init.c */
 
-int compute_image_signature(struct image_thread *thread, struct image_signature *sig, struct image *image);
+int compute_image_signature(struct image_context *ctx, struct image_signature *sig, struct image *image);
 
-int image_sig_init(struct image_thread *thread, struct image_sig_data *data, struct image *image);
+int image_sig_init(struct image_context *ctx, struct image_sig_data *data, struct image *image);
 void image_sig_preprocess(struct image_sig_data *data);
 void image_sig_finish(struct image_sig_data *data, struct image_signature *sig);
 void image_sig_cleanup(struct image_sig_data *data);