Home | History | Annotate | Download | only in MagickCore
      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