2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC H H AAA N N N N EEEEE L %
7 % C H H A A NN N NN N E L %
8 % C HHHHH AAAAA N N N N N N EEE L %
9 % C H H A A N NN N NN E L %
10 % CCCC H H A A N N N N EEEEE LLLLL %
13 % MagickCore Image Channel Methods %
20 % Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/cache-private.h"
45 #include "MagickCore/channel.h"
46 #include "MagickCore/colorspace-private.h"
47 #include "MagickCore/composite-private.h"
48 #include "MagickCore/enhance.h"
49 #include "MagickCore/image.h"
50 #include "MagickCore/list.h"
51 #include "MagickCore/log.h"
52 #include "MagickCore/monitor.h"
53 #include "MagickCore/monitor-private.h"
54 #include "MagickCore/option.h"
55 #include "MagickCore/pixel-accessor.h"
56 #include "MagickCore/pixel-private.h"
57 #include "MagickCore/resource_.h"
58 #include "MagickCore/string-private.h"
59 #include "MagickCore/thread-private.h"
60 #include "MagickCore/token.h"
61 #include "MagickCore/utility.h"
62 #include "MagickCore/version.h"
65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 % C h a n n e l F x I m a g e %
73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 % ChannelFxImage() applies a channel expression to the specified image. The
76 % expression consists of one or more channels, either mnemonic or numeric (e.g.
77 % red, 1), separated by actions as follows:
79 % <=> exchange two channels (e.g. red<=>blue)
80 % => copy one channel to another channel (e.g. red=>green)
81 % = assign a constant value to a channel (e.g. red=50%)
82 % , write new image channels in the specified order (e.g. red, green)
83 % | add a new output image for the next set of channel operations
84 % ; move to the next input image for the source of channel data
86 % For example, to create 3 grayscale images from the red, green, and blue
87 % channels of an image, use:
89 % -channel-fx "red; green; blue"
91 % A channel without an operation symbol implies separate (i.e, semicolon).
93 % The format of the ChannelFxImage method is:
95 % Image *ChannelFxImage(const Image *image,const char *expression,
96 % ExceptionInfo *exception)
98 % A description of each parameter follows:
100 % o image: the image.
102 % o expression: A channel expression.
104 % o exception: return any errors or warnings in this structure.
116 static MagickBooleanType ChannelImage(Image *destination_image,
117 const PixelChannel destination_channel,const ChannelFx channel_op,
118 const Image *source_image,const PixelChannel source_channel,
119 const Quantum pixel,ExceptionInfo *exception)
136 source_view=AcquireVirtualCacheView(source_image,exception);
137 destination_view=AcquireAuthenticCacheView(destination_image,exception);
138 height=MagickMin(source_image->rows,destination_image->rows);
139 width=MagickMin(source_image->columns,destination_image->columns);
140 #if defined(MAGICKCORE_OPENMP_SUPPORT)
141 #pragma omp parallel for schedule(static,4) shared(status) \
142 magick_threads(source_image,source_image,height,1)
144 for (y=0; y < (ssize_t) height; y++)
150 register const Quantum
159 if (status == MagickFalse)
161 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
163 q=GetCacheViewAuthenticPixels(destination_view,0,y,
164 destination_image->columns,1,exception);
165 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
170 destination_traits=GetPixelChannelTraits(destination_image,
171 destination_channel);
172 source_traits=GetPixelChannelTraits(source_image,source_channel);
173 if ((destination_traits == UndefinedPixelTrait) ||
174 (source_traits == UndefinedPixelTrait))
176 for (x=0; x < (ssize_t) width; x++)
178 if (channel_op == AssignChannelOp)
179 SetPixelChannel(destination_image,destination_channel,pixel,q);
181 SetPixelChannel(destination_image,destination_channel,
182 GetPixelChannel(source_image,source_channel,p),q);
183 p+=GetPixelChannels(source_image);
184 q+=GetPixelChannels(destination_image);
186 if (SyncCacheViewAuthenticPixels(destination_view,exception) == MagickFalse)
189 destination_view=DestroyCacheView(destination_view);
190 source_view=DestroyCacheView(source_view);
194 MagickExport Image *ChannelFxImage(const Image *image,const char *expression,
195 ExceptionInfo *exception)
197 #define ChannelFxImageTag "ChannelFx/Image"
206 token[MagickPathExtent];
230 assert(image != (Image *) NULL);
231 assert(image->signature == MagickCoreSignature);
232 if (image->debug != MagickFalse)
233 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
234 assert(exception != (ExceptionInfo *) NULL);
235 assert(exception->signature == MagickCoreSignature);
237 destination_image=CloneImage(source_image,0,0,MagickTrue,exception);
238 if (destination_image == (Image *) NULL)
239 return((Image *) NULL);
240 if (expression == (const char *) NULL)
241 return(destination_image);
242 destination_channel=RedPixelChannel;
243 channel_mask=UndefinedChannel;
245 p=(char *) expression;
246 GetNextToken(p,&p,MagickPathExtent,token);
247 channel_op=ExtractChannelOp;
248 for (channels=0; *token != '\0'; )
254 Interpret channel expression.
260 GetNextToken(p,&p,MagickPathExtent,token);
265 if (GetNextImageInList(source_image) != (Image *) NULL)
266 source_image=GetNextImageInList(source_image);
268 source_image=GetFirstImageInList(source_image);
269 GetNextToken(p,&p,MagickPathExtent,token);
277 (void) SetPixelChannelMask(destination_image,channel_mask);
278 if ((channel_op == ExtractChannelOp) && (channels == 1))
279 (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
280 status=SetImageStorageClass(destination_image,DirectClass,exception);
281 if (status == MagickFalse)
283 destination_image=DestroyImageList(destination_image);
284 return(destination_image);
286 canvas=CloneImage(source_image,0,0,MagickTrue,exception);
287 if (canvas == (Image *) NULL)
289 destination_image=DestroyImageList(destination_image);
290 return(destination_image);
292 AppendImageToList(&destination_image,canvas);
293 destination_image=GetLastImageInList(destination_image);
294 GetNextToken(p,&p,MagickPathExtent,token);
296 destination_channel=RedPixelChannel;
297 channel_mask=UndefinedChannel;
303 i=ParsePixelChannelOption(token);
306 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
307 "UnrecognizedChannelType","`%s'",token);
308 destination_image=DestroyImageList(destination_image);
309 return(destination_image);
311 source_channel=(PixelChannel) i;
312 channel_op=ExtractChannelOp;
313 GetNextToken(p,&p,MagickPathExtent,token);
316 channel_op=ExchangeChannelOp;
317 GetNextToken(p,&p,MagickPathExtent,token);
321 if (channel_op != ExchangeChannelOp)
322 channel_op=AssignChannelOp;
323 GetNextToken(p,&p,MagickPathExtent,token);
327 if (channel_op != ExchangeChannelOp)
328 channel_op=TransferChannelOp;
329 GetNextToken(p,&p,MagickPathExtent,token);
333 case AssignChannelOp:
334 case ExchangeChannelOp:
335 case TransferChannelOp:
337 if (channel_op == AssignChannelOp)
338 pixel=StringToDoubleInterval(token,(double) QuantumRange+1.0);
341 i=ParsePixelChannelOption(token);
344 (void) ThrowMagickException(exception,GetMagickModule(),
345 OptionError,"UnrecognizedChannelType","`%s'",token);
346 destination_image=DestroyImageList(destination_image);
347 return(destination_image);
350 destination_channel=(PixelChannel) i;
351 switch (destination_channel)
353 case RedPixelChannel:
354 case GreenPixelChannel:
355 case BluePixelChannel:
356 case BlackPixelChannel:
357 case IndexPixelChannel:
359 case AlphaPixelChannel:
361 if (image->colorspace != UndefinedColorspace)_
362 destination_image->alpha_trait=BlendPixelTrait;
365 case ReadMaskPixelChannel:
367 destination_image->read_mask=MagickTrue;
370 case WriteMaskPixelChannel:
372 destination_image->write_mask=MagickTrue;
375 case MetaPixelChannel:
378 (void) SetPixelMetaChannels(destination_image,(size_t) (
379 destination_channel-GetPixelChannels(destination_image)+1),
384 channel_mask=(ChannelType) (channel_mask | ParseChannelOption(token));
385 if (((channels >= 1) || (destination_channel >= 1)) &&
386 (IsGrayColorspace(destination_image->colorspace) != MagickFalse))
387 (void) SetImageColorspace(destination_image,sRGBColorspace,exception);
388 GetNextToken(p,&p,MagickPathExtent,token);
394 status=ChannelImage(destination_image,destination_channel,channel_op,
395 source_image,source_channel,ClampToQuantum(pixel),exception);
396 if (status == MagickFalse)
398 destination_image=DestroyImageList(destination_image);
402 if (channel_op == ExchangeChannelOp)
404 status=ChannelImage(destination_image,source_channel,channel_op,
405 source_image,destination_channel,ClampToQuantum(pixel),exception);
406 if (status == MagickFalse)
408 destination_image=DestroyImageList(destination_image);
415 case ExtractChannelOp:
417 channel_mask=(ChannelType) (channel_mask | (1 << destination_channel));
418 destination_channel=(PixelChannel) (destination_channel+1);
424 status=SetImageProgress(source_image,ChannelFxImageTag,p-expression,
426 if (status == MagickFalse)
429 (void) SetPixelChannelMask(destination_image,channel_mask);
430 if ((channel_op == ExtractChannelOp) && (channels == 1))
431 (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
432 status=SetImageStorageClass(destination_image,DirectClass,exception);
433 if (status == MagickFalse)
435 destination_image=GetLastImageInList(destination_image);
436 return((Image *) NULL);
438 return(GetFirstImageInList(destination_image));
442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446 % C o m b i n e I m a g e s %
450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452 % CombineImages() combines one or more images into a single image. The
453 % grayscale value of the pixels of each image in the sequence is assigned in
454 % order to the specified channels of the combined image. The typical
455 % ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
457 % The format of the CombineImages method is:
459 % Image *CombineImages(const Image *images,const ColorspaceType colorspace,
460 % ExceptionInfo *exception)
462 % A description of each parameter follows:
464 % o images: the image sequence.
466 % o colorspace: the image colorspace.
468 % o exception: return any errors or warnings in this structure.
471 MagickExport Image *CombineImages(const Image *image,
472 const ColorspaceType colorspace,ExceptionInfo *exception)
474 #define CombineImageTag "Combine/Image"
492 Ensure the image are the same size.
494 assert(image != (const Image *) NULL);
495 assert(image->signature == MagickCoreSignature);
496 if (image->debug != MagickFalse)
497 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
498 assert(exception != (ExceptionInfo *) NULL);
499 assert(exception->signature == MagickCoreSignature);
500 combine_image=CloneImage(image,0,0,MagickTrue,exception);
501 if (combine_image == (Image *) NULL)
502 return((Image *) NULL);
503 if (SetImageStorageClass(combine_image,DirectClass,exception) == MagickFalse)
505 combine_image=DestroyImage(combine_image);
506 return((Image *) NULL);
508 if ((colorspace == UndefinedColorspace) || (image->number_channels == 1))
509 (void) SetImageColorspace(combine_image,sRGBColorspace,exception);
511 (void) SetImageColorspace(combine_image,colorspace,exception);
512 switch (combine_image->colorspace)
514 case UndefinedColorspace:
517 if (GetImageListLength(image) > 3)
518 combine_image->alpha_trait=BlendPixelTrait;
523 if (GetImageListLength(image) > 1)
524 combine_image->alpha_trait=BlendPixelTrait;
529 if (GetImageListLength(image) > 4)
530 combine_image->alpha_trait=BlendPixelTrait;
541 combine_view=AcquireAuthenticCacheView(combine_image,exception);
542 for (y=0; y < (ssize_t) combine_image->rows; y++)
553 register const Quantum
562 if (status == MagickFalse)
564 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
566 if (pixels == (Quantum *) NULL)
572 for (i=0; i < (ssize_t) GetPixelChannels(combine_image); i++)
577 PixelChannel channel=GetPixelChannelChannel(combine_image,i);
578 PixelTrait traits=GetPixelChannelTraits(combine_image,channel);
579 if (traits == UndefinedPixelTrait)
581 if (next == (Image *) NULL)
583 image_view=AcquireVirtualCacheView(next,exception);
584 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
585 if (p == (const Quantum *) NULL)
588 for (x=0; x < (ssize_t) combine_image->columns; x++)
590 if (x < (ssize_t) next->columns)
592 q[i]=GetPixelGray(next,p);
593 p+=GetPixelChannels(next);
595 q+=GetPixelChannels(combine_image);
597 image_view=DestroyCacheView(image_view);
598 next=GetNextImageInList(next);
600 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
602 if (image->progress_monitor != (MagickProgressMonitor) NULL)
607 proceed=SetImageProgress(image,CombineImageTag,progress++,
608 combine_image->rows);
609 if (proceed == MagickFalse)
613 combine_view=DestroyCacheView(combine_view);
614 if (status == MagickFalse)
615 combine_image=DestroyImage(combine_image);
616 return(combine_image);
620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
624 % G e t I m a g e A l p h a C h a n n e l %
628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630 % GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
631 % not activated. That is, the image is RGB rather than RGBA or CMYK rather
634 % The format of the GetImageAlphaChannel method is:
636 % MagickBooleanType GetImageAlphaChannel(const Image *image)
638 % A description of each parameter follows:
640 % o image: the image.
643 MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
645 assert(image != (const Image *) NULL);
646 if (image->debug != MagickFalse)
647 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
648 assert(image->signature == MagickCoreSignature);
649 return(image->alpha_trait != UndefinedPixelTrait ? MagickTrue : MagickFalse);
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
657 % S e p a r a t e I m a g e %
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663 % SeparateImage() separates a channel from the image and returns it as a
666 % The format of the SeparateImage method is:
668 % Image *SeparateImage(const Image *image,const ChannelType channel,
669 % ExceptionInfo *exception)
671 % A description of each parameter follows:
673 % o image: the image.
675 % o channel: the image channel.
677 % o exception: return any errors or warnings in this structure.
680 MagickExport Image *SeparateImage(const Image *image,
681 const ChannelType channel_type,ExceptionInfo *exception)
683 #define GetChannelBit(mask,bit) (((size_t) (mask) >> (size_t) (bit)) & 0x01)
684 #define SeparateImageTag "Separate/Image"
703 Initialize separate image attributes.
705 assert(image != (Image *) NULL);
706 assert(image->signature == MagickCoreSignature);
707 if (image->debug != MagickFalse)
708 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
709 assert(exception != (ExceptionInfo *) NULL);
710 assert(exception->signature == MagickCoreSignature);
711 separate_image=CloneImage(image,image->columns,image->rows,MagickTrue,
713 if (separate_image == (Image *) NULL)
714 return((Image *) NULL);
715 if (SetImageStorageClass(separate_image,DirectClass,exception) == MagickFalse)
717 separate_image=DestroyImage(separate_image);
718 return((Image *) NULL);
720 (void) SetImageColorspace(separate_image,GRAYColorspace,exception);
721 separate_image->alpha_trait=UndefinedPixelTrait;
727 image_view=AcquireVirtualCacheView(image,exception);
728 separate_view=AcquireAuthenticCacheView(separate_image,exception);
729 #if defined(MAGICKCORE_OPENMP_SUPPORT)
730 #pragma omp parallel for schedule(static,4) shared(progress,status) \
731 magick_threads(image,image,image->rows,1)
733 for (y=0; y < (ssize_t) image->rows; y++)
735 register const Quantum
744 if (status == MagickFalse)
746 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
747 q=QueueCacheViewAuthenticPixels(separate_view,0,y,separate_image->columns,1,
749 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
754 for (x=0; x < (ssize_t) image->columns; x++)
759 if (GetPixelWriteMask(image,p) == 0)
761 SetPixelBackgoundColor(separate_image,q);
762 p+=GetPixelChannels(image);
763 q+=GetPixelChannels(separate_image);
766 SetPixelChannel(separate_image,GrayPixelChannel,0,q);
767 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
769 PixelChannel channel=GetPixelChannelChannel(image,i);
770 PixelTrait traits=GetPixelChannelTraits(image,channel);
771 if ((traits == UndefinedPixelTrait) ||
772 (GetChannelBit(channel_type,channel) == 0))
774 SetPixelChannel(separate_image,GrayPixelChannel,p[i],q);
776 p+=GetPixelChannels(image);
777 q+=GetPixelChannels(separate_image);
779 if (SyncCacheViewAuthenticPixels(separate_view,exception) == MagickFalse)
781 if (image->progress_monitor != (MagickProgressMonitor) NULL)
786 #if defined(MAGICKCORE_OPENMP_SUPPORT)
787 #pragma omp critical (MagickCore_SeparateImage)
789 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
790 if (proceed == MagickFalse)
794 separate_view=DestroyCacheView(separate_view);
795 image_view=DestroyCacheView(image_view);
796 (void) SetImageChannelMask(separate_image,DefaultChannels);
797 if (status == MagickFalse)
798 separate_image=DestroyImage(separate_image);
799 return(separate_image);
803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
807 % S e p a r a t e I m a g e s %
811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 % SeparateImages() returns a separate grayscale image for each channel
816 % The format of the SeparateImages method is:
818 % Image *SeparateImages(const Image *image,ExceptionInfo *exception)
820 % A description of each parameter follows:
822 % o image: the image.
824 % o exception: return any errors or warnings in this structure.
827 MagickExport Image *SeparateImages(const Image *image,ExceptionInfo *exception)
836 assert(image != (Image *) NULL);
837 assert(image->signature == MagickCoreSignature);
838 if (image->debug != MagickFalse)
839 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
840 images=NewImageList();
841 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
843 PixelChannel channel=GetPixelChannelChannel(image,i);
844 PixelTrait traits=GetPixelChannelTraits(image,channel);
845 if ((traits == UndefinedPixelTrait) ||
846 ((traits & UpdatePixelTrait) == 0))
848 separate_image=SeparateImage(image,(ChannelType) (1 << channel),exception);
849 if (separate_image != (Image *) NULL)
850 AppendImageToList(&images,separate_image);
852 if (images == (Image *) NULL)
853 images=SeparateImage(image,UndefinedChannel,exception);
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
862 % S e t I m a g e A l p h a C h a n n e l %
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868 % SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
871 % The format of the SetImageAlphaChannel method is:
873 % MagickBooleanType SetImageAlphaChannel(Image *image,
874 % const AlphaChannelOption alpha_type,ExceptionInfo *exception)
876 % A description of each parameter follows:
878 % o image: the image.
880 % o alpha_type: The alpha channel type: ActivateAlphaChannel,
881 % AssociateAlphaChannel, CopyAlphaChannel, DeactivateAlphaChannel,
882 % DisassociateAlphaChannel, ExtractAlphaChannel, OffAlphaChannel,
883 % OnAlphaChannel, OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel,
884 % and TransparentAlphaChannel.
886 % o exception: return any errors or warnings in this structure.
890 static inline void FlattenPixelInfo(const Image *image,const PixelInfo *p,
891 const double alpha,const Quantum *q,const double beta,
903 Compose pixel p over pixel q with the given alpha.
905 Sa=QuantumScale*alpha;
906 Da=QuantumScale*beta,
907 gamma=Sa*(-Da)+Sa+Da;
908 gamma=PerceptibleReciprocal(gamma);
909 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
911 PixelChannel channel=GetPixelChannelChannel(image,i);
912 PixelTrait traits=GetPixelChannelTraits(image,channel);
913 if (traits == UndefinedPixelTrait)
917 case RedPixelChannel:
919 composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
920 (double) p->red,alpha));
923 case GreenPixelChannel:
925 composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
926 (double) p->green,alpha));
929 case BluePixelChannel:
931 composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
932 (double) p->blue,alpha));
935 case BlackPixelChannel:
937 composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
938 (double) p->black,alpha));
941 case AlphaPixelChannel:
943 composite[i]=ClampToQuantum(QuantumRange*(Sa*(-Da)+Sa+Da));
952 MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
953 const AlphaChannelOption alpha_type,ExceptionInfo *exception)
964 assert(image != (Image *) NULL);
965 if (image->debug != MagickFalse)
966 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
967 assert(image->signature == MagickCoreSignature);
971 case ActivateAlphaChannel:
973 image->alpha_trait=BlendPixelTrait;
976 case AssociateAlphaChannel:
981 status=SetImageStorageClass(image,DirectClass,exception);
982 if (status == MagickFalse)
984 image_view=AcquireAuthenticCacheView(image,exception);
985 #if defined(MAGICKCORE_OPENMP_SUPPORT)
986 #pragma omp parallel for schedule(static,4) shared(status) \
987 magick_threads(image,image,image->rows,1)
989 for (y=0; y < (ssize_t) image->rows; y++)
997 if (status == MagickFalse)
999 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1001 if (q == (Quantum *) NULL)
1006 for (x=0; x < (ssize_t) image->columns; x++)
1014 if (GetPixelWriteMask(image,q) == 0)
1016 q+=GetPixelChannels(image);
1019 gamma=QuantumScale*GetPixelAlpha(image,q);
1020 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1022 PixelChannel channel=GetPixelChannelChannel(image,i);
1023 PixelTrait traits=GetPixelChannelTraits(image,channel);
1024 if (channel == AlphaPixelChannel)
1026 if ((traits & UpdatePixelTrait) == 0)
1028 q[i]=ClampToQuantum(gamma*q[i]);
1030 q+=GetPixelChannels(image);
1032 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1035 image_view=DestroyCacheView(image_view);
1036 image->alpha_trait=CopyPixelTrait;
1039 case BackgroundAlphaChannel:
1042 Set transparent pixels to background color.
1044 if (image->alpha_trait == UndefinedPixelTrait)
1046 status=SetImageStorageClass(image,DirectClass,exception);
1047 if (status == MagickFalse)
1049 image_view=AcquireAuthenticCacheView(image,exception);
1050 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1051 #pragma omp parallel for schedule(static,4) shared(status) \
1052 magick_threads(image,image,image->rows,1)
1054 for (y=0; y < (ssize_t) image->rows; y++)
1062 if (status == MagickFalse)
1064 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1066 if (q == (Quantum *) NULL)
1071 for (x=0; x < (ssize_t) image->columns; x++)
1073 if (GetPixelAlpha(image,q) == TransparentAlpha)
1075 SetPixelViaPixelInfo(image,&image->background_color,q);
1076 SetPixelChannel(image,AlphaPixelChannel,TransparentAlpha,q);
1078 q+=GetPixelChannels(image);
1080 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1083 image_view=DestroyCacheView(image_view);
1086 case CopyAlphaChannel:
1087 case ShapeAlphaChannel:
1090 Copy pixel intensity to the alpha channel.
1092 image->alpha_trait=UpdatePixelTrait;
1093 status=CompositeImage(image,image,IntensityCompositeOp,MagickTrue,0,0,
1095 if (alpha_type == ShapeAlphaChannel)
1096 (void) LevelImageColors(image,&image->background_color,
1097 &image->background_color,MagickTrue,exception);
1100 case DeactivateAlphaChannel:
1102 if (image->alpha_trait == UndefinedPixelTrait)
1103 status=SetImageAlpha(image,OpaqueAlpha,exception);
1104 image->alpha_trait=CopyPixelTrait;
1107 case DisassociateAlphaChannel:
1112 status=SetImageStorageClass(image,DirectClass,exception);
1113 if (status == MagickFalse)
1115 image->alpha_trait=BlendPixelTrait;
1116 image_view=AcquireAuthenticCacheView(image,exception);
1117 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1118 #pragma omp parallel for schedule(static,4) shared(status) \
1119 magick_threads(image,image,image->rows,1)
1121 for (y=0; y < (ssize_t) image->rows; y++)
1129 if (status == MagickFalse)
1131 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1133 if (q == (Quantum *) NULL)
1138 for (x=0; x < (ssize_t) image->columns; x++)
1147 if (GetPixelWriteMask(image,q) == 0)
1149 q+=GetPixelChannels(image);
1152 Sa=QuantumScale*GetPixelAlpha(image,q);
1153 gamma=PerceptibleReciprocal(Sa);
1154 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1156 PixelChannel channel=GetPixelChannelChannel(image,i);
1157 PixelTrait traits=GetPixelChannelTraits(image,channel);
1158 if (channel == AlphaPixelChannel)
1160 if ((traits & UpdatePixelTrait) == 0)
1162 q[i]=ClampToQuantum(gamma*q[i]);
1164 q+=GetPixelChannels(image);
1166 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1169 image_view=DestroyCacheView(image_view);
1170 image->alpha_trait=UndefinedPixelTrait;
1173 case DiscreteAlphaChannel:
1175 if (image->alpha_trait == UndefinedPixelTrait)
1176 status=SetImageAlpha(image,OpaqueAlpha,exception);
1177 image->alpha_trait=UpdatePixelTrait;
1180 case ExtractAlphaChannel:
1182 status=CompositeImage(image,image,AlphaCompositeOp,MagickTrue,0,0,
1184 image->alpha_trait=UndefinedPixelTrait;
1187 case OffAlphaChannel:
1189 image->alpha_trait=UndefinedPixelTrait;
1192 case OnAlphaChannel:
1194 if (image->alpha_trait == UndefinedPixelTrait)
1195 status=SetImageAlpha(image,OpaqueAlpha,exception);
1196 image->alpha_trait=BlendPixelTrait;
1199 case OpaqueAlphaChannel:
1201 status=SetImageAlpha(image,OpaqueAlpha,exception);
1204 case RemoveAlphaChannel:
1207 Remove transparency.
1209 if (image->alpha_trait == UndefinedPixelTrait)
1211 status=SetImageStorageClass(image,DirectClass,exception);
1212 if (status == MagickFalse)
1214 image_view=AcquireAuthenticCacheView(image,exception);
1215 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1216 #pragma omp parallel for schedule(static,4) shared(status) \
1217 magick_threads(image,image,image->rows,1)
1219 for (y=0; y < (ssize_t) image->rows; y++)
1227 if (status == MagickFalse)
1229 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1231 if (q == (Quantum *) NULL)
1236 for (x=0; x < (ssize_t) image->columns; x++)
1238 FlattenPixelInfo(image,&image->background_color,
1239 image->background_color.alpha,q,(double)
1240 GetPixelAlpha(image,q),q);
1241 q+=GetPixelChannels(image);
1243 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1246 image_view=DestroyCacheView(image_view);
1247 image->alpha_trait=image->background_color.alpha_trait;
1250 case SetAlphaChannel:
1252 if (image->alpha_trait == UndefinedPixelTrait)
1253 status=SetImageAlpha(image,OpaqueAlpha,exception);
1256 case TransparentAlphaChannel:
1258 status=SetImageAlpha(image,TransparentAlpha,exception);
1261 case UndefinedAlphaChannel:
1264 if (status == MagickFalse)
1266 (void) SetPixelChannelMask(image,image->channel_mask);
1267 return(SyncImagePixelCache(image,exception));