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