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"
93 MagickExport
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 for (y=0; y < (ssize_t) combine_image->rows; y++)
175 if (status == MagickFalse)
177 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
185 if (((channel & RedChannel) != 0) && (next != (
Image *) NULL))
187 image_view=AcquireVirtualCacheView(next,exception);
188 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
192 for (x=0; x < (ssize_t) combine_image->columns; x++)
194 SetPixelRed(q,ClampToQuantum(GetPixelIntensity(image,p)));
198 image_view=DestroyCacheView(image_view);
199 next=GetNextImageInList(next);
201 if (((channel & GreenChannel) != 0) && (next != (
Image *) NULL))
203 image_view=AcquireVirtualCacheView(next,exception);
204 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
208 for (x=0; x < (ssize_t) combine_image->columns; x++)
210 SetPixelGreen(q,ClampToQuantum(GetPixelIntensity(image,p)));
214 image_view=DestroyCacheView(image_view);
215 next=GetNextImageInList(next);
217 if (((channel & BlueChannel) != 0) && (next != (
Image *) NULL))
219 image_view=AcquireVirtualCacheView(next,exception);
220 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
224 for (x=0; x < (ssize_t) combine_image->columns; x++)
226 SetPixelBlue(q,ClampToQuantum(GetPixelIntensity(image,p)));
230 image_view=DestroyCacheView(image_view);
231 next=GetNextImageInList(next);
233 if (((channel & OpacityChannel) != 0) && (next != (
Image *) NULL))
235 image_view=AcquireVirtualCacheView(next,exception);
236 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
240 for (x=0; x < (ssize_t) combine_image->columns; x++)
242 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,p)));
246 image_view=DestroyCacheView(image_view);
247 next=GetNextImageInList(next);
249 if (((channel & IndexChannel) != 0) &&
250 (image->colorspace == CMYKColorspace) && (next != (
Image *) NULL))
255 image_view=AcquireVirtualCacheView(next,exception);
256 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
259 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
260 for (x=0; x < (ssize_t) combine_image->columns; x++)
262 SetPixelIndex(indexes+x,ClampToQuantum(GetPixelIntensity(image,p)));
265 image_view=DestroyCacheView(image_view);
266 next=GetNextImageInList(next);
268 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
270 if (image->progress_monitor != (MagickProgressMonitor) NULL)
275 #if defined(MAGICKCORE_OPENMP_SUPPORT)
279 proceed=SetImageProgress(image,CombineImageTag,progress,
280 combine_image->rows);
281 if (proceed == MagickFalse)
285 combine_view=DestroyCacheView(combine_view);
286 if (IsGrayColorspace(combine_image->colorspace) != MagickFalse)
287 (void) TransformImageColorspace(combine_image,sRGBColorspace);
288 if (status == MagickFalse)
289 combine_image=DestroyImage(combine_image);
290 return(combine_image);
317 MagickExport MagickBooleanType GetImageAlphaChannel(
const Image *image)
319 assert(image != (
const Image *) NULL);
320 if (IsEventLogging() != MagickFalse)
321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
322 assert(image->signature == MagickCoreSignature);
323 return(image->matte);
356 MagickExport
Image *SeparateImage(
const Image *image,
const ChannelType channel,
368 assert(image != (
Image *) NULL);
369 assert(image->signature == MagickCoreSignature);
370 if (IsEventLogging() != MagickFalse)
371 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
373 assert(exception->signature == MagickCoreSignature);
374 separate_image=CloneImage(image,0,0,MagickTrue,exception);
375 if (separate_image == (
Image *) NULL)
376 return((
Image *) NULL);
377 status=SeparateImageChannel(separate_image,channel);
378 if (status == MagickFalse)
379 separate_image=DestroyImage(separate_image);
380 return(separate_image);
383 MagickExport MagickBooleanType SeparateImageChannel(
Image *image,
384 const ChannelType channel)
386 #define SeparateImageTag "Separate/Image"
403 assert(image != (
Image *) NULL);
404 assert(image->signature == MagickCoreSignature);
405 if (IsEventLogging() != MagickFalse)
406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
407 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
409 if (channel == GrayChannels)
410 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
416 exception=(&image->exception);
417 image_view=AcquireAuthenticCacheView(image,exception);
418 #if defined(MAGICKCORE_OPENMP_SUPPORT)
419 #pragma omp parallel for schedule(static) shared(progress,status) \
420 magick_number_threads(image,image,image->rows,1)
422 for (y=0; y < (ssize_t) image->rows; y++)
425 *magick_restrict indexes;
433 if (status == MagickFalse)
435 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
441 indexes=GetCacheViewAuthenticIndexQueue(image_view);
446 for (x=0; x < (ssize_t) image->columns; x++)
448 SetPixelGreen(q,GetPixelRed(q));
449 SetPixelBlue(q,GetPixelRed(q));
456 for (x=0; x < (ssize_t) image->columns; x++)
458 SetPixelRed(q,GetPixelGreen(q));
459 SetPixelBlue(q,GetPixelGreen(q));
466 for (x=0; x < (ssize_t) image->columns; x++)
468 SetPixelRed(q,GetPixelBlue(q));
469 SetPixelGreen(q,GetPixelBlue(q));
476 for (x=0; x < (ssize_t) image->columns; x++)
478 SetPixelRed(q,GetPixelOpacity(q));
479 SetPixelGreen(q,GetPixelOpacity(q));
480 SetPixelBlue(q,GetPixelOpacity(q));
487 if ((image->storage_class != PseudoClass) &&
488 (image->colorspace != CMYKColorspace))
490 for (x=0; x < (ssize_t) image->columns; x++)
492 SetPixelRed(q,GetPixelIndex(indexes+x));
493 SetPixelGreen(q,GetPixelIndex(indexes+x));
494 SetPixelBlue(q,GetPixelIndex(indexes+x));
499 case TrueAlphaChannel:
501 for (x=0; x < (ssize_t) image->columns; x++)
503 SetPixelRed(q,GetPixelAlpha(q));
504 SetPixelGreen(q,GetPixelAlpha(q));
505 SetPixelBlue(q,GetPixelAlpha(q));
512 for (x=0; x < (ssize_t) image->columns; x++)
514 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,q)));
522 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
524 if (image->progress_monitor != (MagickProgressMonitor) NULL)
529 #if defined(MAGICKCORE_OPENMP_SUPPORT)
533 proceed=SetImageProgress(image,SeparateImageTag,progress,image->rows);
534 if (proceed == MagickFalse)
538 image_view=DestroyCacheView(image_view);
539 if (channel != GrayChannels)
541 image->matte=MagickFalse;
542 (void) SetImageColorspace(image,GRAYColorspace);
577 MagickExport
Image *SeparateImages(
const Image *image,
const ChannelType channel,
584 assert(image != (
Image *) NULL);
585 assert(image->signature == MagickCoreSignature);
586 if (IsEventLogging() != MagickFalse)
587 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
588 images=NewImageList();
589 if ((channel & RedChannel) != 0)
591 separate_image=CloneImage(image,0,0,MagickTrue,exception);
592 (void) SeparateImageChannel(separate_image,RedChannel);
593 AppendImageToList(&images,separate_image);
595 if ((channel & GreenChannel) != 0)
597 separate_image=CloneImage(image,0,0,MagickTrue,exception);
598 (void) SeparateImageChannel(separate_image,GreenChannel);
599 AppendImageToList(&images,separate_image);
601 if ((channel & BlueChannel) != 0)
603 separate_image=CloneImage(image,0,0,MagickTrue,exception);
604 (void) SeparateImageChannel(separate_image,BlueChannel);
605 AppendImageToList(&images,separate_image);
607 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
609 separate_image=CloneImage(image,0,0,MagickTrue,exception);
610 (void) SeparateImageChannel(separate_image,BlackChannel);
611 AppendImageToList(&images,separate_image);
613 if ((channel & AlphaChannel) != 0)
615 separate_image=CloneImage(image,0,0,MagickTrue,exception);
616 (void) SeparateImageChannel(separate_image,TrueAlphaChannel);
617 AppendImageToList(&images,separate_image);
652 MagickExport MagickBooleanType SetImageAlphaChannel(
Image *image,
653 const AlphaChannelType alpha_type)
667 assert(image != (
Image *) NULL);
668 if (IsEventLogging() != MagickFalse)
669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
670 assert(image->signature == MagickCoreSignature);
671 exception=(&image->exception);
675 case ActivateAlphaChannel:
677 if (image->matte == MagickTrue)
679 image->matte=MagickTrue;
682 case AssociateAlphaChannel:
687 status=SetImageStorageClass(image,DirectClass);
688 if (status == MagickFalse)
690 image_view=AcquireAuthenticCacheView(image,exception);
691 #if defined(MAGICKCORE_OPENMP_SUPPORT)
692 #pragma omp parallel for schedule(static) shared(status) \
693 magick_number_threads(image,image,image->rows,1)
695 for (y=0; y < (ssize_t) image->rows; y++)
703 if (status == MagickFalse)
705 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
712 for (x=0; x < (ssize_t) image->columns; x++)
717 gamma=QuantumScale*GetPixelAlpha(q);
718 SetPixelRed(q,ClampToQuantum(gamma*GetPixelRed(q)));
719 SetPixelGreen(q,ClampToQuantum(gamma*GetPixelGreen(q)));
720 SetPixelBlue(q,ClampToQuantum(gamma*GetPixelBlue(q)));
723 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
726 image_view=DestroyCacheView(image_view);
727 image->matte=MagickFalse;
730 case BackgroundAlphaChannel:
747 if (image->matte == MagickFalse)
749 status=SetImageStorageClass(image,DirectClass);
750 if (status == MagickFalse)
752 GetMagickPixelPacket(image,&background);
753 SetMagickPixelPacket(image,&image->background_color,(
const IndexPacket *)
755 if (image->colorspace == CMYKColorspace)
756 ConvertRGBToCMYK(&background);
758 SetPixelPacket(image,&background,&pixel,&index);
760 exception=(&image->exception);
761 image_view=AcquireAuthenticCacheView(image,exception);
762 #if defined(MAGICKCORE_OPENMP_SUPPORT)
763 #pragma omp parallel for schedule(static) shared(status) \
764 magick_number_threads(image,image,image->rows,1)
766 for (y=0; y < (ssize_t) image->rows; y++)
769 *magick_restrict indexes;
777 if (status == MagickFalse)
779 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
786 for (x=0; x < (ssize_t) image->columns; x++)
788 if (q->opacity == TransparentOpacity)
790 SetPixelRed(q,pixel.red);
791 SetPixelGreen(q,pixel.green);
792 SetPixelBlue(q,pixel.blue);
796 if (image->colorspace == CMYKColorspace)
798 indexes=GetCacheViewAuthenticIndexQueue(image_view);
799 for (x=0; x < (ssize_t) image->columns; x++)
800 SetPixelIndex(indexes+x,index);
802 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
805 image_view=DestroyCacheView(image_view);
808 case CopyAlphaChannel:
809 case ShapeAlphaChannel:
815 status=SeparateImageChannel(image,GrayChannels);
816 image->matte=MagickTrue;
817 if (alpha_type == ShapeAlphaChannel)
825 GetMagickPixelPacket(image,&background);
826 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
828 (void) LevelColorsImage(image,&background,&background,MagickTrue);
832 case DeactivateAlphaChannel:
834 if (image->matte == MagickFalse)
836 image->matte=MagickFalse;
839 case DisassociateAlphaChannel:
841 status=SetImageStorageClass(image,DirectClass);
842 if (status == MagickFalse)
844 image->matte=MagickTrue;
845 image_view=AcquireAuthenticCacheView(image,exception);
846 #if defined(MAGICKCORE_OPENMP_SUPPORT)
847 #pragma omp parallel for schedule(static) shared(status) \
848 magick_number_threads(image,image,image->rows,1)
850 for (y=0; y < (ssize_t) image->rows; y++)
858 if (status == MagickFalse)
860 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
867 for (x=0; x < (ssize_t) image->columns; x++)
873 alpha=QuantumScale*GetPixelAlpha(q);
874 gamma=PerceptibleReciprocal(alpha);
875 SetPixelRed(q,ClampToQuantum(gamma*GetPixelRed(q)));
876 SetPixelGreen(q,ClampToQuantum(gamma*GetPixelGreen(q)));
877 SetPixelBlue(q,ClampToQuantum(gamma*GetPixelBlue(q)));
880 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
883 image_view=DestroyCacheView(image_view);
884 image->matte=MagickFalse;
887 case ExtractAlphaChannel:
889 status=SeparateImageChannel(image,TrueAlphaChannel);
890 image->matte=MagickFalse;
893 case RemoveAlphaChannel:
894 case FlattenAlphaChannel:
908 if (image->matte == MagickFalse)
910 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
912 GetMagickPixelPacket(image,&background);
913 SetMagickPixelPacket(image,&image->background_color,(
const IndexPacket *)
915 if (image->colorspace == CMYKColorspace)
916 ConvertRGBToCMYK(&background);
917 (void) memset(&pixel,0,
sizeof(pixel));
919 SetPixelPacket(image,&background,&pixel,&index);
920 image_view=AcquireAuthenticCacheView(image,exception);
921 #if defined(MAGICKCORE_OPENMP_SUPPORT)
922 #pragma omp parallel for schedule(static) shared(status) \
923 magick_number_threads(image,image,image->rows,1)
925 for (y=0; y < (ssize_t) image->rows; y++)
928 *magick_restrict indexes;
936 if (status == MagickFalse)
938 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
945 for (x=0; x < (ssize_t) image->columns; x++)
951 gamma=1.0-QuantumScale*QuantumScale*q->opacity*pixel.opacity;
952 opacity=(double) QuantumRange*(1.0-gamma);
953 gamma=PerceptibleReciprocal(gamma);
954 q->red=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->red,
955 (MagickRealType) q->opacity,(MagickRealType) pixel.red,
956 (MagickRealType) pixel.opacity));
957 q->green=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->green,
958 (MagickRealType) q->opacity,(MagickRealType) pixel.green,
959 (MagickRealType) pixel.opacity));
960 q->blue=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->blue,
961 (MagickRealType) q->opacity,(MagickRealType) pixel.blue,
962 (MagickRealType) pixel.opacity));
963 q->opacity=ClampToQuantum(opacity);
966 if (image->colorspace == CMYKColorspace)
968 indexes=GetCacheViewAuthenticIndexQueue(image_view);
969 for (x=0; x < (ssize_t) image->columns; x++)
970 SetPixelIndex(indexes+x,index);
972 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
975 image_view=DestroyCacheView(image_view);
978 case ResetAlphaChannel:
979 case OpaqueAlphaChannel:
981 status=SetImageOpacity(image,OpaqueOpacity);
984 case SetAlphaChannel:
986 if (image->matte == MagickFalse)
987 status=SetImageOpacity(image,OpaqueOpacity);
990 case TransparentAlphaChannel:
992 status=SetImageOpacity(image,TransparentOpacity);
995 case UndefinedAlphaChannel:
998 if (status == MagickFalse)
1000 return(SyncImagePixelCache(image,&image->exception));