/** * Call MapImages. * * Ruby usage: * - @verbatim ImageList#map(reference) @endverbatim * - @verbatim ImageList#map(reference, dither) @endverbatim * * Notes: * - Default dither is false * - Sets \@scene to self.scene * * @param argc number of input arguments * @param argv array of input arguments * @param self this object * @return a new ImageList with mapped images. */ VALUE ImageList_map(int argc, VALUE *argv, VALUE self) { Image *images, *new_images = NULL; Image *map; unsigned int dither = MagickFalse; VALUE scene, new_imagelist, t; ExceptionInfo *exception; #if defined(HAVE_REMAPIMAGES) QuantizeInfo quantize_info; rb_warning("ImageList#map is deprecated. Use ImageList#remap instead."); #endif switch (argc) { case 2: dither = RTEST(argv[1]); case 1: t = rm_cur_image(argv[0]); map = rm_check_destroyed(t); break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc); break; } // Convert image array to image sequence, clone image sequence. exception = AcquireExceptionInfo(); images = images_from_imagelist(self); new_images = CloneImageList(images, exception); rm_split(images); rm_check_exception(exception, new_images, DestroyOnError); (void) DestroyExceptionInfo(exception); rm_ensure_result(new_images); // Call ImageMagick #if defined(HAVE_REMAPIMAGES) GetQuantizeInfo(&quantize_info); quantize_info.dither = dither; (void) RemapImages(&quantize_info, new_images, map); #else (void) MapImages(new_images, map, dither); #endif rm_check_image_exception(new_images, DestroyOnError); // Set @scene in new ImageList object to same value as in self. new_imagelist = rm_imagelist_from_images(new_images); scene = rb_iv_get(self, "@scene"); (void) imagelist_scene_eq(new_imagelist, scene); RB_GC_GUARD(scene); RB_GC_GUARD(new_imagelist); RB_GC_GUARD(t); return new_imagelist; }
Image::Image( uint32 width, uint32 height, const char* map, StorageType storage, const void* pixels ) throw (GSystem::Exception): m_image( NULL ) { // initialize exception ExceptionInfo exception; GetExceptionInfo( &exception ); m_image = ConstituteImage( width, height, map, storage, pixels, &exception ); if ( m_image == NULL ) { MC2String exceptionString = "Reason: "; exceptionString += exception.reason; exceptionString += "Description: "; exceptionString += exception.description; DestroyExceptionInfo( &exception ); throw GSystem::Exception( "[ImageMagick]" + exceptionString ); } DestroyExceptionInfo( &exception ); GetQuantizeInfo(&m_quantizeInfo); }
Image *get_grayscale_image(Image *img) { QuantizeInfo info; GetQuantizeInfo(&info); info.colorspace = GRAYColorspace; info.number_colors = 256; QuantizeImage(&info, img); return (img); }
// Constructor Magick::Options::Options( void ) : _imageInfo(static_cast<ImageInfo*>(AcquireMagickMemory(sizeof(ImageInfo)))), _quantizeInfo(static_cast<QuantizeInfo*>(AcquireMagickMemory(sizeof(QuantizeInfo)))), _drawInfo(static_cast<DrawInfo*>(AcquireMagickMemory( sizeof(DrawInfo)))) { // Initialize image info with defaults GetImageInfo( _imageInfo ); // Initialize quantization info GetQuantizeInfo( _quantizeInfo ); // Initialize drawing info GetDrawInfo( _imageInfo, _drawInfo ); }
/** * Call RemapImages. * * Ruby usage: * - @verbatim ImageList#remap @endverbatim * - @verbatim ImageList#remap(remap_image) @endverbatim * - @verbatim ImageList#remap(remap_image, dither_method) @endverbatim * * Notes: * - Default remap_image is nil * - Default dither_method is RiemersmaDitherMethod * - Modifies images in-place. * * @param argc number of input arguments * @param argv array of input arguments * @param self this object * @see Image_remap */ VALUE ImageList_remap(int argc, VALUE *argv, VALUE self) { #if defined(HAVE_REMAPIMAGES) || defined(HAVE_AFFINITYIMAGES) Image *images, *remap_image = NULL; QuantizeInfo quantize_info; if (argc > 0 && argv[0] != Qnil) { VALUE t = rm_cur_image(argv[0]); remap_image = rm_check_destroyed(t); RB_GC_GUARD(t); } GetQuantizeInfo(&quantize_info); if (argc > 1) { VALUE_TO_ENUM(argv[1], quantize_info.dither_method, DitherMethod); quantize_info.dither = MagickTrue; } if (argc > 2) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc); } images = images_from_imagelist(self); #if defined(HAVE_REMAPIMAGE) (void) RemapImages(&quantize_info, images, remap_image); #else (void) AffinityImages(&quantize_info, images, remap_image); #endif rm_check_image_exception(images, RetainOnError); rm_split(images); return self; #else self = self; argc = argc; argv = argv; rm_not_implemented(); return(VALUE)0; #endif }
/* * Class: magick_QuantizeInfo * Method: init * Signature: ()V */ JNIEXPORT void JNICALL Java_magick_QuantizeInfo_init (JNIEnv *env, jobject self) { QuantizeInfo *quantizeInfo = NULL; jfieldID fid = 0; quantizeInfo = (QuantizeInfo*) getHandle(env, self, "quantizeInfoHandle", &fid); if (quantizeInfo == NULL) { quantizeInfo = (QuantizeInfo *) AcquireMemory(sizeof(QuantizeInfo)); if (quantizeInfo == NULL) { throwMagickException(env, "Unable to allow memory for handle"); return; } } GetQuantizeInfo(quantizeInfo); setHandle(env, self, "quantizeInfoHandle", (void*) quantizeInfo, &fid); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d X C F I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadXCFImage() reads a GIMP (GNU Image Manipulation Program) image % file and returns it. It allocates the memory necessary for the new Image % structure and returns a pointer to the new image. % % The format of the ReadXCFImage method is: % % image=ReadXCFImage(image_info) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % % */ static Image *ReadXCFImage(const ImageInfo *image_info,ExceptionInfo *exception) { char magick[14]; Image *image; int foundPropEnd = 0; MagickBooleanType status; MagickOffsetType offset; register ssize_t i; size_t length; ssize_t count; size_t image_type; XCFDocInfo doc_info; /* Open image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); image=AcquireImage(image_info); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } count=ReadBlob(image,14,(unsigned char *) magick); if ((count == 0) || (LocaleNCompare((char *) magick,"gimp xcf",8) != 0)) ThrowReaderException(CorruptImageError,"ImproperImageHeader"); (void) ResetMagickMemory(&doc_info,0,sizeof(XCFDocInfo)); doc_info.exception=exception; doc_info.width=ReadBlobMSBLong(image); doc_info.height=ReadBlobMSBLong(image); if ((doc_info.width > 262144) || (doc_info.height > 262144)) ThrowReaderException(CorruptImageError,"ImproperImageHeader"); doc_info.image_type=ReadBlobMSBLong(image); /* Initialize image attributes. */ image->columns=doc_info.width; image->rows=doc_info.height; image_type=doc_info.image_type; doc_info.file_size=GetBlobSize(image); image->compression=NoCompression; image->depth=8; if (image_type == GIMP_RGB) image->colorspace=RGBColorspace; else if (image_type == GIMP_GRAY) image->colorspace=GRAYColorspace; else if (image_type == GIMP_INDEXED) ThrowReaderException(CoderError,"ColormapTypeNotSupported"); (void) SetImageBackgroundColor(image); image->matte=MagickTrue; /* Read properties. */ while ((foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse)) { PropType prop_type = (PropType) ReadBlobMSBLong(image); size_t prop_size = ReadBlobMSBLong(image); switch (prop_type) { case PROP_END: foundPropEnd=1; break; case PROP_COLORMAP: { /* Cannot rely on prop_size here--the value is set incorrectly by some Gimp versions. */ size_t num_colours = ReadBlobMSBLong(image); for (i=0; i < (ssize_t) (3L*num_colours); i++ ) (void) ReadBlobByte(image); /* if (info->file_version == 0) { gint i; g_message (_("XCF warning: version 0 of XCF file format\n" "did not save indexed colormaps correctly.\n" "Substituting grayscale map.")); info->cp += xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1); gimage->cmap = g_new (guchar, gimage->num_cols*3); xcf_seek_pos (info, info->cp + gimage->num_cols); for (i = 0; i<gimage->num_cols; i++) { gimage->cmap[i*3+0] = i; gimage->cmap[i*3+1] = i; gimage->cmap[i*3+2] = i; } } else { info->cp += xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1); gimage->cmap = g_new (guchar, gimage->num_cols*3); info->cp += xcf_read_int8 (info->fp, (guint8*) gimage->cmap, gimage->num_cols*3); } */ break; } case PROP_COMPRESSION: { doc_info.compression = ReadBlobByte(image); if ((doc_info.compression != COMPRESS_NONE) && (doc_info.compression != COMPRESS_RLE) && (doc_info.compression != COMPRESS_ZLIB) && (doc_info.compression != COMPRESS_FRACTAL)) ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression"); } break; case PROP_GUIDES: { /* just skip it - we don't care about guides */ for (i=0; i < (ssize_t) prop_size; i++ ) if (ReadBlobByte(image) == EOF) ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); } break; case PROP_RESOLUTION: { /* float xres = (float) */ (void) ReadBlobMSBLong(image); /* float yres = (float) */ (void) ReadBlobMSBLong(image); /* if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION || yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION) { g_message ("Warning, resolution out of range in XCF file"); xres = gimage->gimp->config->default_xresolution; yres = gimage->gimp->config->default_yresolution; } */ /* BOGUS: we don't write these yet because we aren't reading them properly yet :( image->x_resolution = xres; image->y_resolution = yres; */ } break; case PROP_TATTOO: { /* we need to read it, even if we ignore it */ /*size_t tattoo_state = */ (void) ReadBlobMSBLong(image); } break; case PROP_PARASITES: { /* BOGUS: we may need these for IPTC stuff */ for (i=0; i < (ssize_t) prop_size; i++ ) if (ReadBlobByte(image) == EOF) ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); /* gssize_t base = info->cp; GimpParasite *p; while (info->cp - base < prop_size) { p = xcf_load_parasite (info); gimp_image_parasite_attach (gimage, p); gimp_parasite_free (p); } if (info->cp - base != prop_size) g_message ("Error detected while loading an image's parasites"); */ } break; case PROP_UNIT: { /* BOGUS: ignore for now... */ /*size_t unit = */ (void) ReadBlobMSBLong(image); } break; case PROP_PATHS: { /* BOGUS: just skip it for now */ for (i=0; i< (ssize_t) prop_size; i++ ) if (ReadBlobByte(image) == EOF) ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); /* PathList *paths = xcf_load_bzpaths (gimage, info); gimp_image_set_paths (gimage, paths); */ } break; case PROP_USER_UNIT: { char unit_string[1000]; /*BOGUS: ignored for now */ /*float factor = (float) */ (void) ReadBlobMSBLong(image); /* size_t digits = */ (void) ReadBlobMSBLong(image); for (i=0; i<5; i++) (void) ReadBlobStringWithLongSize(image, unit_string, sizeof(unit_string)); } break; default: { int buf[16]; ssize_t amount; /* read over it... */ while ((prop_size > 0) && (EOFBlob(image) == MagickFalse)) { amount=(ssize_t) MagickMin(16, prop_size); amount=(ssize_t) ReadBlob(image,(size_t) amount,(unsigned char *) &buf); if (!amount) ThrowReaderException(CorruptImageError,"CorruptImage"); prop_size -= (size_t) MagickMin(16,(size_t) amount); } } break; } } if (foundPropEnd == MagickFalse) ThrowReaderException(CorruptImageError,"ImproperImageHeader"); if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) { ; /* do nothing, were just pinging! */ } else { int current_layer = 0, foundAllLayers = MagickFalse, number_layers = 0; MagickOffsetType oldPos=TellBlob(image); XCFLayerInfo *layer_info; /* the read pointer */ do { ssize_t offset = (ssize_t) ReadBlobMSBLong(image); if (offset == 0) foundAllLayers=MagickTrue; else number_layers++; if (EOFBlob(image) != MagickFalse) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } } while (foundAllLayers == MagickFalse); offset=SeekBlob(image,oldPos,SEEK_SET); /* restore the position! */ if (offset < 0) ThrowReaderException(CorruptImageError,"ImproperImageHeader"); /* allocate our array of layer info blocks */ length=(size_t) number_layers; layer_info=(XCFLayerInfo *) AcquireQuantumMemory(length, sizeof(*layer_info)); if (layer_info == (XCFLayerInfo *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); (void) ResetMagickMemory(layer_info,0,number_layers*sizeof(XCFLayerInfo)); for ( ; ; ) { MagickBooleanType layer_ok; MagickOffsetType offset, saved_pos; /* read in the offset of the next layer */ offset=(MagickOffsetType) ReadBlobMSBLong(image); /* if the offset is 0 then we are at the end * of the layer list. */ if (offset == 0) break; /* save the current position as it is where the * next layer offset is stored. */ saved_pos=TellBlob(image); /* seek to the layer offset */ offset=SeekBlob(image,offset,SEEK_SET); /* read in the layer */ layer_ok=ReadOneLayer(image,&doc_info,&layer_info[current_layer]); if (layer_ok == MagickFalse) { int j; for (j=0; j < current_layer; j++) layer_info[j].image=DestroyImage(layer_info[j].image); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } /* restore the saved position so we'll be ready to * read the next offset. */ offset=SeekBlob(image, saved_pos, SEEK_SET); current_layer++; } if (number_layers == 1) { /* Composite the layer data onto the main image, dispose the layer. */ (void) CompositeImage(image,OverCompositeOp,layer_info[0].image, layer_info[0].offset_x,layer_info[0].offset_y); layer_info[0].image =DestroyImage( layer_info[0].image); } else { #if 0 { /* NOTE: XCF layers are REVERSED from composite order! */ signed int j; for (j=number_layers-1; j>=0; j--) { /* BOGUS: need to consider layer blending modes!! */ if ( layer_info[j].visible ) { /* only visible ones, please! */ CompositeImage(image, OverCompositeOp, layer_info[j].image, layer_info[j].offset_x, layer_info[j].offset_y ); layer_info[j].image =DestroyImage( layer_info[j].image ); /* Bob says that if we do this, we'll get REAL gray images! */ if ( image_type == GIMP_GRAY ) { QuantizeInfo qi; GetQuantizeInfo(&qi); qi.colorspace = GRAYColorspace; QuantizeImage( &qi, layer_info[j].image ); } } } } #else { /* NOTE: XCF layers are REVERSED from composite order! */ signed int j; /* first we copy the last layer on top of the main image */ (void) CompositeImage(image,CopyCompositeOp, layer_info[number_layers-1].image, layer_info[number_layers-1].offset_x, layer_info[number_layers-1].offset_y); layer_info[number_layers-1].image=DestroyImage( layer_info[number_layers-1].image); /* now reverse the order of the layers as they are put into subimages */ j=number_layers-2; image->next=layer_info[j].image; layer_info[j].image->previous=image; layer_info[j].image->page.x=layer_info[j].offset_x; layer_info[j].image->page.y=layer_info[j].offset_y; layer_info[j].image->page.width=layer_info[j].width; layer_info[j].image->page.height=layer_info[j].height; for (j=number_layers-3; j>=0; j--) { if (j > 0) layer_info[j].image->next=layer_info[j-1].image; if (j < (number_layers-1)) layer_info[j].image->previous=layer_info[j+1].image; layer_info[j].image->page.x=layer_info[j].offset_x; layer_info[j].image->page.y=layer_info[j].offset_y; layer_info[j].image->page.width=layer_info[j].width; layer_info[j].image->page.height=layer_info[j].height; } } #endif } layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info); #if 0 /* BOGUS: do we need the channels?? */ while (MagickTrue) { /* read in the offset of the next channel */ info->cp += xcf_read_int32 (info->fp, &offset, 1); /* if the offset is 0 then we are at the end * of the channel list. */ if (offset == 0) break; /* save the current position as it is where the * next channel offset is stored. */ saved_pos = info->cp; /* seek to the channel offset */ xcf_seek_pos (info, offset); /* read in the layer */ channel = xcf_load_channel (info, gimage); if (channel == 0) goto error; num_successful_elements++; /* add the channel to the image if its not the selection */ if (channel != gimage->selection_mask) gimp_image_add_channel (gimage, channel, -1); /* restore the saved position so we'll be ready to * read the next offset. */ xcf_seek_pos (info, saved_pos); } #endif } (void) CloseBlob(image); if (image_type == GIMP_GRAY) image->type=GrayscaleType; return(GetFirstImageInList(image)); }
/** * Call QuantizeImages. * * Ruby usage: * - @verbatim ImageList#quantize @endverbatim * - @verbatim ImageList#quantize(number_colors) @endverbatim * - @verbatim ImageList#quantize(number_colors, colorspace) @endverbatim * - @verbatim ImageList#quantize(number_colors, colorspace, dither) @endverbatim * - @verbatim ImageList#quantize(number_colors, colorspace, dither, tree_depth) @endverbatim * - @verbatim ImageList#quantize(number_colors, colorspace, dither, tree_depth, measure_error) @endverbatim * * Notes: * - Default number_colors is 256 * - Default coorspace is Magick::RGBColorsapce * - Default dither is true * - Default tree_depth is 0 * - Default measure_error is false * - Sets \@scene to the same value as self.scene * * @param argc number of input arguments * @param argv array of input arguments * @param self this object * @return a new ImageList with quantized images */ VALUE ImageList_quantize(int argc, VALUE *argv, VALUE self) { Image *images, *new_images; Image *new_image; QuantizeInfo quantize_info; ExceptionInfo *exception; VALUE new_imagelist, scene; GetQuantizeInfo(&quantize_info); switch (argc) { case 5: quantize_info.measure_error = (MagickBooleanType) RTEST(argv[4]); case 4: quantize_info.tree_depth = (unsigned long)NUM2INT(argv[3]); case 3: #if defined(HAVE_TYPE_DITHERMETHOD) && defined(HAVE_ENUM_NODITHERMETHOD) if (rb_obj_is_kind_of(argv[2], Class_DitherMethod)) { VALUE_TO_ENUM(argv[2], quantize_info.dither_method, DitherMethod); quantize_info.dither = quantize_info.dither_method != NoDitherMethod; } #else quantize_info.dither = (MagickBooleanType) RTEST(argv[2]); #endif case 2: VALUE_TO_ENUM(argv[1], quantize_info.colorspace, ColorspaceType); case 1: quantize_info.number_colors = NUM2ULONG(argv[0]); case 0: break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 5)", argc); break; } // Convert image array to image sequence, clone image sequence. exception = AcquireExceptionInfo(); images = images_from_imagelist(self); new_images = CloneImageList(images, exception); rm_split(images); rm_check_exception(exception, new_images, DestroyOnError); rm_ensure_result(new_images); (void) QuantizeImages(&quantize_info, new_images); rm_check_exception(exception, new_images, DestroyOnError); (void) DestroyExceptionInfo(exception); // Create new ImageList object, convert mapped image sequence to images, // append to images array. new_imagelist = ImageList_new(); while ((new_image = RemoveFirstImageFromList(&new_images))) { imagelist_push(new_imagelist, rm_image_new(new_image)); } // Set @scene in new ImageList object to same value as in self. scene = rb_iv_get(self, "@scene"); (void) rb_iv_set(new_imagelist, "@scene", scene); RB_GC_GUARD(new_imagelist); RB_GC_GUARD(scene); return new_imagelist; }
/** * Equivalent to -layers option in ImageMagick 6.2.6. * * Ruby usage: * - @verbatim ImageList#optimize_layers(method) @endverbatim * * @param self this object * @param method the method to use * @return a new imagelist */ VALUE ImageList_optimize_layers(VALUE self, VALUE method) { Image *images, *new_images, *new_images2; LAYERMETHODTYPE mthd; ExceptionInfo *exception; QuantizeInfo quantize_info; new_images2 = NULL; // defeat "unused variable" message exception = AcquireExceptionInfo(); #if defined(HAVE_TYPE_IMAGELAYERMETHOD) VALUE_TO_ENUM(method, mthd, ImageLayerMethod); #else VALUE_TO_ENUM(method, mthd, MagickLayerMethod); #endif images = images_from_imagelist(self); switch (mthd) { case CoalesceLayer: new_images = CoalesceImages(images, exception); break; case DisposeLayer: new_images = DisposeImages(images, exception); break; case OptimizeTransLayer: new_images = clone_imagelist(images); OptimizeImageTransparency(new_images, exception); break; case RemoveDupsLayer: new_images = clone_imagelist(images); RemoveDuplicateLayers(&new_images, exception); break; case RemoveZeroLayer: new_images = clone_imagelist(images); RemoveZeroDelayLayers(&new_images, exception); break; case CompositeLayer: rm_split(images); rb_raise(rb_eNotImpError, "Magick::CompositeLayer is not supported. Use the composite_layers method instead."); break; // In 6.3.4-ish, OptimizeImageLayer replaced OptimizeLayer case OptimizeImageLayer: new_images = OptimizeImageLayers(images, exception); break; // and OptimizeLayer became a "General Purpose, GIF Animation Optimizer" (ref. mogrify.c) case OptimizeLayer: new_images = CoalesceImages(images, exception); rm_split(images); rm_check_exception(exception, new_images, DestroyOnError); new_images2 = OptimizeImageLayers(new_images, exception); DestroyImageList(new_images); rm_check_exception(exception, new_images2, DestroyOnError); new_images = new_images2; OptimizeImageTransparency(new_images, exception); rm_check_exception(exception, new_images, DestroyOnError); // mogrify supports -dither here. We don't. #if defined(HAVE_REMAPIMAGE) GetQuantizeInfo(&quantize_info); (void) RemapImages(&quantize_info, new_images, NULL); #else (void) MapImages(new_images, NULL, 0); #endif break; case OptimizePlusLayer: new_images = OptimizePlusImageLayers(images, exception); break; case CompareAnyLayer: case CompareClearLayer: case CompareOverlayLayer: new_images = CompareImageLayers(images, mthd, exception); break; #if defined(HAVE_ENUM_MOSAICLAYER) case MosaicLayer: new_images = MergeImageLayers(images, mthd, exception); break; #endif #if defined(HAVE_ENUM_FLATTENLAYER) case FlattenLayer: new_images = MergeImageLayers(images, mthd, exception); break; #endif #if defined(HAVE_ENUM_MERGELAYER) case MergeLayer: new_images = MergeImageLayers(images, mthd, exception); break; #endif #if defined(HAVE_ENUM_TRIMBOUNDSLAYER) case TrimBoundsLayer: new_images = MergeImageLayers(images, mthd, exception); break; #endif default: rm_split(images); rb_raise(rb_eArgError, "undefined layer method"); break; } rm_split(images); rm_check_exception(exception, new_images, DestroyOnError); (void) DestroyExceptionInfo(exception); rm_ensure_result(new_images); return rm_imagelist_from_images(new_images); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e E P T I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % WriteEPTImage() writes an image in the Encapsulated Postscript format % with a TIFF preview. % % The format of the WriteEPTImage method is: % % MagickBooleanType WriteEPTImage(const ImageInfo *image_info, % Image *image,ExceptionInfo *exception) % % A description of each parameter follows. % % o image_info: the image info. % % o image: The image. % % o exception: return any errors or warnings in this structure. % */ static MagickBooleanType WriteEPTImage(const ImageInfo *image_info,Image *image, ExceptionInfo *exception) { char filename[MagickPathExtent]; EPTInfo ept_info; Image *write_image; ImageInfo *write_info; MagickBooleanType status; /* Write EPT image. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickCoreSignature); assert(image != (Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); if (status == MagickFalse) return(status); write_image=CloneImage(image,0,0,MagickTrue,exception); if (write_image == (Image *) NULL) return(MagickFalse); write_info=CloneImageInfo(image_info); (void) CopyMagickString(write_info->magick,"EPS",MagickPathExtent); if (LocaleCompare(image_info->magick,"EPT2") == 0) (void) CopyMagickString(write_info->magick,"EPS2",MagickPathExtent); if (LocaleCompare(image_info->magick,"EPT3") == 0) (void) CopyMagickString(write_info->magick,"EPS3",MagickPathExtent); (void) ResetMagickMemory(&ept_info,0,sizeof(ept_info)); ept_info.magick=0xc6d3d0c5ul; ept_info.postscript=(unsigned char *) ImageToBlob(write_info,write_image, &ept_info.postscript_length,exception); write_image=DestroyImage(write_image); write_info=DestroyImageInfo(write_info); if (ept_info.postscript == (void *) NULL) return(MagickFalse); write_image=CloneImage(image,0,0,MagickTrue,exception); if (write_image == (Image *) NULL) return(MagickFalse); write_info=CloneImageInfo(image_info); *write_info->magick='\0'; (void) CopyMagickString(write_info->magick,"TIFF",MagickPathExtent); (void) FormatLocaleString(filename,MagickPathExtent,"tiff:%s", write_info->filename); (void) CopyMagickString(write_info->filename,filename,MagickPathExtent); (void) TransformImage(&write_image,(char *) NULL,"512x512>",exception); if ((write_image->storage_class == DirectClass) || (write_image->colors > 256)) { QuantizeInfo quantize_info; /* EPT preview requires that the image is colormapped. */ GetQuantizeInfo(&quantize_info); quantize_info.dither_method=IdentifyPaletteImage(write_image, exception) == MagickFalse ? RiemersmaDitherMethod : NoDitherMethod; (void) QuantizeImage(&quantize_info,write_image,exception); } write_info->compression=NoCompression; ept_info.tiff=(unsigned char *) ImageToBlob(write_info,write_image, &ept_info.tiff_length,exception); write_image=DestroyImage(write_image); write_info=DestroyImageInfo(write_info); if (ept_info.tiff == (void *) NULL) { ept_info.postscript=(unsigned char *) RelinquishMagickMemory( ept_info.postscript); return(MagickFalse); } /* Write EPT image. */ (void) WriteBlobLSBLong(image,(unsigned int) ept_info.magick); (void) WriteBlobLSBLong(image,30); (void) WriteBlobLSBLong(image,(unsigned int) ept_info.postscript_length); (void) WriteBlobLSBLong(image,0); (void) WriteBlobLSBLong(image,0); (void) WriteBlobLSBLong(image,(unsigned int) ept_info.postscript_length+30); (void) WriteBlobLSBLong(image,(unsigned int) ept_info.tiff_length); (void) WriteBlobLSBShort(image,0xffff); (void) WriteBlob(image,ept_info.postscript_length,ept_info.postscript); (void) WriteBlob(image,ept_info.tiff_length,ept_info.tiff); /* Relinquish resources. */ ept_info.postscript=(unsigned char *) RelinquishMagickMemory( ept_info.postscript); ept_info.tiff=(unsigned char *) RelinquishMagickMemory(ept_info.tiff); (void) CloseBlob(image); return(MagickTrue); }
void * gif_encode(Image *image, int single, int *size) { int width = image->columns; int height = image->rows; int total = width * height; GifByteType red[total]; GifByteType green[total]; GifByteType blue[total]; // Quantize the images using IM/GM first, to reduce // their number of colors to 256. int count = GetImageListLength(image); QuantizeInfo info; GetQuantizeInfo(&info); info.dither = 0; info.number_colors = NCOLORS; QuantizeImage(&info, image); if (count > 1) { #ifdef _MAGICK_USES_IM RemapImages(&info, image->next, image); #else MapImages(image->next, image, 0); #endif } if (!acquire_image_pixels(image, red, green, blue)) { return NULL; } size_t frame_size = sizeof(Frame) + total; Frame *frames = malloc(frame_size * count); ColorMapObject *palette = GifMakeMapObject(NCOLORS, NULL); int palette_size = NCOLORS; // Quantize again using giflib, since it yields a palette which produces // better compression, reducing the file size by 20%. Note that this second // quantization is very fast, because the image already has 256 colors, so // its effect on performance is negligible. if (GifQuantizeBuffer(width, height, &palette_size, red, green, blue, frames->data, palette->Colors) == GIF_ERROR) { GifFreeMapObject(palette); free(frames); return NULL; } frames->width = width; frames->height = height; frames->duration = image->delay; GifColorType *colors = palette->Colors; Image *cur = image->next; PixelCache *cache = pixel_cache_new(); unsigned char *p = (unsigned char*)frames; int ii; for (ii = 1; ii < count; ii++, cur = cur->next) { p += frame_size; Frame *frame = (Frame*)p; frame->width = width; frame->height = height; frame->duration = cur->delay; GifPixelType *data = frame->data; if (!aprox_image_pixels(cur, colors, palette_size, cache, data)) { GifFreeMapObject(palette); free(frames); pixel_cache_free(cache); return NULL; } } pixel_cache_free(cache); void *ret = gif_save(image, palette, frames, count, frame_size, size); GifFreeMapObject(palette); free(frames); return ret; }
/* Method: ImageList#quantize(<number_colors<, colorspace<, dither<, tree_depth<, measure_error>>>>>) defaults: 256, Magick::RGBColorspace, true, 0, false Purpose: call QuantizeImages Returns: a new ImageList with quantized images. 'scene' is set to the same value as self.scene */ VALUE ImageList_quantize(int argc, VALUE *argv, VALUE self) { Image *images, *new_images; Image *new_image; QuantizeInfo quantize_info; ExceptionInfo exception; volatile VALUE new_imagelist, scene; GetQuantizeInfo(&quantize_info); switch (argc) { case 5: quantize_info.measure_error = (MagickBooleanType) RTEST(argv[4]); case 4: quantize_info.tree_depth = (unsigned long)NUM2INT(argv[3]); case 3: quantize_info.dither = (MagickBooleanType) RTEST(argv[2]); case 2: VALUE_TO_ENUM(argv[1], quantize_info.colorspace, ColorspaceType); case 1: quantize_info.number_colors = NUM2ULONG(argv[0]); case 0: break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 5)", argc); break; } if (imagelist_length(self) == 0L) { rb_raise(rb_eArgError, "no images in this image list"); } // Convert image array to image sequence, clone image sequence. GetExceptionInfo(&exception); images = images_from_imagelist(self); new_images = CloneImageList(images, &exception); rm_split(images); rm_check_exception(&exception, new_images, DestroyOnError); (void) DestroyExceptionInfo(&exception); rm_ensure_result(new_images); (void) QuantizeImages(&quantize_info, new_images); rm_check_exception(&exception, new_images, DestroyOnError); // Create new ImageList object, convert mapped image sequence to images, // append to images array. new_imagelist = ImageList_new(); while ((new_image = ShiftImageList(&new_images))) { imagelist_push(new_imagelist, rm_image_new(new_image)); } // Set @scene in new ImageList object to same value as in self. scene = rb_iv_get(self, "@scene"); (void) rb_iv_set(new_imagelist, "@scene", scene); return new_imagelist; }