histogram.c revision ebc891a1d9621a19c509200d7bf3470ca18dde7f
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-2011 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/* 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 68/* 69 Forward declarations. 70*/ 71static MagickBooleanType 72 WriteHISTOGRAMImage(const ImageInfo *,Image *); 73 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*/ 97ModuleExport 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 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*/ 131ModuleExport void UnregisterHISTOGRAMImage(void) 132{ 133 (void) UnregisterMagickInfo("HISTOGRAM"); 134} 135 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 170static 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 177static MagickBooleanType WriteHISTOGRAMImage(const ImageInfo *image_info, 178 Image *image) 179{ 180#define HistogramDensity "256x200" 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 MagickBooleanType 201 status; 202 203 MagickPixelPacket 204 *histogram; 205 206 MagickRealType 207 maximum, 208 scale; 209 210 RectangleInfo 211 geometry; 212 213 register const PixelPacket 214 *p; 215 216 register PixelPacket 217 *q, 218 *r; 219 220 register ssize_t 221 x; 222 223 size_t 224 length; 225 226 ssize_t 227 y; 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 SetRedPixelComponent(r,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 SetGreenPixelComponent(r,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 SetBluePixelComponent(r,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} 392