From 54caf9eea63bd7f50bbe201b60c80aa93b0f6a01 Mon Sep 17 00:00:00 2001 From: Pavel Charvat Date: Wed, 20 Sep 2006 11:43:24 +0200 Subject: [PATCH] revising & testing image library * 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 - --- cf/images | 10 +- images/Makefile | 9 +- images/alpha.c | 2 +- images/color-tool.c | 97 ++++++++++++++++ images/color.c | 242 +++++++++++++++++++++++++++++++++++----- images/color.h | 66 ++++++++++- images/config.c | 20 +++- images/context.c | 63 +++++++++++ images/dup-init.c | 11 +- images/duplicates.h | 2 +- images/error.h | 35 ++++++ images/image-dup-test.c | 16 +-- images/image-sim-test.c | 24 ++-- images/image-test.c | 167 ++++++++++++++++++++++++--- images/image-tool.c | 13 ++- images/image.c | 52 +++------ images/images.h | 124 ++++++++++---------- images/io-libjpeg.c | 13 ++- images/io-libpng.c | 27 +++-- images/io-libungif.c | 18 +-- images/io-main.c | 27 +++-- images/scale.c | 12 +- images/sig-init.c | 11 +- images/signature.h | 4 +- 24 files changed, 819 insertions(+), 246 deletions(-) create mode 100644 images/color-tool.c create mode 100644 images/context.c create mode 100644 images/error.h diff --git a/cf/images b/cf/images index 6f36620e..c4087583 100644 --- 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 ####################################################### diff --git a/images/Makefile b/images/Makefile index 8b7efbdd..a4a2fb26 100644 --- a/images/Makefile +++ b/images/Makefile @@ -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 diff --git a/images/alpha.c b/images/alpha.c index 9f6dfd14..d97207e8 100644 --- a/images/alpha.c +++ b/images/alpha.c @@ -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 index 00000000..112f7386 --- /dev/null +++ b/images/color-tool.c @@ -0,0 +1,97 @@ +/* + * Color spaces tool + * + * (c) 2006 Pavel Charvat + * + * 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 +#include +#include +#include +#include + +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; +} diff --git a/images/color.c b/images/color.c index 80f48294..43d4847a 100644 --- a/images/color.c +++ b/images/color.c @@ -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; diff --git a/images/color.h b/images/color.h index d8cee26b..8c87e87c 100644 --- a/images/color.h +++ b/images/color.h @@ -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: @@ -25,6 +27,60 @@ #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 diff --git a/images/config.c b/images/config.c index 11c93787..a268525e 100644 --- a/images/config.c +++ b/images/config.c @@ -13,6 +13,12 @@ #include +/* 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 index 00000000..bcabc520 --- /dev/null +++ b/images/context.c @@ -0,0 +1,63 @@ +/* + * Image Library -- Image contexts + * + * (c) 2006 Pavel Charvat + * + * 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 + +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); +} diff --git a/images/dup-init.c b/images/dup-init.c index da4b2be4..1dda196c 100644 --- a/images/dup-init.c +++ b/images/dup-init.c @@ -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 @@ -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; } diff --git a/images/duplicates.h b/images/duplicates.h index 07db2afe..dd07b763 100644 --- a/images/duplicates.h +++ b/images/duplicates.h @@ -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 index 00000000..92f3766f --- /dev/null +++ b/images/error.h @@ -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 diff --git a/images/image-dup-test.c b/images/image-dup-test.c index ecfa5500..cbd37e5a 100644 --- a/images/image-dup-test.c +++ b/images/image-dup-test.c @@ -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; } diff --git a/images/image-sim-test.c b/images/image-sim-test.c index bac384ec..22f3951c 100644 --- a/images/image-sim-test.c +++ b/images/image-sim-test.c @@ -13,6 +13,7 @@ #include "images/images.h" #include "images/color.h" #include "images/signature.h" + #include #include #include @@ -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; } diff --git a/images/image-test.c b/images/image-test.c index 1e49d284..c751e8a0 100644 --- a/images/image-test.c +++ b/images/image-test.c @@ -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 #include +#include +#include +#include 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; } diff --git a/images/image-tool.c b/images/image-tool.c index 1d4f68a0..e37f4496 100644 --- a/images/image-tool.c +++ b/images/image-tool.c @@ -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; } diff --git a/images/image.c b/images/image.c index deb8f9f8..48d5d6b9 100644 --- a/images/image.c +++ b/images/image.c @@ -12,34 +12,10 @@ #include "lib/lib.h" #include "lib/mempool.h" #include "images/images.h" -#include - -#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 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); } diff --git a/images/images.h b/images/images.h index 460f5881..2b698dc9 100644 --- a/images/images.h +++ b/images/images.h @@ -1,76 +1,66 @@ +/* + * Image Library -- Main hearer file + * + * (c) 2006 Pavel Charvat + * + * 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); diff --git a/images/io-libjpeg.c b/images/io-libjpeg.c index 10c49d7d..30bd0fff 100644 --- a/images/io-libjpeg.c +++ b/images/io-libjpeg.c @@ -13,7 +13,10 @@ #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 #include #include @@ -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); diff --git a/images/io-libpng.c b/images/io-libpng.c index f15955a6..76b2d247 100644 --- a/images/io-libpng.c +++ b/images/io-libpng.c @@ -13,7 +13,10 @@ #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 #include @@ -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; } diff --git a/images/io-libungif.c b/images/io-libungif.c index 45940ede..c4648431 100644 --- a/images/io-libungif.c +++ b/images/io-libungif.c @@ -13,8 +13,10 @@ #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 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; } diff --git a/images/io-main.c b/images/io-main.c index aca3a8ae..230a7cfd 100644 --- a/images/io-main.c +++ b/images/io-main.c @@ -10,16 +10,19 @@ #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 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); diff --git a/images/scale.c b/images/scale.c index 2c351cbd..e987e0f5 100644 --- a/images/scale.c +++ b/images/scale.c @@ -11,6 +11,8 @@ #include "lib/lib.h" #include "images/images.h" +#include "images/error.h" + #include #define IMAGE_SCALE_PREFIX(x) image_scale_1_##x @@ -30,16 +32,16 @@ #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) diff --git a/images/sig-init.c b/images/sig-init.c index 061bbfec..8a3b5ea2 100644 --- a/images/sig-init.c +++ b/images/sig-init.c @@ -13,15 +13,16 @@ #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 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) diff --git a/images/signature.h b/images/signature.h index 5e3647d1..791acc68 100644 --- a/images/signature.h +++ b/images/signature.h @@ -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); -- 2.39.2