]> mj.ucw.cz Git - libucw.git/commitdiff
little changes in image I/O interface
authorPavel Charvat <pavel.charvat@netcentrum.cz>
Tue, 25 Jul 2006 19:32:21 +0000 (21:32 +0200)
committerPavel Charvat <pavel.charvat@netcentrum.cz>
Tue, 25 Jul 2006 19:32:21 +0000 (21:32 +0200)
added some image parameters needed for gather/format/image.c

images/image-tool.c
images/image.c
images/images.h
images/io-libjpeg.c
images/io-libmagick.c
images/io-libpng.c
images/io-main.c

index 94fdd44dc0f987fe918adc6ec9e9a06a77cdac82..d9b20adc53ab35819b1f053962ee256aa5b41cf5 100644 (file)
@@ -24,13 +24,14 @@ Usage: image-tool [options] infile [outfile]\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-box        scale to fit the box (100x200)\n\
--c --colorspace     force output colorspace (gray, grayalpha, rgb, rgbalpha)\n\
+-b --fit-to-box     scale to fit the box (100x200)\n\
+-c --colorspace     force output colorspace (Gray, GrayAlpha, RGB, RGBAlpha)\n\
+-Q --jpeg-quality   JPEG quality (1..100)\n\
 ", stderr);
   exit(1);
 }
 
-static char *shortopts = "qf:F:s:b:c:" CF_SHORT_OPTS;
+static char *shortopts = "qf:F:s:b:c:Q:" CF_SHORT_OPTS;
 static struct option longopts[] =
 {
   CF_LONG_OPTS
@@ -38,8 +39,9 @@ static struct option longopts[] =
   { "input-format",    0, 0, 'f' },
   { "output-format",   0, 0, 'F' },
   { "size",            0, 0, 's' },
-  { "fit-box",         0, 0, 'b' },
+  { "fit-to-box",      0, 0, 'b' },
   { "colorspace",      0, 0, 'c' },
+  { "jpeg-quality",    0, 0, 'Q' },
   { NULL,              0, 0, 0 }
 };
                                                          
@@ -50,8 +52,9 @@ static byte *output_file_name;
 static enum image_format output_format;
 static uns cols;
 static uns rows;
-static uns fit_box;
+static uns fit_to_box;
 static uns channels_format;
+static uns jpeg_quality;
 
 #define MSG(x...) do{ if (verbose) log(L_INFO, ##x); }while(0)
 
@@ -82,7 +85,7 @@ main(int argc, char **argv)
            *r++ = 0;
            if (!(cols = atoi(optarg)) || !(rows = atoi(r)))
              usage();
-           fit_box = 0;
+           fit_to_box = 0;
            break;
          }
        case 'b':
@@ -93,13 +96,17 @@ main(int argc, char **argv)
            *r++ = 0;
            if (!(cols = atoi(optarg)) || !(rows = atoi(r)))
              usage();
-           fit_box = 1;
+           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;
        default:
          usage();
       }
@@ -126,14 +133,15 @@ main(int argc, char **argv)
       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", image_channels_format_to_name(io.flags & IMAGE_CHANNELS_FORMAT));
+      printf("Colorspace:  %s\n", io.has_palette ? (byte *)"Palette" : image_channels_format_to_name(io.flags & IMAGE_CHANNELS_FORMAT));
+      printf("NumColors:   %d\n", io.number_of_colors);
     }
   else
     {
       MSG("%s %dx%d %s", image_format_to_extension(io.format) ? : (byte *)"?", io.cols, io.rows,
-         image_channels_format_to_name(io.flags & IMAGE_CHANNELS_FORMAT));
+         io.has_palette ? (byte *)"Palette" : image_channels_format_to_name(io.flags & IMAGE_CHANNELS_FORMAT));
       if (cols)
-        if (fit_box)
+        if (fit_to_box)
          {
             image_dimensions_fit_to_box(&io.cols, &io.rows, MIN(cols, 0xffff), MIN(rows, 0xffff), 0);
          }
@@ -144,6 +152,8 @@ main(int argc, char **argv)
           }
       if (channels_format)
         io.flags = io.flags & ~IMAGE_PIXEL_FORMAT | channels_format;
+      if (jpeg_quality)
+       io.jpeg_quality = jpeg_quality;
       TRY(image_io_read_data(&io, 0));
       bclose(io.fastbuf);
       MSG("Writing %s", output_file_name);
