1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % CCCC OOO L OOO RRRR M M AAA PPPP % 7 % C O O L O O R R MM MM A A P P % 8 % C O O L O O RRRR M M M AAAAA PPPP % 9 % C O O L O O R R M M A A P % 10 % CCCC OOO LLLLL OOO R R M M A A P % 11 % % 12 % % 13 % MagickCore Colormap Methods % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 1992 % 18 % % 19 % % 20 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 21 % dedicated to making software imaging solutions freely available. % 22 % % 23 % You may not use this file except in compliance with the License. You may % 24 % obtain a copy of the License at % 25 % % 26 % http://www.imagemagick.org/script/license.php % 27 % % 28 % Unless required by applicable law or agreed to in writing, software % 29 % distributed under the License is distributed on an "AS IS" BASIS, % 30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31 % See the License for the specific language governing permissions and % 32 % limitations under the License. % 33 % % 34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 % 36 % We use linked-lists because splay-trees do not currently support duplicate 37 % key / value pairs (.e.g X11 green compliance and SVG green compliance). 38 % 39 */ 40 41 /* 43 Include declarations. 44 */ 45 #include "MagickCore/studio.h" 46 #include "MagickCore/attribute.h" 47 #include "MagickCore/blob.h" 48 #include "MagickCore/cache-view.h" 49 #include "MagickCore/cache.h" 50 #include "MagickCore/color.h" 51 #include "MagickCore/color-private.h" 52 #include "MagickCore/colormap.h" 53 #include "MagickCore/client.h" 54 #include "MagickCore/configure.h" 55 #include "MagickCore/exception.h" 56 #include "MagickCore/exception-private.h" 57 #include "MagickCore/gem.h" 58 #include "MagickCore/geometry.h" 59 #include "MagickCore/image-private.h" 60 #include "MagickCore/memory_.h" 61 #include "MagickCore/monitor.h" 62 #include "MagickCore/monitor-private.h" 63 #include "MagickCore/option.h" 64 #include "MagickCore/pixel-accessor.h" 65 #include "MagickCore/quantize.h" 66 #include "MagickCore/quantum.h" 67 #include "MagickCore/resource_.h" 68 #include "MagickCore/semaphore.h" 69 #include "MagickCore/string_.h" 70 #include "MagickCore/thread-private.h" 71 #include "MagickCore/token.h" 72 #include "MagickCore/utility.h" 73 #include "MagickCore/xml-tree.h" 74 75 /* 77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 78 % % 79 % % 80 % % 81 % A c q u i r e I m a g e C o l o r m a p % 82 % % 83 % % 84 % % 85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 86 % 87 % AcquireImageColormap() allocates an image colormap and initializes 88 % it to a linear gray colorspace. If the image already has a colormap, 89 % it is replaced. AcquireImageColormap() returns MagickTrue if successful, 90 % otherwise MagickFalse if there is not enough memory. 91 % 92 % The format of the AcquireImageColormap method is: 93 % 94 % MagickBooleanType AcquireImageColormap(Image *image,const size_t colors, 95 % ExceptionInfo *exception) 96 % 97 % A description of each parameter follows: 98 % 99 % o image: the image. 100 % 101 % o colors: the number of colors in the image colormap. 102 % 103 % o exception: return any errors or warnings in this structure. 104 % 105 */ 106 MagickExport MagickBooleanType AcquireImageColormap(Image *image, 107 const size_t colors,ExceptionInfo *exception) 108 { 109 register ssize_t 110 i; 111 112 /* 113 Allocate image colormap. 114 */ 115 assert(image != (Image *) NULL); 116 assert(image->signature == MagickCoreSignature); 117 if (image->debug != MagickFalse) 118 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 119 image->colors=MagickMax(colors,1); 120 if (image->colormap == (PixelInfo *) NULL) 121 image->colormap=(PixelInfo *) AcquireQuantumMemory(image->colors, 122 sizeof(*image->colormap)); 123 else 124 image->colormap=(PixelInfo *) ResizeQuantumMemory(image->colormap, 125 image->colors,sizeof(*image->colormap)); 126 if (image->colormap == (PixelInfo *) NULL) 127 { 128 image->colors=0; 129 image->storage_class=DirectClass; 130 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 131 image->filename); 132 } 133 for (i=0; i < (ssize_t) image->colors; i++) 134 { 135 double 136 pixel; 137 138 pixel=(double) (i*(QuantumRange/MagickMax(colors-1,1))); 139 GetPixelInfo(image,image->colormap+i); 140 image->colormap[i].alpha_trait=BlendPixelTrait; 141 image->colormap[i].red=pixel; 142 image->colormap[i].green=pixel; 143 image->colormap[i].blue=pixel; 144 image->colormap[i].alpha=OpaqueAlpha; 145 } 146 return(SetImageStorageClass(image,PseudoClass,exception)); 147 } 148 149 /* 151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 152 % % 153 % % 154 % % 155 % C y c l e C o l o r m a p I m a g e % 156 % % 157 % % 158 % % 159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 160 % 161 % CycleColormap() displaces an image's colormap by a given number of 162 % positions. If you cycle the colormap a number of times you can produce 163 % a psychodelic effect. 164 % 165 % WARNING: this assumes an images colormap is in a well know and defined 166 % order. Currently Imagemagick has no way of setting that order. 167 % 168 % The format of the CycleColormapImage method is: 169 % 170 % MagickBooleanType CycleColormapImage(Image *image,const ssize_t displace, 171 % ExceptionInfo *exception) 172 % 173 % A description of each parameter follows: 174 % 175 % o image: the image. 176 % 177 % o displace: displace the colormap this amount. 178 % 179 % o exception: return any errors or warnings in this structure. 180 % 181 */ 182 MagickExport MagickBooleanType CycleColormapImage(Image *image, 183 const ssize_t displace,ExceptionInfo *exception) 184 { 185 CacheView 186 *image_view; 187 188 MagickBooleanType 189 status; 190 191 ssize_t 192 y; 193 194 assert(image != (Image *) NULL); 195 assert(image->signature == MagickCoreSignature); 196 if (image->debug != MagickFalse) 197 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 198 if (image->storage_class == DirectClass) 199 (void) SetImageType(image,PaletteType,exception); 200 status=MagickTrue; 201 image_view=AcquireAuthenticCacheView(image,exception); 202 #if defined(MAGICKCORE_OPENMP_SUPPORT) 203 #pragma omp parallel for schedule(static,4) \ 204 magick_threads(image,image,1,1) 205 #endif 206 for (y=0; y < (ssize_t) image->rows; y++) 207 { 208 register ssize_t 209 x; 210 211 register Quantum 212 *magick_restrict q; 213 214 ssize_t 215 index; 216 217 if (status == MagickFalse) 218 continue; 219 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 220 if (q == (Quantum *) NULL) 221 { 222 status=MagickFalse; 223 continue; 224 } 225 for (x=0; x < (ssize_t) image->columns; x++) 226 { 227 index=(ssize_t) (GetPixelIndex(image,q)+displace) % image->colors; 228 if (index < 0) 229 index+=(ssize_t) image->colors; 230 SetPixelIndex(image,(Quantum) index,q); 231 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q); 232 q+=GetPixelChannels(image); 233 } 234 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 235 status=MagickFalse; 236 } 237 image_view=DestroyCacheView(image_view); 238 return(status); 239 } 240 241 /* 243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 244 % % 245 % % 246 % % 247 + S o r t C o l o r m a p B y I n t e n s i t y % 248 % % 249 % % 250 % % 251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 252 % 253 % SortColormapByIntensity() sorts the colormap of a PseudoClass image by 254 % decreasing color intensity. 255 % 256 % The format of the SortColormapByIntensity method is: 257 % 258 % MagickBooleanType SortColormapByIntensity(Image *image, 259 % ExceptionInfo *exception) 260 % 261 % A description of each parameter follows: 262 % 263 % o image: A pointer to an Image structure. 264 % 265 % o exception: return any errors or warnings in this structure. 266 % 267 */ 268 269 #if defined(__cplusplus) || defined(c_plusplus) 270 extern "C" { 271 #endif 272 273 static int IntensityCompare(const void *x,const void *y) 274 { 275 const PixelInfo 276 *color_1, 277 *color_2; 278 279 int 280 intensity; 281 282 color_1=(const PixelInfo *) x; 283 color_2=(const PixelInfo *) y; 284 intensity=(int) GetPixelInfoIntensity((const Image *) NULL,color_2)-(int) 285 GetPixelInfoIntensity((const Image *) NULL,color_1); 286 return(intensity); 287 } 288 289 #if defined(__cplusplus) || defined(c_plusplus) 290 } 291 #endif 292 293 MagickExport MagickBooleanType SortColormapByIntensity(Image *image, 294 ExceptionInfo *exception) 295 { 296 CacheView 297 *image_view; 298 299 MagickBooleanType 300 status; 301 302 register ssize_t 303 i; 304 305 ssize_t 306 y; 307 308 unsigned short 309 *pixels; 310 311 assert(image != (Image *) NULL); 312 if (image->debug != MagickFalse) 313 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 314 assert(image->signature == MagickCoreSignature); 315 if (image->storage_class != PseudoClass) 316 return(MagickTrue); 317 /* 318 Allocate memory for pixel indexes. 319 */ 320 pixels=(unsigned short *) AcquireQuantumMemory((size_t) image->colors, 321 sizeof(*pixels)); 322 if (pixels == (unsigned short *) NULL) 323 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 324 image->filename); 325 /* 326 Assign index values to colormap entries. 327 */ 328 #if defined(MAGICKCORE_OPENMP_SUPPORT) 329 #pragma omp parallel for schedule(static,4) shared(status) \ 330 magick_threads(image,image,1,1) 331 #endif 332 for (i=0; i < (ssize_t) image->colors; i++) 333 image->colormap[i].alpha=(double) i; 334 /* 335 Sort image colormap by decreasing color popularity. 336 */ 337 qsort((void *) image->colormap,(size_t) image->colors, 338 sizeof(*image->colormap),IntensityCompare); 339 /* 340 Update image colormap indexes to sorted colormap order. 341 */ 342 #if defined(MAGICKCORE_OPENMP_SUPPORT) 343 #pragma omp parallel for schedule(static,4) shared(status) 344 #endif 345 for (i=0; i < (ssize_t) image->colors; i++) 346 pixels[(ssize_t) image->colormap[i].alpha]=(unsigned short) i; 347 status=MagickTrue; 348 image_view=AcquireAuthenticCacheView(image,exception); 349 for (y=0; y < (ssize_t) image->rows; y++) 350 { 351 Quantum 352 index; 353 354 register ssize_t 355 x; 356 357 register Quantum 358 *magick_restrict q; 359 360 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 361 if (q == (Quantum *) NULL) 362 { 363 status=MagickFalse; 364 break; 365 } 366 for (x=0; x < (ssize_t) image->columns; x++) 367 { 368 index=(Quantum) pixels[(ssize_t) GetPixelIndex(image,q)]; 369 SetPixelIndex(image,index,q); 370 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q); 371 q+=GetPixelChannels(image); 372 } 373 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 374 status=MagickFalse; 375 if (status == MagickFalse) 376 break; 377 } 378 image_view=DestroyCacheView(image_view); 379 pixels=(unsigned short *) RelinquishMagickMemory(pixels); 380 return(status); 381 } 382