43#include "magick/studio.h"
44#include "magick/cache-private.h"
45#include "magick/channel.h"
46#include "magick/color-private.h"
47#include "magick/colorspace-private.h"
48#include "magick/composite-private.h"
49#include "magick/exception-private.h"
50#include "magick/enhance.h"
51#include "magick/image.h"
52#include "magick/list.h"
53#include "magick/log.h"
54#include "magick/monitor.h"
55#include "magick/monitor-private.h"
56#include "magick/option.h"
57#include "magick/pixel-accessor.h"
58#include "magick/resource_.h"
59#include "magick/string-private.h"
60#include "magick/thread-private.h"
61#include "magick/token.h"
62#include "magick/utility.h"
63#include "magick/version.h"
93MagickExport
Image *CombineImages(
const Image *image,
const ChannelType channel,
96#define CombineImageTag "Combine/Image"
119 assert(image != (
const Image *) NULL);
120 assert(image->signature == MagickCoreSignature);
121 if (IsEventLogging() != MagickFalse)
122 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
124 assert(exception->signature == MagickCoreSignature);
125 for (next=image; next != (
Image *) NULL; next=GetNextImageInList(next))
127 if ((next->columns != image->columns) || (next->rows != image->rows))
128 ThrowImageException(OptionError,
"ImagesAreNotTheSameSize");
130 combine_image=CloneImage(image,0,0,MagickTrue,exception);
131 if (combine_image == (
Image *) NULL)
132 return((
Image *) NULL);
133 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
135 InheritException(exception,&combine_image->exception);
136 combine_image=DestroyImage(combine_image);
137 return((
Image *) NULL);
139 if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse)
141 if (fabs(image->gamma-1.0) <= MagickEpsilon)
142 (void) SetImageColorspace(combine_image,RGBColorspace);
144 (
void) SetImageColorspace(combine_image,sRGBColorspace);
146 if ((channel & OpacityChannel) != 0)
147 combine_image->matte=MagickTrue;
148 (void) SetImageBackgroundColor(combine_image);
154 combine_view=AcquireAuthenticCacheView(combine_image,exception);
155#if defined(MAGICKCORE_OPENMP_SUPPORT)
156 #pragma omp parallel for schedule(static) shared(progress,status) \
157 magick_number_threads(combine_image,combine_image,combine_image->rows,4)
159 for (y=0; y < (ssize_t) combine_image->rows; y++)
179 if (status == MagickFalse)
181 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
189 if (((channel & RedChannel) != 0) && (next != (
Image *) NULL))
191 image_view=AcquireVirtualCacheView(next,exception);
192 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
196 for (x=0; x < (ssize_t) combine_image->columns; x++)
198 SetPixelRed(q,ClampToQuantum(GetPixelIntensity(image,p)));
202 image_view=DestroyCacheView(image_view);
203 next=GetNextImageInList(next);
205 if (((channel & GreenChannel) != 0) && (next != (
Image *) NULL))
207 image_view=AcquireVirtualCacheView(next,exception);
208 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
212 for (x=0; x < (ssize_t) combine_image->columns; x++)
214 SetPixelGreen(q,ClampToQuantum(GetPixelIntensity(image,p)));
218 image_view=DestroyCacheView(image_view);
219 next=GetNextImageInList(next);
221 if (((channel & BlueChannel) != 0) && (next != (
Image *) NULL))
223 image_view=AcquireVirtualCacheView(next,exception);
224 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
228 for (x=0; x < (ssize_t) combine_image->columns; x++)
230 SetPixelBlue(q,ClampToQuantum(GetPixelIntensity(image,p)));
234 image_view=DestroyCacheView(image_view);
235 next=GetNextImageInList(next);
237 if (((channel & OpacityChannel) != 0) && (next != (
Image *) NULL))
239 image_view=AcquireVirtualCacheView(next,exception);
240 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
244 for (x=0; x < (ssize_t) combine_image->columns; x++)
246 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,p)));
250 image_view=DestroyCacheView(image_view);
251 next=GetNextImageInList(next);
253 if (((channel & IndexChannel) != 0) &&
254 (image->colorspace == CMYKColorspace) && (next != (
Image *) NULL))
259 image_view=AcquireVirtualCacheView(next,exception);
260 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
263 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
264 for (x=0; x < (ssize_t) combine_image->columns; x++)
266 SetPixelIndex(indexes+x,ClampToQuantum(GetPixelIntensity(image,p)));
269 image_view=DestroyCacheView(image_view);
270 next=GetNextImageInList(next);
272 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
274 if (image->progress_monitor != (MagickProgressMonitor) NULL)
279#if defined(MAGICKCORE_OPENMP_SUPPORT)
283 proceed=SetImageProgress(image,CombineImageTag,progress,
284 combine_image->rows);
285 if (proceed == MagickFalse)
289 combine_view=DestroyCacheView(combine_view);
290 if (IsGrayColorspace(combine_image->colorspace) != MagickFalse)
291 (void) TransformImageColorspace(combine_image,sRGBColorspace);
292 if (status == MagickFalse)
293 combine_image=DestroyImage(combine_image);
294 return(combine_image);
321MagickExport MagickBooleanType GetImageAlphaChannel(
const Image *image)
323 assert(image != (
const Image *) NULL);
324 if (IsEventLogging() != MagickFalse)
325 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
326 assert(image->signature == MagickCoreSignature);
327 return(image->matte);
360MagickExport
Image *SeparateImage(
const Image *image,
const ChannelType channel,
372 assert(image != (
Image *) NULL);
373 assert(image->signature == MagickCoreSignature);
374 if (IsEventLogging() != MagickFalse)
375 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
377 assert(exception->signature == MagickCoreSignature);
378 separate_image=CloneImage(image,0,0,MagickTrue,exception);
379 if (separate_image == (
Image *) NULL)
380 return((
Image *) NULL);
381 status=SeparateImageChannel(separate_image,channel);
382 if (status == MagickFalse)
383 separate_image=DestroyImage(separate_image);
384 return(separate_image);
387MagickExport MagickBooleanType SeparateImageChannel(
Image *image,
388 const ChannelType channel)
390#define SeparateImageTag "Separate/Image"
407 assert(image != (
Image *) NULL);
408 assert(image->signature == MagickCoreSignature);
409 if (IsEventLogging() != MagickFalse)
410 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
411 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
413 if (channel == GrayChannels)
414 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
420 exception=(&image->exception);
421 image_view=AcquireAuthenticCacheView(image,exception);
422#if defined(MAGICKCORE_OPENMP_SUPPORT)
423 #pragma omp parallel for schedule(static) shared(progress,status) \
424 magick_number_threads(image,image,image->rows,2)
426 for (y=0; y < (ssize_t) image->rows; y++)
429 *magick_restrict indexes;
437 if (status == MagickFalse)
439 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
445 indexes=GetCacheViewAuthenticIndexQueue(image_view);
450 for (x=0; x < (ssize_t) image->columns; x++)
452 SetPixelGreen(q,GetPixelRed(q));
453 SetPixelBlue(q,GetPixelRed(q));
460 for (x=0; x < (ssize_t) image->columns; x++)
462 SetPixelRed(q,GetPixelGreen(q));
463 SetPixelBlue(q,GetPixelGreen(q));
470 for (x=0; x < (ssize_t) image->columns; x++)
472 SetPixelRed(q,GetPixelBlue(q));
473 SetPixelGreen(q,GetPixelBlue(q));
480 for (x=0; x < (ssize_t) image->columns; x++)
482 SetPixelRed(q,GetPixelOpacity(q));
483 SetPixelGreen(q,GetPixelOpacity(q));
484 SetPixelBlue(q,GetPixelOpacity(q));
491 if ((image->storage_class != PseudoClass) &&
492 (image->colorspace != CMYKColorspace))
494 for (x=0; x < (ssize_t) image->columns; x++)
496 SetPixelRed(q,GetPixelIndex(indexes+x));
497 SetPixelGreen(q,GetPixelIndex(indexes+x));
498 SetPixelBlue(q,GetPixelIndex(indexes+x));
503 case TrueAlphaChannel:
505 for (x=0; x < (ssize_t) image->columns; x++)
507 SetPixelRed(q,GetPixelAlpha(q));
508 SetPixelGreen(q,GetPixelAlpha(q));
509 SetPixelBlue(q,GetPixelAlpha(q));
516 for (x=0; x < (ssize_t) image->columns; x++)
518 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,q)));
526 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
528 if (image->progress_monitor != (MagickProgressMonitor) NULL)
533#if defined(MAGICKCORE_OPENMP_SUPPORT)
537 proceed=SetImageProgress(image,SeparateImageTag,progress,image->rows);
538 if (proceed == MagickFalse)
542 image_view=DestroyCacheView(image_view);
543 if (channel != GrayChannels)
545 image->matte=MagickFalse;
546 (void) SetImageColorspace(image,GRAYColorspace);
581MagickExport
Image *SeparateImages(
const Image *image,
const ChannelType channel,
588 assert(image != (
Image *) NULL);
589 assert(image->signature == MagickCoreSignature);
590 if (IsEventLogging() != MagickFalse)
591 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
592 images=NewImageList();
593 if ((channel & RedChannel) != 0)
595 separate_image=CloneImage(image,0,0,MagickTrue,exception);
596 (void) SeparateImageChannel(separate_image,RedChannel);
597 AppendImageToList(&images,separate_image);
599 if ((channel & GreenChannel) != 0)
601 separate_image=CloneImage(image,0,0,MagickTrue,exception);
602 (void) SeparateImageChannel(separate_image,GreenChannel);
603 AppendImageToList(&images,separate_image);
605 if ((channel & BlueChannel) != 0)
607 separate_image=CloneImage(image,0,0,MagickTrue,exception);
608 (void) SeparateImageChannel(separate_image,BlueChannel);
609 AppendImageToList(&images,separate_image);
611 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
613 separate_image=CloneImage(image,0,0,MagickTrue,exception);
614 (void) SeparateImageChannel(separate_image,BlackChannel);
615 AppendImageToList(&images,separate_image);
617 if ((channel & AlphaChannel) != 0)
619 separate_image=CloneImage(image,0,0,MagickTrue,exception);
620 (void) SeparateImageChannel(separate_image,TrueAlphaChannel);
621 AppendImageToList(&images,separate_image);
656MagickExport MagickBooleanType SetImageAlphaChannel(
Image *image,
657 const AlphaChannelType alpha_type)
671 assert(image != (
Image *) NULL);
672 if (IsEventLogging() != MagickFalse)
673 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
674 assert(image->signature == MagickCoreSignature);
675 exception=(&image->exception);
679 case ActivateAlphaChannel:
681 if (image->matte == MagickTrue)
683 image->matte=MagickTrue;
686 case AssociateAlphaChannel:
691 status=SetImageStorageClass(image,DirectClass);
692 if (status == MagickFalse)
694 image_view=AcquireAuthenticCacheView(image,exception);
695 #if defined(MAGICKCORE_OPENMP_SUPPORT)
696 #pragma omp parallel for schedule(static) shared(status) \
697 magick_number_threads(image,image,image->rows,2)
699 for (y=0; y < (ssize_t) image->rows; y++)
707 if (status == MagickFalse)
709 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
716 for (x=0; x < (ssize_t) image->columns; x++)
721 gamma=QuantumScale*(double) GetPixelAlpha(q);
722 SetPixelRed(q,ClampToQuantum(gamma*(
double) GetPixelRed(q)));
723 SetPixelGreen(q,ClampToQuantum(gamma*(
double) GetPixelGreen(q)));
724 SetPixelBlue(q,ClampToQuantum(gamma*(
double) GetPixelBlue(q)));
727 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
730 image_view=DestroyCacheView(image_view);
731 image->matte=MagickFalse;
734 case BackgroundAlphaChannel:
751 if (image->matte == MagickFalse)
753 status=SetImageStorageClass(image,DirectClass);
754 if (status == MagickFalse)
756 GetMagickPixelPacket(image,&background);
757 SetMagickPixelPacket(image,&image->background_color,(
const IndexPacket *)
759 if (image->colorspace == CMYKColorspace)
760 ConvertRGBToCMYK(&background);
762 SetPixelPacket(image,&background,&pixel,&index);
764 exception=(&image->exception);
765 image_view=AcquireAuthenticCacheView(image,exception);
766 #if defined(MAGICKCORE_OPENMP_SUPPORT)
767 #pragma omp parallel for schedule(static) shared(status) \
768 magick_number_threads(image,image,image->rows,2)
770 for (y=0; y < (ssize_t) image->rows; y++)
773 *magick_restrict indexes;
781 if (status == MagickFalse)
783 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
790 for (x=0; x < (ssize_t) image->columns; x++)
792 if (q->opacity == TransparentOpacity)
794 SetPixelRed(q,pixel.red);
795 SetPixelGreen(q,pixel.green);
796 SetPixelBlue(q,pixel.blue);
800 if (image->colorspace == CMYKColorspace)
802 indexes=GetCacheViewAuthenticIndexQueue(image_view);
803 for (x=0; x < (ssize_t) image->columns; x++)
804 SetPixelIndex(indexes+x,index);
806 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
809 image_view=DestroyCacheView(image_view);
812 case CopyAlphaChannel:
813 case ShapeAlphaChannel:
819 status=SeparateImageChannel(image,GrayChannels);
820 image->matte=MagickTrue;
821 if (alpha_type == ShapeAlphaChannel)
829 GetMagickPixelPacket(image,&background);
830 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
832 (void) LevelColorsImage(image,&background,&background,MagickTrue);
836 case DeactivateAlphaChannel:
838 if (image->matte == MagickFalse)
840 image->matte=MagickFalse;
843 case DisassociateAlphaChannel:
845 status=SetImageStorageClass(image,DirectClass);
846 if (status == MagickFalse)
848 image->matte=MagickTrue;
849 image_view=AcquireAuthenticCacheView(image,exception);
850 #if defined(MAGICKCORE_OPENMP_SUPPORT)
851 #pragma omp parallel for schedule(static) shared(status) \
852 magick_number_threads(image,image,image->rows,2)
854 for (y=0; y < (ssize_t) image->rows; y++)
862 if (status == MagickFalse)
864 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
871 for (x=0; x < (ssize_t) image->columns; x++)
877 alpha=QuantumScale*(double) GetPixelAlpha(q);
878 gamma=PerceptibleReciprocal(alpha);
879 SetPixelRed(q,ClampToQuantum(gamma*(
double) GetPixelRed(q)));
880 SetPixelGreen(q,ClampToQuantum(gamma*(
double) GetPixelGreen(q)));
881 SetPixelBlue(q,ClampToQuantum(gamma*(
double) GetPixelBlue(q)));
884 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
887 image_view=DestroyCacheView(image_view);
888 image->matte=MagickFalse;
891 case ExtractAlphaChannel:
893 status=SeparateImageChannel(image,TrueAlphaChannel);
894 image->matte=MagickFalse;
897 case OffIfOpaqueAlphaChannel:
905 image_view=AcquireVirtualCacheView(image,exception);
906 #if defined(MAGICKCORE_OPENMP_SUPPORT)
907 #pragma omp parallel for schedule(static) shared(opaque,status) \
908 magick_number_threads(image,image,image->rows,2)
910 for (y=0; y < (ssize_t) image->rows; y++)
918 if ((status == MagickFalse) || (opaque == MagickFalse))
920 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
926 for (x=0; x < (ssize_t) image->columns; x++)
928 if (GetPixelOpacity(p) != OpaqueOpacity)
936 image_view=DestroyCacheView(image_view);
937 if (opaque != MagickFalse)
938 image->matte=MagickFalse;
941 case ResetAlphaChannel:
942 case RemoveAlphaChannel:
943 case FlattenAlphaChannel:
957 if (image->matte == MagickFalse)
959 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
961 GetMagickPixelPacket(image,&background);
962 SetMagickPixelPacket(image,&image->background_color,(
const IndexPacket *)
964 if (image->colorspace == CMYKColorspace)
965 ConvertRGBToCMYK(&background);
966 (void) memset(&pixel,0,
sizeof(pixel));
968 SetPixelPacket(image,&background,&pixel,&index);
969 image_view=AcquireAuthenticCacheView(image,exception);
970 #if defined(MAGICKCORE_OPENMP_SUPPORT)
971 #pragma omp parallel for schedule(static) shared(status) \
972 magick_number_threads(image,image,image->rows,2)
974 for (y=0; y < (ssize_t) image->rows; y++)
977 *magick_restrict indexes;
985 if (status == MagickFalse)
987 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
994 for (x=0; x < (ssize_t) image->columns; x++)
1000 gamma=1.0-QuantumScale*QuantumScale*(double) q->opacity*(
double)
1002 opacity=(double) QuantumRange*(1.0-gamma);
1003 gamma=PerceptibleReciprocal(gamma);
1004 q->red=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->red,
1005 (MagickRealType) q->opacity,(MagickRealType) pixel.red,
1006 (MagickRealType) pixel.opacity));
1007 q->green=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->green,
1008 (MagickRealType) q->opacity,(MagickRealType) pixel.green,
1009 (MagickRealType) pixel.opacity));
1010 q->blue=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->blue,
1011 (MagickRealType) q->opacity,(MagickRealType) pixel.blue,
1012 (MagickRealType) pixel.opacity));
1013 q->opacity=ClampToQuantum(opacity);
1016 if (image->colorspace == CMYKColorspace)
1018 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1019 for (x=0; x < (ssize_t) image->columns; x++)
1020 SetPixelIndex(indexes+x,index);
1022 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1025 image_view=DestroyCacheView(image_view);
1028 case OpaqueAlphaChannel:
1030 status=SetImageOpacity(image,OpaqueOpacity);
1033 case SetAlphaChannel:
1035 if (image->matte == MagickFalse)
1036 status=SetImageOpacity(image,OpaqueOpacity);
1039 case TransparentAlphaChannel:
1041 status=SetImageOpacity(image,TransparentOpacity);
1044 case UndefinedAlphaChannel:
1047 if (status == MagickFalse)
1049 return(SyncImagePixelCache(image,&image->exception));