index 1db02b104ff287df2893b88fb343a08ce504ed0e..e04d839c573f86a4cbc05acc1343b4bb22d12b2b 100644 (file)
@@ -152,7 +152,7 @@ image_clone(struct image_thread *it, struct image *src, uns flags, struct mempoo
 }
 
 void
-image_destroy(struct image_thread *it UNUSED, struct image *img)
+image_destroy(struct image *img)
 {
   DBG("image_destroy(img=%p)", img);
   xfree((byte *)img);
index 91c43d1946053b0364ca6174cb8643924ec36e68..31c25dc89344c5b8b6c86b85afff903aad701356 100644 (file)
@@ -43,6 +43,13 @@ image_thread_err(struct image_thread *thread, uns code, char *msg)
   thread->err_msg = (byte *)msg;
 }
 
+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);
+}
+
 void image_thread_err_format(struct image_thread *thread, uns code, char *msg, ...);
 
 /* basic image manupulation */
@@ -80,7 +87,7 @@ struct image {
 
 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);
-void image_destroy(struct image_thread *it, struct image *img); /* only with NULL mempool */
+void image_destroy(struct image *img); /* only with NULL mempool */
 void image_clear(struct image_thread *it, struct image *img);
 
 byte *color_space_to_name(enum color_space cs);
@@ -103,27 +110,29 @@ enum image_format {
 };
 
 struct image_io {
-  struct image *image;
-  struct fastbuf *fastbuf;
-  enum image_format format;
-  struct mempool *pool;
-  u32 cols;
-  u32 rows;
-  u32 flags;
+                               /*  R - read_header input */
+                               /*   H - read_header output */
+                               /*    I - read_data input */
+                               /*     O - read_data output */
+                               /*      W - write input */
+
+  struct image *image;         /* [   OW] - image data */
+  enum image_format format;    /* [R   W] - file format (IMAGE_FORMAT_x) */
+  struct fastbuf *fastbuf;      /* [R   W] - source/destination stream */
+  struct mempool *pool;                /* [  I  ] - parameter to image_new */
+  u32 cols;                    /* [ HI  ] - number of columns, parameter to image_new */
+  u32 rows;                    /* [ HI  ] - number of rows, parameter to image_new */
+  u32 flags;                   /* [ HI  ] - parameter to image new, read_header fills IMAGE_CHANNELS_FORMAT */
+  u32 jpeg_quality;            /* [    W] - JPEG compression quality (1..100) */
+  u32 number_of_colors;                /* [ H   ] - number of image colors */
+  u32 has_palette;             /* [ H   ] - true for image with indexed colors */
+
   /* internals */
   struct image_thread *thread;
   struct mempool *internal_pool;
   int image_destroy;
   void *read_data;
   void (*read_cancel)(struct image_io *io);
-  union {
-    struct {
-    } jpeg;
-    struct {
-    } png;
-    struct {
-    } gif;
-  };
 };
 
 void image_io_init(struct image_thread *it, struct image_io *io);
index 1b4679709e17815d6cdcace73e8ff980c9a97407..dddfd79f7dfb8d71363fa926707d1c246f31137e 100644 (file)
@@ -48,7 +48,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(e->io->thread, IMAGE_ERR_READ_FAILED, buf);
+  image_thread_err_dup(e->io->thread, IMAGE_ERR_READ_FAILED, buf);
   longjmp(e->setjmp_buf, 1);
 }
 
@@ -59,7 +59,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(e->io->thread, IMAGE_ERR_WRITE_FAILED,  buf);
+  image_thread_err_dup(e->io->thread, IMAGE_ERR_WRITE_FAILED,  buf);
   longjmp(e->setjmp_buf, 1);
 }
 
@@ -217,20 +217,19 @@ libjpeg_read_header(struct image_io *io)
   /* Read JPEG header and setup decompression options */
   DBG("Reading image header");
   jpeg_read_header(&i->cinfo, TRUE);
-  if (!(io->flags & IMAGE_COLOR_SPACE))
-    switch (i->cinfo.jpeg_color_space)
-      {
-        case JCS_GRAYSCALE:
-         io->flags |= COLOR_SPACE_GRAYSCALE;
-         break;
-        default:
-         io->flags |= COLOR_SPACE_RGB;
-         break;
-      }
-  if (!io->cols)
-    io->cols = i->cinfo.image_width;
-  if (!io->rows)
-    io->rows = i->cinfo.image_height;
+  switch (i->cinfo.jpeg_color_space)
+    {
+      case JCS_GRAYSCALE:
+        io->flags = COLOR_SPACE_GRAYSCALE;
+       io->number_of_colors = 1 << 8;
+        break;
+      default:
+        io->flags = COLOR_SPACE_RGB;
+       io->number_of_colors = 1 << 24;
+        break;
+    }
+  io->cols = i->cinfo.image_width;
+  io->rows = i->cinfo.image_height;
 
   io->read_cancel = libjpeg_read_cancel;
   return 1;
