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,
94 ExceptionInfo *exception)
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);
123 assert(exception != (ExceptionInfo *) NULL);
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,
183 if (pixels == (PixelPacket *) NULL)
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);
193 if (p == (
const PixelPacket *) NULL)
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);
209 if (p == (
const PixelPacket *) NULL)
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);
225 if (p == (
const PixelPacket *) NULL)
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);
241 if (p == (
const PixelPacket *) NULL)
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);
261 if (p == (
const PixelPacket *) NULL)
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);
295 combine_image->type=UndefinedType;
296 return(combine_image);
323MagickExport MagickBooleanType GetImageAlphaChannel(
const Image *image)
325 assert(image != (
const Image *) NULL);
326 if (IsEventLogging() != MagickFalse)
327 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
328 assert(image->signature == MagickCoreSignature);
329 return(image->matte);
362MagickExport Image *SeparateImage(
const Image *image,
const ChannelType channel,
363 ExceptionInfo *exception)
374 assert(image != (Image *) NULL);
375 assert(image->signature == MagickCoreSignature);
376 if (IsEventLogging() != MagickFalse)
377 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
378 assert(exception != (ExceptionInfo *) NULL);
379 assert(exception->signature == MagickCoreSignature);
380 separate_image=CloneImage(image,0,0,MagickTrue,exception);
381 if (separate_image == (Image *) NULL)
382 return((Image *) NULL);
383 status=SeparateImageChannel(separate_image,channel);
384 if (status == MagickFalse)
385 separate_image=DestroyImage(separate_image);
386 return(separate_image);
389MagickExport MagickBooleanType SeparateImageChannel(Image *image,
390 const ChannelType channel)
392#define SeparateImageTag "Separate/Image"
409 assert(image != (Image *) NULL);
410 assert(image->signature == MagickCoreSignature);
411 if (IsEventLogging() != MagickFalse)
412 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
413 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
415 if (channel == GrayChannels)
416 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
422 exception=(&image->exception);
423 image_view=AcquireAuthenticCacheView(image,exception);
424#if defined(MAGICKCORE_OPENMP_SUPPORT)
425 #pragma omp parallel for schedule(static) shared(progress,status) \
426 magick_number_threads(image,image,image->rows,2)
428 for (y=0; y < (ssize_t) image->rows; y++)
431 *magick_restrict indexes;
439 if (status == MagickFalse)
441 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
442 if (q == (PixelPacket *) NULL)
447 indexes=GetCacheViewAuthenticIndexQueue(image_view);
452 for (x=0; x < (ssize_t) image->columns; x++)
454 SetPixelGreen(q,GetPixelRed(q));
455 SetPixelBlue(q,GetPixelRed(q));
462 for (x=0; x < (ssize_t) image->columns; x++)
464 SetPixelRed(q,GetPixelGreen(q));
465 SetPixelBlue(q,GetPixelGreen(q));
472 for (x=0; x < (ssize_t) image->columns; x++)
474 SetPixelRed(q,GetPixelBlue(q));
475 SetPixelGreen(q,GetPixelBlue(q));
482 for (x=0; x < (ssize_t) image->columns; x++)
484 SetPixelRed(q,GetPixelOpacity(q));
485 SetPixelGreen(q,GetPixelOpacity(q));
486 SetPixelBlue(q,GetPixelOpacity(q));
493 if ((image->storage_class != PseudoClass) &&
494 (image->colorspace != CMYKColorspace))
496 for (x=0; x < (ssize_t) image->columns; x++)
498 SetPixelRed(q,GetPixelIndex(indexes+x));
499 SetPixelGreen(q,GetPixelIndex(indexes+x));
500 SetPixelBlue(q,GetPixelIndex(indexes+x));
505 case TrueAlphaChannel:
507 for (x=0; x < (ssize_t) image->columns; x++)
509 SetPixelRed(q,GetPixelAlpha(q));
510 SetPixelGreen(q,GetPixelAlpha(q));
511 SetPixelBlue(q,GetPixelAlpha(q));
518 for (x=0; x < (ssize_t) image->columns; x++)
520 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,q)));
528 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
530 if (image->progress_monitor != (MagickProgressMonitor) NULL)
535#if defined(MAGICKCORE_OPENMP_SUPPORT)
539 proceed=SetImageProgress(image,SeparateImageTag,progress,image->rows);
540 if (proceed == MagickFalse)
544 image_view=DestroyCacheView(image_view);
545 if (channel != GrayChannels)
547 image->matte=MagickFalse;
548 (void) SetImageColorspace(image,GRAYColorspace);
583MagickExport Image *SeparateImages(
const Image *image,
const ChannelType channel,
584 ExceptionInfo *exception)
590 assert(image != (Image *) NULL);
591 assert(image->signature == MagickCoreSignature);
592 if (IsEventLogging() != MagickFalse)
593 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
594 images=NewImageList();
595 if ((channel & RedChannel) != 0)
597 separate_image=CloneImage(image,0,0,MagickTrue,exception);
598 (void) SeparateImageChannel(separate_image,RedChannel);
599 AppendImageToList(&images,separate_image);
601 if ((channel & GreenChannel) != 0)
603 separate_image=CloneImage(image,0,0,MagickTrue,exception);
604 (void) SeparateImageChannel(separate_image,GreenChannel);
605 AppendImageToList(&images,separate_image);
607 if ((channel & BlueChannel) != 0)
609 separate_image=CloneImage(image,0,0,MagickTrue,exception);
610 (void) SeparateImageChannel(separate_image,BlueChannel);
611 AppendImageToList(&images,separate_image);
613 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
615 separate_image=CloneImage(image,0,0,MagickTrue,exception);
616 (void) SeparateImageChannel(separate_image,BlackChannel);
617 AppendImageToList(&images,separate_image);
619 if ((channel & AlphaChannel) != 0)
621 separate_image=CloneImage(image,0,0,MagickTrue,exception);
622 (void) SeparateImageChannel(separate_image,TrueAlphaChannel);
623 AppendImageToList(&images,separate_image);
658MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
659 const AlphaChannelType alpha_type)
673 assert(image != (Image *) NULL);
674 if (IsEventLogging() != MagickFalse)
675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
676 assert(image->signature == MagickCoreSignature);
677 exception=(&image->exception);
681 case ActivateAlphaChannel:
683 if (image->matte == MagickTrue)
685 image->matte=MagickTrue;
688 case AssociateAlphaChannel:
693 status=SetImageStorageClass(image,DirectClass);
694 if (status == MagickFalse)
696 image_view=AcquireAuthenticCacheView(image,exception);
697 #if defined(MAGICKCORE_OPENMP_SUPPORT)
698 #pragma omp parallel for schedule(static) shared(status) \
699 magick_number_threads(image,image,image->rows,2)
701 for (y=0; y < (ssize_t) image->rows; y++)
709 if (status == MagickFalse)
711 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
713 if (q == (PixelPacket *) NULL)
718 for (x=0; x < (ssize_t) image->columns; x++)
723 gamma=QuantumScale*(double) GetPixelAlpha(q);
724 SetPixelRed(q,ClampToQuantum(gamma*(
double) GetPixelRed(q)));
725 SetPixelGreen(q,ClampToQuantum(gamma*(
double) GetPixelGreen(q)));
726 SetPixelBlue(q,ClampToQuantum(gamma*(
double) GetPixelBlue(q)));
729 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
732 image_view=DestroyCacheView(image_view);
733 image->matte=MagickFalse;
736 case BackgroundAlphaChannel:
753 if (image->matte == MagickFalse)
755 status=SetImageStorageClass(image,DirectClass);
756 if (status == MagickFalse)
758 GetMagickPixelPacket(image,&background);
759 SetMagickPixelPacket(image,&image->background_color,(
const IndexPacket *)
761 if (image->colorspace == CMYKColorspace)
762 ConvertRGBToCMYK(&background);
764 SetPixelPacket(image,&background,&pixel,&index);
766 exception=(&image->exception);
767 image_view=AcquireAuthenticCacheView(image,exception);
768 #if defined(MAGICKCORE_OPENMP_SUPPORT)
769 #pragma omp parallel for schedule(static) shared(status) \
770 magick_number_threads(image,image,image->rows,2)
772 for (y=0; y < (ssize_t) image->rows; y++)
775 *magick_restrict indexes;
783 if (status == MagickFalse)
785 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
787 if (q == (PixelPacket *) NULL)
792 for (x=0; x < (ssize_t) image->columns; x++)
794 if (q->opacity == TransparentOpacity)
796 SetPixelRed(q,pixel.red);
797 SetPixelGreen(q,pixel.green);
798 SetPixelBlue(q,pixel.blue);
802 if (image->colorspace == CMYKColorspace)
804 indexes=GetCacheViewAuthenticIndexQueue(image_view);
805 for (x=0; x < (ssize_t) image->columns; x++)
806 SetPixelIndex(indexes+x,index);
808 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
811 image_view=DestroyCacheView(image_view);
814 case CopyAlphaChannel:
815 case ShapeAlphaChannel:
821 status=SeparateImageChannel(image,GrayChannels);
822 image->matte=MagickTrue;
823 if (alpha_type == ShapeAlphaChannel)
831 GetMagickPixelPacket(image,&background);
832 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
834 (void) LevelColorsImage(image,&background,&background,MagickTrue);
838 case DeactivateAlphaChannel:
840 if (image->matte == MagickFalse)
842 image->matte=MagickFalse;
845 case DisassociateAlphaChannel:
847 status=SetImageStorageClass(image,DirectClass);
848 if (status == MagickFalse)
850 image->matte=MagickTrue;
851 image_view=AcquireAuthenticCacheView(image,exception);
852 #if defined(MAGICKCORE_OPENMP_SUPPORT)
853 #pragma omp parallel for schedule(static) shared(status) \
854 magick_number_threads(image,image,image->rows,2)
856 for (y=0; y < (ssize_t) image->rows; y++)
864 if (status == MagickFalse)
866 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
868 if (q == (PixelPacket *) NULL)
873 for (x=0; x < (ssize_t) image->columns; x++)
879 alpha=QuantumScale*(double) GetPixelAlpha(q);
880 gamma=MagickSafeReciprocal(alpha);
881 SetPixelRed(q,ClampToQuantum(gamma*(
double) GetPixelRed(q)));
882 SetPixelGreen(q,ClampToQuantum(gamma*(
double) GetPixelGreen(q)));
883 SetPixelBlue(q,ClampToQuantum(gamma*(
double) GetPixelBlue(q)));
886 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
889 image_view=DestroyCacheView(image_view);
890 image->matte=MagickFalse;
893 case ExtractAlphaChannel:
895 status=SeparateImageChannel(image,TrueAlphaChannel);
896 image->matte=MagickFalse;
899 case OffIfOpaqueAlphaChannel:
907 image_view=AcquireVirtualCacheView(image,exception);
908 #if defined(MAGICKCORE_OPENMP_SUPPORT)
909 #pragma omp parallel for schedule(static) shared(opaque,status) \
910 magick_number_threads(image,image,image->rows,2)
912 for (y=0; y < (ssize_t) image->rows; y++)
920 if ((status == MagickFalse) || (opaque == MagickFalse))
922 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
923 if (p == (
const PixelPacket *) NULL)
928 for (x=0; x < (ssize_t) image->columns; x++)
930 if (GetPixelOpacity(p) != OpaqueOpacity)
938 image_view=DestroyCacheView(image_view);
939 if (opaque != MagickFalse)
940 image->matte=MagickFalse;
943 case ResetAlphaChannel:
944 case RemoveAlphaChannel:
945 case FlattenAlphaChannel:
959 if (image->matte == MagickFalse)
961 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
963 GetMagickPixelPacket(image,&background);
964 SetMagickPixelPacket(image,&image->background_color,(
const IndexPacket *)
966 if (image->colorspace == CMYKColorspace)
967 ConvertRGBToCMYK(&background);
968 (void) memset(&pixel,0,
sizeof(pixel));
970 SetPixelPacket(image,&background,&pixel,&index);
971 image_view=AcquireAuthenticCacheView(image,exception);
972 #if defined(MAGICKCORE_OPENMP_SUPPORT)
973 #pragma omp parallel for schedule(static) shared(status) \
974 magick_number_threads(image,image,image->rows,2)
976 for (y=0; y < (ssize_t) image->rows; y++)
979 *magick_restrict indexes;
987 if (status == MagickFalse)
989 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
991 if (q == (PixelPacket *) NULL)
996 for (x=0; x < (ssize_t) image->columns; x++)
1002 gamma=1.0-QuantumScale*QuantumScale*(double) q->opacity*(
double)
1004 opacity=(double) QuantumRange*(1.0-gamma);
1005 gamma=MagickSafeReciprocal(gamma);
1006 q->red=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->red,
1007 (MagickRealType) q->opacity,(MagickRealType) pixel.red,
1008 (MagickRealType) pixel.opacity));
1009 q->green=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->green,
1010 (MagickRealType) q->opacity,(MagickRealType) pixel.green,
1011 (MagickRealType) pixel.opacity));
1012 q->blue=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->blue,
1013 (MagickRealType) q->opacity,(MagickRealType) pixel.blue,
1014 (MagickRealType) pixel.opacity));
1015 q->opacity=ClampToQuantum(opacity);
1018 if (image->colorspace == CMYKColorspace)
1020 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1021 for (x=0; x < (ssize_t) image->columns; x++)
1022 SetPixelIndex(indexes+x,index);
1024 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1027 image_view=DestroyCacheView(image_view);
1030 case OpaqueAlphaChannel:
1032 status=SetImageOpacity(image,OpaqueOpacity);
1035 case SetAlphaChannel:
1037 if (image->matte == MagickFalse)
1038 status=SetImageOpacity(image,OpaqueOpacity);
1041 case TransparentAlphaChannel:
1043 status=SetImageOpacity(image,TransparentOpacity);
1046 case UndefinedAlphaChannel:
1049 if (status == MagickFalse)
1051 return(SyncImagePixelCache(image,&image->exception));