% MagickCore Image Channel Methods %
% %
% Software Design %
-% John Cristy %
+% Cristy %
% December 2003 %
% %
% %
-% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
Include declarations.
*/
#include "MagickCore/studio.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/channel.h"
#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/enhance.h"
#include "MagickCore/image.h"
#include "MagickCore/list.h"
#include "MagickCore/log.h"
#include "MagickCore/monitor-private.h"
#include "MagickCore/option.h"
#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/pixel-private.h"
#include "MagickCore/resource_.h"
#include "MagickCore/string-private.h"
#include "MagickCore/thread-private.h"
/*
Interpret channel expression.
*/
- if (*token == ',')
+ switch (*token)
+ {
+ case ',':
{
- destination_channel=(PixelChannel) ((ssize_t) destination_channel+1);
GetMagickToken(p,&p,token);
+ break;
}
- if (*token == '|')
+ case '|':
{
if (GetNextImageInList(source_image) != (Image *) NULL)
source_image=GetNextImageInList(source_image);
else
source_image=GetFirstImageInList(source_image);
GetMagickToken(p,&p,token);
+ break;
}
- if (*token == ';')
+ case ';':
{
Image
*canvas;
SetPixelChannelMask(destination_image,channel_mask);
- if ((channel_op == ExtractChannelOp) && (destination_channel == 1))
+ if ((channel_op == ExtractChannelOp) && (channels == 1))
(void) SetImageColorspace(destination_image,GRAYColorspace,exception);
status=SetImageStorageClass(destination_image,DirectClass,exception);
if (status == MagickFalse)
channels=0;
destination_channel=RedPixelChannel;
channel_mask=UndefinedChannel;
+ break;
}
+ default:
+ break;
+ }
i=ParsePixelChannelOption(token);
if (i < 0)
{
return(destination_image);
}
destination_channel=(PixelChannel) i;
+ switch (destination_channel)
+ {
+ case RedPixelChannel:
+ case GreenPixelChannel:
+ case BluePixelChannel:
+ case BlackPixelChannel:
+ case IndexPixelChannel:
+ break;
+ case AlphaPixelChannel:
+ {
+ destination_image->alpha_trait=BlendPixelTrait;
+ break;
+ }
+ case ReadMaskPixelChannel:
+ {
+ destination_image->read_mask=MagickTrue;
+ break;
+ }
+ case WriteMaskPixelChannel:
+ {
+ destination_image->write_mask=MagickTrue;
+ break;
+ }
+ case MetaPixelChannel:
+ default:
+ {
+ (void) SetPixelMetaChannels(destination_image,(size_t) (i-
+ GetPixelChannels(destination_image)+1),exception);
+ break;
+ }
+ }
channel_mask=(ChannelType) (channel_mask | ParseChannelOption(token));
- if (LocaleCompare(token,"gray") == 0)
- (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
- if ((LocaleCompare(token,"black") == 0) ||
- (LocaleCompare(token,"c") == 0) ||
- (LocaleCompare(token,"cyan") == 0) ||
- (LocaleCompare(token,"k") == 0) ||
- (LocaleCompare(token,"m") == 0) ||
- (LocaleCompare(token,"magenta") == 0) ||
- (LocaleCompare(token,"y") == 0) ||
- (LocaleCompare(token,"yellow") == 0))
- (void) SetImageColorspace(destination_image,CMYKColorspace,exception);
- if ((LocaleCompare(token,"Cb") == 0) ||
- (LocaleCompare(token,"Cr") == 0))
- (void) SetImageColorspace(destination_image,YCbCrColorspace,
- exception);
- if (LocaleCompare(token,"alpha") == 0)
- (void) SetImageAlpha(destination_image,OpaqueAlpha,exception);
- if (i >= (ssize_t) GetPixelChannels(destination_image))
- (void) SetPixelMetaChannels(destination_image,(size_t) (i-
- GetPixelChannels(destination_image)+1),exception);
+ if (((channels >= 1) || (destination_channel >= 1)) &&
+ (IsGrayColorspace(destination_image->colorspace) != MagickFalse))
+ (void) SetImageColorspace(destination_image,sRGBColorspace,exception);
GetMagickToken(p,&p,token);
break;
}
break;
}
SetPixelChannelMask(destination_image,channel_mask);
- if ((channel_op == ExtractChannelOp) && (destination_channel == 1))
+ if ((channel_op == ExtractChannelOp) && (channels == 1))
(void) SetImageColorspace(destination_image,GRAYColorspace,exception);
status=SetImageStorageClass(destination_image,DirectClass,exception);
if (status == MagickFalse)
combine_image=DestroyImage(combine_image);
return((Image *) NULL);
}
+ (void) SetImageColorspace(combine_image,colorspace,exception);
if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
combine_image->alpha_trait=BlendPixelTrait;
/*
}
}
combine_view=DestroyCacheView(combine_view);
- (void) TransformImageColorspace(combine_image,colorspace,exception);
if (status == MagickFalse)
combine_image=DestroyImage(combine_image);
return(combine_image);
% %
% %
% %
+% G e t I m a g e A l p h a C h a n n e l %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
+% not activated. That is, the image is RGB rather than RGBA or CMYK rather
+% than CMYKA.
+%
+% The format of the GetImageAlphaChannel method is:
+%
+% MagickBooleanType GetImageAlphaChannel(const Image *image)
+%
+% A description of each parameter follows:
+%
+% o image: the image.
+%
+*/
+MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
+{
+ assert(image != (const Image *) NULL);
+ if (image->debug != MagickFalse)
+ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+ assert(image->signature == MagickSignature);
+ return(image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
% S e p a r a t e I m a g e %
% %
% %
y;
/*
- Initialize spread image attributes.
+ Initialize separate image attributes.
*/
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
separate_image=DestroyImage(separate_image);
return((Image *) NULL);
}
- separate_image->alpha_trait=UndefinedPixelTrait;
(void) SetImageColorspace(separate_image,GRAYColorspace,exception);
+ separate_image->alpha_trait=UndefinedPixelTrait;
/*
Separate image.
*/
register ssize_t
i;
- if (GetPixelMask(image,p) == 0)
+ if (GetPixelReadMask(image,p) == 0)
{
+ SetPixelBackgoundColor(separate_image,q);
p+=GetPixelChannels(image);
q+=GetPixelChannels(separate_image);
continue;
SetPixelChannel(separate_image,GrayPixelChannel,0,q);
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
{
- double
- pixel;
-
PixelChannel channel=GetPixelChannelChannel(image,i);
PixelTrait traits=GetPixelChannelTraits(image,channel);
if ((traits == UndefinedPixelTrait) ||
(GetChannelBit(channel_type,channel) == 0))
continue;
- pixel=p[i];
- if (IssRGBColorspace(image->colorspace) != MagickFalse)
- pixel=DecodePixelGamma(pixel);
- SetPixelChannel(separate_image,GrayPixelChannel,ClampToQuantum(pixel),
- q);
+ SetPixelChannel(separate_image,GrayPixelChannel,p[i],q);
}
p+=GetPixelChannels(image);
q+=GetPixelChannels(separate_image);
images=SeparateImage(image,UndefinedChannel,exception);
return(images);
}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% S e t I m a g e A l p h a C h a n n e l %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
+% channel.
+%
+% The format of the SetImageAlphaChannel method is:
+%
+% MagickBooleanType SetImageAlphaChannel(Image *image,
+% const AlphaChannelOption alpha_type,ExceptionInfo *exception)
+%
+% A description of each parameter follows:
+%
+% o image: the image.
+%
+% o alpha_type: The alpha channel type: ActivateAlphaChannel,
+% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
+% OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
+% TransparentAlphaChannel.
+%
+% o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline void FlattenPixelInfo(const Image *image,const PixelInfo *p,
+ const double alpha,const Quantum *q,const double beta,
+ Quantum *composite)
+{
+ double
+ Da,
+ gamma,
+ Sa;
+
+ register ssize_t
+ i;
+
+ /*
+ Compose pixel p over pixel q with the given alpha.
+ */
+ Sa=QuantumScale*alpha;
+ Da=QuantumScale*beta,
+ gamma=Sa*(-Da)+Sa+Da;
+ gamma=PerceptibleReciprocal(gamma);
+ for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+ {
+ PixelChannel channel=GetPixelChannelChannel(image,i);
+ PixelTrait traits=GetPixelChannelTraits(image,channel);
+ if (traits == UndefinedPixelTrait)
+ continue;
+ switch (channel)
+ {
+ case RedPixelChannel:
+ {
+ composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
+ (double) p->red,alpha));
+ break;
+ }
+ case GreenPixelChannel:
+ {
+ composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
+ (double) p->green,alpha));
+ break;
+ }
+ case BluePixelChannel:
+ {
+ composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
+ (double) p->blue,alpha));
+ break;
+ }
+ case BlackPixelChannel:
+ {
+ composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
+ (double) p->black,alpha));
+ break;
+ }
+ case AlphaPixelChannel:
+ {
+ composite[i]=ClampToQuantum(QuantumRange*(Sa*(-Da)+Sa+Da));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
+ const AlphaChannelOption alpha_type,ExceptionInfo *exception)
+{
+ MagickBooleanType
+ status;
+
+ assert(image != (Image *) NULL);
+ if (image->debug != MagickFalse)
+ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+ assert(image->signature == MagickSignature);
+ status=MagickTrue;
+ switch (alpha_type)
+ {
+ case ActivateAlphaChannel:
+ {
+ image->alpha_trait=BlendPixelTrait;
+ break;
+ }
+ case BackgroundAlphaChannel:
+ {
+ CacheView
+ *image_view;
+
+ ssize_t
+ y;
+
+ /*
+ Set transparent pixels to background color.
+ */
+ if (image->alpha_trait != BlendPixelTrait)
+ break;
+ if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
+ break;
+ image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(static,4) shared(status) \
+ magick_threads(image,image,image->rows,1)
+#endif
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ register Quantum
+ *restrict q;
+
+ register ssize_t
+ x;
+
+ if (status == MagickFalse)
+ continue;
+ q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+ exception);
+ if (q == (Quantum *) NULL)
+ {
+ status=MagickFalse;
+ continue;
+ }
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ if (GetPixelAlpha(image,q) == TransparentAlpha)
+ {
+ SetPixelInfoPixel(image,&image->background_color,q);
+ SetPixelChannel(image,AlphaPixelChannel,TransparentAlpha,q);
+ }
+ q+=GetPixelChannels(image);
+ }
+ if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+ status=MagickFalse;
+ }
+ image_view=DestroyCacheView(image_view);
+ return(status);
+ }
+ case CopyAlphaChannel:
+ case ShapeAlphaChannel:
+ {
+ /*
+ Copy pixel intensity to the alpha channel.
+ */
+ status=CompositeImage(image,image,IntensityCompositeOp,MagickTrue,0,0,
+ exception);
+ if (alpha_type == ShapeAlphaChannel)
+ (void) LevelImageColors(image,&image->background_color,
+ &image->background_color,MagickTrue,exception);
+ break;
+ }
+ case DeactivateAlphaChannel:
+ {
+ image->alpha_trait=CopyPixelTrait;
+ break;
+ }
+ case ExtractAlphaChannel:
+ {
+ status=CompositeImage(image,image,AlphaCompositeOp,MagickTrue,0,0,
+ exception);
+ image->alpha_trait=CopyPixelTrait;
+ break;
+ }
+ case OpaqueAlphaChannel:
+ {
+ status=SetImageAlpha(image,OpaqueAlpha,exception);
+ break;
+ }
+ case RemoveAlphaChannel:
+ {
+ CacheView
+ *image_view;
+
+ ssize_t
+ y;
+
+ /*
+ Remove transparency.
+ */
+ if (image->alpha_trait != BlendPixelTrait)
+ break;
+ if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
+ break;
+ image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(static,4) shared(status) \
+ magick_threads(image,image,image->rows,1)
+#endif
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ register Quantum
+ *restrict q;
+
+ register ssize_t
+ x;
+
+ if (status == MagickFalse)
+ continue;
+ q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+ exception);
+ if (q == (Quantum *) NULL)
+ {
+ status=MagickFalse;
+ continue;
+ }
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ FlattenPixelInfo(image,&image->background_color,
+ image->background_color.alpha,q,(double)
+ GetPixelAlpha(image,q),q);
+ q+=GetPixelChannels(image);
+ }
+ if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+ status=MagickFalse;
+ }
+ image_view=DestroyCacheView(image_view);
+ image->alpha_trait=image->background_color.alpha_trait;
+ return(status);
+ }
+ case SetAlphaChannel:
+ {
+ if (image->alpha_trait != BlendPixelTrait)
+ status=SetImageAlpha(image,OpaqueAlpha,exception);
+ break;
+ }
+ case TransparentAlphaChannel:
+ {
+ status=SetImageAlpha(image,TransparentAlpha,exception);
+ break;
+ }
+ case UndefinedAlphaChannel:
+ break;
+ }
+ if (status == MagickFalse)
+ return(status);
+ return(SyncImagePixelCache(image,exception));
+}