Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %       H   H  IIIII  SSSSS  TTTTT   OOO    GGGG  RRRR    AAA   M   M         %
      7 %       H   H    I    SS       T    O   O  G      R   R  A   A  MM MM         %
      8 %       HHHHH    I     SSS     T    O   O  G  GG  RRRR   AAAAA  M M M         %
      9 %       H   H    I       SS    T    O   O  G   G  R R    A   A  M   M         %
     10 %       H   H  IIIII  SSSSS    T     OOO    GGG   R  R   A   A  M   M         %
     11 %                                                                             %
     12 %                                                                             %
     13 %                          Write A Histogram Image.                           %
     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 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/artifact.h"
     45 #include "MagickCore/blob.h"
     46 #include "MagickCore/blob-private.h"
     47 #include "MagickCore/cache.h"
     48 #include "MagickCore/color.h"
     49 #include "MagickCore/color-private.h"
     50 #include "MagickCore/constitute.h"
     51 #include "MagickCore/exception.h"
     52 #include "MagickCore/exception-private.h"
     53 #include "MagickCore/geometry.h"
     54 #include "MagickCore/histogram.h"
     55 #include "MagickCore/image-private.h"
     56 #include "MagickCore/magick.h"
     57 #include "MagickCore/memory_.h"
     58 #include "MagickCore/monitor.h"
     59 #include "MagickCore/monitor-private.h"
     60 #include "MagickCore/option.h"
     61 #include "MagickCore/pixel-accessor.h"
     62 #include "MagickCore/property.h"
     63 #include "MagickCore/quantum-private.h"
     64 #include "MagickCore/resource_.h"
     65 #include "MagickCore/static.h"
     66 #include "MagickCore/statistic.h"
     67 #include "MagickCore/string_.h"
     68 #include "MagickCore/module.h"
     69 #include "MagickCore/token.h"
     70 #include "MagickCore/utility.h"
     71 
     72 /*
     74   Forward declarations.
     75 */
     76 static MagickBooleanType
     77   WriteHISTOGRAMImage(const ImageInfo *,Image *,ExceptionInfo *);
     78 
     79 /*
     81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     82 %                                                                             %
     83 %                                                                             %
     84 %                                                                             %
     85 %   R e g i s t e r H I S T O G R A M I m a g e                               %
     86 %                                                                             %
     87 %                                                                             %
     88 %                                                                             %
     89 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     90 %
     91 %  RegisterHISTOGRAMImage() adds attributes for the Histogram image format
     92 %  to the list of supported formats.  The attributes include the image format
     93 %  tag, a method to read and/or write the format, whether the format
     94 %  supports the saving of more than one frame to the same file or blob,
     95 %  whether the format supports native in-memory I/O, and a brief
     96 %  description of the format.
     97 %
     98 %  The format of the RegisterHISTOGRAMImage method is:
     99 %
    100 %      size_t RegisterHISTOGRAMImage(void)
    101 %
    102 */
    103 ModuleExport size_t RegisterHISTOGRAMImage(void)
    104 {
    105   MagickInfo
    106     *entry;
    107 
    108   entry=AcquireMagickInfo("HISTOGRAM","HISTOGRAM","Histogram of the image");
    109   entry->encoder=(EncodeImageHandler *) WriteHISTOGRAMImage;
    110   entry->flags^=CoderAdjoinFlag;
    111   entry->format_type=ImplicitFormatType;
    112   (void) RegisterMagickInfo(entry);
    113   return(MagickImageCoderSignature);
    114 }
    115 
    116 /*
    118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    119 %                                                                             %
    120 %                                                                             %
    121 %                                                                             %
    122 %   U n r e g i s t e r H I S T O G R A M I m a g e                           %
    123 %                                                                             %
    124 %                                                                             %
    125 %                                                                             %
    126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    127 %
    128 %  UnregisterHISTOGRAMImage() removes format registrations made by the
    129 %  HISTOGRAM module from the list of supported formats.
    130 %
    131 %  The format of the UnregisterHISTOGRAMImage method is:
    132 %
    133 %      UnregisterHISTOGRAMImage(void)
    134 %
    135 */
    136 ModuleExport void UnregisterHISTOGRAMImage(void)
    137 {
    138   (void) UnregisterMagickInfo("HISTOGRAM");
    139 }
    140 
    141 /*
    143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    144 %                                                                             %
    145 %                                                                             %
    146 %                                                                             %
    147 %   W r i t e H I S T O G R A M I m a g e                                     %
    148 %                                                                             %
    149 %                                                                             %
    150 %                                                                             %
    151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    152 %
    153 %  WriteHISTOGRAMImage() writes an image to a file in Histogram format.
    154 %  The image shows a histogram of the color (or gray) values in the image.  The
    155 %  image consists of three overlaid histograms:  a red one for the red channel,
    156 %  a green one for the green channel, and a blue one for the blue channel.  The
    157 %  image comment contains a list of unique pixel values and the number of times
    158 %  each occurs in the image.
    159 %
    160 %  This method is strongly based on a similar one written by
    161 %  muquit (at) warm.semcor.com which in turn is based on ppmhistmap of netpbm.
    162 %
    163 %  The format of the WriteHISTOGRAMImage method is:
    164 %
    165 %      MagickBooleanType WriteHISTOGRAMImage(const ImageInfo *image_info,
    166 %        Image *image,ExceptionInfo *exception)
    167 %
    168 %  A description of each parameter follows.
    169 %
    170 %    o image_info: the image info.
    171 %
    172 %    o image:  The image.
    173 %
    174 %    o exception: return any errors or warnings in this structure.
    175 %
    176 */
    177 static MagickBooleanType WriteHISTOGRAMImage(const ImageInfo *image_info,
    178   Image *image,ExceptionInfo *exception)
    179 {
    180 #define HistogramDensity  "256x200"
    181 
    182   char
    183     filename[MagickPathExtent];
    184 
    185   const char
    186     *option;
    187 
    188   Image
    189     *histogram_image;
    190 
    191   ImageInfo
    192     *write_info;
    193 
    194   MagickBooleanType
    195     status;
    196 
    197   PixelInfo
    198     *histogram;
    199 
    200   double
    201     maximum,
    202     scale;
    203 
    204   RectangleInfo
    205     geometry;
    206 
    207   register const Quantum
    208     *p;
    209 
    210   register Quantum
    211     *q,
    212     *r;
    213 
    214   register ssize_t
    215     x;
    216 
    217   size_t
    218     length;
    219 
    220   ssize_t
    221     y;
    222 
    223   /*
    224     Allocate histogram image.
    225   */
    226   assert(image_info != (const ImageInfo *) NULL);
    227   assert(image_info->signature == MagickCoreSignature);
    228   assert(image != (Image *) NULL);
    229   assert(image->signature == MagickCoreSignature);
    230   if (image->debug != MagickFalse)
    231     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    232       image_info->filename);
    233   SetGeometry(image,&geometry);
    234   if (image_info->density == (char *) NULL)
    235     (void) ParseAbsoluteGeometry(HistogramDensity,&geometry);
    236   else
    237     (void) ParseAbsoluteGeometry(image_info->density,&geometry);
    238   histogram_image=CloneImage(image,geometry.width,geometry.height,MagickTrue,
    239     exception);
    240   if (histogram_image == (Image *) NULL)
    241     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    242   (void) SetImageStorageClass(histogram_image,DirectClass,exception);
    243   /*
    244     Allocate histogram count arrays.
    245   */
    246   length=MagickMax((size_t) ScaleQuantumToChar(QuantumRange)+1UL,
    247     histogram_image->columns);
    248   histogram=(PixelInfo *) AcquireQuantumMemory(length,sizeof(*histogram));
    249   if (histogram == (PixelInfo *) NULL)
    250     {
    251       histogram_image=DestroyImage(histogram_image);
    252       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    253     }
    254   /*
    255     Initialize histogram count arrays.
    256   */
    257   (void) ResetMagickMemory(histogram,0,length*sizeof(*histogram));
    258   for (y=0; y < (ssize_t) image->rows; y++)
    259   {
    260     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    261     if (p == (const Quantum *) NULL)
    262       break;
    263     for (x=0; x < (ssize_t) image->columns; x++)
    264     {
    265       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
    266         histogram[ScaleQuantumToChar(GetPixelRed(image,p))].red++;
    267       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
    268         histogram[ScaleQuantumToChar(GetPixelGreen(image,p))].green++;
    269       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
    270         histogram[ScaleQuantumToChar(GetPixelBlue(image,p))].blue++;
    271       p+=GetPixelChannels(image);
    272     }
    273   }
    274   maximum=histogram[0].red;
    275   for (x=0; x < (ssize_t) histogram_image->columns; x++)
    276   {
    277     if (((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) &&
    278         (maximum < histogram[x].red))
    279       maximum=histogram[x].red;
    280     if (((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) &&
    281         (maximum < histogram[x].green))
    282       maximum=histogram[x].green;
    283     if (((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) &&
    284         (maximum < histogram[x].blue))
    285       maximum=histogram[x].blue;
    286   }
    287   scale=0.0;
    288   if (fabs(maximum) >= MagickEpsilon)
    289     scale=(double) histogram_image->rows/maximum;
    290   /*
    291     Initialize histogram image.
    292   */
    293   (void) QueryColorCompliance("#000000",AllCompliance,
    294     &histogram_image->background_color,exception);
    295   (void) SetImageBackgroundColor(histogram_image,exception);
    296   for (x=0; x < (ssize_t) histogram_image->columns; x++)
    297   {
    298     q=GetAuthenticPixels(histogram_image,x,0,1,histogram_image->rows,exception);
    299     if (q == (Quantum *) NULL)
    300       break;
    301     if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
    302       {
    303         y=(ssize_t) ceil(histogram_image->rows-scale*histogram[x].red-0.5);
    304         r=q+y*GetPixelChannels(histogram_image);
    305         for ( ; y < (ssize_t) histogram_image->rows; y++)
    306         {
    307           SetPixelRed(histogram_image,QuantumRange,r);
    308           r+=GetPixelChannels(histogram_image);
    309         }
    310       }
    311     if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
    312       {
    313         y=(ssize_t) ceil(histogram_image->rows-scale*histogram[x].green-0.5);
    314         r=q+y*GetPixelChannels(histogram_image);
    315         for ( ; y < (ssize_t) histogram_image->rows; y++)
    316         {
    317           SetPixelGreen(histogram_image,QuantumRange,r);
    318           r+=GetPixelChannels(histogram_image);
    319         }
    320       }
    321     if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
    322       {
    323         y=(ssize_t) ceil(histogram_image->rows-scale*histogram[x].blue-0.5);
    324         r=q+y*GetPixelChannels(histogram_image);
    325         for ( ; y < (ssize_t) histogram_image->rows; y++)
    326         {
    327           SetPixelBlue(histogram_image,QuantumRange,r);
    328           r+=GetPixelChannels(histogram_image);
    329         }
    330       }
    331     if (SyncAuthenticPixels(histogram_image,exception) == MagickFalse)
    332       break;
    333     status=SetImageProgress(image,SaveImageTag,y,histogram_image->rows);
    334     if (status == MagickFalse)
    335       break;
    336   }
    337   histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
    338   option=GetImageOption(image_info,"histogram:unique-colors");
    339   if ((option == (const char *) NULL) || (IsStringTrue(option) != MagickFalse))
    340     {
    341       FILE
    342         *file;
    343 
    344       int
    345         unique_file;
    346 
    347       /*
    348         Add a unique colors as an image comment.
    349       */
    350       file=(FILE *) NULL;
    351       unique_file=AcquireUniqueFileResource(filename);
    352       if (unique_file != -1)
    353         file=fdopen(unique_file,"wb");
    354       if ((unique_file != -1) && (file != (FILE *) NULL))
    355         {
    356           char
    357             *property;
    358 
    359           (void) GetNumberColors(image,file,exception);
    360           (void) fclose(file);
    361           property=FileToString(filename,~0UL,exception);
    362           if (property != (char *) NULL)
    363             {
    364               (void) SetImageProperty(histogram_image,"comment",property,
    365                 exception);
    366               property=DestroyString(property);
    367             }
    368         }
    369       (void) RelinquishUniqueFileResource(filename);
    370     }
    371   /*
    372     Write Histogram image.
    373   */
    374   (void) CopyMagickString(histogram_image->filename,image_info->filename,
    375     MagickPathExtent);
    376   write_info=CloneImageInfo(image_info);
    377   *write_info->magick='\0';
    378   (void) SetImageInfo(write_info,1,exception);
    379   if ((*write_info->magick == '\0') ||
    380       (LocaleCompare(write_info->magick,"HISTOGRAM") == 0))
    381     (void) FormatLocaleString(histogram_image->filename,MagickPathExtent,
    382       "miff:%s",write_info->filename);
    383   histogram_image->blob=DetachBlob(histogram_image->blob);
    384   histogram_image->blob=CloneBlobInfo(image->blob);
    385   status=WriteImage(write_info,histogram_image,exception);
    386   image->blob=DetachBlob(image->blob);
    387   image->blob=CloneBlobInfo(histogram_image->blob);
    388   histogram_image=DestroyImage(histogram_image);
    389   write_info=DestroyImageInfo(write_info);
    390   return(status);
    391 }
    392