@@ -275,7 +274,7 @@ libjpeg_read_data(struct image_io *io)
       DBG("Libjpeg failed to read the image, longjump saved us");
       jpeg_destroy_decompress(&i->cinfo);
       if (need_scale || !io->pool)
-       image_destroy(io->thread, img);
+       image_destroy(img);
       return 0;
     }
 
@@ -335,17 +334,17 @@ libjpeg_read_data(struct image_io *io)
       struct image *dest = image_new(io->thread, io->cols, io->rows, io->flags, io->pool);
       if (!dest)
         {
-         image_destroy(io->thread, img);
+         image_destroy(img);
          return 0;
        }
       if (!(image_scale(io->thread, dest, img)))
         {
-         image_destroy(io->thread, img);
+         image_destroy(img);
          if (!io->pool)
-           image_destroy(io->thread, dest);
+           image_destroy(dest);
          return 0;
        }
-      image_destroy(io->thread, img);
+      image_destroy(img);
       io->image = dest;
     }
   else
@@ -403,6 +402,8 @@ libjpeg_write(struct image_io *io)
        return 0;
     }
   jpeg_set_defaults(&i.cinfo);
+  if (io->jpeg_quality)
+    jpeg_set_quality(&i.cinfo, MIN(io->jpeg_quality, 100), 1);
 
   /* Compress the image */
   jpeg_start_compress(&i.cinfo, TRUE);
index b74c717469bec61a162515565b03b7d6f40673ab..aa426872920d17941ea0ee0141e89ca255b14e5f 100644 (file)
@@ -91,22 +91,20 @@ libmagick_read_header(struct image_io *io)
     }
 
   /* Fill image parameters */
-  if (!io->cols)
-    io->cols = rd->image->columns;
-  if (!io->rows)
-    io->rows = rd->image->rows;
-  if (!(io->flags & IMAGE_CHANNELS_FORMAT))
+  io->cols = rd->image->columns;
+  io->rows = rd->image->rows;
+  switch (rd->image->colorspace)
     {
-      switch (rd->image->colorspace)
-        {
-         case GRAYColorspace:
-           io->flags |= COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
-           break;
-         default:
-           io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA;
-           break;
-       }
+      case GRAYColorspace:
+        io->flags |= COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
+        break;
+      default:
+        io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA;
+        break;
     }
+  io->number_of_colors = rd->image->colors;
+  if (rd->image->storage_class == PseudoClass && rd->image->compression != JPEGCompression)
+    io->has_palette = 1;
 
   io->read_cancel = libmagick_read_cancel;
   return 1;
@@ -223,7 +221,7 @@ libmagick_read_data(struct image_io *io)
       if (unlikely(!img2))
         goto err2;
       int result = image_scale(io->thread, img2, img);
-      image_destroy(io->thread, img);
+      image_destroy(img);
       img = img2;
       need_destroy = !io->pool;
       if (unlikely(!result))
@@ -240,7 +238,7 @@ err:
   libmagick_destroy_read_data(rd);
 err2:
   if (need_destroy)
-    image_destroy(io->thread, img);
+    image_destroy(img);
   return 0;
 }
 
