]> mj.ucw.cz Git - libucw.git/commitdiff
Libucw-images: Added `ucw-' prefix to utils.
authorPavel Charvat <pchar@ucw.cz>
Fri, 6 Dec 2013 22:11:57 +0000 (23:11 +0100)
committerPavel Charvat <pchar@ucw.cz>
Fri, 6 Dec 2013 22:11:57 +0000 (23:11 +0100)
images/Makefile
images/color-tool.c [deleted file]
images/image-dup-test.c [deleted file]
images/image-sim-test.c [deleted file]
images/image-tool.c [deleted file]
images/ucw-color-tool.c [new file with mode: 0644]
images/ucw-image-dup-test.c [new file with mode: 0644]
images/ucw-image-sim-test.c [new file with mode: 0644]
images/ucw-image-tool.c [new file with mode: 0644]

index 35cfbd10d87b28776e4f69b8352cdf7dea73614f..f475127ed7860380c0a97a1512d5a4b04be5cc0c 100644 (file)
@@ -2,7 +2,7 @@
 
 DIRS+=images
 
-LIBIMAGES_PROGS=$(o)/images/image-tool $(o)/images/color-tool
+LIBIMAGES_PROGS=$(o)/images/ucw-image-tool $(o)/images/ucw-color-tool
 LIBIMAGES_CONFIGS+=images
 LIBIMAGES_MODS=math config context image scale color io-main
 LIBIMAGES_INCLUDES=images.h error.h color.h math.h
@@ -23,12 +23,12 @@ LIBIMAGES_DEPS+=$(o)/images/libucw-images-pic.a
 endif
 
 ifdef CONFIG_IMAGES_DUP
-LIBIMAGES_PROGS+=$(o)/images/image-dup-test
+LIBIMAGES_PROGS+=$(o)/images/ucw-image-dup-test
 LIBIMAGES_MODS+=dup-init dup-cmp
 LIBIMAGES_INCLUDES+=duplicates.h
 endif
 ifdef CONFIG_IMAGES_SIM
-LIBIMAGES_PROGS+=$(o)/images/image-sim-test
+LIBIMAGES_PROGS+=$(o)/images/ucw-image-sim-test
 LIBIMAGES_MODS+=sig-cmp
 endif
 ifneq ($(CONFIG_IMAGES_DUP)$(CONFIG_IMAGES_SIM),)
@@ -73,10 +73,10 @@ $(o)/images/libucw-images.so: $(addsuffix .oo,$(addprefix $(o)/images/,$(LIBIMAG
 $(o)/images/libucw-images.so: SONAME_SUFFIX=.$(UCW_ABI_VERSION)
 $(o)/images/libucw-images.pc: $(LIBIMAGES_DEPS)
 
-$(o)/images/image-tool: $(o)/images/image-tool.o $(LIBIMAGES)
-$(o)/images/color-tool: $(o)/images/color-tool.o $(LIBIMAGES)
-$(o)/images/image-dup-test: $(o)/images/image-dup-test.o $(LIBIMAGES)
-$(o)/images/image-sim-test: $(o)/images/image-sim-test.o $(LIBIMAGES)
+$(o)/images/ucw-image-tool: $(o)/images/ucw-image-tool.o $(LIBIMAGES)
+$(o)/images/ucw-color-tool: $(o)/images/ucw-color-tool.o $(LIBIMAGES)
+$(o)/images/ucw-image-dup-test: $(o)/images/ucw-image-dup-test.o $(LIBIMAGES)
+$(o)/images/ucw-image-sim-test: $(o)/images/ucw-image-sim-test.o $(LIBIMAGES)
 
 TESTS+=$(o)/images/image-test.test
 $(o)/images/image-test: $(o)/images/image-test.o $(LIBIMAGES)
diff --git a/images/color-tool.c b/images/color-tool.c
deleted file mode 100644 (file)
index 73d97e4..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *     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 <ucw/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;
-}
diff --git a/images/image-dup-test.c b/images/image-dup-test.c
deleted file mode 100644 (file)
index feece3d..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- *     Image duplicates testing
- *
- *     (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 <ucw/lib.h>
-#include <ucw/getopt.h>
-#include <ucw/fastbuf.h>
-#include <ucw/mempool.h>
-#include <images/images.h>
-#include <images/color.h>
-#include <images/duplicates.h>
-
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-
-static void NONRET
-usage(void)
-{
-  fputs("\
-Usage: image-dup-test [options] image1 image2 \n\
-\n\
--q --quiet           no progress messages\n\
--f --format-1        image1 format (jpeg, gif, png)\n\
--F --format-2        image2 format\n\
--g --background      background color (hexadecimal RRGGBB)\n\
--t --transformations hexadecimal value of allowed transformtion (1=identity, FF=all)\n\
-", stderr);
-  exit(1);
-}
-
-static char *shortopts = "qf:F:g:t:" CF_SHORT_OPTS;
-static struct option longopts[] =
-{
-  CF_LONG_OPTS
-  { "quiet",           0, 0, 'q' },
-  { "format-1",                0, 0, 'f' },
-  { "format-2",                0, 0, 'F' },
-  { "background",      0, 0, 'g' },
-  { "transormations",  0, 0, 't' },
-  { NULL,              0, 0, 0 }
-};
-
-static uns verbose = 1;
-static byte *file_name_1;
-static byte *file_name_2;
-static enum image_format format_1;
-static enum image_format format_2;
-static struct color background_color;
-static uns transformations = IMAGE_DUP_TRANS_ALL;
-
-#define MSG(x...) do{ if (verbose) msg(L_INFO, ##x); }while(0)
-
-int
-main(int argc, char **argv)
-{
-  log_init(argv[0]);
-  int opt;
-  while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
-    switch (opt)
-      {
-       case 'q':
-         verbose = 0;
-         break;
-       case 'f':
-         if (!(format_1 = image_extension_to_format(optarg)))
-           usage();
-         break;
-       case 'F':
-         if (!(format_2 = image_extension_to_format(optarg)))
-           usage();
-         break;
-       case 'g':
-         {
-           if (strlen(optarg) != 6)
-             usage();
-           errno = 0;
-           char *end;
-           long int v = strtol(optarg, &end, 16);
-           if (errno || *end || v < 0)
-             usage();
-           color_make_rgb(&background_color, (v >> 16) & 255, (v >> 8) & 255, v & 255);
-         }
-         break;
-       case 't':
-         {
-           errno = 0;
-           char *end;
-           long int v = strtol(optarg, &end, 16);
-           if (errno || *end || v < 0 || v > 0xff)
-             usage();
-           transformations = v;
-         }
-         break;
-       default:
-         usage();
-      }
-
-  if (argc != optind + 2)
-    usage();
-  file_name_1 = argv[optind++];
-  file_name_2 = argv[optind];
-
-#define TRY(x) do{ if (!(x)) exit(1); }while(0)
-  MSG("Initializing image library");
-  struct image_context ctx;
-  struct image_dup_context idc;
-  struct image_io io;
-  image_context_init(&ctx);
-  image_dup_context_init(&ctx, &idc);
-
-  struct image *img1, *img2;
-
-  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);
-  TRY(image_io_read_header(&io));
-  io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
-  if (background_color.color_space)
-    io.background_color = background_color;
-  else if (!io.background_color.color_space)
-    io.background_color = color_black;
-  TRY(image_io_read_data(&io, 1));
-  bclose(io.fastbuf);
-  img1 = io.image;
-  MSG("Image size=%ux%u", img1->cols, img1->rows);
-
-  image_io_reset(&io);
-  MSG("Reading %s", file_name_2);
-  io.fastbuf = bopen(file_name_2, O_RDONLY, 1 << 18);
-  io.format = format_2 ? : image_file_name_to_format(file_name_2);
-  TRY(image_io_read_header(&io));
-  io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
-  if (background_color.color_space)
-    io.background_color = background_color;
-  else if (!io.background_color.color_space)
-    io.background_color = color_black;
-  TRY(image_io_read_data(&io, 1));
-  bclose(io.fastbuf);
-  img2 = io.image;
-  image_io_cleanup(&io);
-  MSG("Image size=%ux%u", img2->cols, img2->rows);
-
-  struct image_dup *dup1, *dup2;
-  struct mempool *pool = mp_new(1 << 18);
-  MSG("Creating internal structures");
-  dup1 = mp_start(pool, image_dup_estimate_size(img1->cols, img1->rows, 1, idc.qtree_limit));
-  uns size = image_dup_new(&idc, img1, dup1, 1);
-  TRY(size);
-  mp_end(pool, (void *)dup1 + size);
-  dup2 = mp_start(pool, image_dup_estimate_size(img2->cols, img2->rows, 1, idc.qtree_limit));
-  size = image_dup_new(&idc, img2, dup2, 1);
-  TRY(size);
-  mp_end(pool, (void *)dup2 + size);
-
-  idc.flags = transformations | IMAGE_DUP_SCALE | IMAGE_DUP_WANT_ALL;
-  MSG("Similarity bitmap %02x", image_dup_compare(&idc, dup1, dup2));
-
-  mp_delete(pool);
-
-  image_destroy(img1);
-  image_destroy(img2);
-  image_dup_context_cleanup(&idc);
-  image_context_cleanup(&ctx);
-  MSG("Done.");
-  return 0;
-}
diff --git a/images/image-sim-test.c b/images/image-sim-test.c
deleted file mode 100644 (file)
index 52cf677..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- *     Image similarity testing
- *
- *     (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 <ucw/lib.h>
-#include <ucw/getopt.h>
-#include <ucw/fastbuf.h>
-#include <ucw/base64.h>
-#include <ucw/base224.h>
-#include <images/images.h>
-#include <images/color.h>
-#include <images/signature.h>
-
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-static void NONRET
-usage(void)
-{
-  fputs("\
-Usage: image-sim-test [options] image1 [image2] \n\
-\n\
--q --quiet           no progress messages\n\
--f --format-1        image1 format (jpeg, gif, png)\n\
--F --format-2        image2 format\n\
--g --background      background color (hexadecimal RRGGBB)\n\
--r --segmentation-1  writes image1 segmentation to given file\n\
--R --segmentation-2  writes image2 segmentation to given file\n\
--6 --base64          display base64 encoded signature(s)\n\
--2 --base224         display base224 encoded signature(s)\n\
-", stderr);
-  exit(1);
-}
-
-static char *shortopts = "qf:F:g:t:r:R:62" CF_SHORT_OPTS;
-static struct option longopts[] =
-{
-  CF_LONG_OPTS
-  { "quiet",           0, 0, 'q' },
-  { "format-1",                0, 0, 'f' },
-  { "format-2",                0, 0, 'F' },
-  { "background",      0, 0, 'g' },
-  { "segmentation-1",  0, 0, 'r' },
-  { "segmentation-2",  0, 0, 'R' },
-  { "base64",          0, 0, '6' },
-  { "base224",         0, 0, '2' },
-  { NULL,              0, 0, 0 }
-};
-
-static uns verbose = 1;
-static byte *file_name_1;
-static byte *file_name_2;
-static enum image_format format_1;
-static enum image_format format_2;
-static struct color background_color;
-static byte *segmentation_name_1;
-static byte *segmentation_name_2;
-static uns display_base64;
-static uns display_base224;
-
-#define MSG(x...) do{ if (verbose) msg(L_INFO, ##x); }while(0)
-#define TRY(x) do{ if (!(x)) exit(1); }while(0)
-
-static void
-msg_str(byte *s, void *param UNUSED)
-{
-  MSG("%s", s);
-}
-
-static void
-dump_signature(struct image_signature *sig)
-{
-  byte buf[MAX(IMAGE_VECTOR_DUMP_MAX, IMAGE_REGION_DUMP_MAX)];
-  image_vector_dump(buf, &sig->vec);
-  MSG("vector: %s", buf);
-  for (uns i = 0; i < sig->len; i++)
-    {
-      image_region_dump(buf, sig->reg + i);
-      MSG("region %u: %s", i, buf);
-    }
-  uns sig_size = image_signature_size(sig->len);
-  if (display_base64)
-    {
-      byte buf[BASE64_ENC_LENGTH(sig_size) + 1];
-      uns enc_size = base64_encode(buf, (byte *)sig, sig_size);
-      buf[enc_size] = 0;
-      MSG("base64 encoded: %s", buf);
-    }
-  if (display_base224)
-    {
-      byte buf[BASE224_ENC_LENGTH(sig_size) + 1];
-      uns enc_size = base224_encode(buf, (byte *)sig, sig_size);
-      buf[enc_size] = 0;
-      MSG("base224 encoded: %s", buf);
-    }
-}
-
-static struct image_context ctx;
-static struct image_io io;
-
-static void
-write_segmentation(struct image_sig_data *data, byte *fn)
-{
-  MSG("Writing segmentation to %s", fn);
-
-  struct fastbuf *fb = bopen(fn, O_WRONLY | O_CREAT | O_TRUNC, 4096);
-  struct image *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++)
-    {
-      byte c[3];
-      double luv[3], xyz[3], srgb[3];
-      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_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);
-      for (struct image_sig_block *block = data->regions[i].blocks; block; block = block->next)
-        {
-         uns x1 = block->x * 4;
-         uns y1 = block->y * 4;
-         uns x2 = MIN(x1 + 4, img->cols);
-         uns y2 = MIN(y1 + 4, img->rows);
-         byte *p = img->pixels + x1 * 3 + y1 * img->row_size;
-         for (uns y = y1; y < y2; y++, p += img->row_size)
-           {
-             byte *p2 = p;
-             for (uns x = x1; x < x2; x++, p2 += 3)
-               {
-                 p2[0] = c[0];
-                 p2[1] = c[1];
-                 p2[2] = c[2];
-               }
-           }
-        }
-    }
-
-  io.fastbuf = fb;
-  io.image = img;
-  io.format = image_file_name_to_format(fn);
-  TRY(image_io_write(&io));
-  image_io_reset(&io);
-
-  image_destroy(img);
-  bclose(fb);
-}
-
-int
-main(int argc, char **argv)
-{
-  log_init(argv[0]);
-  int opt;
-  while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
-    switch (opt)
-      {
-       case 'q':
-         verbose = 0;
-         break;
-       case 'f':
-         if (!(format_1 = image_extension_to_format(optarg)))
-           usage();
-         break;
-       case 'F':
-         if (!(format_2 = image_extension_to_format(optarg)))
-           usage();
-         break;
-       case 'g':
-         {
-           if (strlen(optarg) != 6)
-             usage();
-           errno = 0;
-           char *end;
-           long int v = strtol(optarg, &end, 16);
-           if (errno || *end || v < 0)
-             usage();
-           color_make_rgb(&background_color, (v >> 16) & 255, (v >> 8) & 255, v & 255);
-         }
-         break;
-       case 'r':
-         segmentation_name_1 = optarg;
-         break;
-       case 'R':
-         segmentation_name_2 = optarg;
-         break;
-       case '6':
-         display_base64++;
-         break;
-       case '2':
-         display_base224++;
-         break;
-       default:
-         usage();
-      }
-
-  if (argc != optind + 2 && argc != optind + 1)
-    usage();
-  file_name_1 = argv[optind++];
-  if (argc > optind)
-    file_name_2 = argv[optind++];
-
-  MSG("Initializing image library");
-  srandom(time(NULL) ^ getpid());
-  srgb_to_luv_init();
-  image_context_init(&ctx);
-
-  struct image *img1, *img2;
-
-  TRY(image_io_init(&ctx, &io));
-
-  if (file_name_1)
-    {
-      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);
-      TRY(image_io_read_header(&io));
-      io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
-      if (background_color.color_space)
-        io.background_color = background_color;
-      else if (!io.background_color.color_space)
-        io.background_color = color_black;
-      TRY(image_io_read_data(&io, 1));
-      bclose(io.fastbuf);
-      img1 = io.image;
-      MSG("Image size=%ux%u", img1->cols, img1->rows);
-      image_io_reset(&io);
-    }
-  else
-    img1 = NULL;
-
-  if (file_name_2)
-    {
-      MSG("Reading %s", file_name_2);
-      io.fastbuf = bopen(file_name_2, O_RDONLY, 1 << 18);
-      io.format = format_2 ? : image_file_name_to_format(file_name_2);
-      TRY(image_io_read_header(&io));
-      io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
-      if (background_color.color_space)
-        io.background_color = background_color;
-      else if (!io.background_color.color_space)
-        io.background_color = color_black;
-      TRY(image_io_read_data(&io, 1));
-      bclose(io.fastbuf);
-      img2 = io.image;
-      MSG("Image size=%ux%u", img2->cols, img2->rows);
-      image_io_reset(&io);
-    }
-  else
-    img2 = NULL;
-
-  struct image_signature sig1, sig2;
-  MSG("Computing signatures");
-  if (img1)
-    {
-      struct image_sig_data data;
-      TRY(image_sig_init(&ctx, &data, img1));
-      image_sig_preprocess(&data);
-      if (data.valid)
-        {
-         image_sig_segmentation(&data);
-         image_sig_detect_textured(&data);
-       }
-      if (segmentation_name_1)
-       write_segmentation(&data, segmentation_name_1);
-      image_sig_finish(&data, &sig1);
-      image_sig_cleanup(&data);
-      dump_signature(&sig1);
-    }
-  if (img2)
-    {
-      struct image_sig_data data;
-      TRY(image_sig_init(&ctx, &data, img2));
-      image_sig_preprocess(&data);
-      if (data.valid)
-        {
-         image_sig_segmentation(&data);
-         image_sig_detect_textured(&data);
-       }
-      if (segmentation_name_2)
-       write_segmentation(&data, segmentation_name_2);
-      image_sig_finish(&data, &sig2);
-      image_sig_cleanup(&data);
-      dump_signature(&sig2);
-    }
-
-  if (img1 && img2)
-    {
-      uns dist;
-      if (verbose)
-        {
-          struct fastbuf *fb = bfdopen(0, 4096);
-          dist = image_signatures_dist_explain(&sig1, &sig2, msg_str, NULL);
-          bclose(fb);
-       }
-      else
-       dist = image_signatures_dist(&sig1, &sig2);
-      MSG("dist=%u", dist);
-    }
-
-  if (img1)
-    image_destroy(img1);
-  if (img2)
-    image_destroy(img2);
-
-  image_io_cleanup(&io);
-  image_context_cleanup(&ctx);
-  MSG("Done.");
-  return 0;
-}
diff --git a/images/image-tool.c b/images/image-tool.c
deleted file mode 100644 (file)
index 3f24d02..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- *     Image Library -- Simple image manipulation utility
- *
- *     (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 <ucw/lib.h>
-#include <ucw/fastbuf.h>
-#include <images/images.h>
-#include <images/color.h>
-
-#include <getopt.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-
-static void NONRET
-usage(void)
-{
-  fputs("\
-Usage: image-tool [options] infile [outfile]\n\
-\n\
--q --quiet               no progress messages\n\
--f --input-format        input image format (jpeg, gif, png)\n\
--F --output-format       output image format\n\
--s --size                force output dimensions (100x200)\n\
--b --fit-to-box          scale to fit the box (100x200)\n\
--c --colorspace          force output colorspace (Grayscale, Grayscale+Alpha, RGB, RGB+Alpha, ...)\n\
--Q --jpeg-quality        JPEG quality (1..100)\n\
--g --background          background color (hexadecimal RRGGBB)\n\
--G --default-background  background applied only if the image contains no background info (RRGGBB, default=FFFFFF)\n\
--a --remove-alpha        remove alpha channel\n\
--e --exif                reads Exif data\n"
-, stderr);
-  exit(1);
-}
-
-static char *shortopts = "qf:F:s:b:c:Q:g:G:ae";
-static struct option longopts[] =
-{
-  { "quiet",                   0, 0, 'q' },
-  { "input-format",            0, 0, 'f' },
-  { "output-format",           0, 0, 'F' },
-  { "size",                    0, 0, 's' },
-  { "fit-to-box",              0, 0, 'b' },
-  { "colorspace",              0, 0, 'c' },
-  { "jpeg-quality",            0, 0, 'Q' },
-  { "background",              0, 0, 'g' },
-  { "default-background",      0, 0, 'G' },
-  { "remove-alpha",            0, 0, 'a' },
-  { "exif",                    0, 0, 'e' },
-  { NULL,                      0, 0, 0 }
-};
-
-static uns verbose = 1;
-static byte *input_file_name;
-static enum image_format input_format;
-static byte *output_file_name;
-static enum image_format output_format;
-static uns cols;
-static uns rows;
-static uns fit_to_box;
-static uns channels_format;
-static uns jpeg_quality;
-static struct color background_color;
-static struct color default_background_color;
-static uns remove_alpha;
-static uns exif;
-
-static void
-parse_color(struct color *color, byte *s)
-{
-  if (strlen(s) != 6)
-    usage();
-  errno = 0;
-  char *end;
-  long int v = strtol(s, &end, 16);
-  if (errno || *end || v < 0)
-    usage();
-  color_make_rgb(color, (v >> 16) & 255, (v >> 8) & 255, v & 255);
-}
-
-#define MSG(x...) do{ if (verbose) msg(L_INFO, ##x); }while(0)
-
-int
-main(int argc, char **argv)
-{
-  log_init(argv[0]);
-  int opt;
-  default_background_color = color_white;
-  while ((opt = getopt_long(argc, argv, shortopts, longopts, NULL)) >= 0)
-    switch (opt)
-      {
-       case 'q':
-         verbose = 0;
-         break;
-       case 'f':
-         if (!(input_format = image_extension_to_format(optarg)))
-           usage();
-         break;
-       case 'F':
-         if (!(output_format = image_extension_to_format(optarg)))
-           usage();
-         break;
-       case 's':
-         {
-           byte *r = strchr(optarg, 'x');
-           if (!r)
-             usage();
-           *r++ = 0;
-           if (!(cols = atoi(optarg)) || !(rows = atoi(r)))
-             usage();
-           fit_to_box = 0;
-           break;
-         }
-       case 'b':
-         {
-           byte *r = strchr(optarg, 'x');
-           if (!r)
-             usage();
-           *r++ = 0;
-           if (!(cols = atoi(optarg)) || !(rows = atoi(r)))
-             usage();
-           fit_to_box = 1;
-           break;
-         }
-       case 'c':
-         if (!(channels_format = image_name_to_channels_format(optarg)))
-           usage();
-         break;
-       case 'Q':
-         if (!(jpeg_quality = atoi(optarg)))
-           usage();
-         break;
-       case 'g':
-         parse_color(&background_color, optarg);
-         break;
-       case 'G':
-         parse_color(&default_background_color, optarg);
-         break;
-       case 'a':
-         remove_alpha++;
-         break;
-       case 'e':
-         exif++;
-         break;
-       default:
-         usage();
-      }
-
-  if (argc != optind + 1 && argc != optind + 2)
-    usage();
-  input_file_name = argv[optind++];
-  if (argc > optind)
-    output_file_name = argv[optind];
-
-#define TRY(x) do{ if (!(x)) exit(1); }while(0)
-  MSG("Initializing image library");
-  struct image_context ctx;
-  struct image_io io;
-  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);
-  byte cs_buf[IMAGE_CHANNELS_FORMAT_MAX_SIZE];
-  io.fastbuf = bopen(input_file_name, O_RDONLY, 1 << 18);
-  io.format = input_format ? : image_file_name_to_format(input_file_name);
-  if (exif)
-    io.flags |= IMAGE_IO_WANT_EXIF;
-  TRY(image_io_read_header(&io));
-  if (!output_file_name)
-    {
-      bclose(io.fastbuf);
-      printf("Format:      %s\n", image_format_to_extension(io.format) ? : (byte *)"?");
-      printf("Dimensions:  %dx%d\n", io.cols, io.rows);
-      printf("Colorspace:  %s\n", (io.flags & IMAGE_IO_HAS_PALETTE) ? (byte *)"Palette" : image_channels_format_to_name(io.flags, cs_buf));
-      printf("NumColors:   %u\n", io.number_of_colors);
-      if (io.background_color.color_space)
-        {
-         byte rgb[3];
-         TRY(color_put(&ctx, &io.background_color, rgb, COLOR_SPACE_RGB));
-          printf("Background:  %02x%02x%02x\n", rgb[0], rgb[1], rgb[2]);
-       }
-      if (io.exif_size)
-       printf("ExifSize:    %u\n", io.exif_size);
-    }
-  else
-    {
-      MSG("%s %dx%d %s", image_format_to_extension(io.format) ? : (byte *)"?", io.cols, io.rows,
-         (io.flags & IMAGE_IO_HAS_PALETTE) ? (byte *)"Palette" : image_channels_format_to_name(io.flags, cs_buf));
-      if (cols)
-        if (fit_to_box)
-         {
-            image_dimensions_fit_to_box(&io.cols, &io.rows, MIN(cols, 0xffff), MIN(rows, 0xffff), 0);
-         }
-        else
-          {
-            io.cols = cols;
-            io.rows = rows;
-          }
-      if (background_color.color_space)
-       io.background_color = background_color;
-      else if (!io.background_color.color_space)
-       io.background_color = default_background_color;
-      if (remove_alpha)
-       io.flags &= ~IMAGE_ALPHA;
-      if (channels_format)
-        io.flags = io.flags & ~IMAGE_PIXEL_FORMAT | channels_format;
-      if (!(io.flags & IMAGE_ALPHA))
-        io.flags |= IMAGE_IO_USE_BACKGROUND;
-      if (jpeg_quality)
-       io.jpeg_quality = jpeg_quality;
-      uns output_fmt = output_format ? : image_file_name_to_format(output_file_name);
-      uns output_cs = io.flags & IMAGE_COLOR_SPACE;
-      if (output_fmt != IMAGE_FORMAT_JPEG &&
-         output_cs != COLOR_SPACE_GRAYSCALE &&
-         output_cs != COLOR_SPACE_RGB)
-        {
-         MSG("Forcing RGB color space");
-         io.flags = (io.flags & ~IMAGE_COLOR_SPACE) | COLOR_SPACE_RGB;
-       }
-      TRY(image_io_read_data(&io, 0));
-      bclose(io.fastbuf);
-      MSG("Writing %s", output_file_name);
-      io.fastbuf = bopen(output_file_name, O_WRONLY | O_CREAT | O_TRUNC, 1 << 18);
-      io.format = output_format ? : image_file_name_to_format(output_file_name);
-      MSG("%s %dx%d %s", image_format_to_extension(io.format) ? : (byte *)"?", io.cols, io.rows,
-         image_channels_format_to_name(io.flags, cs_buf));
-      TRY(image_io_write(&io));
-      bclose(io.fastbuf);
-    }
-
-  image_io_cleanup(&io);
-  image_context_cleanup(&ctx);
-  MSG("Done.");
-  return 0;
-}
diff --git a/images/ucw-color-tool.c b/images/ucw-color-tool.c
new file mode 100644 (file)
index 0000000..091f982
--- /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 <ucw/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: ucw-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/ucw-image-dup-test.c b/images/ucw-image-dup-test.c
new file mode 100644 (file)
index 0000000..d5a9794
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *     Image duplicates testing
+ *
+ *     (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 <ucw/lib.h>
+#include <ucw/getopt.h>
+#include <ucw/fastbuf.h>
+#include <ucw/mempool.h>
+#include <images/images.h>
+#include <images/color.h>
+#include <images/duplicates.h>
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+static void NONRET
+usage(void)
+{
+  fputs("\
+Usage: ucw-image-dup-test [options] image1 image2 \n\
+\n\
+-q --quiet           no progress messages\n\
+-f --format-1        image1 format (jpeg, gif, png)\n\
+-F --format-2        image2 format\n\
+-g --background      background color (hexadecimal RRGGBB)\n\
+-t --transformations hexadecimal value of allowed transformtion (1=identity, FF=all)\n\
+", stderr);
+  exit(1);
+}
+
+static char *shortopts = "qf:F:g:t:" CF_SHORT_OPTS;
+static struct option longopts[] =
+{
+  CF_LONG_OPTS
+  { "quiet",           0, 0, 'q' },
+  { "format-1",                0, 0, 'f' },
+  { "format-2",                0, 0, 'F' },
+  { "background",      0, 0, 'g' },
+  { "transormations",  0, 0, 't' },
+  { NULL,              0, 0, 0 }
+};
+
+static uns verbose = 1;
+static byte *file_name_1;
+static byte *file_name_2;
+static enum image_format format_1;
+static enum image_format format_2;
+static struct color background_color;
+static uns transformations = IMAGE_DUP_TRANS_ALL;
+
+#define MSG(x...) do{ if (verbose) msg(L_INFO, ##x); }while(0)
+
+int
+main(int argc, char **argv)
+{
+  log_init(argv[0]);
+  int opt;
+  while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
+    switch (opt)
+      {
+       case 'q':
+         verbose = 0;
+         break;
+       case 'f':
+         if (!(format_1 = image_extension_to_format(optarg)))
+           usage();
+         break;
+       case 'F':
+         if (!(format_2 = image_extension_to_format(optarg)))
+           usage();
+         break;
+       case 'g':
+         {
+           if (strlen(optarg) != 6)
+             usage();
+           errno = 0;
+           char *end;
+           long int v = strtol(optarg, &end, 16);
+           if (errno || *end || v < 0)
+             usage();
+           color_make_rgb(&background_color, (v >> 16) & 255, (v >> 8) & 255, v & 255);
+         }
+         break;
+       case 't':
+         {
+           errno = 0;
+           char *end;
+           long int v = strtol(optarg, &end, 16);
+           if (errno || *end || v < 0 || v > 0xff)
+             usage();
+           transformations = v;
+         }
+         break;
+       default:
+         usage();
+      }
+
+  if (argc != optind + 2)
+    usage();
+  file_name_1 = argv[optind++];
+  file_name_2 = argv[optind];
+
+#define TRY(x) do{ if (!(x)) exit(1); }while(0)
+  MSG("Initializing image library");
+  struct image_context ctx;
+  struct image_dup_context idc;
+  struct image_io io;
+  image_context_init(&ctx);
+  image_dup_context_init(&ctx, &idc);
+
+  struct image *img1, *img2;
+
+  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);
+  TRY(image_io_read_header(&io));
+  io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
+  if (background_color.color_space)
+    io.background_color = background_color;
+  else if (!io.background_color.color_space)
+    io.background_color = color_black;
+  TRY(image_io_read_data(&io, 1));
+  bclose(io.fastbuf);
+  img1 = io.image;
+  MSG("Image size=%ux%u", img1->cols, img1->rows);
+
+  image_io_reset(&io);
+  MSG("Reading %s", file_name_2);
+  io.fastbuf = bopen(file_name_2, O_RDONLY, 1 << 18);
+  io.format = format_2 ? : image_file_name_to_format(file_name_2);
+  TRY(image_io_read_header(&io));
+  io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
+  if (background_color.color_space)
+    io.background_color = background_color;
+  else if (!io.background_color.color_space)
+    io.background_color = color_black;
+  TRY(image_io_read_data(&io, 1));
+  bclose(io.fastbuf);
+  img2 = io.image;
+  image_io_cleanup(&io);
+  MSG("Image size=%ux%u", img2->cols, img2->rows);
+
+  struct image_dup *dup1, *dup2;
+  struct mempool *pool = mp_new(1 << 18);
+  MSG("Creating internal structures");
+  dup1 = mp_start(pool, image_dup_estimate_size(img1->cols, img1->rows, 1, idc.qtree_limit));
+  uns size = image_dup_new(&idc, img1, dup1, 1);
+  TRY(size);
+  mp_end(pool, (void *)dup1 + size);
+  dup2 = mp_start(pool, image_dup_estimate_size(img2->cols, img2->rows, 1, idc.qtree_limit));
+  size = image_dup_new(&idc, img2, dup2, 1);
+  TRY(size);
+  mp_end(pool, (void *)dup2 + size);
+
+  idc.flags = transformations | IMAGE_DUP_SCALE | IMAGE_DUP_WANT_ALL;
+  MSG("Similarity bitmap %02x", image_dup_compare(&idc, dup1, dup2));
+
+  mp_delete(pool);
+
+  image_destroy(img1);
+  image_destroy(img2);
+  image_dup_context_cleanup(&idc);
+  image_context_cleanup(&ctx);
+  MSG("Done.");
+  return 0;
+}
diff --git a/images/ucw-image-sim-test.c b/images/ucw-image-sim-test.c
new file mode 100644 (file)
index 0000000..873621f
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ *     Image similarity testing
+ *
+ *     (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 <ucw/lib.h>
+#include <ucw/getopt.h>
+#include <ucw/fastbuf.h>
+#include <ucw/base64.h>
+#include <ucw/base224.h>
+#include <images/images.h>
+#include <images/color.h>
+#include <images/signature.h>
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static void NONRET
+usage(void)
+{
+  fputs("\
+Usage: ucw-image-sim-test [options] image1 [image2] \n\
+\n\
+-q --quiet           no progress messages\n\
+-f --format-1        image1 format (jpeg, gif, png)\n\
+-F --format-2        image2 format\n\
+-g --background      background color (hexadecimal RRGGBB)\n\
+-r --segmentation-1  writes image1 segmentation to given file\n\
+-R --segmentation-2  writes image2 segmentation to given file\n\
+-6 --base64          display base64 encoded signature(s)\n\
+-2 --base224         display base224 encoded signature(s)\n\
+", stderr);
+  exit(1);
+}
+
+static char *shortopts = "qf:F:g:t:r:R:62" CF_SHORT_OPTS;
+static struct option longopts[] =
+{
+  CF_LONG_OPTS
+  { "quiet",           0, 0, 'q' },
+  { "format-1",                0, 0, 'f' },
+  { "format-2",                0, 0, 'F' },
+  { "background",      0, 0, 'g' },
+  { "segmentation-1",  0, 0, 'r' },
+  { "segmentation-2",  0, 0, 'R' },
+  { "base64",          0, 0, '6' },
+  { "base224",         0, 0, '2' },
+  { NULL,              0, 0, 0 }
+};
+
+static uns verbose = 1;
+static byte *file_name_1;
+static byte *file_name_2;
+static enum image_format format_1;
+static enum image_format format_2;
+static struct color background_color;
+static byte *segmentation_name_1;
+static byte *segmentation_name_2;
+static uns display_base64;
+static uns display_base224;
+
+#define MSG(x...) do{ if (verbose) msg(L_INFO, ##x); }while(0)
+#define TRY(x) do{ if (!(x)) exit(1); }while(0)
+
+static void
+msg_str(byte *s, void *param UNUSED)
+{
+  MSG("%s", s);
+}
+
+static void
+dump_signature(struct image_signature *sig)
+{
+  byte buf[MAX(IMAGE_VECTOR_DUMP_MAX, IMAGE_REGION_DUMP_MAX)];
+  image_vector_dump(buf, &sig->vec);
+  MSG("vector: %s", buf);
+  for (uns i = 0; i < sig->len; i++)
+    {
+      image_region_dump(buf, sig->reg + i);
+      MSG("region %u: %s", i, buf);
+    }
+  uns sig_size = image_signature_size(sig->len);
+  if (display_base64)
+    {
+      byte buf[BASE64_ENC_LENGTH(sig_size) + 1];
+      uns enc_size = base64_encode(buf, (byte *)sig, sig_size);
+      buf[enc_size] = 0;
+      MSG("base64 encoded: %s", buf);
+    }
+  if (display_base224)
+    {
+      byte buf[BASE224_ENC_LENGTH(sig_size) + 1];
+      uns enc_size = base224_encode(buf, (byte *)sig, sig_size);
+      buf[enc_size] = 0;
+      MSG("base224 encoded: %s", buf);
+    }
+}
+
+static struct image_context ctx;
+static struct image_io io;
+
+static void
+write_segmentation(struct image_sig_data *data, byte *fn)
+{
+  MSG("Writing segmentation to %s", fn);
+
+  struct fastbuf *fb = bopen(fn, O_WRONLY | O_CREAT | O_TRUNC, 4096);
+  struct image *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++)
+    {
+      byte c[3];
+      double luv[3], xyz[3], srgb[3];
+      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_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);
+      for (struct image_sig_block *block = data->regions[i].blocks; block; block = block->next)
+        {
+         uns x1 = block->x * 4;
+         uns y1 = block->y * 4;
+         uns x2 = MIN(x1 + 4, img->cols);
+         uns y2 = MIN(y1 + 4, img->rows);
+         byte *p = img->pixels + x1 * 3 + y1 * img->row_size;
+         for (uns y = y1; y < y2; y++, p += img->row_size)
+           {
+             byte *p2 = p;
+             for (uns x = x1; x < x2; x++, p2 += 3)
+               {
+                 p2[0] = c[0];
+                 p2[1] = c[1];
+                 p2[2] = c[2];
+               }
+           }
+        }
+    }
+
+  io.fastbuf = fb;
+  io.image = img;
+  io.format = image_file_name_to_format(fn);
+  TRY(image_io_write(&io));
+  image_io_reset(&io);
+
+  image_destroy(img);
+  bclose(fb);
+}
+
+int
+main(int argc, char **argv)
+{
+  log_init(argv[0]);
+  int opt;
+  while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
+    switch (opt)
+      {
+       case 'q':
+         verbose = 0;
+         break;
+       case 'f':
+         if (!(format_1 = image_extension_to_format(optarg)))
+           usage();
+         break;
+       case 'F':
+         if (!(format_2 = image_extension_to_format(optarg)))
+           usage();
+         break;
+       case 'g':
+         {
+           if (strlen(optarg) != 6)
+             usage();
+           errno = 0;
+           char *end;
+           long int v = strtol(optarg, &end, 16);
+           if (errno || *end || v < 0)
+             usage();
+           color_make_rgb(&background_color, (v >> 16) & 255, (v >> 8) & 255, v & 255);
+         }
+         break;
+       case 'r':
+         segmentation_name_1 = optarg;
+         break;
+       case 'R':
+         segmentation_name_2 = optarg;
+         break;
+       case '6':
+         display_base64++;
+         break;
+       case '2':
+         display_base224++;
+         break;
+       default:
+         usage();
+      }
+
+  if (argc != optind + 2 && argc != optind + 1)
+    usage();
+  file_name_1 = argv[optind++];
+  if (argc > optind)
+    file_name_2 = argv[optind++];
+
+  MSG("Initializing image library");
+  srandom(time(NULL) ^ getpid());
+  srgb_to_luv_init();
+  image_context_init(&ctx);
+
+  struct image *img1, *img2;
+
+  TRY(image_io_init(&ctx, &io));
+
+  if (file_name_1)
+    {
+      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);
+      TRY(image_io_read_header(&io));
+      io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
+      if (background_color.color_space)
+        io.background_color = background_color;
+      else if (!io.background_color.color_space)
+        io.background_color = color_black;
+      TRY(image_io_read_data(&io, 1));
+      bclose(io.fastbuf);
+      img1 = io.image;
+      MSG("Image size=%ux%u", img1->cols, img1->rows);
+      image_io_reset(&io);
+    }
+  else
+    img1 = NULL;
+
+  if (file_name_2)
+    {
+      MSG("Reading %s", file_name_2);
+      io.fastbuf = bopen(file_name_2, O_RDONLY, 1 << 18);
+      io.format = format_2 ? : image_file_name_to_format(file_name_2);
+      TRY(image_io_read_header(&io));
+      io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
+      if (background_color.color_space)
+        io.background_color = background_color;
+      else if (!io.background_color.color_space)
+        io.background_color = color_black;
+      TRY(image_io_read_data(&io, 1));
+      bclose(io.fastbuf);
+      img2 = io.image;
+      MSG("Image size=%ux%u", img2->cols, img2->rows);
+      image_io_reset(&io);
+    }
+  else
+    img2 = NULL;
+
+  struct image_signature sig1, sig2;
+  MSG("Computing signatures");
+  if (img1)
+    {
+      struct image_sig_data data;
+      TRY(image_sig_init(&ctx, &data, img1));
+      image_sig_preprocess(&data);
+      if (data.valid)
+        {
+         image_sig_segmentation(&data);
+         image_sig_detect_textured(&data);
+       }
+      if (segmentation_name_1)
+       write_segmentation(&data, segmentation_name_1);
+      image_sig_finish(&data, &sig1);
+      image_sig_cleanup(&data);
+      dump_signature(&sig1);
+    }
+  if (img2)
+    {
+      struct image_sig_data data;
+      TRY(image_sig_init(&ctx, &data, img2));
+      image_sig_preprocess(&data);
+      if (data.valid)
+        {
+         image_sig_segmentation(&data);
+         image_sig_detect_textured(&data);
+       }
+      if (segmentation_name_2)
+       write_segmentation(&data, segmentation_name_2);
+      image_sig_finish(&data, &sig2);
+      image_sig_cleanup(&data);
+      dump_signature(&sig2);
+    }
+
+  if (img1 && img2)
+    {
+      uns dist;
+      if (verbose)
+        {
+          struct fastbuf *fb = bfdopen(0, 4096);
+          dist = image_signatures_dist_explain(&sig1, &sig2, msg_str, NULL);
+          bclose(fb);
+       }
+      else
+       dist = image_signatures_dist(&sig1, &sig2);
+      MSG("dist=%u", dist);
+    }
+
+  if (img1)
+    image_destroy(img1);
+  if (img2)
+    image_destroy(img2);
+
+  image_io_cleanup(&io);
+  image_context_cleanup(&ctx);
+  MSG("Done.");
+  return 0;
+}
diff --git a/images/ucw-image-tool.c b/images/ucw-image-tool.c
new file mode 100644 (file)
index 0000000..4b7f3df
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ *     Image Library -- Simple image manipulation utility
+ *
+ *     (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 <ucw/lib.h>
+#include <ucw/fastbuf.h>
+#include <images/images.h>
+#include <images/color.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+static void NONRET
+usage(void)
+{
+  fputs("\
+Usage: ucw-image-tool [options] infile [outfile]\n\
+\n\
+-q --quiet               no progress messages\n\
+-f --input-format        input image format (jpeg, gif, png)\n\
+-F --output-format       output image format\n\
+-s --size                force output dimensions (100x200)\n\
+-b --fit-to-box          scale to fit the box (100x200)\n\
+-c --colorspace          force output colorspace (Grayscale, Grayscale+Alpha, RGB, RGB+Alpha, ...)\n\
+-Q --jpeg-quality        JPEG quality (1..100)\n\
+-g --background          background color (hexadecimal RRGGBB)\n\
+-G --default-background  background applied only if the image contains no background info (RRGGBB, default=FFFFFF)\n\
+-a --remove-alpha        remove alpha channel\n\
+-e --exif                reads Exif data\n"
+, stderr);
+  exit(1);
+}
+
+static char *shortopts = "qf:F:s:b:c:Q:g:G:ae";
+static struct option longopts[] =
+{
+  { "quiet",                   0, 0, 'q' },
+  { "input-format",            0, 0, 'f' },
+  { "output-format",           0, 0, 'F' },
+  { "size",                    0, 0, 's' },
+  { "fit-to-box",              0, 0, 'b' },
+  { "colorspace",              0, 0, 'c' },
+  { "jpeg-quality",            0, 0, 'Q' },
+  { "background",              0, 0, 'g' },
+  { "default-background",      0, 0, 'G' },
+  { "remove-alpha",            0, 0, 'a' },
+  { "exif",                    0, 0, 'e' },
+  { NULL,                      0, 0, 0 }
+};
+
+static uns verbose = 1;
+static byte *input_file_name;
+static enum image_format input_format;
+static byte *output_file_name;
+static enum image_format output_format;
+static uns cols;
+static uns rows;
+static uns fit_to_box;
+static uns channels_format;
+static uns jpeg_quality;
+static struct color background_color;
+static struct color default_background_color;
+static uns remove_alpha;
+static uns exif;
+
+static void
+parse_color(struct color *color, byte *s)
+{
+  if (strlen(s) != 6)
+    usage();
+  errno = 0;
+  char *end;
+  long int v = strtol(s, &end, 16);
+  if (errno || *end || v < 0)
+    usage();
+  color_make_rgb(color, (v >> 16) & 255, (v >> 8) & 255, v & 255);
+}
+
+#define MSG(x...) do{ if (verbose) msg(L_INFO, ##x); }while(0)
+
+int
+main(int argc, char **argv)
+{
+  log_init(argv[0]);
+  int opt;
+  default_background_color = color_white;
+  while ((opt = getopt_long(argc, argv, shortopts, longopts, NULL)) >= 0)
+    switch (opt)
+      {
+       case 'q':
+         verbose = 0;
+         break;
+       case 'f':
+         if (!(input_format = image_extension_to_format(optarg)))
+           usage();
+         break;
+       case 'F':
+         if (!(output_format = image_extension_to_format(optarg)))
+           usage();
+         break;
+       case 's':
+         {
+           byte *r = strchr(optarg, 'x');
+           if (!r)
+             usage();
+           *r++ = 0;
+           if (!(cols = atoi(optarg)) || !(rows = atoi(r)))
+             usage();
+           fit_to_box = 0;
+           break;
+         }
+       case 'b':
+         {
+           byte *r = strchr(optarg, 'x');
+           if (!r)
+             usage();
+           *r++ = 0;
+           if (!(cols = atoi(optarg)) || !(rows = atoi(r)))
+             usage();
+           fit_to_box = 1;
+           break;
+         }
+       case 'c':
+         if (!(channels_format = image_name_to_channels_format(optarg)))
+           usage();
+         break;
+       case 'Q':
+         if (!(jpeg_quality = atoi(optarg)))
+           usage();
+         break;
+       case 'g':
+         parse_color(&background_color, optarg);
+         break;
+       case 'G':
+         parse_color(&default_background_color, optarg);
+         break;
+       case 'a':
+         remove_alpha++;
+         break;
+       case 'e':
+         exif++;
+         break;
+       default:
+         usage();
+      }
+
+  if (argc != optind + 1 && argc != optind + 2)
+    usage();
+  input_file_name = argv[optind++];
+  if (argc > optind)
+    output_file_name = argv[optind];
+
+#define TRY(x) do{ if (!(x)) exit(1); }while(0)
+  MSG("Initializing image library");
+  struct image_context ctx;
+  struct image_io io;
+  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);
+  byte cs_buf[IMAGE_CHANNELS_FORMAT_MAX_SIZE];
+  io.fastbuf = bopen(input_file_name, O_RDONLY, 1 << 18);
+  io.format = input_format ? : image_file_name_to_format(input_file_name);
+  if (exif)
+    io.flags |= IMAGE_IO_WANT_EXIF;
+  TRY(image_io_read_header(&io));
+  if (!output_file_name)
+    {
+      bclose(io.fastbuf);
+      printf("Format:      %s\n", image_format_to_extension(io.format) ? : (byte *)"?");
+      printf("Dimensions:  %dx%d\n", io.cols, io.rows);
+      printf("Colorspace:  %s\n", (io.flags & IMAGE_IO_HAS_PALETTE) ? (byte *)"Palette" : image_channels_format_to_name(io.flags, cs_buf));
+      printf("NumColors:   %u\n", io.number_of_colors);
+      if (io.background_color.color_space)
+        {
+         byte rgb[3];
+         TRY(color_put(&ctx, &io.background_color, rgb, COLOR_SPACE_RGB));
+          printf("Background:  %02x%02x%02x\n", rgb[0], rgb[1], rgb[2]);
+       }
+      if (io.exif_size)
+       printf("ExifSize:    %u\n", io.exif_size);
+    }
+  else
+    {
+      MSG("%s %dx%d %s", image_format_to_extension(io.format) ? : (byte *)"?", io.cols, io.rows,
+         (io.flags & IMAGE_IO_HAS_PALETTE) ? (byte *)"Palette" : image_channels_format_to_name(io.flags, cs_buf));
+      if (cols)
+        if (fit_to_box)
+         {
+            image_dimensions_fit_to_box(&io.cols, &io.rows, MIN(cols, 0xffff), MIN(rows, 0xffff), 0);
+         }
+        else
+          {
+            io.cols = cols;
+            io.rows = rows;
+          }
+      if (background_color.color_space)
+       io.background_color = background_color;
+      else if (!io.background_color.color_space)
+       io.background_color = default_background_color;
+      if (remove_alpha)
+       io.flags &= ~IMAGE_ALPHA;
+      if (channels_format)
+        io.flags = io.flags & ~IMAGE_PIXEL_FORMAT | channels_format;
+      if (!(io.flags & IMAGE_ALPHA))
+        io.flags |= IMAGE_IO_USE_BACKGROUND;
+      if (jpeg_quality)
+       io.jpeg_quality = jpeg_quality;
+      uns output_fmt = output_format ? : image_file_name_to_format(output_file_name);
+      uns output_cs = io.flags & IMAGE_COLOR_SPACE;
+      if (output_fmt != IMAGE_FORMAT_JPEG &&
+         output_cs != COLOR_SPACE_GRAYSCALE &&
+         output_cs != COLOR_SPACE_RGB)
+        {
+         MSG("Forcing RGB color space");
+         io.flags = (io.flags & ~IMAGE_COLOR_SPACE) | COLOR_SPACE_RGB;
+       }
+      TRY(image_io_read_data(&io, 0));
+      bclose(io.fastbuf);
+      MSG("Writing %s", output_file_name);
+      io.fastbuf = bopen(output_file_name, O_WRONLY | O_CREAT | O_TRUNC, 1 << 18);
+      io.format = output_format ? : image_file_name_to_format(output_file_name);
+      MSG("%s %dx%d %s", image_format_to_extension(io.format) ? : (byte *)"?", io.cols, io.rows,
+         image_channels_format_to_name(io.flags, cs_buf));
+      TRY(image_io_write(&io));
+      bclose(io.fastbuf);
+    }
+
+  image_io_cleanup(&io);
+  image_context_cleanup(&ctx);
+  MSG("Done.");
+  return 0;
+}