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-2019 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 % https://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) shared(status) \
142 magick_number_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 status=SetImageStorageClass(destination_image,DirectClass,exception);
243 if (status == MagickFalse)
245 destination_image=GetLastImageInList(destination_image);
246 return((Image *) NULL);
248 destination_channel=RedPixelChannel;
249 channel_mask=UndefinedChannel;
251 p=(char *) expression;
252 (void) GetNextToken(p,&p,MagickPathExtent,token);
253 channel_op=ExtractChannelOp;
254 for (channels=0; *token != '\0'; )
260 Interpret channel expression.
266 (void) GetNextToken(p,&p,MagickPathExtent,token);
271 if (GetNextImageInList(source_image) != (Image *) NULL)
272 source_image=GetNextImageInList(source_image);
274 source_image=GetFirstImageInList(source_image);
275 (void) GetNextToken(p,&p,MagickPathExtent,token);
283 (void) SetPixelChannelMask(destination_image,channel_mask);
284 if ((channel_op == ExtractChannelOp) && (channels == 1))
286 (void) SetPixelMetaChannels(destination_image,0,exception);
287 (void) SetImageColorspace(destination_image,GRAYColorspace,
290 canvas=CloneImage(source_image,0,0,MagickTrue,exception);
291 if (canvas == (Image *) NULL)
293 destination_image=DestroyImageList(destination_image);
294 return(destination_image);
296 AppendImageToList(&destination_image,canvas);
297 destination_image=GetLastImageInList(destination_image);
298 status=SetImageStorageClass(destination_image,DirectClass,exception);
299 if (status == MagickFalse)
301 destination_image=GetLastImageInList(destination_image);
302 return((Image *) NULL);
304 (void) GetNextToken(p,&p,MagickPathExtent,token);
306 destination_channel=RedPixelChannel;
307 channel_mask=UndefinedChannel;
313 i=ParsePixelChannelOption(token);
316 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
317 "UnrecognizedChannelType","`%s'",token);
318 destination_image=DestroyImageList(destination_image);
319 return(destination_image);
321 source_channel=(PixelChannel) i;
322 channel_op=ExtractChannelOp;
323 (void) GetNextToken(p,&p,MagickPathExtent,token);
326 channel_op=ExchangeChannelOp;
327 (void) GetNextToken(p,&p,MagickPathExtent,token);
331 if (channel_op != ExchangeChannelOp)
332 channel_op=AssignChannelOp;
333 (void) GetNextToken(p,&p,MagickPathExtent,token);
337 if (channel_op != ExchangeChannelOp)
338 channel_op=TransferChannelOp;
339 (void) GetNextToken(p,&p,MagickPathExtent,token);
343 case AssignChannelOp:
344 case ExchangeChannelOp:
345 case TransferChannelOp:
347 if (channel_op == AssignChannelOp)
348 pixel=StringToDoubleInterval(token,(double) QuantumRange+1.0);
351 i=ParsePixelChannelOption(token);
354 (void) ThrowMagickException(exception,GetMagickModule(),
355 OptionError,"UnrecognizedChannelType","`%s'",token);
356 destination_image=DestroyImageList(destination_image);
357 return(destination_image);
360 destination_channel=(PixelChannel) i;
361 if (i >= (ssize_t) GetPixelChannels(destination_image))
362 (void) SetPixelMetaChannels(destination_image,(size_t) (
363 destination_channel-GetPixelChannels(destination_image)+1),
365 if (image->colorspace != UndefinedColorspace)
366 switch (destination_channel)
368 case RedPixelChannel:
369 case GreenPixelChannel:
370 case BluePixelChannel:
371 case BlackPixelChannel:
372 case IndexPixelChannel:
374 case AlphaPixelChannel:
376 destination_image->alpha_trait=BlendPixelTrait;
379 case CompositeMaskPixelChannel:
381 destination_image->channels=(ChannelType)
382 (destination_image->channels | CompositeMaskChannel);
385 case ReadMaskPixelChannel:
387 destination_image->channels=(ChannelType)
388 (destination_image->channels | ReadMaskChannel);
391 case WriteMaskPixelChannel:
393 destination_image->channels=(ChannelType)
394 (destination_image->channels | WriteMaskChannel);
397 case MetaPixelChannel:
400 (void) SetPixelMetaChannels(destination_image,(size_t) (
401 destination_channel-GetPixelChannels(destination_image)+1),
406 channel_mask=(ChannelType) (channel_mask | ParseChannelOption(token));
407 if (((channels >= 1) || (destination_channel >= 1)) &&
408 (IsGrayColorspace(destination_image->colorspace) != MagickFalse))
409 (void) SetImageColorspace(destination_image,sRGBColorspace,exception);
410 (void) GetNextToken(p,&p,MagickPathExtent,token);
416 status=ChannelImage(destination_image,destination_channel,channel_op,
417 source_image,source_channel,ClampToQuantum(pixel),exception);
418 if (status == MagickFalse)
420 destination_image=DestroyImageList(destination_image);
424 if (channel_op == ExchangeChannelOp)
426 status=ChannelImage(destination_image,source_channel,channel_op,
427 source_image,destination_channel,ClampToQuantum(pixel),exception);
428 if (status == MagickFalse)
430 destination_image=DestroyImageList(destination_image);
437 case ExtractChannelOp:
439 channel_mask=(ChannelType) (channel_mask |
440 (1UL << destination_channel));
441 destination_channel=(PixelChannel) (destination_channel+1);
447 status=SetImageProgress(source_image,ChannelFxImageTag,p-expression,
449 if (status == MagickFalse)
452 (void) SetPixelChannelMask(destination_image,channel_mask);
453 if ((channel_op == ExtractChannelOp) && (channels == 1))
455 (void) SetPixelMetaChannels(destination_image,0,exception);
456 (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
458 return(GetFirstImageInList(destination_image));
462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466 % C o m b i n e I m a g e s %
470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 % CombineImages() combines one or more images into a single image. The
473 % grayscale value of the pixels of each image in the sequence is assigned in
474 % order to the specified channels of the combined image. The typical
475 % ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
477 % The format of the CombineImages method is:
479 % Image *CombineImages(const Image *images,const ColorspaceType colorspace,
480 % ExceptionInfo *exception)
482 % A description of each parameter follows:
484 % o images: the image sequence.
486 % o colorspace: the image colorspace.
488 % o exception: return any errors or warnings in this structure.
491 MagickExport Image *CombineImages(const Image *image,
492 const ColorspaceType colorspace,ExceptionInfo *exception)
494 #define CombineImageTag "Combine/Image"
512 Ensure the image are the same size.
514 assert(image != (const Image *) NULL);
515 assert(image->signature == MagickCoreSignature);
516 if (image->debug != MagickFalse)
517 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
518 assert(exception != (ExceptionInfo *) NULL);
519 assert(exception->signature == MagickCoreSignature);
520 combine_image=CloneImage(image,0,0,MagickTrue,exception);
521 if (combine_image == (Image *) NULL)
522 return((Image *) NULL);
523 if (SetImageStorageClass(combine_image,DirectClass,exception) == MagickFalse)
525 combine_image=DestroyImage(combine_image);
526 return((Image *) NULL);
528 if (colorspace != UndefinedColorspace)
529 (void) SetImageColorspace(combine_image,colorspace,exception);
531 if (fabs(image->gamma-1.0) <= MagickEpsilon)
532 (void) SetImageColorspace(combine_image,RGBColorspace,exception);
534 (void) SetImageColorspace(combine_image,sRGBColorspace,exception);
535 switch (combine_image->colorspace)
537 case UndefinedColorspace:
540 if (GetImageListLength(image) > 3)
541 combine_image->alpha_trait=BlendPixelTrait;
544 case LinearGRAYColorspace:
547 if (GetImageListLength(image) > 1)
548 combine_image->alpha_trait=BlendPixelTrait;
553 if (GetImageListLength(image) > 4)
554 combine_image->alpha_trait=BlendPixelTrait;
565 combine_view=AcquireAuthenticCacheView(combine_image,exception);
566 for (y=0; y < (ssize_t) combine_image->rows; y++)
577 register const Quantum
586 if (status == MagickFalse)
588 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
590 if (pixels == (Quantum *) NULL)
596 for (i=0; i < (ssize_t) GetPixelChannels(combine_image); i++)
601 PixelChannel channel = GetPixelChannelChannel(combine_image,i);
602 PixelTrait traits = GetPixelChannelTraits(combine_image,channel);
603 if (traits == UndefinedPixelTrait)
605 if (next == (Image *) NULL)
607 image_view=AcquireVirtualCacheView(next,exception);
608 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
609 if (p == (const Quantum *) NULL)
612 for (x=0; x < (ssize_t) combine_image->columns; x++)
614 if (x < (ssize_t) next->columns)
616 q[i]=GetPixelGray(next,p);
617 p+=GetPixelChannels(next);
619 q+=GetPixelChannels(combine_image);
621 image_view=DestroyCacheView(image_view);
622 next=GetNextImageInList(next);
624 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
626 if (image->progress_monitor != (MagickProgressMonitor) NULL)
631 #if defined(MAGICKCORE_OPENMP_SUPPORT)
635 proceed=SetImageProgress(image,CombineImageTag,progress,
636 combine_image->rows);
637 if (proceed == MagickFalse)
641 combine_view=DestroyCacheView(combine_view);
642 if (status == MagickFalse)
643 combine_image=DestroyImage(combine_image);
644 return(combine_image);
648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
652 % G e t I m a g e A l p h a C h a n n e l %
656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
658 % GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
659 % not activated. That is, the image is RGB rather than RGBA or CMYK rather
662 % The format of the GetImageAlphaChannel method is:
664 % MagickBooleanType GetImageAlphaChannel(const Image *image)
666 % A description of each parameter follows:
668 % o image: the image.
671 MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
673 assert(image != (const Image *) NULL);
674 if (image->debug != MagickFalse)
675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
676 assert(image->signature == MagickCoreSignature);
677 return(image->alpha_trait != UndefinedPixelTrait ? MagickTrue : MagickFalse);
681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
685 % S e p a r a t e I m a g e %
689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691 % SeparateImage() separates a channel from the image and returns it as a
694 % The format of the SeparateImage method is:
696 % Image *SeparateImage(const Image *image,const ChannelType channel,
697 % ExceptionInfo *exception)
699 % A description of each parameter follows:
701 % o image: the image.
703 % o channel: the image channel.
705 % o exception: return any errors or warnings in this structure.
708 MagickExport Image *SeparateImage(const Image *image,
709 const ChannelType channel_type,ExceptionInfo *exception)
711 #define GetChannelBit(mask,bit) (((size_t) (mask) >> (size_t) (bit)) & 0x01)
712 #define SeparateImageTag "Separate/Image"
731 Initialize separate image attributes.
733 assert(image != (Image *) NULL);
734 assert(image->signature == MagickCoreSignature);
735 if (image->debug != MagickFalse)
736 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
737 assert(exception != (ExceptionInfo *) NULL);
738 assert(exception->signature == MagickCoreSignature);
739 separate_image=CloneImage(image,0,0,MagickTrue,exception);
740 if (separate_image == (Image *) NULL)
741 return((Image *) NULL);
742 if (SetImageStorageClass(separate_image,DirectClass,exception) == MagickFalse)
744 separate_image=DestroyImage(separate_image);
745 return((Image *) NULL);
747 separate_image->alpha_trait=UndefinedPixelTrait;
748 (void) SetImageColorspace(separate_image,GRAYColorspace,exception);
749 separate_image->gamma=image->gamma;
755 image_view=AcquireVirtualCacheView(image,exception);
756 separate_view=AcquireAuthenticCacheView(separate_image,exception);
757 #if defined(MAGICKCORE_OPENMP_SUPPORT)
758 #pragma omp parallel for schedule(static) shared(progress,status) \
759 magick_number_threads(image,image,image->rows,1)
761 for (y=0; y < (ssize_t) image->rows; y++)
763 register const Quantum
772 if (status == MagickFalse)
774 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
775 q=QueueCacheViewAuthenticPixels(separate_view,0,y,separate_image->columns,1,
777 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
782 for (x=0; x < (ssize_t) image->columns; x++)
787 SetPixelChannel(separate_image,GrayPixelChannel,(Quantum) 0,q);
788 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
790 PixelChannel channel = GetPixelChannelChannel(image,i);
791 PixelTrait traits = GetPixelChannelTraits(image,channel);
792 if ((traits == UndefinedPixelTrait) ||
793 (GetChannelBit(channel_type,channel) == 0))
795 SetPixelChannel(separate_image,GrayPixelChannel,p[i],q);
797 p+=GetPixelChannels(image);
798 q+=GetPixelChannels(separate_image);
800 if (SyncCacheViewAuthenticPixels(separate_view,exception) == MagickFalse)
802 if (image->progress_monitor != (MagickProgressMonitor) NULL)
807 #if defined(MAGICKCORE_OPENMP_SUPPORT)
811 proceed=SetImageProgress(image,SeparateImageTag,progress,image->rows);
812 if (proceed == MagickFalse)
816 separate_view=DestroyCacheView(separate_view);
817 image_view=DestroyCacheView(image_view);
818 (void) SetImageChannelMask(separate_image,DefaultChannels);
819 if (status == MagickFalse)
820 separate_image=DestroyImage(separate_image);
821 return(separate_image);
825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
829 % S e p a r a t e I m a g e s %
833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835 % SeparateImages() returns a separate grayscale image for each channel
838 % The format of the SeparateImages method is:
840 % Image *SeparateImages(const Image *image,ExceptionInfo *exception)
842 % A description of each parameter follows:
844 % o image: the image.
846 % o exception: return any errors or warnings in this structure.
849 MagickExport Image *SeparateImages(const Image *image,ExceptionInfo *exception)
858 assert(image != (Image *) NULL);
859 assert(image->signature == MagickCoreSignature);
860 if (image->debug != MagickFalse)
861 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
862 images=NewImageList();
863 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
865 PixelChannel channel = GetPixelChannelChannel(image,i);
866 PixelTrait traits = GetPixelChannelTraits(image,channel);
867 if ((traits == UndefinedPixelTrait) || ((traits & UpdatePixelTrait) == 0))
869 separate_image=SeparateImage(image,(ChannelType) (1UL << channel),
871 if (separate_image != (Image *) NULL)
872 AppendImageToList(&images,separate_image);
874 if (images == (Image *) NULL)
875 images=SeparateImage(image,UndefinedChannel,exception);
880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
884 % S e t I m a g e A l p h a C h a n n e l %
888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
890 % SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
893 % The format of the SetImageAlphaChannel method is:
895 % MagickBooleanType SetImageAlphaChannel(Image *image,
896 % const AlphaChannelOption alpha_type,ExceptionInfo *exception)
898 % A description of each parameter follows:
900 % o image: the image.
902 % o alpha_type: The alpha channel type: ActivateAlphaChannel,
903 % AssociateAlphaChannel, CopyAlphaChannel, DeactivateAlphaChannel,
904 % DisassociateAlphaChannel, ExtractAlphaChannel, OffAlphaChannel,
905 % OnAlphaChannel, OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel,
906 % and TransparentAlphaChannel.
908 % o exception: return any errors or warnings in this structure.
912 static inline void FlattenPixelInfo(const Image *image,const PixelInfo *p,
913 const double alpha,const Quantum *q,const double beta,
925 Compose pixel p over pixel q with the given alpha.
927 Sa=QuantumScale*alpha;
928 Da=QuantumScale*beta,
929 gamma=Sa*(-Da)+Sa+Da;
930 gamma=PerceptibleReciprocal(gamma);
931 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
933 PixelChannel channel = GetPixelChannelChannel(image,i);
934 PixelTrait traits = GetPixelChannelTraits(image,channel);
935 if (traits == UndefinedPixelTrait)
939 case RedPixelChannel:
941 composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
942 (double) p->red,alpha));
945 case GreenPixelChannel:
947 composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
948 (double) p->green,alpha));
951 case BluePixelChannel:
953 composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
954 (double) p->blue,alpha));
957 case BlackPixelChannel:
959 composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
960 (double) p->black,alpha));
963 case AlphaPixelChannel:
965 composite[i]=ClampToQuantum(QuantumRange*(Sa*(-Da)+Sa+Da));
974 MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
975 const AlphaChannelOption alpha_type,ExceptionInfo *exception)
986 assert(image != (Image *) NULL);
987 if (image->debug != MagickFalse)
988 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
989 assert(image->signature == MagickCoreSignature);
993 case ActivateAlphaChannel:
995 image->alpha_trait=BlendPixelTrait;
998 case AssociateAlphaChannel:
1003 status=SetImageStorageClass(image,DirectClass,exception);
1004 if (status == MagickFalse)
1006 image_view=AcquireAuthenticCacheView(image,exception);
1007 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1008 #pragma omp parallel for schedule(static) shared(status) \
1009 magick_number_threads(image,image,image->rows,1)
1011 for (y=0; y < (ssize_t) image->rows; y++)
1019 if (status == MagickFalse)
1021 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1023 if (q == (Quantum *) NULL)
1028 for (x=0; x < (ssize_t) image->columns; x++)
1036 gamma=QuantumScale*GetPixelAlpha(image,q);
1037 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1039 PixelChannel channel = GetPixelChannelChannel(image,i);
1040 PixelTrait traits = GetPixelChannelTraits(image,channel);
1041 if (channel == AlphaPixelChannel)
1043 if ((traits & UpdatePixelTrait) == 0)
1045 q[i]=ClampToQuantum(gamma*q[i]);
1047 q+=GetPixelChannels(image);
1049 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1052 image_view=DestroyCacheView(image_view);
1053 image->alpha_trait=CopyPixelTrait;
1056 case BackgroundAlphaChannel:
1059 Set transparent pixels to background color.
1061 if (image->alpha_trait == UndefinedPixelTrait)
1063 status=SetImageStorageClass(image,DirectClass,exception);
1064 if (status == MagickFalse)
1066 image_view=AcquireAuthenticCacheView(image,exception);
1067 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1068 #pragma omp parallel for schedule(static) shared(status) \
1069 magick_number_threads(image,image,image->rows,1)
1071 for (y=0; y < (ssize_t) image->rows; y++)
1079 if (status == MagickFalse)
1081 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1083 if (q == (Quantum *) NULL)
1088 for (x=0; x < (ssize_t) image->columns; x++)
1090 if (GetPixelAlpha(image,q) == TransparentAlpha)
1092 SetPixelViaPixelInfo(image,&image->background_color,q);
1093 SetPixelChannel(image,AlphaPixelChannel,TransparentAlpha,q);
1095 q+=GetPixelChannels(image);
1097 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1100 image_view=DestroyCacheView(image_view);
1103 case CopyAlphaChannel:
1105 image->alpha_trait=UpdatePixelTrait;
1106 status=CompositeImage(image,image,IntensityCompositeOp,MagickTrue,0,0,
1110 case DeactivateAlphaChannel:
1112 if (image->alpha_trait == UndefinedPixelTrait)
1113 status=SetImageAlpha(image,OpaqueAlpha,exception);
1114 image->alpha_trait=CopyPixelTrait;
1117 case DisassociateAlphaChannel:
1122 status=SetImageStorageClass(image,DirectClass,exception);
1123 if (status == MagickFalse)
1125 image->alpha_trait=BlendPixelTrait;
1126 image_view=AcquireAuthenticCacheView(image,exception);
1127 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1128 #pragma omp parallel for schedule(static) shared(status) \
1129 magick_number_threads(image,image,image->rows,1)
1131 for (y=0; y < (ssize_t) image->rows; y++)
1139 if (status == MagickFalse)
1141 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1143 if (q == (Quantum *) NULL)
1148 for (x=0; x < (ssize_t) image->columns; x++)
1157 Sa=QuantumScale*GetPixelAlpha(image,q);
1158 gamma=PerceptibleReciprocal(Sa);
1159 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1161 PixelChannel channel = GetPixelChannelChannel(image,i);
1162 PixelTrait traits = GetPixelChannelTraits(image,channel);
1163 if (channel == AlphaPixelChannel)
1165 if ((traits & UpdatePixelTrait) == 0)
1167 q[i]=ClampToQuantum(gamma*q[i]);
1169 q+=GetPixelChannels(image);
1171 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1174 image_view=DestroyCacheView(image_view);
1175 image->alpha_trait=UndefinedPixelTrait;
1178 case DiscreteAlphaChannel:
1180 if (image->alpha_trait == UndefinedPixelTrait)
1181 status=SetImageAlpha(image,OpaqueAlpha,exception);
1182 image->alpha_trait=UpdatePixelTrait;
1185 case ExtractAlphaChannel:
1187 status=CompositeImage(image,image,AlphaCompositeOp,MagickTrue,0,0,
1189 image->alpha_trait=UndefinedPixelTrait;
1192 case OffAlphaChannel:
1194 image->alpha_trait=UndefinedPixelTrait;
1197 case OnAlphaChannel:
1199 if (image->alpha_trait == UndefinedPixelTrait)
1200 status=SetImageAlpha(image,OpaqueAlpha,exception);
1201 image->alpha_trait=BlendPixelTrait;
1204 case OpaqueAlphaChannel:
1206 status=SetImageAlpha(image,OpaqueAlpha,exception);
1209 case RemoveAlphaChannel:
1212 Remove transparency.
1214 if (image->alpha_trait == UndefinedPixelTrait)
1216 status=SetImageStorageClass(image,DirectClass,exception);
1217 if (status == MagickFalse)
1219 image_view=AcquireAuthenticCacheView(image,exception);
1220 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1221 #pragma omp parallel for schedule(static) shared(status) \
1222 magick_number_threads(image,image,image->rows,1)
1224 for (y=0; y < (ssize_t) image->rows; y++)
1232 if (status == MagickFalse)
1234 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1236 if (q == (Quantum *) NULL)
1241 for (x=0; x < (ssize_t) image->columns; x++)
1243 FlattenPixelInfo(image,&image->background_color,
1244 image->background_color.alpha,q,(double) GetPixelAlpha(image,q),q);
1245 q+=GetPixelChannels(image);
1247 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1250 image_view=DestroyCacheView(image_view);
1251 image->alpha_trait=image->background_color.alpha_trait;
1254 case SetAlphaChannel:
1256 if (image->alpha_trait == UndefinedPixelTrait)
1257 status=SetImageAlpha(image,OpaqueAlpha,exception);
1260 case ShapeAlphaChannel:
1266 Remove transparency.
1268 ConformPixelInfo(image,&image->background_color,&background,exception);
1269 background.alpha_trait=BlendPixelTrait;
1270 image->alpha_trait=BlendPixelTrait;
1271 status=SetImageStorageClass(image,DirectClass,exception);
1272 if (status == MagickFalse)
1274 image_view=AcquireAuthenticCacheView(image,exception);
1275 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1276 #pragma omp parallel for schedule(static) shared(status) \
1277 magick_number_threads(image,image,image->rows,1)
1279 for (y=0; y < (ssize_t) image->rows; y++)
1290 if (status == MagickFalse)
1292 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1294 if (q == (Quantum *) NULL)
1300 for (x=0; x < (ssize_t) image->columns; x++)
1302 pixel.alpha=GetPixelIntensity(image,q);
1303 SetPixelViaPixelInfo(image,&pixel,q);
1304 q+=GetPixelChannels(image);
1306 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1309 image_view=DestroyCacheView(image_view);
1312 case TransparentAlphaChannel:
1314 status=SetImageAlpha(image,TransparentAlpha,exception);
1317 case UndefinedAlphaChannel:
1320 if (status == MagickFalse)
1322 (void) SetPixelChannelMask(image,image->channel_mask);
1323 return(SyncImagePixelCache(image,exception));