2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % AAA TTTTT TTTTT RRRR IIIII BBBB U U TTTTT EEEEE %
7 % A A T T R R I B B U U T E %
8 % AAAAA T T RRRR I BBBB U U T EEE %
9 % A A T T R R I B B U U T E %
10 % A A T T R R IIIII BBBB UUU T EEEEE %
13 % MagickCore Get / Set Image Attributes %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % https://imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/attribute.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/cache-private.h"
50 #include "MagickCore/cache-view.h"
51 #include "MagickCore/channel.h"
52 #include "MagickCore/client.h"
53 #include "MagickCore/color.h"
54 #include "MagickCore/color-private.h"
55 #include "MagickCore/colormap.h"
56 #include "MagickCore/colormap-private.h"
57 #include "MagickCore/colorspace.h"
58 #include "MagickCore/colorspace-private.h"
59 #include "MagickCore/composite.h"
60 #include "MagickCore/composite-private.h"
61 #include "MagickCore/constitute.h"
62 #include "MagickCore/draw.h"
63 #include "MagickCore/draw-private.h"
64 #include "MagickCore/effect.h"
65 #include "MagickCore/enhance.h"
66 #include "MagickCore/exception.h"
67 #include "MagickCore/exception-private.h"
68 #include "MagickCore/geometry.h"
69 #include "MagickCore/histogram.h"
70 #include "MagickCore/identify.h"
71 #include "MagickCore/image.h"
72 #include "MagickCore/image-private.h"
73 #include "MagickCore/list.h"
74 #include "MagickCore/log.h"
75 #include "MagickCore/memory_.h"
76 #include "MagickCore/magick.h"
77 #include "MagickCore/monitor.h"
78 #include "MagickCore/monitor-private.h"
79 #include "MagickCore/option.h"
80 #include "MagickCore/paint.h"
81 #include "MagickCore/pixel.h"
82 #include "MagickCore/pixel-accessor.h"
83 #include "MagickCore/property.h"
84 #include "MagickCore/quantize.h"
85 #include "MagickCore/quantum-private.h"
86 #include "MagickCore/random_.h"
87 #include "MagickCore/resource_.h"
88 #include "MagickCore/semaphore.h"
89 #include "MagickCore/segment.h"
90 #include "MagickCore/splay-tree.h"
91 #include "MagickCore/string_.h"
92 #include "MagickCore/string-private.h"
93 #include "MagickCore/thread-private.h"
94 #include "MagickCore/threshold.h"
95 #include "MagickCore/transform.h"
96 #include "MagickCore/utility.h"
99 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 + G e t I m a g e B o u n d i n g B o x %
107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 % GetImageBoundingBox() returns the bounding box of an image canvas.
111 % The format of the GetImageBoundingBox method is:
113 % RectangleInfo GetImageBoundingBox(const Image *image,
114 % ExceptionInfo *exception)
116 % A description of each parameter follows:
118 % o bounds: Method GetImageBoundingBox returns the bounding box of an
121 % o image: the image.
123 % o exception: return any errors or warnings in this structure.
127 typedef struct _EdgeInfo
136 static double GetEdgeBackgroundFactor(const Image *image,
137 const CacheView *image_view,const GravityType gravity,const size_t width,
138 const size_t height,const ssize_t x_offset,const ssize_t y_offset,
139 ExceptionInfo *exception)
160 register const Quantum
167 Determine the percent of image background for this edge.
171 case NorthWestGravity:
175 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
178 case NorthEastGravity:
181 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
185 case SouthEastGravity:
188 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,
189 (ssize_t) image->rows-1,1,1,exception);
192 case SouthWestGravity:
195 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
200 GetPixelInfoPixel(image,p,&background);
201 artifact=GetImageArtifact(image,"trim:background-color");
202 if (artifact != (const char *) NULL)
203 (void) QueryColorCompliance(artifact,AllCompliance,&background,exception);
204 edge_geometry.width=width;
205 edge_geometry.height=height;
206 edge_geometry.x=x_offset;
207 edge_geometry.y=y_offset;
208 GravityAdjustGeometry(image->columns,image->rows,gravity,&edge_geometry);
209 edge_image=CropImage(image,&edge_geometry,exception);
210 if (edge_image == (Image *) NULL)
213 edge_view=AcquireVirtualCacheView(edge_image,exception);
214 for (y=0; y < (ssize_t) edge_image->rows; y++)
219 p=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
220 if (p == (const Quantum *) NULL)
222 for (x=0; x < (ssize_t) edge_image->columns; x++)
224 GetPixelInfoPixel(edge_image,p,&pixel);
225 if (IsFuzzyEquivalencePixelInfo(&pixel,&background) == MagickFalse)
227 p+=GetPixelChannels(edge_image);
230 factor/=((double) edge_image->columns*edge_image->rows);
231 edge_view=DestroyCacheView(edge_view);
232 edge_image=DestroyImage(edge_image);
236 static inline double GetMinEdgeBackgroundFactor(const EdgeInfo *edge)
241 factor=MagickMin(MagickMin(MagickMin(edge->left,edge->right),edge->top),
246 static RectangleInfo GetEdgeBoundingBox(const Image *image,
247 ExceptionInfo *exception)
270 Get the image bounding box.
272 assert(image != (Image *) NULL);
273 assert(image->signature == MagickCoreSignature);
274 if (image->debug != MagickFalse)
275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
276 SetGeometry(image,&bounds);
277 edge_image=CloneImage(image,0,0,MagickTrue,exception);
278 if (edge_image == (Image *) NULL)
280 (void) ParseAbsoluteGeometry("0x0+0+0",&edge_image->page);
281 memset(&vertex,0,sizeof(vertex));
282 edge_view=AcquireVirtualCacheView(edge_image,exception);
283 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,WestGravity,
285 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,EastGravity,
287 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,NorthGravity,
289 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,SouthGravity,
291 percent_background=1.0;
292 artifact=GetImageArtifact(edge_image,"trim:percent-background");
293 if (artifact != (const char *) NULL)
294 percent_background=StringToDouble(artifact,(char **) NULL)/100.0;
295 percent_background=MagickMin(MagickMax(1.0-percent_background,MagickEpsilon),
297 background_factor=GetMinEdgeBackgroundFactor(&edge);
298 for ( ; background_factor < percent_background;
299 background_factor=GetMinEdgeBackgroundFactor(&edge))
301 if ((bounds.width == 0) || (bounds.height == 0))
303 if (fabs(edge.left-background_factor) < MagickEpsilon)
310 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
311 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
312 vertex.top,exception);
313 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
314 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
315 vertex.top,exception);
316 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
317 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
318 vertex.bottom,exception);
321 if (fabs(edge.right-background_factor) < MagickEpsilon)
328 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
329 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
330 vertex.top,exception);
331 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
332 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
333 vertex.top,exception);
334 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
335 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
336 vertex.bottom,exception);
339 if (fabs(edge.top-background_factor) < MagickEpsilon)
346 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
347 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
348 vertex.top,exception);
349 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
350 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
351 vertex.top,exception);
352 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
353 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
354 vertex.top,exception);
357 if (fabs(edge.bottom-background_factor) < MagickEpsilon)
364 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
365 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
366 vertex.top,exception);
367 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
368 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
369 vertex.top,exception);
370 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
371 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
372 vertex.bottom,exception);
376 edge_view=DestroyCacheView(edge_view);
377 edge_image=DestroyImage(edge_image);
378 bounds.x=(ssize_t) vertex.left;
379 bounds.y=(ssize_t) vertex.top;
380 if ((bounds.width == 0) || (bounds.height == 0))
381 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
382 "GeometryDoesNotContainImage","`%s'",image->filename);
386 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
387 ExceptionInfo *exception)
405 register const Quantum
411 assert(image != (Image *) NULL);
412 assert(image->signature == MagickCoreSignature);
413 if (image->debug != MagickFalse)
414 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
415 artifact=GetImageArtifact(image,"trim:percent-background");
416 if (artifact != (const char *) NULL)
417 return(GetEdgeBoundingBox(image,exception));
420 bounds.x=(ssize_t) image->columns;
421 bounds.y=(ssize_t) image->rows;
422 GetPixelInfo(image,&target[0]);
423 image_view=AcquireVirtualCacheView(image,exception);
424 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
425 if (p == (const Quantum *) NULL)
427 image_view=DestroyCacheView(image_view);
430 GetPixelInfoPixel(image,p,&target[0]);
431 GetPixelInfo(image,&target[1]);
432 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
434 if (p != (const Quantum *) NULL)
435 GetPixelInfoPixel(image,p,&target[1]);
436 GetPixelInfo(image,&target[2]);
437 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
439 if (p != (const Quantum *) NULL)
440 GetPixelInfoPixel(image,p,&target[2]);
442 GetPixelInfo(image,&zero);
443 #if defined(MAGICKCORE_OPENMP_SUPPORT)
444 #pragma omp parallel for schedule(static) shared(status) \
445 magick_number_threads(image,image,image->rows,1)
447 for (y=0; y < (ssize_t) image->rows; y++)
455 register const Quantum
461 if (status == MagickFalse)
463 #if defined(MAGICKCORE_OPENMP_SUPPORT)
464 # pragma omp critical (MagickCore_GetImageBoundingBox)
467 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
468 if (p == (const Quantum *) NULL)
474 for (x=0; x < (ssize_t) image->columns; x++)
476 GetPixelInfoPixel(image,p,&pixel);
477 if ((x < bounding_box.x) &&
478 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
480 if ((x > (ssize_t) bounding_box.width) &&
481 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
482 bounding_box.width=(size_t) x;
483 if ((y < bounding_box.y) &&
484 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
486 if ((y > (ssize_t) bounding_box.height) &&
487 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
488 bounding_box.height=(size_t) y;
489 p+=GetPixelChannels(image);
491 #if defined(MAGICKCORE_OPENMP_SUPPORT)
492 # pragma omp critical (MagickCore_GetImageBoundingBox)
495 if (bounding_box.x < bounds.x)
496 bounds.x=bounding_box.x;
497 if (bounding_box.y < bounds.y)
498 bounds.y=bounding_box.y;
499 if (bounding_box.width > bounds.width)
500 bounds.width=bounding_box.width;
501 if (bounding_box.height > bounds.height)
502 bounds.height=bounding_box.height;
505 image_view=DestroyCacheView(image_view);
506 if ((bounds.width == 0) || (bounds.height == 0))
507 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
508 "GeometryDoesNotContainImage","`%s'",image->filename);
511 bounds.width-=(bounds.x-1);
512 bounds.height-=(bounds.y-1);
518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522 % G e t I m a g e D e p t h %
526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
528 % GetImageDepth() returns the depth of a particular image channel.
530 % The format of the GetImageDepth method is:
532 % size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
534 % A description of each parameter follows:
536 % o image: the image.
538 % o exception: return any errors or warnings in this structure.
541 MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
563 assert(image != (Image *) NULL);
564 assert(image->signature == MagickCoreSignature);
565 if (image->debug != MagickFalse)
566 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
567 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
568 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
569 sizeof(*current_depth));
570 if (current_depth == (size_t *) NULL)
571 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
573 for (i=0; i < (ssize_t) number_threads; i++)
575 if ((image->storage_class == PseudoClass) &&
576 (image->alpha_trait == UndefinedPixelTrait))
578 for (i=0; i < (ssize_t) image->colors; i++)
581 id = GetOpenMPThreadId();
583 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
592 range=GetQuantumRange(current_depth[id]);
593 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
594 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].red),range) == MagickFalse)
596 if ((atDepth != MagickFalse) &&
597 (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
598 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].green),range) == MagickFalse)
600 if ((atDepth != MagickFalse) &&
601 (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
602 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].blue),range) == MagickFalse)
604 if ((atDepth != MagickFalse))
609 depth=current_depth[0];
610 for (i=1; i < (ssize_t) number_threads; i++)
611 if (depth < current_depth[i])
612 depth=current_depth[i];
613 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
616 image_view=AcquireVirtualCacheView(image,exception);
617 #if !defined(MAGICKCORE_HDRI_SUPPORT)
618 if ((1UL*QuantumRange) <= MaxMap)
624 Scale pixels to desired (optimized with depth map).
626 depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
627 if (depth_map == (size_t *) NULL)
628 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
629 for (i=0; i <= (ssize_t) MaxMap; i++)
634 for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
642 range=GetQuantumRange(depth);
644 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
649 #if defined(MAGICKCORE_OPENMP_SUPPORT)
650 #pragma omp parallel for schedule(static) shared(status) \
651 magick_number_threads(image,image,image->rows,1)
653 for (y=0; y < (ssize_t) image->rows; y++)
656 id = GetOpenMPThreadId();
658 register const Quantum
664 if (status == MagickFalse)
666 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
667 if (p == (const Quantum *) NULL)
669 for (x=0; x < (ssize_t) image->columns; x++)
674 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
676 PixelChannel channel = GetPixelChannelChannel(image,i);
677 PixelTrait traits = GetPixelChannelTraits(image,channel);
678 if ((traits & UpdatePixelTrait) == 0)
680 if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
681 current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
683 p+=GetPixelChannels(image);
685 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
688 image_view=DestroyCacheView(image_view);
689 depth=current_depth[0];
690 for (i=1; i < (ssize_t) number_threads; i++)
691 if (depth < current_depth[i])
692 depth=current_depth[i];
693 depth_map=(size_t *) RelinquishMagickMemory(depth_map);
694 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
701 #if defined(MAGICKCORE_OPENMP_SUPPORT)
702 #pragma omp parallel for schedule(static) shared(status) \
703 magick_number_threads(image,image,image->rows,1)
705 for (y=0; y < (ssize_t) image->rows; y++)
708 id = GetOpenMPThreadId();
710 register const Quantum
716 if (status == MagickFalse)
718 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
719 if (p == (const Quantum *) NULL)
721 for (x=0; x < (ssize_t) image->columns; x++)
726 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
734 channel=GetPixelChannelChannel(image,i);
735 traits=GetPixelChannelTraits(image,channel);
736 if ((traits & UpdatePixelTrait) == 0)
738 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
743 range=GetQuantumRange(current_depth[id]);
744 if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
749 p+=GetPixelChannels(image);
751 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
754 image_view=DestroyCacheView(image_view);
755 depth=current_depth[0];
756 for (i=1; i < (ssize_t) number_threads; i++)
757 if (depth < current_depth[i])
758 depth=current_depth[i];
759 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768 % G e t I m a g e Q u a n t u m D e p t h %
772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
774 % GetImageQuantumDepth() returns the depth of the image rounded to a legal
775 % quantum depth: 8, 16, or 32.
777 % The format of the GetImageQuantumDepth method is:
779 % size_t GetImageQuantumDepth(const Image *image,
780 % const MagickBooleanType constrain)
782 % A description of each parameter follows:
784 % o image: the image.
786 % o constrain: A value other than MagickFalse, constrains the depth to
787 % a maximum of MAGICKCORE_QUANTUM_DEPTH.
790 MagickExport size_t GetImageQuantumDepth(const Image *image,
791 const MagickBooleanType constrain)
808 if (constrain != MagickFalse)
809 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
818 % G e t I m a g e T y p e %
822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824 % GetImageType() returns the type of image:
826 % Bilevel Grayscale GrayscaleMatte
827 % Palette PaletteMatte TrueColor
828 % TrueColorMatte ColorSeparation ColorSeparationMatte
830 % The format of the GetImageType method is:
832 % ImageType GetImageType(const Image *image)
834 % A description of each parameter follows:
836 % o image: the image.
839 MagickExport ImageType GetImageType(const Image *image)
841 assert(image != (Image *) NULL);
842 assert(image->signature == MagickCoreSignature);
843 if (image->colorspace == CMYKColorspace)
845 if (image->alpha_trait == UndefinedPixelTrait)
846 return(ColorSeparationType);
847 return(ColorSeparationAlphaType);
849 if (IsImageMonochrome(image) != MagickFalse)
851 if (IsImageGray(image) != MagickFalse)
853 if (image->alpha_trait != UndefinedPixelTrait)
854 return(GrayscaleAlphaType);
855 return(GrayscaleType);
857 if (IsPaletteImage(image) != MagickFalse)
859 if (image->alpha_trait != UndefinedPixelTrait)
860 return(PaletteAlphaType);
863 if (image->alpha_trait != UndefinedPixelTrait)
864 return(TrueColorAlphaType);
865 return(TrueColorType);
869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
873 % I d e n t i f y I m a g e G r a y %
877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879 % IdentifyImageGray() returns grayscale if all the pixels in the image have
880 % the same red, green, and blue intensities, and bi-level is the intensity is
881 % either 0 or QuantumRange. Otherwise undefined is returned.
883 % The format of the IdentifyImageGray method is:
885 % ImageType IdentifyImageGray(const Image *image,ExceptionInfo *exception)
887 % A description of each parameter follows:
889 % o image: the image.
891 % o exception: return any errors or warnings in this structure.
894 MagickExport ImageType IdentifyImageGray(const Image *image,
895 ExceptionInfo *exception)
903 register const Quantum
912 assert(image != (Image *) NULL);
913 assert(image->signature == MagickCoreSignature);
914 if (image->debug != MagickFalse)
915 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
916 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
917 (image->type == GrayscaleAlphaType))
919 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
920 return(UndefinedType);
922 image_view=AcquireVirtualCacheView(image,exception);
923 for (y=0; y < (ssize_t) image->rows; y++)
925 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
926 if (p == (const Quantum *) NULL)
928 for (x=0; x < (ssize_t) image->columns; x++)
930 if (IsPixelGray(image,p) == MagickFalse)
935 if ((type == BilevelType) &&
936 (IsPixelMonochrome(image,p) == MagickFalse))
938 p+=GetPixelChannels(image);
940 if (type == UndefinedType)
943 image_view=DestroyCacheView(image_view);
944 if ((type == GrayscaleType) && (image->alpha_trait != UndefinedPixelTrait))
945 type=GrayscaleAlphaType;
950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954 % I d e n t i f y I m a g e M o n o c h r o m e %
958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
960 % IdentifyImageMonochrome() returns MagickTrue if all the pixels in the image
961 % have the same red, green, and blue intensities and the intensity is either
964 % The format of the IdentifyImageMonochrome method is:
966 % MagickBooleanType IdentifyImageMonochrome(const Image *image,
967 % ExceptionInfo *exception)
969 % A description of each parameter follows:
971 % o image: the image.
973 % o exception: return any errors or warnings in this structure.
976 MagickExport MagickBooleanType IdentifyImageMonochrome(const Image *image,
977 ExceptionInfo *exception)
988 register const Quantum
994 assert(image != (Image *) NULL);
995 assert(image->signature == MagickCoreSignature);
996 if (image->debug != MagickFalse)
997 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
998 if (image->type == BilevelType)
1000 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1001 return(MagickFalse);
1003 image_view=AcquireVirtualCacheView(image,exception);
1004 for (y=0; y < (ssize_t) image->rows; y++)
1006 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1007 if (p == (const Quantum *) NULL)
1009 for (x=0; x < (ssize_t) image->columns; x++)
1011 if (IsPixelMonochrome(image,p) == MagickFalse)
1013 bilevel=MagickFalse;
1016 p+=GetPixelChannels(image);
1018 if (bilevel == MagickFalse)
1021 image_view=DestroyCacheView(image_view);
1026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030 % I d e n t i f y I m a g e T y p e %
1034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036 % IdentifyImageType() returns the potential type of image:
1038 % Bilevel Grayscale GrayscaleMatte
1039 % Palette PaletteMatte TrueColor
1040 % TrueColorMatte ColorSeparation ColorSeparationMatte
1042 % To ensure the image type matches its potential, use SetImageType():
1044 % (void) SetImageType(image,IdentifyImageType(image,exception),exception);
1046 % The format of the IdentifyImageType method is:
1048 % ImageType IdentifyImageType(const Image *image,ExceptionInfo *exception)
1050 % A description of each parameter follows:
1052 % o image: the image.
1054 % o exception: return any errors or warnings in this structure.
1057 MagickExport ImageType IdentifyImageType(const Image *image,
1058 ExceptionInfo *exception)
1060 assert(image != (Image *) NULL);
1061 assert(image->signature == MagickCoreSignature);
1062 if (image->debug != MagickFalse)
1063 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1064 if (image->colorspace == CMYKColorspace)
1066 if (image->alpha_trait == UndefinedPixelTrait)
1067 return(ColorSeparationType);
1068 return(ColorSeparationAlphaType);
1070 if (IdentifyImageMonochrome(image,exception) != MagickFalse)
1071 return(BilevelType);
1072 if (IdentifyImageGray(image,exception) != UndefinedType)
1074 if (image->alpha_trait != UndefinedPixelTrait)
1075 return(GrayscaleAlphaType);
1076 return(GrayscaleType);
1078 if (IdentifyPaletteImage(image,exception) != MagickFalse)
1080 if (image->alpha_trait != UndefinedPixelTrait)
1081 return(PaletteAlphaType);
1082 return(PaletteType);
1084 if (image->alpha_trait != UndefinedPixelTrait)
1085 return(TrueColorAlphaType);
1086 return(TrueColorType);
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094 % I s I m a g e G r a y %
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 % IsImageGray() returns MagickTrue if the type of the image is grayscale or
1103 % The format of the IsImageGray method is:
1105 % MagickBooleanType IsImageGray(const Image *image)
1107 % A description of each parameter follows:
1109 % o image: the image.
1112 MagickExport MagickBooleanType IsImageGray(const Image *image)
1114 assert(image != (Image *) NULL);
1115 assert(image->signature == MagickCoreSignature);
1116 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1117 (image->type == GrayscaleAlphaType))
1119 return(MagickFalse);
1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 % I s I m a g e M o n o c h r o m e %
1131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1133 % IsImageMonochrome() returns MagickTrue if type of the image is bi-level.
1135 % The format of the IsImageMonochrome method is:
1137 % MagickBooleanType IsImageMonochrome(const Image *image)
1139 % A description of each parameter follows:
1141 % o image: the image.
1144 MagickExport MagickBooleanType IsImageMonochrome(const Image *image)
1146 assert(image != (Image *) NULL);
1147 assert(image->signature == MagickCoreSignature);
1148 if (image->type == BilevelType)
1150 return(MagickFalse);
1154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 % I s I m a g e O p a q u e %
1162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164 % IsImageOpaque() returns MagickTrue if none of the pixels in the image have
1165 % an alpha value other than OpaqueAlpha (QuantumRange).
1167 % Will return true immediatally is alpha channel is not available.
1169 % The format of the IsImageOpaque method is:
1171 % MagickBooleanType IsImageOpaque(const Image *image,
1172 % ExceptionInfo *exception)
1174 % A description of each parameter follows:
1176 % o image: the image.
1178 % o exception: return any errors or warnings in this structure.
1181 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
1182 ExceptionInfo *exception)
1187 register const Quantum
1197 Determine if image is opaque.
1199 assert(image != (Image *) NULL);
1200 assert(image->signature == MagickCoreSignature);
1201 if (image->debug != MagickFalse)
1202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1203 if (image->alpha_trait == UndefinedPixelTrait)
1205 image_view=AcquireVirtualCacheView(image,exception);
1206 for (y=0; y < (ssize_t) image->rows; y++)
1208 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1209 if (p == (const Quantum *) NULL)
1211 for (x=0; x < (ssize_t) image->columns; x++)
1213 if (GetPixelAlpha(image,p) != OpaqueAlpha)
1215 p+=GetPixelChannels(image);
1217 if (x < (ssize_t) image->columns)
1220 image_view=DestroyCacheView(image_view);
1221 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
1225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1229 % S e t I m a g e D e p t h %
1233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1235 % SetImageDepth() sets the depth of the image.
1237 % The format of the SetImageDepth method is:
1239 % MagickBooleanType SetImageDepth(Image *image,const size_t depth,
1240 % ExceptionInfo *exception)
1242 % A description of each parameter follows:
1244 % o image: the image.
1246 % o channel: the channel.
1248 % o depth: the image depth.
1250 % o exception: return any errors or warnings in this structure.
1253 MagickExport MagickBooleanType SetImageDepth(Image *image,
1254 const size_t depth,ExceptionInfo *exception)
1268 assert(image != (Image *) NULL);
1269 if (image->debug != MagickFalse)
1270 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1271 assert(image->signature == MagickCoreSignature);
1272 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
1277 range=GetQuantumRange(depth);
1278 if (image->storage_class == PseudoClass)
1283 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1284 #pragma omp parallel for schedule(static) shared(status) \
1285 magick_number_threads(image,image,image->colors,1)
1287 for (i=0; i < (ssize_t) image->colors; i++)
1289 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1290 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1291 ClampPixel(image->colormap[i].red),range),range);
1292 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1293 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1294 ClampPixel(image->colormap[i].green),range),range);
1295 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1296 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1297 ClampPixel(image->colormap[i].blue),range),range);
1298 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1299 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1300 ClampPixel(image->colormap[i].alpha),range),range);
1304 image_view=AcquireAuthenticCacheView(image,exception);
1305 #if !defined(MAGICKCORE_HDRI_SUPPORT)
1306 if ((1UL*QuantumRange) <= MaxMap)
1315 Scale pixels to desired (optimized with depth map).
1317 depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
1318 if (depth_map == (Quantum *) NULL)
1319 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1320 for (i=0; i <= (ssize_t) MaxMap; i++)
1321 depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
1323 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1324 #pragma omp parallel for schedule(static) shared(status) \
1325 magick_number_threads(image,image,image->rows,1)
1327 for (y=0; y < (ssize_t) image->rows; y++)
1335 if (status == MagickFalse)
1337 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1339 if (q == (Quantum *) NULL)
1344 for (x=0; x < (ssize_t) image->columns; x++)
1349 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1357 channel=GetPixelChannelChannel(image,i);
1358 traits=GetPixelChannelTraits(image,channel);
1359 if ((traits & UpdatePixelTrait) == 0)
1361 q[i]=depth_map[ScaleQuantumToMap(q[i])];
1363 q+=GetPixelChannels(image);
1365 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1371 image_view=DestroyCacheView(image_view);
1372 depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1373 if (status != MagickFalse)
1379 Scale pixels to desired depth.
1381 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1382 #pragma omp parallel for schedule(static) shared(status) \
1383 magick_number_threads(image,image,image->rows,1)
1385 for (y=0; y < (ssize_t) image->rows; y++)
1393 if (status == MagickFalse)
1395 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1396 if (q == (Quantum *) NULL)
1401 for (x=0; x < (ssize_t) image->columns; x++)
1406 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1414 channel=GetPixelChannelChannel(image,i);
1415 traits=GetPixelChannelTraits(image,channel);
1416 if ((traits & UpdatePixelTrait) == 0)
1418 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(ClampPixel((MagickRealType)
1419 q[i]),range),range);
1421 q+=GetPixelChannels(image);
1423 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1429 image_view=DestroyCacheView(image_view);
1430 if (status != MagickFalse)
1436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 % S e t I m a g e T y p e %
1444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446 % SetImageType() sets the type of image. Choose from these types:
1448 % Bilevel Grayscale GrayscaleMatte
1449 % Palette PaletteMatte TrueColor
1450 % TrueColorMatte ColorSeparation ColorSeparationMatte
1453 % The format of the SetImageType method is:
1455 % MagickBooleanType SetImageType(Image *image,const ImageType type,
1456 % ExceptionInfo *exception)
1458 % A description of each parameter follows:
1460 % o image: the image.
1462 % o type: Image type.
1464 % o exception: return any errors or warnings in this structure.
1467 MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
1468 ExceptionInfo *exception)
1482 assert(image != (Image *) NULL);
1483 if (image->debug != MagickFalse)
1484 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1485 assert(image->signature == MagickCoreSignature);
1487 image_info=AcquireImageInfo();
1488 image_info->dither=image->dither;
1489 artifact=GetImageArtifact(image,"dither");
1490 if (artifact != (const char *) NULL)
1491 (void) SetImageOption(image_info,"dither",artifact);
1496 status=TransformImageColorspace(image,GRAYColorspace,exception);
1497 (void) NormalizeImage(image,exception);
1498 quantize_info=AcquireQuantizeInfo(image_info);
1499 quantize_info->number_colors=2;
1500 quantize_info->colorspace=GRAYColorspace;
1501 quantize_info->dither_method=NoDitherMethod;
1502 status=QuantizeImage(quantize_info,image,exception);
1503 quantize_info=DestroyQuantizeInfo(quantize_info);
1504 image->alpha_trait=UndefinedPixelTrait;
1509 status=TransformImageColorspace(image,GRAYColorspace,exception);
1510 image->alpha_trait=UndefinedPixelTrait;
1513 case GrayscaleAlphaType:
1515 status=TransformImageColorspace(image,GRAYColorspace,exception);
1516 if (image->alpha_trait == UndefinedPixelTrait)
1517 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1522 status=TransformImageColorspace(image,sRGBColorspace,exception);
1523 if ((image->storage_class == DirectClass) || (image->colors > 256))
1525 quantize_info=AcquireQuantizeInfo(image_info);
1526 quantize_info->number_colors=256;
1527 status=QuantizeImage(quantize_info,image,exception);
1528 quantize_info=DestroyQuantizeInfo(quantize_info);
1530 image->alpha_trait=UndefinedPixelTrait;
1533 case PaletteBilevelAlphaType:
1538 status=TransformImageColorspace(image,sRGBColorspace,exception);
1539 if (image->alpha_trait == UndefinedPixelTrait)
1540 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1541 channel_mask=SetImageChannelMask(image,AlphaChannel);
1542 (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
1543 (void) SetImageChannelMask(image,channel_mask);
1544 quantize_info=AcquireQuantizeInfo(image_info);
1545 status=QuantizeImage(quantize_info,image,exception);
1546 quantize_info=DestroyQuantizeInfo(quantize_info);
1549 case PaletteAlphaType:
1551 status=TransformImageColorspace(image,sRGBColorspace,exception);
1552 if (image->alpha_trait == UndefinedPixelTrait)
1553 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1554 quantize_info=AcquireQuantizeInfo(image_info);
1555 quantize_info->colorspace=TransparentColorspace;
1556 status=QuantizeImage(quantize_info,image,exception);
1557 quantize_info=DestroyQuantizeInfo(quantize_info);
1562 status=TransformImageColorspace(image,sRGBColorspace,exception);
1563 if (image->storage_class != DirectClass)
1564 status=SetImageStorageClass(image,DirectClass,exception);
1565 image->alpha_trait=UndefinedPixelTrait;
1568 case TrueColorAlphaType:
1570 status=TransformImageColorspace(image,sRGBColorspace,exception);
1571 if (image->storage_class != DirectClass)
1572 status=SetImageStorageClass(image,DirectClass,exception);
1573 if (image->alpha_trait == UndefinedPixelTrait)
1574 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1577 case ColorSeparationType:
1579 status=TransformImageColorspace(image,CMYKColorspace,exception);
1580 if (image->storage_class != DirectClass)
1581 status=SetImageStorageClass(image,DirectClass,exception);
1582 image->alpha_trait=UndefinedPixelTrait;
1585 case ColorSeparationAlphaType:
1587 status=TransformImageColorspace(image,CMYKColorspace,exception);
1588 if (image->storage_class != DirectClass)
1589 status=SetImageStorageClass(image,DirectClass,exception);
1590 if (image->alpha_trait == UndefinedPixelTrait)
1591 status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1598 image_info=DestroyImageInfo(image_info);
1599 if (status == MagickFalse)