@@ -274,6 +272,8 @@ libmagick_write(struct image_io *io)
     {
       case IMAGE_FORMAT_JPEG:
        strcpy(info->magick, "JPEG");
+       if (io->jpeg_quality)
+         info->quality = MIN(io->jpeg_quality, 100);
        break;
       case IMAGE_FORMAT_PNG:
        strcpy(info->magick, "PNG");
index 4b4864f61f5b31cbc9eaf98eb8e8dd9091ea31e3..c2847a8220c82bc7ae3c414dc2bdcc0d795fefd5 100644 (file)
@@ -43,7 +43,7 @@ static void NONRET
 libpng_read_error(png_structp png_ptr, png_const_charp msg)
 {
   DBG("libpng_read_error()");
-  image_thread_err(png_get_error_ptr(png_ptr), IMAGE_ERR_READ_FAILED, (byte *)msg);
+  image_thread_err_dup(png_get_error_ptr(png_ptr), IMAGE_ERR_READ_FAILED, (byte *)msg);
   longjmp(png_jmpbuf(png_ptr), 1);
 }
 
@@ -51,7 +51,7 @@ static void NONRET
 libpng_write_error(png_structp png_ptr, png_const_charp msg)
 {
   DBG("libpng_write_error()");
-  image_thread_err(png_get_error_ptr(png_ptr), IMAGE_ERR_WRITE_FAILED, (byte *)msg);
+  image_thread_err_dup(png_get_error_ptr(png_ptr), IMAGE_ERR_WRITE_FAILED, (byte *)msg);
   longjmp(png_jmpbuf(png_ptr), 1);
 }
 
@@ -138,31 +138,40 @@ libpng_read_header(struct image_io *io)
   png_get_IHDR(rd->png_ptr, rd->info_ptr, &rd->cols, &rd->rows, &rd->bit_depth, &rd->color_type, NULL, NULL, NULL);
 
   /* Fill image_io values */
-  if (!io->cols)
-    io->cols = rd->cols;
-  if (!io->rows)
-    io->rows = rd->rows;
-  if (!(io->flags & IMAGE_CHANNELS_FORMAT))
-    switch (rd->color_type)
-      {
-       case PNG_COLOR_TYPE_GRAY:
-         io->flags |= COLOR_SPACE_GRAYSCALE;
-         break;
-       case PNG_COLOR_TYPE_GRAY_ALPHA:
-         io->flags |= COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
-         break;
-       case PNG_COLOR_TYPE_RGB:
-         io->flags |= COLOR_SPACE_RGB;
-         break;
-       case PNG_COLOR_TYPE_RGB_ALPHA:
-       case PNG_COLOR_TYPE_PALETTE:
-         io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA;
-         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");
-         break;
-      }
+  io->cols = rd->cols;
+  io->rows = rd->rows;
+  switch (rd->color_type)
+    {
+      case PNG_COLOR_TYPE_GRAY:
+        io->flags |= COLOR_SPACE_GRAYSCALE;
+       io->number_of_colors = 1 << 8;
+        break;
+      case PNG_COLOR_TYPE_GRAY_ALPHA:
+        io->flags |= COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
+       io->number_of_colors = 1 << 8;
+        break;
+      case PNG_COLOR_TYPE_RGB:
+        io->flags |= COLOR_SPACE_RGB;
+       io->number_of_colors = 1 << 24;
+        break;
+      case PNG_COLOR_TYPE_RGB_ALPHA:
+       io->number_of_colors = 1 << 24;
+        io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA;
+        break;
+      case PNG_COLOR_TYPE_PALETTE:
+        io->flags |= COLOR_SPACE_RGB | IMAGE_ALPHA;
+       int num_palette;
+       if (png_get_PLTE(rd->png_ptr, rd->info_ptr, NULL, &num_palette))
+         io->number_of_colors = num_palette;
+       else
+         io->number_of_colors = 1 << rd->bit_depth;
+       io->has_palette = 1;
+        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");
+        break;
+    }  
 
   /* Success */
   io->read_cancel = libpng_read_cancel;
@@ -203,7 +212,7 @@ libpng_read_data(struct image_io *io)
       DBG("Libpng failed to read the image, longjump saved us");
       png_destroy_read_struct(&rd->png_ptr, &rd->info_ptr, &rd->end_ptr);
       if (need_scale || !io->pool)
-       image_destroy(io->thread, img);
+       image_destroy(img);
       return 0;
     }
 
@@ -272,14 +281,14 @@ libpng_read_data(struct image_io *io)
       struct image *dest = image_new(io->thread, io->cols, io->rows, io->flags, io->pool);
       if (!dest)
         {
-         image_destroy(io->thread, img);
+         image_destroy(img);
          return 0;
        }
       if (!image_scale(io->thread, dest, img))
         {
-         image_destroy(io->thread, img);
+         image_destroy(img);
          if (!io->pool)
-           image_destroy(io->thread, dest);
+           image_destroy(dest);
          return 0;
        }
       io->image = dest;
index 76f5db904eb5b501a86bd623264e6d14b7248801..65f61782c3665b548d6976e891649c698f3aede0 100644 (file)
@@ -37,7 +37,7 @@ image_io_image_destroy(struct image_io *io)
 {
   if (io->image_destroy)
     {
-      image_destroy(io->thread, io->image);
+      image_destroy(io->image);
       io->image_destroy = 0;
       io->image = NULL;
     }