From 19b12adae1eafc2b9fde886157ab3a35d80705dc Mon Sep 17 00:00:00 2001 From: Pavel Charvat Date: Sun, 23 Apr 2006 16:17:12 +0200 Subject: [PATCH] - removed alpha channel - added a simple algorithm for fast repeated image comparisions (will be used in duplicates finder) - some small fixes --- images/Makefile | 2 +- images/image-dup.c | 354 +++++++++++++++++++++++++++++++++++++++++++++ images/image-dup.h | 25 ++++ images/image-idx.c | 31 +--- images/image-obj.c | 113 +++++++-------- images/image-obj.h | 13 +- images/image-sig.c | 16 +- images/images.h | 7 +- 8 files changed, 459 insertions(+), 102 deletions(-) create mode 100644 images/image-dup.c create mode 100644 images/image-dup.h diff --git a/images/Makefile b/images/Makefile index 34196a3d..71e4c79b 100644 --- a/images/Makefile +++ b/images/Makefile @@ -7,7 +7,7 @@ PROGS+=$(addprefix $(o)/images/,image-idx image-test decomp) $(o)/images/image-sig.o $(o)/images/image-sig.oo: CFLAGS+=-I/usr/include/GraphicsMagick $(o)/images/image-idx.o $(o)/images/image-idx.oo: CFLAGS+=-I/usr/include/GraphicsMagick $(o)/images/image-obj.o $(o)/images/image-obj.oo: CFLAGS+=-I/usr/include/GraphicsMagick -$(o)/images/image-idx: $(o)/images/image-idx.o $(o)/images/image-obj.o $(o)/indexer/iconfig.o $(o)/images/image-sig.o $(LIBSH) $(LIBLANG) $(LIBCHARSET) +$(o)/images/image-idx: $(o)/images/image-idx.o $(o)/images/image-obj.o $(o)/images/image-dup.o $(o)/indexer/iconfig.o $(o)/images/image-sig.o $(LIBSH) $(LIBLANG) $(LIBCHARSET) $(o)/images/image-idx: LIBS+=-lGraphicsMagick -ljpeg -lpng $(o)/images/image-test: $(o)/images/image-test.o $(LIBSH) diff --git a/images/image-dup.c b/images/image-dup.c new file mode 100644 index 00000000..688ee50b --- /dev/null +++ b/images/image-dup.c @@ -0,0 +1,354 @@ +/* + * Image Library -- Duplicates Comparison + * + * (c) 2006 Pavel Charvat + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + * + * FIXME: + * - many possible optimization + * - compare normalized pictures (brightness, ...) + * - better image scale... now it can completely miss some rows/cols of pixels + * - maybe better/slower last step + * - different thresholds for various transformations + * - do not test all transformations for symetric pictures + * - ... secret ideas :-) + */ + +#undef LOCAL_DEBUG + +#include "sherlock/sherlock.h" +#include "lib/mempool.h" +#include "images/images.h" +#include "images/image-dup.h" + +static uns image_dup_scale_min_size = 8; +static uns image_dup_ratio_threshold = 140; +static uns image_dup_error_threshold = 2000; + +static inline byte * +image_dup_block(struct image_dup *dup, uns col, uns row) +{ + ASSERT(col <= dup->cols && row <= dup->rows); + return dup->buf + (dup->line << row) + (3 << (row + col)); +} + +static inline void +pixels_average(byte *dest, byte *src1, byte *src2) +{ + dest[0] = ((uns)src1[0] + (uns)src2[0]) >> 1; + dest[1] = ((uns)src1[1] + (uns)src2[1]) >> 1; + dest[2] = ((uns)src1[2] + (uns)src2[2]) >> 1; +} + +void +image_dup_init(struct image_dup *dup, struct image *image, struct mempool *pool) +{ + ASSERT(image->width && image->height); + + dup->image = image; + dup->width = image->width; + dup->height = image->height; + for (dup->cols = 0; (uns)(1 << dup->cols) < image->width; dup->cols++); + for (dup->rows = 0; (uns)(1 << dup->rows) < image->height; dup->rows++); + dup->buf = mp_alloc(pool, 12 << (dup->cols + dup->rows)); + dup->line = 6 << dup->cols; + dup->flags = 0; + if (image->width >= image_dup_scale_min_size && image->height >= image_dup_scale_min_size) + dup->flags |= IMAGE_DUP_FLAG_SCALE; + + /* Scale original image to right bottom block */ + { + byte *d = image_dup_block(dup, dup->cols, dup->rows); + uns width = 1 << dup->cols; + uns height = 1 << dup->rows; + uns line_size = 3 * image->width; + uns src_y = 0; + for (uns y = 0; y < height; y++) + { + byte *line = image->pixels + line_size * (src_y >> dup->rows); + uns src_x = 0; + for (uns x = 0; x < width; x++) + { + byte *s = line + 3 * (src_x >> dup->cols); + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d += 3; + src_x += image->width; + } + src_y += image->height; + } + } + + /* Complete bottom row */ + for (uns i = dup->cols; i--; ) + { + byte *d = image_dup_block(dup, i, dup->rows); + byte *s = image_dup_block(dup, i + 1, dup->rows); + for (uns y = 0; y < (uns)(1 << dup->rows); y++) + for (uns x = 0; x < (uns)(1 << i); x++) + { + pixels_average(d, s, s + 3); + d += 3; + s += 6; + } + } + + /* Complete remaining blocks */ + for (uns i = 0; i <= dup->cols; i++) + { + uns line_size = (3 << i); + for (uns j = dup->rows; j--; ) + { + byte *d = image_dup_block(dup, i, j); + byte *s = image_dup_block(dup, i, j + 1); + for (uns y = 0; y < (uns)(1 << j); y++) + { + for (uns x = 0; x < (uns)(1 << i); x++) + { + pixels_average(d, s, s + line_size); + d += 3; + s += 3; + } + s += line_size; + } + } + } +} + +static inline uns +err (int a, int b) +{ + a -= b; + return a * a; +} + +static inline uns +err_sum(byte *pos1, byte *end1, byte *pos2) +{ + uns e = 0; + while (pos1 != end1) + e += err(*pos1++, *pos2++); + return e; +} + +static inline uns +err_sum_transformed(byte *pos1, byte *end1, byte *pos2, uns width, int add1, int add2) +{ + DBG("err_sum_transformed(): %p %p %p %d %d %d", pos1, end1, pos2, width, add1, add2); + uns e = 0; + while (pos1 != end1) + { + for (uns i = 0; i < width; i++, pos2 += add1) + { + e += err(pos1[0], pos2[0]); + e += err(pos1[1], pos2[1]); + e += err(pos1[2], pos2[2]); + pos1 += 3; + } + pos2 += add2; + } + return e; +} + +static inline int +aspect_ratio_test(uns width1, uns height1, uns width2, uns height2) +{ + uns r1 = width1 * height2; + uns r2 = height1 * width2; + return + r1 <= ((r2 * image_dup_ratio_threshold) >> 5) && + r2 <= ((r1 * image_dup_ratio_threshold) >> 5); +} + +static inline int +average_compare(struct image_dup *dup1, struct image_dup *dup2) +{ + byte *block1 = image_dup_block(dup1, 0, 0); + byte *block2 = image_dup_block(dup2, 0, 0); + uns e = + err(block1[0], block2[0]) + + err(block1[1], block2[1]) + + err(block1[2], block2[2]); + return e <= image_dup_error_threshold; +} + +static int +blocks_compare(struct image_dup *dup1, struct image_dup *dup2, uns col, uns row, uns trans) +{ + DBG("blocks_compare(): col=%d row=%d trans=%d", col, row, trans); + byte *block1 = image_dup_block(dup1, col, row); + byte *block2 = (trans < 4) ? image_dup_block(dup2, col, row) : image_dup_block(dup2, row, col); + int add1, add2; + switch (trans) + { + case 0: ; + uns err = (err_sum(block1, block1 + (3 << (col + row)), block2) >> (col + row)); + DBG("average error=%d", err); + return err <= image_dup_error_threshold; + case 1: + add1 = -3; + add2 = 6 << col; + block2 += (3 << col) - 3; + break; + case 2: + add1 = 1; + add2 = -(6 << col); + block2 += (3 << (col + row)) - (3 << col); + break; + case 3: + add1 = -3; + add2 = 0; + block2 += (3 << (col + row)) - 3; + break; + case 4: + add1 = (3 << col); + add2 = -(3 << (col + row)) + 3; + break; + case 5: + add1 = -(3 << col); + add2 = (3 << (col + row)) + 3; + block2 += (3 << (col + row)) - (3 << col); + break; + case 6: + add1 = (3 << col); + add2 = -(3 << (col + row)) - 3; + block2 += (3 << col) - 3; + break; + case 7: + add1 = -(3 << col); + add2 = (3 << (col + row)) - 3; + block2 += (3 << (col + row)) - 3; + break; + default: + ASSERT(0); + } + uns err = (err_sum_transformed(block1, block1 + (3 << (col + row)), block2, (1 << col), add1, add2) >> (col + row)); + DBG("average error=%d", err); + return err <= image_dup_error_threshold; +} + +static int +same_size_compare(struct image_dup *dup1, struct image_dup *dup2, uns trans) +{ + byte *block1 = dup1->image->pixels; + byte *block2 = dup2->image->pixels; + DBG("same_size_compare(): trans=%d", trans); + int add1, add2; + switch (trans) + { + case 0: ; + uns err = (err_sum(block1, block1 + 3 * dup1->width * dup1->height, block2) / (dup1->width * dup1->height)); + DBG("average error=%d", err); + return err <= image_dup_error_threshold; + case 1: + add1 = -3; + add2 = 6 * dup1->width; + block2 += 3 * (dup1->width - 1); + break; + case 2: + add1 = 1; + add2 = -6 * dup1->width; + block2 += 3 * dup1->width * (dup1->height - 1); + break; + case 3: + add1 = -3; + add2 = 0; + block2 += 3 * (dup1->width * dup1->height - 1); + break; + case 4: + add1 = 3 * dup1->width; + add2 = -3 * (dup1->width * dup1->height - 1); + break; + case 5: + add1 = -3 * dup1->width; + add2 = 3 * (dup1->width * dup1->height + 1); + block2 += 3 * dup1->width * (dup1->height - 1); + break; + case 6: + add1 = 3 * dup1->width; + add2 = -3 * (dup1->width * dup1->height + 1); + block2 += 3 * (dup1->width - 1); + break; + case 7: + add1 = -3 * dup1->width; + add2 = 3 * (dup1->width * dup1->height - 1); + block2 += 3 * (dup1->width * dup1->height - 1); + break; + default: + ASSERT(0); + } + uns err = (err_sum_transformed(block1, block1 + 3 * dup1->width * dup1->height, block2, dup1->width, add1, add2) / (dup1->width * dup1->height)); + DBG("average error=%d", err); + return err <= image_dup_error_threshold; +} + +int +image_dup_compare(struct image_dup *dup1, struct image_dup *dup2, uns trans) +{ + if (!average_compare(dup1, dup2)) + return 0; + if ((dup1->flags & dup2->flags) & IMAGE_DUP_FLAG_SCALE) + { + DBG("Scale support"); + if (!aspect_ratio_test(dup1->width, dup1->height, dup2->width, dup2->height)) + trans &= 0xf0; + if (!aspect_ratio_test(dup1->width, dup1->height, dup2->height, dup2->width)) + trans &= 0x0f; + } + else + { + DBG("No scale support"); + if (!(dup1->width == dup2->width && dup1->height == dup2->height)) + trans &= 0xf0; + if (!(dup1->width == dup2->height && dup1->height == dup2->width)) + trans &= 0x0f; + } + if (!trans) + return 0; + if (trans & 0x0f) + { + uns cols = MIN(dup1->cols, dup2->cols); + uns rows = MIN(dup1->rows, dup2->rows); + for (uns t = 0; t < 4; t++) + if (trans & (1 << t)) + { + DBG("Testing trans %d", t); + for (uns i = MAX(cols, rows); i--; ) + { + uns col = MAX(0, (int)(cols - i)); + uns row = MAX(0, (int)(rows - i)); + if (!blocks_compare(dup1, dup2, col, row, t)) + break; + if (!i && + (dup1->width != dup2->width || dup1->height != dup2->height || + same_size_compare(dup1, dup2, t))) + return 1; + } + } + } + if (trans & 0xf0) + { + uns cols = MIN(dup1->cols, dup2->rows); + uns rows = MIN(dup1->rows, dup2->cols); + for (uns t = 4; t < 8; t++) + if (trans & (1 << t)) + { + DBG("Testing trans %d", t); + for (uns i = MAX(cols, rows); i--; ) + { + uns col = MAX(0, (int)(cols - i)); + uns row = MAX(0, (int)(rows - i)); + if (!blocks_compare(dup1, dup2, col, row, t)) + break; + if (!i && + (dup1->width != dup2->height || dup1->height != dup2->width || + same_size_compare(dup1, dup2, t)) ) + return 1; + } + } + } + return 0; +} diff --git a/images/image-dup.h b/images/image-dup.h new file mode 100644 index 00000000..524db4e1 --- /dev/null +++ b/images/image-dup.h @@ -0,0 +1,25 @@ +#ifndef _IMAGES_IMAGE_DUP_H +#define _IMAGES_IMAGE_DUP_H + +struct image; + +struct image_dup { + struct image *image; + byte *buf; + uns flags; + uns cols; + uns rows; + uns line; + uns width; + uns height; +}; + +#define IMAGE_DUP_FLAG_SCALE 0x1 + +#define IMAGE_DUP_TRANS_ID 0x01 +#define IMAGE_DUP_TRANS_ALL 0xff + +void image_dup_init(struct image_dup *dup, struct image *image, struct mempool *pool); +int image_dup_compare(struct image_dup *dup1, struct image_dup *dup2, uns trans); + +#endif diff --git a/images/image-idx.c b/images/image-idx.c index 0600fc2c..8868dfe3 100644 --- a/images/image-idx.c +++ b/images/image-idx.c @@ -24,13 +24,14 @@ #include "images/images.h" #include "images/image-obj.h" #include "images/image-sig.h" +#include "images/image-dup.h" #include #include #include /* This should happen in gatherer or scanner */ -UNUSED static void +static void generate_signatures(uns limit) { struct fastbuf *fb_cards = index_bopen("cards", O_RDONLY); @@ -59,13 +60,13 @@ generate_signatures(uns limit) die("Failed to read card"); if (attr = obj_find_attr(obj, 'N')) { - DBG("Reading oid=%d url=%s", oid, obj_find_aval(obj_find_attr(obj, 'U' + OBJ_ATTR_SON)->son, 'U')); + byte *url = obj_find_aval(obj_find_attr(obj, 'U' + OBJ_ATTR_SON)->son, 'U'); + DBG("Reading oid=%d url=%s", oid, url); struct image_obj imo; imo_init(&imo, pool, obj); if (imo_decompress_thumbnail(&imo)) { - int err; - if (!(err = compute_image_signature(&imo.thumb, &sig))) + if (compute_image_signature(&imo.thumb, &sig)) { bwrite(fb_signatures, &oid, sizeof(oid)); bwrite(fb_signatures, &sig.vec, sizeof(struct image_vector)); @@ -77,7 +78,7 @@ generate_signatures(uns limit) break; } else - DBG("Cannot create signature, error=%d", err); + DBG("Cannot create signature"); } else DBG("Cannot decompress thumbnail"); @@ -95,25 +96,6 @@ generate_signatures(uns limit) bclose(fb_signatures); } -UNUSED static void -generate_random_signatures(uns count) -{ - log(L_INFO, "Generating %d random signatures", count); - struct fastbuf *fb_signatures = index_bopen("image-sig", O_CREAT | O_WRONLY | O_TRUNC); - bputl(fb_signatures, count); - for (uns i = 0; i < count; i++) - { - oid_t oid = i; - struct image_vector vec; - for (uns j = 0; j < IMAGE_VEC_K; j++) - vec.f[j] = random_max(256); - bwrite(fb_signatures, &oid, sizeof(oid)); - bwrite(fb_signatures, &vec, sizeof(vec)); - bputc(fb_signatures, 0); - } - bclose(fb_signatures); -} - struct signature_record { oid_t oid; struct image_vector vec; @@ -333,7 +315,6 @@ main(int argc UNUSED, char **argv) usage("Invalid usage"); generate_signatures(~0U); - //generate_random_signatures(1000000); build_search_tree(); return 0; diff --git a/images/image-obj.c b/images/image-obj.c index f5171d55..06753ca6 100644 --- a/images/image-obj.c +++ b/images/image-obj.c @@ -10,7 +10,7 @@ * - improve thumbnail creation in gatherer... faster compression, * only grayscale/RGB colorspaces and maybe fixed headers (abbreviated datastreams in libjpeg) * - hook memory allocation managers, get rid of multiple initializations - * - alpha channel is propably useless (we could assume white background) + * - supply background color to transparent PNG images * - optimize decompression parameters * - create interface for thumbnail compression (for gatherer) and reading (MUX) * - benchmatk libraries @@ -145,41 +145,33 @@ libpng_decompress_thumbnail(struct image_obj *imo) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - { - png_set_tRNS_to_alpha(png_ptr); - imo->thumb.flags |= IMAGE_ALPHA; - } - else - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + png_set_strip_alpha(png_ptr); break; case PNG_COLOR_TYPE_GRAY: imo->thumb.flags |= IMAGE_GRAYSCALE; png_set_gray_to_rgb(png_ptr); - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + png_set_strip_alpha(png_ptr); break; case PNG_COLOR_TYPE_GRAY_ALPHA: - imo->thumb.flags |= IMAGE_GRAYSCALE | IMAGE_ALPHA; + imo->thumb.flags |= IMAGE_GRAYSCALE; png_set_gray_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_RGB: - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_RGB_ALPHA: - imo->thumb.flags |= IMAGE_ALPHA; + png_set_strip_alpha(png_ptr); break; default: ASSERT(0); } png_read_update_info(png_ptr, info_ptr); - ASSERT(png_get_channels(png_ptr, info_ptr) == sizeof(struct pixel)); - ASSERT(png_get_rowbytes(png_ptr, info_ptr) == sizeof(struct pixel) * width); + ASSERT(png_get_channels(png_ptr, info_ptr) == 3); /* Read image data */ DBG("Reading image data"); - struct pixel *pixels = imo->thumb.pixels = mp_alloc(imo->pool, width * height * sizeof(struct pixel)); + byte *pixels = imo->thumb.pixels = mp_alloc(imo->pool, width * height * 3); png_bytep rows[height]; - for (uns i = 0; i < height; i++, pixels += width) + for (uns i = 0; i < height; i++, pixels += width * 3) rows[i] = (png_bytep)pixels; png_read_image(png_ptr, rows); png_read_end(png_ptr, end_ptr); @@ -296,23 +288,15 @@ libjpeg_decompress_thumbnail(struct image_obj *imo) DBG("Reading image data"); jpeg_start_decompress(&cinfo); ASSERT(imo->thumb.width == cinfo.output_width && imo->thumb.height == cinfo.output_height); - struct pixel *pixels = imo->thumb.pixels = mp_alloc(imo->pool, cinfo.output_width * cinfo.output_height * sizeof(struct pixel)); + ASSERT(sizeof(JSAMPLE) == 1); + byte *pixels = imo->thumb.pixels = mp_alloc(imo->pool, cinfo.output_width * cinfo.output_height * 3); if (cinfo.out_color_space == JCS_RGB) { /* Read RGB pixels */ uns size = cinfo.output_width * 3; - JSAMPLE buf[size], *buf_end = buf + size; while (cinfo.output_scanline < cinfo.output_height) { - JSAMPLE *p = buf; - jpeg_read_scanlines(&cinfo, &p, 1); - for (; p != buf_end; p += 3) - { - pixels->r = p[0] >> (sizeof(JSAMPLE) * 8 - 8); - pixels->g = p[1] >> (sizeof(JSAMPLE) * 8 - 8); - pixels->b = p[2] >> (sizeof(JSAMPLE) * 8 - 8); - pixels->a = 255; - pixels++; - } + jpeg_read_scanlines(&cinfo, (JSAMPLE **)&pixels, 1); + pixels += size; } } else @@ -324,9 +308,8 @@ libjpeg_decompress_thumbnail(struct image_obj *imo) jpeg_read_scanlines(&cinfo, &p, 1); for (; p != buf_end; p++) { - pixels->r = pixels->g = pixels->b = p[0] >> (sizeof(JSAMPLE) * 8 - 8); - pixels->a = 255; - pixels++; + pixels[0] = pixels[1] = pixels[2] = p[0]; + pixels += 3; } } } @@ -386,13 +369,14 @@ magick_decompress_thumbnail(struct image_obj *imo) PixelPacket *pixels = (PixelPacket *)AcquireImagePixels(image, 0, 0, image->columns, image->rows, &magick_exception); ASSERT(pixels); uns size = image->columns * image->rows; - struct pixel *p = imo->thumb.pixels = mp_alloc(imo->pool, size * sizeof(struct pixel)); - for (uns i = 0; i < size; i++, p++, pixels++) + byte *p = imo->thumb.pixels = mp_alloc(imo->pool, size * 3); + for (uns i = 0; i < size; i++) { - p->r = pixels->red >> (QuantumDepth - 8); - p->g = pixels->green >> (QuantumDepth - 8); - p->b = pixels->blue >> (QuantumDepth - 8); - p->a = 255; + p[0] = pixels->red >> (QuantumDepth - 8); + p[1] = pixels->green >> (QuantumDepth - 8); + p[2] = pixels->blue >> (QuantumDepth - 8); + p += 3; + pixels++; } DestroyImage(image); return 1; @@ -408,7 +392,8 @@ static int extract_image_info(struct image_obj *imo) { DBG("Parsing image info attribute"); - imo->flags |= IMAGE_OBJ_INFO; + ASSERT(!(imo->flags & IMAGE_OBJ_VALID_INFO)); + imo->flags |= IMAGE_OBJ_VALID_INFO; byte *info = obj_find_aval(imo->obj, 'G'); if (!info) { @@ -419,8 +404,17 @@ extract_image_info(struct image_obj *imo) byte color_space[MAX_ATTR_SIZE], thumb_format[MAX_ATTR_SIZE]; UNUSED uns cnt = sscanf(info, "%d%d%s%d%d%d%s", &imo->width, &imo->height, color_space, &colors, &imo->thumb.width, &imo->thumb.height, thumb_format); ASSERT(cnt == 7); - if (*thumb_format == 'j') - imo->flags |= IMAGE_OBJ_THUMB_JPEG; + switch (*thumb_format) + { + case 'j': + imo->thumb_format = IMAGE_OBJ_FORMAT_JPEG; + break; + case 'p': + imo->thumb_format = IMAGE_OBJ_FORMAT_PNG; + break; + default: + ASSERT(0); + } return 1; } @@ -428,7 +422,9 @@ static int extract_thumb_data(struct image_obj *imo) { DBG("Extracting thumbnail data"); - imo->flags |= IMAGE_OBJ_THUMB_DATA; + ASSERT(!(imo->flags & IMAGE_OBJ_VALID_DATA) && + (imo->flags & IMAGE_OBJ_VALID_INFO)); + imo->flags |= IMAGE_OBJ_VALID_DATA; struct oattr *attr = obj_find_attr(imo->obj, 'N'); if (!attr) { @@ -454,31 +450,32 @@ static int extract_thumb_image(struct image_obj *imo) { DBG("Decompressing thumbnail image"); - imo->flags |= IMAGE_OBJ_THUMB_IMAGE; - - /* JPEG format */ - if (imo->flags & IMAGE_OBJ_THUMB_JPEG) + ASSERT(!(imo->flags & IMAGE_OBJ_VALID_IMAGE) && + (imo->flags & IMAGE_OBJ_VALID_INFO) && + (imo->flags & IMAGE_OBJ_VALID_DATA)); + imo->flags |= IMAGE_OBJ_VALID_IMAGE; + switch (imo->thumb_format) { + case IMAGE_OBJ_FORMAT_JPEG: #if defined(USE_LIBJPEG) - return libjpeg_decompress_thumbnail(imo); + return libjpeg_decompress_thumbnail(imo); #elif defined(USE_MAGICK) - return magick_decompress_thumbnail(imo); + return magick_decompress_thumbnail(imo); #else - DBG("JPEG not supported"); - return 0; -#endif - } - /* PNG format */ - else - { + DBG("JPEG not supported"); + return 0; +#endif + case IMAGE_OBJ_FORMAT_PNG: #if defined(USE_LIBPNG) - return libpng_decompress_thumbnail(imo); + return libpng_decompress_thumbnail(imo); #elif defined(USE_MAGICK) - return magick_decompress_thumbnail(imo); + return magick_decompress_thumbnail(imo); #else - DBG("PNG not supported"); - return 0; + DBG("PNG not supported"); + return 0; #endif + default: + ASSERT(0); } } diff --git a/images/image-obj.h b/images/image-obj.h index bce83591..95976bc8 100644 --- a/images/image-obj.h +++ b/images/image-obj.h @@ -15,11 +15,15 @@ struct mempool; struct odes; +enum image_obj_format { + IMAGE_OBJ_FORMAT_JPEG, + IMAGE_OBJ_FORMAT_PNG +}; + enum image_obj_flag { - IMAGE_OBJ_INFO = 0x1, - IMAGE_OBJ_THUMB_JPEG = 0x2, - IMAGE_OBJ_THUMB_DATA = 0x4, - IMAGE_OBJ_THUMB_IMAGE = 0x8 + IMAGE_OBJ_VALID_INFO = 0x1, + IMAGE_OBJ_VALID_DATA = 0x2, + IMAGE_OBJ_VALID_IMAGE = 0x4 }; struct image_obj { @@ -28,6 +32,7 @@ struct image_obj { uns flags; uns width; uns height; + uns thumb_format; byte *thumb_data; uns thumb_size; struct image thumb; diff --git a/images/image-sig.c b/images/image-sig.c index cc159fce..fab1de39 100644 --- a/images/image-sig.c +++ b/images/image-sig.c @@ -81,9 +81,9 @@ compute_image_signature(struct image *image, struct image_signature *sig) struct block *blocks = xmalloc(blocks_count * sizeof(struct block)), *block = blocks; /* FIXME: use mempool */ /* Every 4x4 block (FIXME: deal with smaller blocks near the edges) */ - struct pixel *p = image->pixels; - for (uns block_y = 0; block_y < h; block_y++, p += (width & 3) + width * 3) - for (uns block_x = 0; block_x < w; block_x++, p -= 4 * width - 4, block++) + byte *p = image->pixels; + for (uns block_y = 0; block_y < h; block_y++, p += 3 * ((width & 3) + width * 3)) + for (uns block_x = 0; block_x < w; block_x++, p -= 3 * (4 * width - 4), block++) { int t[16], s[16], *tp = t; @@ -94,13 +94,13 @@ compute_image_signature(struct image *image, struct image_signature *sig) uns l_sum = 0; uns u_sum = 0; uns v_sum = 0; - for (uns y = 0; y < 4; y++, p += width - 4) - for (uns x = 0; x < 4; x++, p += 1) + for (uns y = 0; y < 4; y++, p += 3 * (width - 4)) + for (uns x = 0; x < 4; x++, p += 3) { double rgb[3], luv[3], xyz[3]; - rgb[0] = p->r / 255.; - rgb[1] = p->g / 255.; - rgb[2] = p->b / 255.; + rgb[0] = p[0] / 255.; + rgb[1] = p[1] / 255.; + rgb[2] = p[2] / 255.; srgb_to_xyz_slow(rgb, xyz); xyz_to_luv_slow(xyz, luv); l_sum += *tp++ = luv[0]; diff --git a/images/images.h b/images/images.h index 711210bb..4f2bd2aa 100644 --- a/images/images.h +++ b/images/images.h @@ -3,18 +3,13 @@ enum image_flag { IMAGE_GRAYSCALE = 0x1, /* grayscale image */ - IMAGE_ALPHA = 0x2, /* alpha present */ }; -struct pixel { - byte r, g, b, a; -} PACKED; - struct image { uns flags; /* enum image_flag */ uns width; /* number of columns */ uns height; /* number of rows */ - struct pixel *pixels; /* RGBA */ + byte *pixels; /* RGB */ }; #endif -- 2.39.2