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)
157 register const Quantum
164 Determine the percent of image background for this edge.
168 case NorthWestGravity:
172 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
175 case NorthEastGravity:
178 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
182 case SouthEastGravity:
185 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,
186 (ssize_t) image->rows-1,1,1,exception);
189 case SouthWestGravity:
192 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
197 GetPixelInfoPixel(image,p,&background);
198 edge_geometry.width=width;
199 edge_geometry.height=height;
200 edge_geometry.x=x_offset;
201 edge_geometry.y=y_offset;
202 GravityAdjustGeometry(image->columns,image->rows,gravity,&edge_geometry);
203 edge_image=CropImage(image,&edge_geometry,exception);
204 if (edge_image == (Image *) NULL)
207 edge_view=AcquireVirtualCacheView(edge_image,exception);
208 for (y=0; y < (ssize_t) edge_image->rows; y++)
213 p=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
214 if (p == (const Quantum *) NULL)
216 for (x=0; x < (ssize_t) edge_image->columns; x++)
218 GetPixelInfoPixel(edge_image,p,&pixel);
219 if (IsFuzzyEquivalencePixelInfo(&pixel,&background) == MagickFalse)
221 p+=GetPixelChannels(edge_image);
224 factor/=((double) edge_image->columns*edge_image->rows);
225 edge_view=DestroyCacheView(edge_view);
226 edge_image=DestroyImage(edge_image);
230 static inline double GetMinEdgeBackgroundFactor(const EdgeInfo *edge)
235 factor=MagickMin(MagickMin(MagickMin(edge->left,edge->right),edge->top),
240 static RectangleInfo GetEdgeBoundingBox(const Image *image,
241 ExceptionInfo *exception)
264 Get the image bounding box.
266 assert(image != (Image *) NULL);
267 assert(image->signature == MagickCoreSignature);
268 if (image->debug != MagickFalse)
269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
270 SetGeometry(image,&bounds);
271 edge_image=CloneImage(image,0,0,MagickTrue,exception);
272 if (edge_image == (Image *) NULL)
274 (void) ParseAbsoluteGeometry("0x0+0+0",&edge_image->page);
275 memset(&vertex,0,sizeof(vertex));
276 edge_view=AcquireVirtualCacheView(edge_image,exception);
277 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,WestGravity,
279 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,EastGravity,
281 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,NorthGravity,
283 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,SouthGravity,
285 percent_background=1.0;
286 artifact=GetImageArtifact(edge_image,"trim:percent-background");
287 if (artifact != (const char *) NULL)
288 percent_background=StringToDouble(artifact,(char **) NULL)/100.0;
289 percent_background=MagickMin(MagickMax(1.0-percent_background,MagickEpsilon),
291 background_factor=GetMinEdgeBackgroundFactor(&edge);
292 for ( ; background_factor < percent_background;
293 background_factor=GetMinEdgeBackgroundFactor(&edge))
295 if ((bounds.width == 0) || (bounds.height == 0))
297 if (fabs(edge.left-background_factor) < MagickEpsilon)
304 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
305 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
306 vertex.top,exception);
307 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
308 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
309 vertex.top,exception);
310 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
311 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
312 vertex.bottom,exception);
315 if (fabs(edge.right-background_factor) < MagickEpsilon)
322 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
323 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
324 vertex.top,exception);
325 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
326 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
327 vertex.top,exception);
328 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
329 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
330 vertex.bottom,exception);
333 if (fabs(edge.top-background_factor) < MagickEpsilon)
340 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
341 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
342 vertex.top,exception);
343 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
344 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
345 vertex.top,exception);
346 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
347 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
348 vertex.top,exception);
351 if (fabs(edge.bottom-background_factor) < MagickEpsilon)
358 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
359 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
360 vertex.top,exception);
361 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
362 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
363 vertex.top,exception);
364 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
365 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
366 vertex.bottom,exception);
370 edge_view=DestroyCacheView(edge_view);
371 edge_image=DestroyImage(edge_image);
372 bounds.x=(ssize_t) vertex.left;
373 bounds.y=(ssize_t) vertex.top;
374 if ((bounds.width == 0) || (bounds.height == 0))
375 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
376 "GeometryDoesNotContainImage","`%s'",image->filename);
380 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
381 ExceptionInfo *exception)
399 register const Quantum
405 assert(image != (Image *) NULL);
406 assert(image->signature == MagickCoreSignature);
407 if (image->debug != MagickFalse)
408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
409 artifact=GetImageArtifact(image,"trim:percent-background");
410 if (artifact != (const char *) NULL)
411 return(GetEdgeBoundingBox(image,exception));
414 bounds.x=(ssize_t) image->columns;
415 bounds.y=(ssize_t) image->rows;
416 GetPixelInfo(image,&target[0]);
417 image_view=AcquireVirtualCacheView(image,exception);
418 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
419 if (p == (const Quantum *) NULL)
421 image_view=DestroyCacheView(image_view);
424 GetPixelInfoPixel(image,p,&target[0]);
425 GetPixelInfo(image,&target[1]);
426 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
428 if (p != (const Quantum *) NULL)
429 GetPixelInfoPixel(image,p,&target[1]);
430 GetPixelInfo(image,&target[2]);
431 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
433 if (p != (const Quantum *) NULL)
434 GetPixelInfoPixel(image,p,&target[2]);
436 GetPixelInfo(image,&zero);
437 #if defined(MAGICKCORE_OPENMP_SUPPORT)
438 #pragma omp parallel for schedule(static) shared(status) \
439 magick_number_threads(image,image,image->rows,1)
441 for (y=0; y < (ssize_t) image->rows; y++)
449 register const Quantum
455 if (status == MagickFalse)
457 #if defined(MAGICKCORE_OPENMP_SUPPORT)
458 # pragma omp critical (MagickCore_GetImageBoundingBox)
461 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
462 if (p == (const Quantum *) NULL)
468 for (x=0; x < (ssize_t) image->columns; x++)
470 GetPixelInfoPixel(image,p,&pixel);
471 if ((x < bounding_box.x) &&
472 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
474 if ((x > (ssize_t) bounding_box.width) &&
475 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
476 bounding_box.width=(size_t) x;
477 if ((y < bounding_box.y) &&
478 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
480 if ((y > (ssize_t) bounding_box.height) &&
481 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
482 bounding_box.height=(size_t) y;
483 p+=GetPixelChannels(image);
485 #if defined(MAGICKCORE_OPENMP_SUPPORT)
486 # pragma omp critical (MagickCore_GetImageBoundingBox)
489 if (bounding_box.x < bounds.x)
490 bounds.x=bounding_box.x;
491 if (bounding_box.y < bounds.y)
492 bounds.y=bounding_box.y;
493 if (bounding_box.width > bounds.width)
494 bounds.width=bounding_box.width;
495 if (bounding_box.height > bounds.height)
496 bounds.height=bounding_box.height;
499 image_view=DestroyCacheView(image_view);
500 if ((bounds.width == 0) || (bounds.height == 0))
501 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
502 "GeometryDoesNotContainImage","`%s'",image->filename);
505 bounds.width-=(bounds.x-1);
506 bounds.height-=(bounds.y-1);
512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
516 % G e t I m a g e D e p t h %
520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522 % GetImageDepth() returns the depth of a particular image channel.
524 % The format of the GetImageDepth method is:
526 % size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
528 % A description of each parameter follows:
530 % o image: the image.
532 % o exception: return any errors or warnings in this structure.
535 MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
557 assert(image != (Image *) NULL);
558 assert(image->signature == MagickCoreSignature);
559 if (image->debug != MagickFalse)
560 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
561 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
562 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
563 sizeof(*current_depth));
564 if (current_depth == (size_t *) NULL)
565 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
567 for (i=0; i < (ssize_t) number_threads; i++)
569 if ((image->storage_class == PseudoClass) &&
570 (image->alpha_trait == UndefinedPixelTrait))
572 for (i=0; i < (ssize_t) image->colors; i++)
575 id = GetOpenMPThreadId();
577 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
586 range=GetQuantumRange(current_depth[id]);
587 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
588 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].red),range) == MagickFalse)
590 if ((atDepth != MagickFalse) &&
591 (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
592 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].green),range) == MagickFalse)
594 if ((atDepth != MagickFalse) &&
595 (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
596 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].blue),range) == MagickFalse)
598 if ((atDepth != MagickFalse))
603 depth=current_depth[0];
604 for (i=1; i < (ssize_t) number_threads; i++)
605 if (depth < current_depth[i])
606 depth=current_depth[i];
607 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
610 image_view=AcquireVirtualCacheView(image,exception);
611 #if !defined(MAGICKCORE_HDRI_SUPPORT)
612 if ((1UL*QuantumRange) <= MaxMap)
618 Scale pixels to desired (optimized with depth map).
620 depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
621 if (depth_map == (size_t *) NULL)
622 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
623 for (i=0; i <= (ssize_t) MaxMap; i++)
628 for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
636 range=GetQuantumRange(depth);
638 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
643 #if defined(MAGICKCORE_OPENMP_SUPPORT)
644 #pragma omp parallel for schedule(static) shared(status) \
645 magick_number_threads(image,image,image->rows,1)
647 for (y=0; y < (ssize_t) image->rows; y++)
650 id = GetOpenMPThreadId();
652 register const Quantum
658 if (status == MagickFalse)
660 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
661 if (p == (const Quantum *) NULL)
663 for (x=0; x < (ssize_t) image->columns; x++)
668 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
670 PixelChannel channel = GetPixelChannelChannel(image,i);
671 PixelTrait traits = GetPixelChannelTraits(image,channel);
672 if ((traits & UpdatePixelTrait) == 0)
674 if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
675 current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
677 p+=GetPixelChannels(image);
679 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
682 image_view=DestroyCacheView(image_view);
683 depth=current_depth[0];
684 for (i=1; i < (ssize_t) number_threads; i++)
685 if (depth < current_depth[i])
686 depth=current_depth[i];
687 depth_map=(size_t *) RelinquishMagickMemory(depth_map);
688 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
695 #if defined(MAGICKCORE_OPENMP_SUPPORT)
696 #pragma omp parallel for schedule(static) shared(status) \
697 magick_number_threads(image,image,image->rows,1)
699 for (y=0; y < (ssize_t) image->rows; y++)
702 id = GetOpenMPThreadId();
704 register const Quantum
710 if (status == MagickFalse)
712 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
713 if (p == (const Quantum *) NULL)
715 for (x=0; x < (ssize_t) image->columns; x++)
720 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
728 channel=GetPixelChannelChannel(image,i);
729 traits=GetPixelChannelTraits(image,channel);
730 if ((traits & UpdatePixelTrait) == 0)
732 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
737 range=GetQuantumRange(current_depth[id]);
738 if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
743 p+=GetPixelChannels(image);
745 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
748 image_view=DestroyCacheView(image_view);
749 depth=current_depth[0];
750 for (i=1; i < (ssize_t) number_threads; i++)
751 if (depth < current_depth[i])
752 depth=current_depth[i];
753 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
762 % G e t I m a g e Q u a n t u m D e p t h %
766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768 % GetImageQuantumDepth() returns the depth of the image rounded to a legal
769 % quantum depth: 8, 16, or 32.
771 % The format of the GetImageQuantumDepth method is:
773 % size_t GetImageQuantumDepth(const Image *image,
774 % const MagickBooleanType constrain)
776 % A description of each parameter follows:
778 % o image: the image.
780 % o constrain: A value other than MagickFalse, constrains the depth to
781 % a maximum of MAGICKCORE_QUANTUM_DEPTH.
784 MagickExport size_t GetImageQuantumDepth(const Image *image,
785 const MagickBooleanType constrain)
802 if (constrain != MagickFalse)
803 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
812 % G e t I m a g e T y p e %
816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
818 % GetImageType() returns the type of image:
820 % Bilevel Grayscale GrayscaleMatte
821 % Palette PaletteMatte TrueColor
822 % TrueColorMatte ColorSeparation ColorSeparationMatte
824 % The format of the GetImageType method is:
826 % ImageType GetImageType(const Image *image)
828 % A description of each parameter follows:
830 % o image: the image.
833 MagickExport ImageType GetImageType(const Image *image)
835 assert(image != (Image *) NULL);
836 assert(image->signature == MagickCoreSignature);
837 if (image->colorspace == CMYKColorspace)
839 if (image->alpha_trait == UndefinedPixelTrait)
840 return(ColorSeparationType);
841 return(ColorSeparationAlphaType);
843 if (IsImageMonochrome(image) != MagickFalse)
845 if (IsImageGray(image) != MagickFalse)
847 if (image->alpha_trait != UndefinedPixelTrait)
848 return(GrayscaleAlphaType);
849 return(GrayscaleType);
851 if (IsPaletteImage(image) != MagickFalse)
853 if (image->alpha_trait != UndefinedPixelTrait)
854 return(PaletteAlphaType);
857 if (image->alpha_trait != UndefinedPixelTrait)
858 return(TrueColorAlphaType);
859 return(TrueColorType);
863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 % I d e n t i f y I m a g e G r a y %
871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
873 % IdentifyImageGray() returns grayscale if all the pixels in the image have
874 % the same red, green, and blue intensities, and bi-level is the intensity is
875 % either 0 or QuantumRange. Otherwise undefined is returned.
877 % The format of the IdentifyImageGray method is:
879 % ImageType IdentifyImageGray(const Image *image,ExceptionInfo *exception)
881 % A description of each parameter follows:
883 % o image: the image.
885 % o exception: return any errors or warnings in this structure.
888 MagickExport ImageType IdentifyImageGray(const Image *image,
889 ExceptionInfo *exception)
897 register const Quantum
906 assert(image != (Image *) NULL);
907 assert(image->signature == MagickCoreSignature);
908 if (image->debug != MagickFalse)
909 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
910 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
911 (image->type == GrayscaleAlphaType))
913 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
914 return(UndefinedType);
916 image_view=AcquireVirtualCacheView(image,exception);
917 for (y=0; y < (ssize_t) image->rows; y++)
919 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
920 if (p == (const Quantum *) NULL)
922 for (x=0; x < (ssize_t) image->columns; x++)
924 if (IsPixelGray(image,p) == MagickFalse)
929 if ((type == BilevelType) &&
930 (IsPixelMonochrome(image,p) == MagickFalse))
932 p+=GetPixelChannels(image);
934 if (type == UndefinedType)
937 image_view=DestroyCacheView(image_view);
938 if ((type == GrayscaleType) && (image->alpha_trait != UndefinedPixelTrait))
939 type=GrayscaleAlphaType;
944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
948 % I d e n t i f y I m a g e M o n o c h r o m e %
952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954 % IdentifyImageMonochrome() returns MagickTrue if all the pixels in the image
955 % have the same red, green, and blue intensities and the intensity is either
958 % The format of the IdentifyImageMonochrome method is:
960 % MagickBooleanType IdentifyImageMonochrome(const Image *image,
961 % ExceptionInfo *exception)
963 % A description of each parameter follows:
965 % o image: the image.
967 % o exception: return any errors or warnings in this structure.
970 MagickExport MagickBooleanType IdentifyImageMonochrome(const Image *image,
971 ExceptionInfo *exception)
982 register const Quantum
988 assert(image != (Image *) NULL);
989 assert(image->signature == MagickCoreSignature);
990 if (image->debug != MagickFalse)
991 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
992 if (image->type == BilevelType)
994 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
997 image_view=AcquireVirtualCacheView(image,exception);
998 for (y=0; y < (ssize_t) image->rows; y++)
1000 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1001 if (p == (const Quantum *) NULL)
1003 for (x=0; x < (ssize_t) image->columns; x++)
1005 if (IsPixelMonochrome(image,p) == MagickFalse)
1007 bilevel=MagickFalse;
1010 p+=GetPixelChannels(image);
1012 if (bilevel == MagickFalse)
1015 image_view=DestroyCacheView(image_view);
1020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1024 % I d e n t i f y I m a g e T y p e %
1028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030 % IdentifyImageType() returns the potential type of image:
1032 % Bilevel Grayscale GrayscaleMatte
1033 % Palette PaletteMatte TrueColor
1034 % TrueColorMatte ColorSeparation ColorSeparationMatte
1036 % To ensure the image type matches its potential, use SetImageType():
1038 % (void) SetImageType(image,IdentifyImageType(image,exception),exception);
1040 % The format of the IdentifyImageType method is:
1042 % ImageType IdentifyImageType(const Image *image,ExceptionInfo *exception)
1044 % A description of each parameter follows:
1046 % o image: the image.
1048 % o exception: return any errors or warnings in this structure.
1051 MagickExport ImageType IdentifyImageType(const Image *image,
1052 ExceptionInfo *exception)
1054 assert(image != (Image *) NULL);
1055 assert(image->signature == MagickCoreSignature);
1056 if (image->debug != MagickFalse)
1057 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1058 if (image->colorspace == CMYKColorspace)
1060 if (image->alpha_trait == UndefinedPixelTrait)
1061 return(ColorSeparationType);
1062 return(ColorSeparationAlphaType);
1064 if (IdentifyImageMonochrome(image,exception) != MagickFalse)
1065 return(BilevelType);
1066 if (IdentifyImageGray(image,exception) != UndefinedType)
1068 if (image->alpha_trait != UndefinedPixelTrait)
1069 return(GrayscaleAlphaType);
1070 return(GrayscaleType);
1072 if (IdentifyPaletteImage(image,exception) != MagickFalse)
1074 if (image->alpha_trait != UndefinedPixelTrait)
1075 return(PaletteAlphaType);
1076 return(PaletteType);
1078 if (image->alpha_trait != UndefinedPixelTrait)
1079 return(TrueColorAlphaType);
1080 return(TrueColorType);
1084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088 % I s I m a g e G r a y %
1092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094 % IsImageGray() returns MagickTrue if the type of the image is grayscale or
1097 % The format of the IsImageGray method is:
1099 % MagickBooleanType IsImageGray(const Image *image)
1101 % A description of each parameter follows:
1103 % o image: the image.
1106 MagickExport MagickBooleanType IsImageGray(const Image *image)
1108 assert(image != (Image *) NULL);
1109 assert(image->signature == MagickCoreSignature);
1110 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1111 (image->type == GrayscaleAlphaType))
1113 return(MagickFalse);
1117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121 % I s I m a g e M o n o c h r o m e %
1125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 % IsImageMonochrome() returns MagickTrue if type of the image is bi-level.
1129 % The format of the IsImageMonochrome method is:
1131 % MagickBooleanType IsImageMonochrome(const Image *image)
1133 % A description of each parameter follows:
1135 % o image: the image.
1138 MagickExport MagickBooleanType IsImageMonochrome(const Image *image)
1140 assert(image != (Image *) NULL);
1141 assert(image->signature == MagickCoreSignature);
1142 if (image->type == BilevelType)
1144 return(MagickFalse);
1148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 % I s I m a g e O p a q u e %
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 % IsImageOpaque() returns MagickTrue if none of the pixels in the image have
1159 % an alpha value other than OpaqueAlpha (QuantumRange).
1161 % Will return true immediatally is alpha channel is not available.
1163 % The format of the IsImageOpaque method is:
1165 % MagickBooleanType IsImageOpaque(const Image *image,
1166 % ExceptionInfo *exception)
1168 % A description of each parameter follows:
1170 % o image: the image.
1172 % o exception: return any errors or warnings in this structure.
1175 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
1176 ExceptionInfo *exception)
1181 register const Quantum
1191 Determine if image is opaque.
1193 assert(image != (Image *) NULL);
1194 assert(image->signature == MagickCoreSignature);
1195 if (image->debug != MagickFalse)
1196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1197 if (image->alpha_trait == UndefinedPixelTrait)
1199 image_view=AcquireVirtualCacheView(image,exception);
1200 for (y=0; y < (ssize_t) image->rows; y++)
1202 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1203 if (p == (const Quantum *) NULL)
1205 for (x=0; x < (ssize_t) image->columns; x++)
1207 if (GetPixelAlpha(image,p) != OpaqueAlpha)
1209 p+=GetPixelChannels(image);
1211 if (x < (ssize_t) image->columns)
1214 image_view=DestroyCacheView(image_view);
1215 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
1219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1223 % S e t I m a g e D e p t h %
1227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1229 % SetImageDepth() sets the depth of the image.
1231 % The format of the SetImageDepth method is:
1233 % MagickBooleanType SetImageDepth(Image *image,const size_t depth,
1234 % ExceptionInfo *exception)
1236 % A description of each parameter follows:
1238 % o image: the image.
1240 % o channel: the channel.
1242 % o depth: the image depth.
1244 % o exception: return any errors or warnings in this structure.
1247 MagickExport MagickBooleanType SetImageDepth(Image *image,
1248 const size_t depth,ExceptionInfo *exception)
1262 assert(image != (Image *) NULL);
1263 if (image->debug != MagickFalse)
1264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1265 assert(image->signature == MagickCoreSignature);
1266 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
1271 range=GetQuantumRange(depth);
1272 if (image->storage_class == PseudoClass)
1277 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1278 #pragma omp parallel for schedule(static) shared(status) \
1279 magick_number_threads(image,image,image->colors,1)
1281 for (i=0; i < (ssize_t) image->colors; i++)
1283 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1284 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1285 ClampPixel(image->colormap[i].red),range),range);
1286 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1287 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1288 ClampPixel(image->colormap[i].green),range),range);
1289 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1290 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1291 ClampPixel(image->colormap[i].blue),range),range);
1292 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1293 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1294 ClampPixel(image->colormap[i].alpha),range),range);
1298 image_view=AcquireAuthenticCacheView(image,exception);
1299 #if !defined(MAGICKCORE_HDRI_SUPPORT)
1300 if ((1UL*QuantumRange) <= MaxMap)
1309 Scale pixels to desired (optimized with depth map).
1311 depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
1312 if (depth_map == (Quantum *) NULL)
1313 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1314 for (i=0; i <= (ssize_t) MaxMap; i++)
1315 depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
1317 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1318 #pragma omp parallel for schedule(static) shared(status) \
1319 magick_number_threads(image,image,image->rows,1)
1321 for (y=0; y < (ssize_t) image->rows; y++)
1329 if (status == MagickFalse)
1331 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1333 if (q == (Quantum *) NULL)
1338 for (x=0; x < (ssize_t) image->columns; x++)
1343 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1351 channel=GetPixelChannelChannel(image,i);
1352 traits=GetPixelChannelTraits(image,channel);
1353 if ((traits & UpdatePixelTrait) == 0)
1355 q[i]=depth_map[ScaleQuantumToMap(q[i])];
1357 q+=GetPixelChannels(image);
1359 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1365 image_view=DestroyCacheView(image_view);
1366 depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1367 if (status != MagickFalse)
1373 Scale pixels to desired depth.
1375 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1376 #pragma omp parallel for schedule(static) shared(status) \
1377 magick_number_threads(image,image,image->rows,1)
1379 for (y=0; y < (ssize_t) image->rows; y++)
1387 if (status == MagickFalse)
1389 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1390 if (q == (Quantum *) NULL)
1395 for (x=0; x < (ssize_t) image->columns; x++)
1400 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1408 channel=GetPixelChannelChannel(image,i);
1409 traits=GetPixelChannelTraits(image,channel);
1410 if ((traits & UpdatePixelTrait) == 0)
1412 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(ClampPixel((MagickRealType)
1413 q[i]),range),range);
1415 q+=GetPixelChannels(image);
1417 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1423 image_view=DestroyCacheView(image_view);
1424 if (status != MagickFalse)
1430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434 % S e t I m a g e T y p e %
1438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 % SetImageType() sets the type of image. Choose from these types:
1442 % Bilevel Grayscale GrayscaleMatte
1443 % Palette PaletteMatte TrueColor
1444 % TrueColorMatte ColorSeparation ColorSeparationMatte
1447 % The format of the SetImageType method is:
1449 % MagickBooleanType SetImageType(Image *image,const ImageType type,
1450 % ExceptionInfo *exception)
1452 % A description of each parameter follows:
1454 % o image: the image.
1456 % o type: Image type.
1458 % o exception: return any errors or warnings in this structure.
1461 MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
1462 ExceptionInfo *exception)
1476 assert(image != (Image *) NULL);
1477 if (image->debug != MagickFalse)
1478 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1479 assert(image->signature == MagickCoreSignature);
1481 image_info=AcquireImageInfo();
1482 image_info->dither=image->dither;
1483 artifact=GetImageArtifact(image,"dither");
1484 if (artifact != (const char *) NULL)
1485 (void) SetImageOption(image_info,"dither",artifact);
1490 status=TransformImageColorspace(image,GRAYColorspace,exception);
1491 (void) NormalizeImage(image,exception);
1492 quantize_info=AcquireQuantizeInfo(image_info);
1493 quantize_info->number_colors=2;
1494 quantize_info->colorspace=GRAYColorspace;
1495 quantize_info->dither_method=NoDitherMethod;
1496 status=QuantizeImage(quantize_info,image,exception);
1497 quantize_info=DestroyQuantizeInfo(quantize_info);
1498 image->alpha_trait=UndefinedPixelTrait;
1503 status=TransformImageColorspace(image,GRAYColorspace,exception);
1504 image->alpha_trait=UndefinedPixelTrait;
1507 case GrayscaleAlphaType:
1509 status=TransformImageColorspace(image,GRAYColorspace,exception);
1510 if (image->alpha_trait == UndefinedPixelTrait)
1511 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1516 status=TransformImageColorspace(image,sRGBColorspace,exception);
1517 if ((image->storage_class == DirectClass) || (image->colors > 256))
1519 quantize_info=AcquireQuantizeInfo(image_info);
1520 quantize_info->number_colors=256;
1521 status=QuantizeImage(quantize_info,image,exception);
1522 quantize_info=DestroyQuantizeInfo(quantize_info);
1524 image->alpha_trait=UndefinedPixelTrait;
1527 case PaletteBilevelAlphaType:
1532 status=TransformImageColorspace(image,sRGBColorspace,exception);
1533 if (image->alpha_trait == UndefinedPixelTrait)
1534 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1535 channel_mask=SetImageChannelMask(image,AlphaChannel);
1536 (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
1537 (void) SetImageChannelMask(image,channel_mask);
1538 quantize_info=AcquireQuantizeInfo(image_info);
1539 status=QuantizeImage(quantize_info,image,exception);
1540 quantize_info=DestroyQuantizeInfo(quantize_info);
1543 case PaletteAlphaType:
1545 status=TransformImageColorspace(image,sRGBColorspace,exception);
1546 if (image->alpha_trait == UndefinedPixelTrait)
1547 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1548 quantize_info=AcquireQuantizeInfo(image_info);
1549 quantize_info->colorspace=TransparentColorspace;
1550 status=QuantizeImage(quantize_info,image,exception);
1551 quantize_info=DestroyQuantizeInfo(quantize_info);
1556 status=TransformImageColorspace(image,sRGBColorspace,exception);
1557 if (image->storage_class != DirectClass)
1558 status=SetImageStorageClass(image,DirectClass,exception);
1559 image->alpha_trait=UndefinedPixelTrait;
1562 case TrueColorAlphaType:
1564 status=TransformImageColorspace(image,sRGBColorspace,exception);
1565 if (image->storage_class != DirectClass)
1566 status=SetImageStorageClass(image,DirectClass,exception);
1567 if (image->alpha_trait == UndefinedPixelTrait)
1568 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1571 case ColorSeparationType:
1573 status=TransformImageColorspace(image,CMYKColorspace,exception);
1574 if (image->storage_class != DirectClass)
1575 status=SetImageStorageClass(image,DirectClass,exception);
1576 image->alpha_trait=UndefinedPixelTrait;
1579 case ColorSeparationAlphaType:
1581 status=TransformImageColorspace(image,CMYKColorspace,exception);
1582 if (image->storage_class != DirectClass)
1583 status=SetImageStorageClass(image,DirectClass,exception);
1584 if (image->alpha_trait == UndefinedPixelTrait)
1585 status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1592 image_info=DestroyImageInfo(image_info);
1593 if (status == MagickFalse)