From: Pavel Charvat Date: Tue, 25 Jul 2006 07:36:52 +0000 (+0200) Subject: slow image compression via GraphicsMagick X-Git-Tag: holmes-import~636 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=220ef64e42102f6cac027dd763aac043897721f1;p=libucw.git slow image compression via GraphicsMagick --- diff --git a/images/io-libmagick.c b/images/io-libmagick.c index 7ec37930..1bbdfc0c 100644 --- a/images/io-libmagick.c +++ b/images/io-libmagick.c @@ -1,5 +1,5 @@ /* - * Image Library -- GraphicsMagick + * Image Library -- GraphicsMagick (slow fallback library) * * (c) 2006 Pavel Charvat * @@ -21,6 +21,8 @@ #define MAX_FILE_SIZE (1 << 30) #define QUANTUM_SCALE (QuantumDepth - 8) #define QUANTUM_TO_BYTE(x) ((uns)(x) >> QUANTUM_SCALE) +#define BYTE_TO_QUANTUM(x) ((uns)(x) << QUANTUM_SCALE) +#define OPACITY_MAX ((1 << QuantumDepth) - 1) struct magick_read_data { ExceptionInfo exception; @@ -56,7 +58,7 @@ libmagick_read_header(struct image_io *io) /* Read entire stream */ sh_off_t file_size = bfilesize(io->fastbuf) - btell(io->fastbuf); - if (file_size > MAX_FILE_SIZE) + if (unlikely(file_size > MAX_FILE_SIZE)) { image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Too long stream."); return 0; @@ -77,12 +79,12 @@ libmagick_read_header(struct image_io *io) /* Read the image */ rd->image = BlobToImage(rd->info, buf, buf_size, &rd->exception); xfree(buf); - if (!rd->image) + if (unlikely(!rd->image)) { image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "GraphicsMagick failed to read the image."); goto err; } - if (rd->image->columns > IMAGE_MAX_SIZE || rd->image->rows > IMAGE_MAX_SIZE) + if (unlikely(rd->image->columns > IMAGE_MAX_SIZE || rd->image->rows > IMAGE_MAX_SIZE)) { image_thread_err(io->thread, IMAGE_ERR_INVALID_DIMENSIONS, "Image too large."); goto err; @@ -147,12 +149,12 @@ libmagick_read_data(struct image_io *io) struct image *img = need_scale ? image_new(io->thread, rd->image->columns, rd->image->rows, io->flags & IMAGE_CHANNELS_FORMAT, NULL) : image_new(io->thread, io->cols, io->rows, io->flags, io->pool); - if (!img) + if (unlikely(!img)) goto err; /* Acquire pixels */ PixelPacket *src = (PixelPacket *)AcquireImagePixels(rd->image, 0, 0, rd->image->columns, rd->image->rows, &rd->exception); - if (!src) + if (unlikely(!src)) { image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot acquire image pixels."); goto err; @@ -218,13 +220,13 @@ libmagick_read_data(struct image_io *io) if (need_scale) { struct image *img2 = image_new(io->thread, io->cols, io->rows, io->flags, io->pool); - if (!img2) + if (unlikely(!img2)) goto err2; int result = image_scale(io->thread, img2, img); image_destroy(io->thread, img); img = img2; need_destroy = !io->pool; - if (!result) + if (unlikely(!result)) goto err2; } @@ -245,6 +247,145 @@ err2: int libmagick_write(struct image_io *io) { - image_thread_err(io->thread, IMAGE_ERR_NOT_IMPLEMENTED, "GraphicsMagick write not implemented."); - return 0; + DBG("libmagick_write()"); + + /* Initialize GraphicsMagick */ + int result = 0; + ExceptionInfo exception; + ImageInfo *info; + InitializeMagick(NULL); + GetExceptionInfo(&exception); + info = CloneImageInfo(NULL); + + /* Setup image parameters and allocate the image*/ + switch (io->flags & IMAGE_COLOR_SPACE) + { + case COLOR_SPACE_GRAYSCALE: + info->colorspace = GRAYColorspace; + break; + case COLOR_SPACE_RGB: + info->colorspace = RGBColorspace; + break; + default: + ASSERT(0); + } + switch (io->format) + { + case IMAGE_FORMAT_JPEG: + strcpy(info->magick, "JPEG"); + break; + case IMAGE_FORMAT_PNG: + strcpy(info->magick, "PNG"); + break; + case IMAGE_FORMAT_GIF: + strcpy(info->magick, "GIF"); + break; + default: + ASSERT(0); + } + Image *image = AllocateImage(info); + if (unlikely(!image)) + { + image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "GraphicsMagick failed to allocate the image."); + goto err; + } + image->columns = io->cols; + image->rows = io->rows; + + /* Get pixels */ + PixelPacket *pixels = SetImagePixels(image, 0, 0, io->cols, io->rows), *dest = pixels; + if (unlikely(!pixels)) + { + image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "Cannot get GraphicsMagick pixels."); + goto err2; + } + + /* Convert pixels */ + struct image *img = io->image; + switch (img->pixel_size) + { + case 1: +# define IMAGE_WALK_INLINE +# define IMAGE_WALK_UNROLL 4 +# define IMAGE_WALK_COL_STEP 1 +# define IMAGE_WALK_DO_STEP do{ \ + dest->red = BYTE_TO_QUANTUM(pos[0]); \ + dest->green = BYTE_TO_QUANTUM(pos[0]); \ + dest->blue = BYTE_TO_QUANTUM(pos[0]); \ + dest->opacity = OPACITY_MAX; \ + dest++; }while(0) +# include "images/image-walk.h" + break; + case 2: +# define IMAGE_WALK_INLINE +# define IMAGE_WALK_UNROLL 4 +# define IMAGE_WALK_COL_STEP 2 +# define IMAGE_WALK_DO_STEP do{ \ + dest->red = BYTE_TO_QUANTUM(pos[0]); \ + dest->green = BYTE_TO_QUANTUM(pos[0]); \ + dest->blue = BYTE_TO_QUANTUM(pos[0]); \ + dest->opacity = BYTE_TO_QUANTUM(pos[1]); \ + dest++; }while(0) +# include "images/image-walk.h" + break; + case 3: +# define IMAGE_WALK_INLINE +# define IMAGE_WALK_UNROLL 4 +# define IMAGE_WALK_COL_STEP 3 +# define IMAGE_WALK_DO_STEP do{ \ + dest->red = BYTE_TO_QUANTUM(pos[0]); \ + dest->green = BYTE_TO_QUANTUM(pos[1]); \ + dest->blue = BYTE_TO_QUANTUM(pos[2]); \ + dest->opacity = OPACITY_MAX; \ + dest++; }while(0) +# include "images/image-walk.h" + break; + case 4: +# define IMAGE_WALK_INLINE +# define IMAGE_WALK_UNROLL 4 +# define IMAGE_WALK_COL_STEP 4 +# define IMAGE_WALK_DO_STEP do{ \ + dest->red = BYTE_TO_QUANTUM(pos[0]); \ + dest->green = BYTE_TO_QUANTUM(pos[1]); \ + dest->blue = BYTE_TO_QUANTUM(pos[2]); \ + dest->opacity = BYTE_TO_QUANTUM(pos[3]); \ + dest++; }while(0) +# include "images/image-walk.h" + break; + } + + /* Store pixels */ + if (unlikely(!SyncImagePixels(image))) + { + image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "Cannot sync GraphicsMagick pixels."); + goto err2; + } + + /* Write image */ + size_t buf_len = 0; + void *buf = ImageToBlob(info, image, &buf_len, &exception); + if (unlikely(!buf)) + { + image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "GraphicsMagick failed to compress the image."); + goto err2; + } + if (unlikely(buf_len > MAX_FILE_SIZE)) + { + image_thread_err(io->thread, IMAGE_ERR_WRITE_FAILED, "Image too large."); + goto err2; + } + + /* Write to stream */ + bwrite(io->fastbuf, buf, buf_len); + + /* Success */ + result = 1; + +err2: + DestroyImage(image); +err: + DestroyImageInfo(info); + DestroyExceptionInfo(&exception); + DestroyMagick(); + return result; } diff --git a/images/io-main.c b/images/io-main.c index eb04faa9..583a0fbe 100644 --- a/images/io-main.c +++ b/images/io-main.c @@ -90,7 +90,7 @@ image_io_read_header(struct image_io *io) case IMAGE_FORMAT_GIF: #if defined(CONFIG_LIBUNGIG) return libungif_read_header(io); -#elif defined(CONFIG_LIBMAGICK) +#elif defined(CONFIG_LIBMAGICK) return libmagick_read_header(io); #endif break; @@ -174,13 +174,21 @@ image_io_write(struct image_io *io) case IMAGE_FORMAT_JPEG: #if defined(CONFIG_LIBJPEG) return libjpeg_write(io); +#elif defined(CONFIG_LIBMAGICK) + return libmagick_write(io); #endif break; case IMAGE_FORMAT_PNG: +#if defined(CONFIG_LIBMAGICK) + return libmagick_write(io); +#endif break; case IMAGE_FORMAT_GIF: +#if defined(CONFIG_LIBMAGICK) + return libmagick_write(io); +#endif break; default: