/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % CCCC OOO L OOO RRRR M M AAA PPPP % % C O O L O O R R MM MM A A P P % % C O O L O O RRRR M M M AAAAA PPPP % % C O O L O O R R M M A A P % % CCCC OOO LLLLL OOO R R M M A A P % % % % % % MagickCore Colormap Methods % % % % Software Design % % John Cristy % % July 1992 % % % % % % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % http://www.imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % We use linked-lists because splay-trees do not currently support duplicate % key / value pairs (.e.g X11 green compliance and SVG green compliance). % */ /* Include declarations. */ #include "MagickCore/studio.h" #include "MagickCore/blob.h" #include "MagickCore/cache-view.h" #include "MagickCore/cache.h" #include "MagickCore/color.h" #include "MagickCore/color-private.h" #include "MagickCore/colormap.h" #include "MagickCore/client.h" #include "MagickCore/configure.h" #include "MagickCore/exception.h" #include "MagickCore/exception-private.h" #include "MagickCore/gem.h" #include "MagickCore/geometry.h" #include "MagickCore/image-private.h" #include "MagickCore/memory_.h" #include "MagickCore/monitor.h" #include "MagickCore/monitor-private.h" #include "MagickCore/option.h" #include "MagickCore/pixel-accessor.h" #include "MagickCore/quantize.h" #include "MagickCore/quantum.h" #include "MagickCore/semaphore.h" #include "MagickCore/string_.h" #include "MagickCore/token.h" #include "MagickCore/utility.h" #include "MagickCore/xml-tree.h" /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % A c q u i r e I m a g e C o l o r m a p % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AcquireImageColormap() allocates an image colormap and initializes % it to a linear gray colorspace. If the image already has a colormap, % it is replaced. AcquireImageColormap() returns MagickTrue if successful, % otherwise MagickFalse if there is not enough memory. % % The format of the AcquireImageColormap method is: % % MagickBooleanType AcquireImageColormap(Image *image, % const size_t colors,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: the image. % % o colors: the number of colors in the image colormap. % % o exception: return any errors or warnings in this structure. % */ static inline size_t MagickMax(const size_t x, const size_t y) { if (x > y) return(x); return(y); } MagickExport MagickBooleanType AcquireImageColormap(Image *image, const size_t colors,ExceptionInfo *exception) { register ssize_t i; size_t length; /* Allocate image colormap. */ assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); image->colors=colors; length=(size_t) colors; if (image->colormap == (PixelInfo *) NULL) image->colormap=(PixelInfo *) AcquireQuantumMemory(length, sizeof(*image->colormap)); else image->colormap=(PixelInfo *) ResizeQuantumMemory(image->colormap,length, sizeof(*image->colormap)); if (image->colormap == (PixelInfo *) NULL) ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename); for (i=0; i < (ssize_t) image->colors; i++) { size_t pixel; pixel=(size_t) (i*(QuantumRange/MagickMax(colors-1,1))); image->colormap[i].red=(Quantum) pixel; image->colormap[i].green=(Quantum) pixel; image->colormap[i].blue=(Quantum) pixel; image->colormap[i].alpha=OpaqueAlpha; } return(SetImageStorageClass(image,PseudoClass,exception)); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % C y c l e C o l o r m a p I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % CycleColormap() displaces an image's colormap by a given number of % positions. If you cycle the colormap a number of times you can produce % a psychodelic effect. % % WARNING: this assumes an images colormap is in a well know and defined % order. Currently Imagemagick has no way of setting that order. % % The format of the CycleColormapImage method is: % % MagickBooleanType CycleColormapImage(Image *image,const ssize_t displace, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image: the image. % % o displace: displace the colormap this amount. % % o exception: return any errors or warnings in this structure. % */ MagickExport MagickBooleanType CycleColormapImage(Image *image, const ssize_t displace,ExceptionInfo *exception) { CacheView *image_view; MagickBooleanType status; ssize_t y; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); if (image->storage_class == DirectClass) (void) SetImageType(image,PaletteType,exception); status=MagickTrue; image_view=AcquireCacheView(image); #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(static,4) shared(status) #endif for (y=0; y < (ssize_t) image->rows; y++) { register ssize_t x; register Quantum *restrict q; ssize_t index; if (status == MagickFalse) continue; q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); if (q == (Quantum *) NULL) { status=MagickFalse; continue; } for (x=0; x < (ssize_t) image->columns; x++) { index=(ssize_t) (GetPixelIndex(image,q)+displace) % image->colors; if (index < 0) index+=(ssize_t) image->colors; SetPixelIndex(image,(Quantum) index,q); SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q); q+=GetPixelChannels(image); } if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) status=MagickFalse; } image_view=DestroyCacheView(image_view); return(status); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + S o r t C o l o r m a p B y I n t e n s i t y % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % SortColormapByIntensity() sorts the colormap of a PseudoClass image by % decreasing color intensity. % % The format of the SortColormapByIntensity method is: % % MagickBooleanType SortColormapByIntensity(Image *image, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image: A pointer to an Image structure. % % o exception: return any errors or warnings in this structure. % */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif static int IntensityCompare(const void *x,const void *y) { const PixelInfo *color_1, *color_2; int intensity; color_1=(const PixelInfo *) x; color_2=(const PixelInfo *) y; intensity=(int) GetPixelInfoIntensity(color_2)-(int) GetPixelInfoIntensity(color_1); return(intensity); } #if defined(__cplusplus) || defined(c_plusplus) } #endif MagickExport MagickBooleanType SortColormapByIntensity(Image *image, ExceptionInfo *exception) { CacheView *image_view; MagickBooleanType status; register ssize_t i; ssize_t y; unsigned short *pixels; assert(image != (Image *) NULL); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); assert(image->signature == MagickSignature); if (image->storage_class != PseudoClass) return(MagickTrue); /* Allocate memory for pixel indexes. */ pixels=(unsigned short *) AcquireQuantumMemory((size_t) image->colors, sizeof(*pixels)); if (pixels == (unsigned short *) NULL) ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename); /* Assign index values to colormap entries. */ #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(static,4) shared(status) #endif for (i=0; i < (ssize_t) image->colors; i++) image->colormap[i].alpha=(Quantum) i; /* Sort image colormap by decreasing color popularity. */ qsort((void *) image->colormap,(size_t) image->colors, sizeof(*image->colormap),IntensityCompare); /* Update image colormap indexes to sorted colormap order. */ #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(static,4) shared(status) #endif for (i=0; i < (ssize_t) image->colors; i++) pixels[(ssize_t) image->colormap[i].alpha]=(unsigned short) i; status=MagickTrue; image_view=AcquireCacheView(image); for (y=0; y < (ssize_t) image->rows; y++) { Quantum index; register ssize_t x; register Quantum *restrict q; q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); if (q == (Quantum *) NULL) { status=MagickFalse; break; } for (x=0; x < (ssize_t) image->columns; x++) { index=(Quantum) pixels[(ssize_t) GetPixelIndex(image,q)]; SetPixelIndex(image,index,q); SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q); q+=GetPixelChannels(image); } if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) status=MagickFalse; if (status == MagickFalse) break; } image_view=DestroyCacheView(image_view); pixels=(unsigned short *) RelinquishMagickMemory(pixels); return(status); }