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"
136static double GetEdgeBackgroundCensus(
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)
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 if (p == (
const Quantum *) NULL)
202 GetPixelInfoPixel(image,p,&background);
203 artifact=GetImageArtifact(image,
"background");
204 if (artifact != (
const char *) NULL)
205 (void) QueryColorCompliance(artifact,AllCompliance,&background,exception);
206 artifact=GetImageArtifact(image,
"trim:background-color");
207 if (artifact != (
const char *) NULL)
208 (void) QueryColorCompliance(artifact,AllCompliance,&background,exception);
209 edge_geometry.width=width;
210 edge_geometry.height=height;
211 edge_geometry.x=x_offset;
212 edge_geometry.y=y_offset;
213 GravityAdjustGeometry(image->columns,image->rows,gravity,&edge_geometry);
214 edge_image=CropImage(image,&edge_geometry,exception);
215 if (edge_image == (Image *) NULL)
218 edge_view=AcquireVirtualCacheView(edge_image,exception);
219 for (y=0; y < (ssize_t) edge_image->rows; y++)
224 p=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
225 if (p == (
const Quantum *) NULL)
227 for (x=0; x < (ssize_t) edge_image->columns; x++)
229 GetPixelInfoPixel(edge_image,p,&pixel);
230 if (IsFuzzyEquivalencePixelInfo(&pixel,&background) == MagickFalse)
232 p+=(ptrdiff_t) GetPixelChannels(edge_image);
235 census/=((double) edge_image->columns*edge_image->rows);
236 edge_view=DestroyCacheView(edge_view);
237 edge_image=DestroyImage(edge_image);
241static inline double GetMinEdgeBackgroundCensus(
const CensusInfo *edge)
246 census=MagickMin(MagickMin(MagickMin(edge->left,edge->right),edge->top),
251static RectangleInfo GetEdgeBoundingBox(
const Image *image,
252 ExceptionInfo *exception)
277 assert(image != (Image *) NULL);
278 assert(image->signature == MagickCoreSignature);
279 if (IsEventLogging() != MagickFalse)
280 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
281 SetGeometry(image,&bounds);
282 edge_image=CloneImage(image,0,0,MagickTrue,exception);
283 if (edge_image == (Image *) NULL)
285 (void) ParseAbsoluteGeometry(
"0x0+0+0",&edge_image->page);
286 (void) memset(&vertex,0,
sizeof(vertex));
287 edge_view=AcquireVirtualCacheView(edge_image,exception);
288 edge.left=GetEdgeBackgroundCensus(edge_image,edge_view,WestGravity,
290 edge.right=GetEdgeBackgroundCensus(edge_image,edge_view,EastGravity,
292 edge.top=GetEdgeBackgroundCensus(edge_image,edge_view,NorthGravity,
294 edge.bottom=GetEdgeBackgroundCensus(edge_image,edge_view,SouthGravity,
296 percent_background=1.0;
297 artifact=GetImageArtifact(edge_image,
"trim:percent-background");
298 if (artifact != (
const char *) NULL)
299 percent_background=StringToDouble(artifact,(
char **) NULL)/100.0;
300 percent_background=MagickMin(MagickMax(1.0-percent_background,MagickEpsilon),
302 background_census=GetMinEdgeBackgroundCensus(&edge);
303 for ( ; background_census < percent_background;
304 background_census=GetMinEdgeBackgroundCensus(&edge))
306 if ((bounds.width == 0) || (bounds.height == 0))
308 if (fabs(edge.left-background_census) < MagickEpsilon)
315 edge.left=GetEdgeBackgroundCensus(edge_image,edge_view,
316 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
317 vertex.top,exception);
318 edge.top=GetEdgeBackgroundCensus(edge_image,edge_view,
319 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
320 vertex.top,exception);
321 edge.bottom=GetEdgeBackgroundCensus(edge_image,edge_view,
322 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
323 vertex.bottom,exception);
326 if (fabs(edge.right-background_census) < MagickEpsilon)
333 edge.right=GetEdgeBackgroundCensus(edge_image,edge_view,
334 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
335 vertex.top,exception);
336 edge.top=GetEdgeBackgroundCensus(edge_image,edge_view,
337 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
338 vertex.top,exception);
339 edge.bottom=GetEdgeBackgroundCensus(edge_image,edge_view,
340 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
341 vertex.bottom,exception);
344 if (fabs(edge.top-background_census) < MagickEpsilon)
351 edge.left=GetEdgeBackgroundCensus(edge_image,edge_view,
352 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
353 vertex.top,exception);
354 edge.right=GetEdgeBackgroundCensus(edge_image,edge_view,
355 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
356 vertex.top,exception);
357 edge.top=GetEdgeBackgroundCensus(edge_image,edge_view,
358 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
359 vertex.top,exception);
362 if (fabs(edge.bottom-background_census) < MagickEpsilon)
369 edge.left=GetEdgeBackgroundCensus(edge_image,edge_view,
370 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
371 vertex.top,exception);
372 edge.right=GetEdgeBackgroundCensus(edge_image,edge_view,
373 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
374 vertex.top,exception);
375 edge.bottom=GetEdgeBackgroundCensus(edge_image,edge_view,
376 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
377 vertex.bottom,exception);
381 edge_view=DestroyCacheView(edge_view);
382 edge_image=DestroyImage(edge_image);
383 bounds.x=(ssize_t) vertex.left;
384 bounds.y=(ssize_t) vertex.top;
385 if ((bounds.width == 0) || (bounds.height == 0))
386 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
387 "GeometryDoesNotContainImage",
"`%s'",image->filename);
391MagickExport RectangleInfo GetImageBoundingBox(
const Image *image,
392 ExceptionInfo *exception)
416 assert(image != (Image *) NULL);
417 assert(image->signature == MagickCoreSignature);
418 if (IsEventLogging() != MagickFalse)
419 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
420 artifact=GetImageArtifact(image,
"trim:percent-background");
421 if (artifact != (
const char *) NULL)
422 return(GetEdgeBoundingBox(image,exception));
423 artifact=GetImageArtifact(image,
"trim:edges");
424 if (artifact == (
const char *) NULL)
426 bounds.width=(size_t) (image->columns == 1 ? 1 : 0);
427 bounds.height=(size_t) (image->rows == 1 ? 1 : 0);
428 bounds.x=(ssize_t) image->columns;
429 bounds.y=(ssize_t) image->rows;
438 bounds.width=(size_t) image->columns;
439 bounds.height=(size_t) image->rows;
442 edges=AcquireString(artifact);
444 while ((q=StringToken(
",",&r)) != (
char *) NULL)
446 if (LocaleCompare(q,
"north") == 0)
447 bounds.y=(ssize_t) image->rows;
448 if (LocaleCompare(q,
"east") == 0)
450 if (LocaleCompare(q,
"south") == 0)
452 if (LocaleCompare(q,
"west") == 0)
453 bounds.x=(ssize_t) image->columns;
455 edges=DestroyString(edges);
457 GetPixelInfo(image,&target[0]);
458 image_view=AcquireVirtualCacheView(image,exception);
459 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
460 if (p == (
const Quantum *) NULL)
462 image_view=DestroyCacheView(image_view);
465 GetPixelInfoPixel(image,p,&target[0]);
466 GetPixelInfo(image,&target[1]);
467 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
469 if (p != (
const Quantum *) NULL)
470 GetPixelInfoPixel(image,p,&target[1]);
471 GetPixelInfo(image,&target[2]);
472 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
474 if (p != (
const Quantum *) NULL)
475 GetPixelInfoPixel(image,p,&target[2]);
476 GetPixelInfo(image,&target[3]);
477 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,(ssize_t)
478 image->rows-1,1,1,exception);
479 if (p != (
const Quantum *) NULL)
480 GetPixelInfoPixel(image,p,&target[3]);
482 GetPixelInfo(image,&zero);
483#if defined(MAGICKCORE_OPENMP_SUPPORT)
484 #pragma omp parallel for schedule(static) shared(status) \
485 magick_number_threads(image,image,image->rows,2)
487 for (y=0; y < (ssize_t) image->rows; y++)
501 if (status == MagickFalse)
503#if defined(MAGICKCORE_OPENMP_SUPPORT)
504# pragma omp critical (MagickCore_GetImageBoundingBox)
507 q=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
508 if (q == (
const Quantum *) NULL)
514 for (x=0; x < (ssize_t) image->columns; x++)
516 GetPixelInfoPixel(image,q,&pixel);
517 if ((x < bounding_box.x) &&
518 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
520 if ((x > (ssize_t) bounding_box.width) &&
521 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
522 bounding_box.width=(size_t) x;
523 if ((y < bounding_box.y) &&
524 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
526 if ((y > (ssize_t) bounding_box.height) &&
527 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
528 bounding_box.height=(size_t) y;
529 if ((x < (ssize_t) bounding_box.width) &&
530 (y > (ssize_t) bounding_box.height) &&
531 (IsFuzzyEquivalencePixelInfo(&pixel,&target[3]) == MagickFalse))
533 bounding_box.width=(size_t) x;
534 bounding_box.height=(size_t) y;
536 q+=(ptrdiff_t) GetPixelChannels(image);
538#if defined(MAGICKCORE_OPENMP_SUPPORT)
539# pragma omp critical (MagickCore_GetImageBoundingBox)
542 if (bounding_box.x < bounds.x)
543 bounds.x=bounding_box.x;
544 if (bounding_box.y < bounds.y)
545 bounds.y=bounding_box.y;
546 if (bounding_box.width > bounds.width)
547 bounds.width=bounding_box.width;
548 if (bounding_box.height > bounds.height)
549 bounds.height=bounding_box.height;
552 image_view=DestroyCacheView(image_view);
553 if ((bounds.width == 0) || (bounds.height == 0) ||
554 (bounds.x > (ssize_t) bounds.width) ||
555 (bounds.y > (ssize_t) bounds.height))
556 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
557 "GeometryDoesNotContainImage",
"`%s'",image->filename);
560 bounds.width-=(size_t) (bounds.x-1);
561 bounds.height-=(size_t) (bounds.y-1);
594static double LexicographicalOrder(PointInfo *a,PointInfo *b,PointInfo *c)
599 return((b->x-a->x)*(c->y-a->y)-(b->y-a->y)*(c->x-a->x));
602static PixelInfo GetEdgeBackgroundColor(
const Image *image,
603 const CacheView *image_view,ExceptionInfo *exception)
622 memset(&edge_background,0,
sizeof(edge_background));
623 artifact=GetImageArtifact(image,
"convex-hull:background-color");
624 if (artifact == (
const char *) NULL)
625 artifact=GetImageArtifact(image,
"background");
626#if defined(MAGICKCORE_OPENMP_SUPPORT)
627 #pragma omp parallel for schedule(static)
629 for (i=0; i < 4; i++)
653 (void) memset(&edge_geometry,0,
sizeof(edge_geometry));
659 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
662 edge_geometry.width=1;
663 edge_geometry.height=0;
668 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
671 edge_geometry.width=1;
672 edge_geometry.height=0;
677 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
678 gravity=NorthGravity;
679 edge_geometry.width=0;
680 edge_geometry.height=1;
685 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,
686 (ssize_t) image->rows-1,1,1,exception);
687 gravity=SouthGravity;
688 edge_geometry.width=0;
689 edge_geometry.height=1;
693 GetPixelInfoPixel(image,p,background+i);
694 if (artifact != (
const char *) NULL)
695 (void) QueryColorCompliance(artifact,AllCompliance,background+i,
697 GravityAdjustGeometry(image->columns,image->rows,gravity,&edge_geometry);
698 edge_image=CropImage(image,&edge_geometry,exception);
699 if (edge_image == (Image *) NULL)
701 edge_view=AcquireVirtualCacheView(edge_image,exception);
702 for (y=0; y < (ssize_t) edge_image->rows; y++)
707 p=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,
709 if (p == (
const Quantum *) NULL)
711 for (x=0; x < (ssize_t) edge_image->columns; x++)
713 GetPixelInfoPixel(edge_image,p,&pixel);
714 if (IsFuzzyEquivalencePixelInfo(&pixel,background+i) == MagickFalse)
716 p+=(ptrdiff_t) GetPixelChannels(edge_image);
719 edge_view=DestroyCacheView(edge_view);
720 edge_image=DestroyImage(edge_image);
723 for (i=0; i < 4; i++)
724 if (census[i] > edge_census)
726 edge_background=background[i];
727 edge_census=census[i];
729 return(edge_background);
732void TraceConvexHull(PointInfo *vertices,
size_t number_vertices,
733 PointInfo ***monotone_chain,
size_t *chain_length)
748 chain=(*monotone_chain);
750 for (i=0; i < (ssize_t) number_vertices; i++)
753 (LexicographicalOrder(chain[n-2],chain[n-1],&vertices[i]) <= 0.0))
755 chain[n++]=(&vertices[i]);
758 for (i=(ssize_t) number_vertices-2; i >= 0; i--)
760 while ((n >= demark) &&
761 (LexicographicalOrder(chain[n-2],chain[n-1],&vertices[i]) <= 0.0))
763 chain[n++]=(&vertices[i]);
768MagickExport PointInfo *GetImageConvexHull(
const Image *image,
769 size_t *number_vertices,ExceptionInfo *exception)
798 assert(image != (Image *) NULL);
799 assert(image->signature == MagickCoreSignature);
800 if (IsEventLogging() != MagickFalse)
801 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
803 if (HeapOverflowSanityCheck(image->columns,image->rows*
sizeof(*vertices)) != MagickFalse)
805 (void) ThrowMagickException(exception,GetMagickModule(),
806 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
807 return((PointInfo *) NULL);
809 vertices_info=AcquireVirtualMemory(image->columns,image->rows*
811 if (HeapOverflowSanityCheck(2*image->columns,2*image->rows*
sizeof(*monotone_chain)) != MagickFalse)
813 (void) ThrowMagickException(exception,GetMagickModule(),
814 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
815 vertices_info=RelinquishVirtualMemory(vertices_info);
816 return((PointInfo *) NULL);
818 monotone_info=AcquireVirtualMemory(2*image->columns,2*image->rows*
819 sizeof(*monotone_chain));
820 if ((vertices_info == (MemoryInfo *) NULL) ||
821 (monotone_info == (MemoryInfo *) NULL))
823 if (monotone_info != (MemoryInfo *) NULL)
824 monotone_info=(MemoryInfo *) RelinquishVirtualMemory(monotone_info);
825 if (vertices_info != (MemoryInfo *) NULL)
826 vertices_info=RelinquishVirtualMemory(vertices_info);
827 return((PointInfo *) NULL);
829 vertices=(PointInfo *) GetVirtualMemoryBlob(vertices_info);
830 monotone_chain=(PointInfo **) GetVirtualMemoryBlob(monotone_info);
831 image_view=AcquireVirtualCacheView(image,exception);
832 background=GetEdgeBackgroundColor(image,image_view,exception);
835 for (y=0; y < (ssize_t) image->rows; y++)
843 if (status == MagickFalse)
845 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
846 if (p == (
const Quantum *) NULL)
851 for (x=0; x < (ssize_t) image->columns; x++)
856 GetPixelInfoPixel(image,p,&pixel);
857 if (IsFuzzyEquivalencePixelInfo(&pixel,&background) == MagickFalse)
859 vertices[n].x=(double) x;
860 vertices[n].y=(double) y;
863 p+=(ptrdiff_t) GetPixelChannels(image);
866 image_view=DestroyCacheView(image_view);
870 TraceConvexHull(vertices,n,&monotone_chain,number_vertices);
871 convex_hull=(PointInfo *) AcquireQuantumMemory(*number_vertices,
872 sizeof(*convex_hull));
873 if (convex_hull != (PointInfo *) NULL)
874 for (n=0; n < *number_vertices; n++)
875 convex_hull[n]=(*monotone_chain[n]);
876 monotone_info=RelinquishVirtualMemory(monotone_info);
877 vertices_info=RelinquishVirtualMemory(vertices_info);
905MagickExport
size_t GetImageDepth(
const Image *image,ExceptionInfo *exception)
927 assert(image != (Image *) NULL);
928 assert(image->signature == MagickCoreSignature);
929 if (IsEventLogging() != MagickFalse)
930 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
931 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
932 current_depth=(
size_t *) AcquireQuantumMemory(number_threads,
933 sizeof(*current_depth));
934 if (current_depth == (
size_t *) NULL)
935 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
937 for (i=0; i < (ssize_t) number_threads; i++)
939 if ((image->storage_class == PseudoClass) &&
940 ((image->alpha_trait & BlendPixelTrait) == 0))
942 for (i=0; i < (ssize_t) image->colors; i++)
945 id = GetOpenMPThreadId();
947 while (current_depth[
id] < MAGICKCORE_QUANTUM_DEPTH)
956 range=GetQuantumRange(current_depth[
id]);
957 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
958 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].red),range) == MagickFalse)
960 if ((atDepth != MagickFalse) &&
961 (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
962 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].green),range) == MagickFalse)
964 if ((atDepth != MagickFalse) &&
965 (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
966 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].blue),range) == MagickFalse)
968 if ((atDepth != MagickFalse))
973 depth=current_depth[0];
974 for (i=1; i < (ssize_t) number_threads; i++)
975 if (depth < current_depth[i])
976 depth=current_depth[i];
977 current_depth=(
size_t *) RelinquishMagickMemory(current_depth);
980 image_view=AcquireVirtualCacheView(image,exception);
981#if !defined(MAGICKCORE_HDRI_SUPPORT)
982 DisableMSCWarning(4127)
983 if ((1UL*QuantumRange) <= MaxMap)
992 depth_map=(
size_t *) AcquireQuantumMemory(MaxMap+1,
sizeof(*depth_map));
993 if (depth_map == (
size_t *) NULL)
994 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
995 for (i=0; i <= (ssize_t) MaxMap; i++)
997 for (depth=1; depth < (size_t) MAGICKCORE_QUANTUM_DEPTH; depth++)
1005 range=GetQuantumRange(depth);
1007 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
1012#if defined(MAGICKCORE_OPENMP_SUPPORT)
1013 #pragma omp parallel for schedule(static) shared(status) \
1014 magick_number_threads(image,image,image->rows,1)
1016 for (y=0; y < (ssize_t) image->rows; y++)
1019 id = GetOpenMPThreadId();
1027 if (status == MagickFalse)
1029 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1030 if (p == (
const Quantum *) NULL)
1032 for (x=0; x < (ssize_t) image->columns; x++)
1037 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
1039 PixelChannel channel = GetPixelChannelChannel(image,j);
1040 PixelTrait traits = GetPixelChannelTraits(image,channel);
1041 if ((traits & UpdatePixelTrait) == 0)
1043 if (depth_map[ScaleQuantumToMap(p[j])] > current_depth[
id])
1044 current_depth[id]=depth_map[ScaleQuantumToMap(p[j])];
1046 p+=(ptrdiff_t) GetPixelChannels(image);
1048 if (current_depth[
id] == MAGICKCORE_QUANTUM_DEPTH)
1051 image_view=DestroyCacheView(image_view);
1052 depth=current_depth[0];
1053 for (i=1; i < (ssize_t) number_threads; i++)
1054 if (depth < current_depth[i])
1055 depth=current_depth[i];
1056 depth_map=(
size_t *) RelinquishMagickMemory(depth_map);
1057 current_depth=(
size_t *) RelinquishMagickMemory(current_depth);
1064#if defined(MAGICKCORE_OPENMP_SUPPORT)
1065 #pragma omp parallel for schedule(static) shared(status) \
1066 magick_number_threads(image,image,image->rows,1)
1068 for (y=0; y < (ssize_t) image->rows; y++)
1071 id = GetOpenMPThreadId();
1079 if (status == MagickFalse)
1081 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1082 if (p == (
const Quantum *) NULL)
1084 for (x=0; x < (ssize_t) image->columns; x++)
1089 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
1097 channel=GetPixelChannelChannel(image,j);
1098 traits=GetPixelChannelTraits(image,channel);
1099 if ((traits & UpdatePixelTrait) == 0)
1101 while (current_depth[
id] < MAGICKCORE_QUANTUM_DEPTH)
1106 range=GetQuantumRange(current_depth[
id]);
1107 if (p[j] == ScaleAnyToQuantum(ScaleQuantumToAny(p[j],range),range))
1109 current_depth[id]++;
1112 p+=(ptrdiff_t) GetPixelChannels(image);
1114 if (current_depth[
id] == MAGICKCORE_QUANTUM_DEPTH)
1117 image_view=DestroyCacheView(image_view);
1118 depth=current_depth[0];
1119 for (i=1; i < (ssize_t) number_threads; i++)
1120 if (depth < current_depth[i])
1121 depth=current_depth[i];
1122 current_depth=(
size_t *) RelinquishMagickMemory(current_depth);
1172static inline double getAngle(PointInfo *p,PointInfo *q)
1177 return(RadiansToDegrees(atan2(q->y-p->y,q->x-p->x)));
1180static inline double getDistance(PointInfo *p,PointInfo *q)
1185 distance=hypot(p->x-q->x,p->y-q->y);
1186 return(distance*distance);
1189static inline double getProjection(PointInfo *p,PointInfo *q,PointInfo *v)
1197 distance=getDistance(p,q);
1198 if (distance < MagickEpsilon)
1200 return((q->x-p->x)*(v->x-p->x)+(v->y-p->y)*(q->y-p->y))/sqrt(distance);
1203static inline double getFeretDiameter(PointInfo *p,PointInfo *q,PointInfo *v)
1211 distance=getDistance(p,q);
1212 if (distance < MagickEpsilon)
1214 return((q->x-p->x)*(v->y-p->y)-(v->x-p->x)*(q->y-p->y))/sqrt(distance);
1217MagickExport PointInfo *GetImageMinimumBoundingBox(Image *image,
1218 size_t *number_vertices,ExceptionInfo *exception)
1236 number_hull_vertices;
1244 assert(image != (Image *) NULL);
1245 assert(image->signature == MagickCoreSignature);
1246 if (IsEventLogging() != MagickFalse)
1247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1249 vertices=GetImageConvexHull(image,&number_hull_vertices,exception);
1250 if (vertices == (PointInfo *) NULL)
1251 return((PointInfo *) NULL);
1253 bounding_box=(PointInfo *) AcquireQuantumMemory(*number_vertices,
1254 sizeof(*bounding_box));
1255 if (bounding_box == (PointInfo *) NULL)
1257 vertices=(PointInfo *) RelinquishMagickMemory(vertices);
1258 return((PointInfo *) NULL);
1260 caliper_info.area=2.0*image->columns*image->rows;
1261 caliper_info.width=(double) image->columns+image->rows;
1262 caliper_info.height=0.0;
1263 caliper_info.projection=0.0;
1264 caliper_info.p=(-1);
1265 caliper_info.q=(-1);
1266 caliper_info.v=(-1);
1267 for (i=0; i < (ssize_t) number_hull_vertices; i++)
1271 max_projection = 0.0,
1272 min_diameter = -1.0,
1273 min_projection = 0.0;
1284 for (j=0; j < (ssize_t) number_hull_vertices; j++)
1286 diameter=fabs(getFeretDiameter(&vertices[i],
1287 &vertices[(i+1) % (ssize_t) number_hull_vertices],&vertices[j]));
1288 if (min_diameter < diameter)
1290 min_diameter=diameter;
1292 q=(i+1) % (ssize_t) number_hull_vertices;
1296 for (k=0; k < (ssize_t) number_hull_vertices; k++)
1304 projection=getProjection(&vertices[p],&vertices[q],&vertices[k]);
1305 min_projection=MagickMin(min_projection,projection);
1306 max_projection=MagickMax(max_projection,projection);
1308 area=min_diameter*(max_projection-min_projection);
1309 if (caliper_info.area > area)
1311 caliper_info.area=area;
1312 caliper_info.width=min_diameter;
1313 caliper_info.height=max_projection-min_projection;
1314 caliper_info.projection=max_projection;
1319 if ((caliper_info.p < 0) || (caliper_info.q < 0) || (caliper_info.v < 0))
1321 vertices=(PointInfo *) RelinquishMagickMemory(vertices);
1322 bounding_box=(PointInfo *) RelinquishMagickMemory(bounding_box);
1324 return((PointInfo *) NULL);
1330 diameter=getFeretDiameter(&vertices[caliper_info.p],
1331 &vertices[caliper_info.q],&vertices[caliper_info.v]);
1332 angle=atan2(vertices[caliper_info.q].y-vertices[caliper_info.p].y,
1333 vertices[caliper_info.q].x-vertices[caliper_info.p].x);
1334 bounding_box[0].x=vertices[caliper_info.p].x+cos(angle)*
1335 caliper_info.projection;
1336 bounding_box[0].y=vertices[caliper_info.p].y+sin(angle)*
1337 caliper_info.projection;
1338 bounding_box[1].x=floor(bounding_box[0].x+cos(angle+MagickPI/2.0)*diameter+
1340 bounding_box[1].y=floor(bounding_box[0].y+sin(angle+MagickPI/2.0)*diameter+
1342 bounding_box[2].x=floor(bounding_box[1].x+cos(angle)*(-caliper_info.height)+
1344 bounding_box[2].y=floor(bounding_box[1].y+sin(angle)*(-caliper_info.height)+
1346 bounding_box[3].x=floor(bounding_box[2].x+cos(angle+MagickPI/2.0)*(-diameter)+
1348 bounding_box[3].y=floor(bounding_box[2].y+sin(angle+MagickPI/2.0)*(-diameter)+
1353 (void) FormatImageProperty(image,
"minimum-bounding-box:area",
"%.*g",
1354 GetMagickPrecision(),caliper_info.area);
1355 (void) FormatImageProperty(image,
"minimum-bounding-box:width",
"%.*g",
1356 GetMagickPrecision(),caliper_info.width);
1357 (void) FormatImageProperty(image,
"minimum-bounding-box:height",
"%.*g",
1358 GetMagickPrecision(),caliper_info.height);
1359 (void) FormatImageProperty(image,
"minimum-bounding-box:_p",
"%.*g,%.*g",
1360 GetMagickPrecision(),vertices[caliper_info.p].x,
1361 GetMagickPrecision(),vertices[caliper_info.p].y);
1362 (void) FormatImageProperty(image,
"minimum-bounding-box:_q",
"%.*g,%.*g",
1363 GetMagickPrecision(),vertices[caliper_info.q].x,
1364 GetMagickPrecision(),vertices[caliper_info.q].y);
1365 (void) FormatImageProperty(image,
"minimum-bounding-box:_v",
"%.*g,%.*g",
1366 GetMagickPrecision(),vertices[caliper_info.v].x,
1367 GetMagickPrecision(),vertices[caliper_info.v].y);
1371 distance=hypot(bounding_box[0].x,bounding_box[0].y);
1372 angle=getAngle(&bounding_box[0],&bounding_box[1]);
1373 for (i=1; i < 4; i++)
1375 double d = hypot(bounding_box[i].x,bounding_box[i].y);
1379 angle=getAngle(&bounding_box[i],&bounding_box[(i+1) % 4]);
1382 artifact=GetImageArtifact(image,
"minimum-bounding-box:orientation");
1383 if (artifact != (
const char *) NULL)
1397 point=bounding_box[0];
1398 for (i=1; i < 4; i++)
1400 if (bounding_box[i].x < point.x)
1401 point.x=bounding_box[i].x;
1402 if (bounding_box[i].y < point.y)
1403 point.y=bounding_box[i].y;
1405 for (i=0; i < 4; i++)
1407 bounding_box[i].x-=point.x;
1408 bounding_box[i].y-=point.y;
1410 for (i=0; i < 4; i++)
1417 delta.x=bounding_box[(i+1) % 4].x-bounding_box[i].x;
1418 delta.y=bounding_box[(i+1) % 4].y-bounding_box[i].y;
1419 slope=delta.y*MagickSafeReciprocal(delta.x);
1420 intercept=bounding_box[(i+1) % 4].y-slope*bounding_box[i].x;
1421 d=fabs((slope*bounding_box[i].x-bounding_box[i].y+intercept)*
1422 MagickSafeReciprocal(sqrt(slope*slope+1.0)));
1423 if ((i == 0) || (d < distance))
1429 angle=RadiansToDegrees(atan(point.y*MagickSafeReciprocal(point.x)));
1430 length=hypot(point.x,point.y);
1431 p_length=fabs((
double) MagickMax(caliper_info.width,caliper_info.height)-
1433 q_length=fabs(length-(
double) MagickMin(caliper_info.width,
1434 caliper_info.height));
1435 if (LocaleCompare(artifact,
"landscape") == 0)
1437 if (p_length > q_length)
1438 angle+=(angle < 0.0) ? 90.0 : -90.0;
1441 if (LocaleCompare(artifact,
"portrait") == 0)
1443 if (p_length < q_length)
1444 angle+=(angle >= 0.0) ? 90.0 : -90.0;
1447 (void) FormatImageProperty(image,
"minimum-bounding-box:angle",
"%.*g",
1448 GetMagickPrecision(),angle);
1449 (void) FormatImageProperty(image,
"minimum-bounding-box:unrotate",
"%.*g",
1450 GetMagickPrecision(),-angle);
1451 vertices=(PointInfo *) RelinquishMagickMemory(vertices);
1452 return(bounding_box);
1482MagickExport
size_t GetImageQuantumDepth(
const Image *image,
1483 const MagickBooleanType constrain)
1500 if (constrain != MagickFalse)
1501 depth=(size_t) MagickMin((
double) depth,(
double) MAGICKCORE_QUANTUM_DEPTH);
1531MagickExport ImageType GetImageType(
const Image *image)
1533 assert(image != (Image *) NULL);
1534 assert(image->signature == MagickCoreSignature);
1535 if (image->colorspace == CMYKColorspace)
1537 if ((image->alpha_trait & BlendPixelTrait) == 0)
1538 return(ColorSeparationType);
1539 return(ColorSeparationAlphaType);
1541 if (IsImageMonochrome(image) != MagickFalse)
1542 return(BilevelType);
1543 if (IsImageGray(image) != MagickFalse)
1545 if (image->alpha_trait != UndefinedPixelTrait)
1546 return(GrayscaleAlphaType);
1547 return(GrayscaleType);
1549 if (IsPaletteImage(image) != MagickFalse)
1551 if (image->alpha_trait != UndefinedPixelTrait)
1552 return(PaletteAlphaType);
1553 return(PaletteType);
1555 if (image->alpha_trait != UndefinedPixelTrait)
1556 return(TrueColorAlphaType);
1557 return(TrueColorType);
1586MagickExport ImageType IdentifyImageGray(
const Image *image,
1587 ExceptionInfo *exception)
1596 status = MagickTrue;
1601 assert(image != (Image *) NULL);
1602 assert(image->signature == MagickCoreSignature);
1603 if (IsEventLogging() != MagickFalse)
1604 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1605 if (IsImageGray(image) != MagickFalse)
1606 return(image->type);
1607 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1608 return(UndefinedType);
1609 image_view=AcquireVirtualCacheView(image,exception);
1610#if defined(MAGICKCORE_OPENMP_SUPPORT)
1611 #pragma omp parallel for schedule(static) shared(status,type) \
1612 magick_number_threads(image,image,image->rows,2)
1614 for (y=0; y < (ssize_t) image->rows; y++)
1622 if (status == MagickFalse)
1624 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1625 if (p == (
const Quantum *) NULL)
1630 for (x=0; x < (ssize_t) image->columns; x++)
1632 if (IsPixelGray(image,p) == MagickFalse)
1637 if ((type == BilevelType) && (IsPixelMonochrome(image,p) == MagickFalse))
1639 p+=(ptrdiff_t) GetPixelChannels(image);
1642 image_view=DestroyCacheView(image_view);
1643 if ((type == GrayscaleType) && (image->alpha_trait != UndefinedPixelTrait))
1644 type=GrayscaleAlphaType;
1645 if (status == MagickFalse)
1646 return(UndefinedType);
1677MagickExport MagickBooleanType IdentifyImageMonochrome(
const Image *image,
1678 ExceptionInfo *exception)
1689 assert(image != (Image *) NULL);
1690 assert(image->signature == MagickCoreSignature);
1691 if (IsEventLogging() != MagickFalse)
1692 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1693 if (image->type == BilevelType)
1695 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1696 return(MagickFalse);
1697 image_view=AcquireVirtualCacheView(image,exception);
1698#if defined(MAGICKCORE_OPENMP_SUPPORT)
1699 #pragma omp parallel for schedule(static) shared(type) \
1700 magick_number_threads(image,image,image->rows,2)
1702 for (y=0; y < (ssize_t) image->rows; y++)
1710 if (type == UndefinedType)
1712 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1713 if (p == (
const Quantum *) NULL)
1718 for (x=0; x < (ssize_t) image->columns; x++)
1720 if (IsPixelMonochrome(image,p) == MagickFalse)
1725 p+=(ptrdiff_t) GetPixelChannels(image);
1728 image_view=DestroyCacheView(image_view);
1729 return(type == BilevelType ? MagickTrue : MagickFalse);
1764MagickExport ImageType IdentifyImageType(
const Image *image,
1765 ExceptionInfo *exception)
1770 assert(image != (Image *) NULL);
1771 assert(image->signature == MagickCoreSignature);
1772 if (IsEventLogging() != MagickFalse)
1773 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1774 if (image->colorspace == CMYKColorspace)
1776 if ((image->alpha_trait & BlendPixelTrait) == 0)
1777 return(ColorSeparationType);
1778 return(ColorSeparationAlphaType);
1780 type=IdentifyImageGray(image,exception);
1781 if (IsGrayImageType(type))
1783 if (IdentifyPaletteImage(image,exception) != MagickFalse)
1785 if (image->alpha_trait != UndefinedPixelTrait)
1786 return(PaletteAlphaType);
1787 return(PaletteType);
1789 if (image->alpha_trait != UndefinedPixelTrait)
1790 return(TrueColorAlphaType);
1791 return(TrueColorType);
1817MagickExport MagickBooleanType IsImageGray(
const Image *image)
1819 assert(image != (Image *) NULL);
1820 assert(image->signature == MagickCoreSignature);
1821 if (IsGrayImageType(image->type) != MagickFalse)
1823 return(MagickFalse);
1848MagickExport MagickBooleanType IsImageMonochrome(
const Image *image)
1850 assert(image != (Image *) NULL);
1851 assert(image->signature == MagickCoreSignature);
1852 if (image->type == BilevelType)
1854 return(MagickFalse);
1885MagickExport MagickBooleanType IsImageOpaque(
const Image *image,
1886 ExceptionInfo *exception)
1892 opaque = MagickTrue;
1900 assert(image != (Image *) NULL);
1901 assert(image->signature == MagickCoreSignature);
1902 if (IsEventLogging() != MagickFalse)
1903 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1904 if ((image->alpha_trait & BlendPixelTrait) == 0)
1906 image_view=AcquireVirtualCacheView(image,exception);
1907#if defined(MAGICKCORE_OPENMP_SUPPORT)
1908 #pragma omp parallel for schedule(static) shared(opaque) \
1909 magick_number_threads(image,image,image->rows,2)
1911 for (y=0; y < (ssize_t) image->rows; y++)
1919 if (opaque == MagickFalse)
1921 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1922 if (p == (
const Quantum *) NULL)
1927 for (x=0; x < (ssize_t) image->columns; x++)
1929 if (GetPixelAlpha(image,p) != OpaqueAlpha)
1934 p+=(ptrdiff_t) GetPixelChannels(image);
1937 image_view=DestroyCacheView(image_view);
1971static MagickBooleanType FloydSteinbergImageDepth(Image *image,
1972 const size_t depth,ExceptionInfo *exception)
1995 status=SetImageStorageClass(image,DirectClass,exception);
1996 if (status == MagickFalse)
1997 return(MagickFalse);
1998 channels=GetPixelChannels(image);
1999 distortion=(
double *) AcquireQuantumMemory(image->columns,3*channels*
2000 sizeof(*distortion));
2001 if (distortion == (
double *) NULL)
2002 return(MagickFalse);
2003 (void) memset(distortion,0,3*image->columns*channels*
sizeof(*distortion));
2004 range=GetQuantumRange(depth);
2005 image_view=AcquireAuthenticCacheView(image,exception);
2006 for (y=0; y < (ssize_t) image->rows; y++)
2016 if (status == MagickFalse)
2018 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2019 if (q == (Quantum *) NULL)
2027 u=(y % 3)*(ssize_t) (image->columns*channels);
2028 (void) memset(distortion+u,0,image->columns*channels*
sizeof(*distortion));
2029 v=((y+1) % 3)*(ssize_t) (image->columns*channels);
2030 for (x=0; x < (ssize_t) image->columns; x++)
2035 for (i=0; i < (ssize_t) channels; i++)
2050 channel=GetPixelChannelChannel(image,i);
2051 traits=GetPixelChannelTraits(image,channel);
2052 if ((traits & UpdatePixelTrait) == 0)
2058 pixel=(double) q[i]+distortion[u];
2059 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(ClampPixel((MagickRealType)
2060 pixel),range),range);
2064 error=pixel-(double) q[i];
2065 if ((x+1) < (ssize_t) image->columns)
2066 distortion[u+(ssize_t) channels]+=7.0*error/16.0;
2067 if ((y+1) < (ssize_t) image->rows)
2073 distortion[v-(ssize_t) channels]+=3.0*error/16.0;
2074 distortion[v]+=5.0*error/16.0;
2075 if ((x+1) < (ssize_t) image->columns)
2076 distortion[v+(ssize_t) channels]+=1.0*error/16.0;
2081 q+=(ptrdiff_t) GetPixelChannels(image);
2083 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2089 image_view=DestroyCacheView(image_view);
2090 distortion=(
double *) RelinquishMagickMemory(distortion);
2091 if (status != MagickFalse)
2096MagickExport MagickBooleanType SetImageDepth(Image *image,
2097 const size_t depth,ExceptionInfo *exception)
2114 assert(image != (Image *) NULL);
2115 if (IsEventLogging() != MagickFalse)
2116 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
2117 assert(image->signature == MagickCoreSignature);
2118 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
2123 artifact=GetImageArtifact(image,
"dither");
2124 if ((artifact != (
const char *) NULL) &&
2125 (LocaleCompare(artifact,
"FloydSteinberg") == 0))
2126 return(FloydSteinbergImageDepth(image,depth,exception));
2127 range=GetQuantumRange(depth);
2128 if (image->storage_class == PseudoClass)
2133#if defined(MAGICKCORE_OPENMP_SUPPORT)
2134 #pragma omp parallel for schedule(static) shared(status) \
2135 magick_number_threads(image,image,image->colors,1)
2137 for (i=0; i < (ssize_t) image->colors; i++)
2139 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
2140 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
2141 ClampPixel(image->colormap[i].red),range),range);
2142 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
2143 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
2144 ClampPixel(image->colormap[i].green),range),range);
2145 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
2146 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
2147 ClampPixel(image->colormap[i].blue),range),range);
2148 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
2149 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
2150 ClampPixel(image->colormap[i].alpha),range),range);
2154 image_view=AcquireAuthenticCacheView(image,exception);
2155#if !defined(MAGICKCORE_HDRI_SUPPORT)
2156 DisableMSCWarning(4127)
2157 if ((1UL*QuantumRange) <= MaxMap)
2169 depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,
sizeof(*depth_map));
2170 if (depth_map == (Quantum *) NULL)
2171 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
2172 for (i=0; i <= (ssize_t) MaxMap; i++)
2173 depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
2175#if defined(MAGICKCORE_OPENMP_SUPPORT)
2176 #pragma omp parallel for schedule(static) shared(status) \
2177 magick_number_threads(image,image,image->rows,2)
2179 for (y=0; y < (ssize_t) image->rows; y++)
2187 if (status == MagickFalse)
2189 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2191 if (q == (Quantum *) NULL)
2196 for (x=0; x < (ssize_t) image->columns; x++)
2201 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
2209 channel=GetPixelChannelChannel(image,j);
2210 traits=GetPixelChannelTraits(image,channel);
2211 if ((traits & UpdatePixelTrait) == 0)
2213 q[j]=depth_map[ScaleQuantumToMap(q[j])];
2215 q+=(ptrdiff_t) GetPixelChannels(image);
2217 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2223 image_view=DestroyCacheView(image_view);
2224 depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
2225 if (status != MagickFalse)
2233#if defined(MAGICKCORE_OPENMP_SUPPORT)
2234 #pragma omp parallel for schedule(static) shared(status) \
2235 magick_number_threads(image,image,image->rows,2)
2237 for (y=0; y < (ssize_t) image->rows; y++)
2245 if (status == MagickFalse)
2247 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2248 if (q == (Quantum *) NULL)
2253 for (x=0; x < (ssize_t) image->columns; x++)
2258 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2266 channel=GetPixelChannelChannel(image,i);
2267 traits=GetPixelChannelTraits(image,channel);
2268 if ((traits & UpdatePixelTrait) == 0)
2270 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(ClampPixel((MagickRealType)
2271 q[i]),range),range);
2273 q+=(ptrdiff_t) GetPixelChannels(image);
2275 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2281 image_view=DestroyCacheView(image_view);
2282 if (status != MagickFalse)
2319MagickExport MagickBooleanType SetImageType(Image *image,
const ImageType type,
2320 ExceptionInfo *exception)
2334 assert(image != (Image *) NULL);
2335 if (IsEventLogging() != MagickFalse)
2336 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
2337 assert(image->signature == MagickCoreSignature);
2339 image_info=AcquireImageInfo();
2340 image_info->dither=image->dither;
2341 artifact=GetImageArtifact(image,
"dither");
2342 if (artifact != (
const char *) NULL)
2343 (void) SetImageOption(image_info,
"dither",artifact);
2348 if (IsGrayImageType(image->type) == MagickFalse)
2349 status=TransformImageColorspace(image,GRAYColorspace,exception);
2350 (void) NormalizeImage(image,exception);
2351 (void) BilevelImage(image,(
double) QuantumRange/2.0,exception);
2352 quantize_info=AcquireQuantizeInfo(image_info);
2353 quantize_info->number_colors=2;
2354 quantize_info->colorspace=GRAYColorspace;
2355 status=QuantizeImage(quantize_info,image,exception);
2356 quantize_info=DestroyQuantizeInfo(quantize_info);
2357 image->alpha_trait=UndefinedPixelTrait;
2362 if (IsGrayImageType(image->type) == MagickFalse)
2363 status=TransformImageColorspace(image,GRAYColorspace,exception);
2364 image->alpha_trait=UndefinedPixelTrait;
2367 case GrayscaleAlphaType:
2369 if (IsGrayImageType(image->type) == MagickFalse)
2370 status=TransformImageColorspace(image,GRAYColorspace,exception);
2371 if ((image->alpha_trait & BlendPixelTrait) == 0)
2372 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
2377 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2378 status=TransformImageColorspace(image,sRGBColorspace,exception);
2379 if ((image->storage_class == DirectClass) || (image->colors > 256))
2381 quantize_info=AcquireQuantizeInfo(image_info);
2382 quantize_info->number_colors=256;
2383 status=QuantizeImage(quantize_info,image,exception);
2384 quantize_info=DestroyQuantizeInfo(quantize_info);
2386 image->alpha_trait=UndefinedPixelTrait;
2389 case PaletteBilevelAlphaType:
2394 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2395 status=TransformImageColorspace(image,sRGBColorspace,exception);
2396 if ((image->alpha_trait & BlendPixelTrait) == 0)
2397 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
2398 channel_mask=SetImageChannelMask(image,AlphaChannel);
2399 (void) BilevelImage(image,(
double) QuantumRange/2.0,exception);
2400 (void) SetImageChannelMask(image,channel_mask);
2401 quantize_info=AcquireQuantizeInfo(image_info);
2402 status=QuantizeImage(quantize_info,image,exception);
2403 quantize_info=DestroyQuantizeInfo(quantize_info);
2406 case PaletteAlphaType:
2408 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2409 status=TransformImageColorspace(image,sRGBColorspace,exception);
2410 if ((image->alpha_trait & BlendPixelTrait) == 0)
2411 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
2412 quantize_info=AcquireQuantizeInfo(image_info);
2413 status=QuantizeImage(quantize_info,image,exception);
2414 quantize_info=DestroyQuantizeInfo(quantize_info);
2419 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2420 status=TransformImageColorspace(image,sRGBColorspace,exception);
2421 if (image->storage_class != DirectClass)
2422 status=SetImageStorageClass(image,DirectClass,exception);
2423 image->alpha_trait=UndefinedPixelTrait;
2426 case TrueColorAlphaType:
2428 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2429 status=TransformImageColorspace(image,sRGBColorspace,exception);
2430 if (image->storage_class != DirectClass)
2431 status=SetImageStorageClass(image,DirectClass,exception);
2432 if ((image->alpha_trait & BlendPixelTrait) == 0)
2433 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
2436 case ColorSeparationType:
2438 if (image->colorspace != CMYKColorspace)
2439 status=TransformImageColorspace(image,CMYKColorspace,exception);
2440 if (image->storage_class != DirectClass)
2441 status=SetImageStorageClass(image,DirectClass,exception);
2442 image->alpha_trait=UndefinedPixelTrait;
2445 case ColorSeparationAlphaType:
2447 if (image->colorspace != CMYKColorspace)
2448 status=TransformImageColorspace(image,CMYKColorspace,exception);
2449 if (image->storage_class != DirectClass)
2450 status=SetImageStorageClass(image,DirectClass,exception);
2451 if ((image->alpha_trait & BlendPixelTrait) == 0)
2452 status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
2459 image_info=DestroyImageInfo(image_info);
2460 if (status == MagickFalse)