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