Include declarations.
*/
#include "MagickCore/studio.h"
+#include "MagickCore/colorspace-private.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/resource_.h"
#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
#include "MagickCore/token.h"
#include "MagickCore/utility.h"
#include "MagickCore/version.h"
% red, 1), separated by actions as follows:
%
% <=> exchange two channels (e.g. red<=>blue)
-% => transfer a channel to another (e.g. red=>green)
-% = assign a constant (e.g. red=50%)
-% , separate channel operations (e.g. red, green)
-% | read channels from next input image (e.g. red | green)
-% ; write channels to next output image (e.g. red; green; blue)
+% => copy one channel to another channel (e.g. red=>green)
+% = assign a constant value to a channel (e.g. red=50%)
+% , write new image channels in the specified order (e.g. red, green)
+% | add a new output image for the next set of channel operations
+% ; move to the next input image for the source of channel data
%
-% A channel without a operation symbol implies extract. For example, to create
-% 3 grayscale images from the red, green, and blue channels of an image, use:
+% For example, to create 3 grayscale images from the red, green, and blue
+% channels of an image, use:
%
% -channel-fx "red; green; blue"
%
+% A channel without an operation symbol implies separate (i.e, semicolon).
+%
% The format of the ChannelFxImage method is:
%
% Image *ChannelFxImage(const Image *image,const char *expression,
status;
size_t
- height;
+ height,
+ width;
ssize_t
y;
status=MagickTrue;
- source_view=AcquireCacheView(source_image);
- destination_view=AcquireCacheView(destination_image);
+ source_view=AcquireVirtualCacheView(source_image,exception);
+ destination_view=AcquireAuthenticCacheView(destination_image,exception);
height=MagickMin(source_image->rows,destination_image->rows);
+ width=MagickMin(source_image->columns,destination_image->columns);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static) shared(status)
+ #pragma omp parallel for schedule(static,4) shared(status) \
+ dynamic_number_threads(source_image,width,height,1)
#endif
for (y=0; y < (ssize_t) height; y++)
{
+ PixelTrait
+ destination_traits,
+ source_traits;
+
register const Quantum
*restrict p;
register ssize_t
x;
- size_t
- width;
-
if (status == MagickFalse)
continue;
p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
exception);
- q=QueueCacheViewAuthenticPixels(destination_view,0,y,
+ q=GetCacheViewAuthenticPixels(destination_view,0,y,
destination_image->columns,1,exception);
if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
{
status=MagickFalse;
continue;
}
- width=MagickMin(source_image->columns,destination_image->columns);
+ destination_traits=GetPixelChannelTraits(destination_image,
+ destination_channel);
+ source_traits=GetPixelChannelTraits(source_image,source_channel);
+ if ((destination_traits == UndefinedPixelTrait) ||
+ (source_traits == UndefinedPixelTrait))
+ continue;
for (x=0; x < (ssize_t) width; x++)
{
- PixelTrait
- destination_traits,
- source_traits;
-
- ssize_t
- offset;
-
- destination_traits=GetPixelChannelMapTraits(destination_image,
- destination_channel);
- if (destination_traits == UndefinedPixelTrait)
- continue;
if (channel_op == AssignChannelOp)
SetPixelChannel(destination_image,destination_channel,pixel,q);
else
- {
- source_traits=GetPixelChannelMapTraits(source_image,source_channel);
- if (source_traits == UndefinedPixelTrait)
- continue;
- offset=GetPixelChannelMapOffset(source_image,source_channel);
- SetPixelChannel(destination_image,destination_channel,p[offset],q);
- p+=GetPixelChannels(source_image);
- }
+ SetPixelChannel(destination_image,destination_channel,
+ GetPixelChannel(source_image,source_channel,p),q);
+ p+=GetPixelChannels(source_image);
q+=GetPixelChannels(destination_image);
}
if (SyncCacheViewAuthenticPixels(destination_view,exception) == MagickFalse)
{
#define ChannelFxImageTag "ChannelFx/Image"
- char
- token[MaxTextExtent];
-
ChannelFx
channel_op;
+ ChannelType
+ channel_mask;
+
+ char
+ token[MaxTextExtent];
+
const char
*p;
Image
*destination_image;
+ MagickBooleanType
+ status;
+
PixelChannel
source_channel,
destination_channel;
destination_image=CloneImage(source_image,0,0,MagickTrue,exception);
if (destination_image == (Image *) NULL)
return((Image *) NULL);
- if (SetImageBackgroundColor(destination_image,exception) == MagickFalse)
- {
- destination_image=GetLastImageInList(destination_image);
- return((Image *) NULL);
- }
+ if (IsGrayColorspace(image->colorspace) != MagickFalse)
+ (void) TransformImageColorspace((Image *) image,RGBColorspace,exception);
if (expression == (const char *) NULL)
return(destination_image);
destination_channel=RedPixelChannel;
+ channel_mask=UndefinedChannel;
pixel=0.0;
p=(char *) expression;
GetMagickToken(p,&p,token);
- for (channels=0; *p != '\0'; )
+ channel_op=ExtractChannelOp;
+ for (channels=0; *token != '\0'; )
{
- MagickBooleanType
- status;
-
ssize_t
i;
Image
*canvas;
- if (channels == 1)
+ SetPixelChannelMask(destination_image,channel_mask);
+ if ((channel_op == ExtractChannelOp) && (destination_channel == 1))
+ (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
+ status=SetImageStorageClass(destination_image,DirectClass,exception);
+ if (status == MagickFalse)
{
- destination_image->colorspace=GRAYColorspace;
- InitializePixelChannelMap(destination_image);
+ destination_image=DestroyImageList(destination_image);
+ return(destination_image);
}
canvas=CloneImage(source_image,0,0,MagickTrue,exception);
if (canvas == (Image *) NULL)
{
- destination_image=GetLastImageInList(destination_image);
- return((Image *) NULL);
+ destination_image=DestroyImageList(destination_image);
+ return(destination_image);
}
+ if (IsGrayColorspace(canvas->colorspace) != MagickFalse)
+ (void) TransformImageColorspace(canvas,RGBColorspace,exception);
AppendImageToList(&destination_image,canvas);
destination_image=GetLastImageInList(destination_image);
- if (SetImageBackgroundColor(destination_image,exception) == MagickFalse)
- {
- destination_image=GetLastImageInList(destination_image);
- return((Image *) NULL);
- }
GetMagickToken(p,&p,token);
channels=0;
destination_channel=RedPixelChannel;
+ channel_mask=UndefinedChannel;
}
i=ParsePixelChannelOption(token);
if (i < 0)
{
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
- "UnrecognizedChannelType","`%s'",token);
+ "UnrecognizedChannelType","'%s'",token);
destination_image=DestroyImageList(destination_image);
- break;
+ return(destination_image);
}
source_channel=(PixelChannel) i;
channel_op=ExtractChannelOp;
{
case AssignChannelOp:
{
- pixel=StringToDouble(token);
+ pixel=StringToDoubleInterval(token,(double) QuantumRange+1.0);
GetMagickToken(p,&p,token);
break;
}
if (i < 0)
{
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
- "UnrecognizedChannelType","`%s'",token);
+ "UnrecognizedChannelType","'%s'",token);
destination_image=DestroyImageList(destination_image);
- break;
+ return(destination_image);
}
destination_channel=(PixelChannel) i;
+ 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);
GetMagickToken(p,&p,token);
break;
}
- case ExtractChannelOp:
+ default:
break;
- }
+ }
status=ChannelImage(destination_image,destination_channel,channel_op,
source_image,source_channel,ClampToQuantum(pixel),exception);
if (status == MagickFalse)
destination_image=DestroyImageList(destination_image);
break;
}
+ channels++;
if (channel_op == ExchangeChannelOp)
{
- status=ChannelImage(destination_image,destination_channel,channel_op,
- source_image,source_channel,ClampToQuantum(pixel),exception);
+ status=ChannelImage(destination_image,source_channel,channel_op,
+ source_image,destination_channel,ClampToQuantum(pixel),exception);
if (status == MagickFalse)
{
destination_image=DestroyImageList(destination_image);
break;
}
+ channels++;
}
- channels++;
+ switch (channel_op)
+ {
+ case ExtractChannelOp:
+ {
+ channel_mask=(ChannelType) (channel_mask | (1 << destination_channel));
+ destination_channel=(PixelChannel) (destination_channel+1);
+ break;
+ }
+ default:
+ break;
+ }
status=SetImageProgress(source_image,ChannelFxImageTag,p-expression,
strlen(expression));
if (status == MagickFalse)
break;
}
- if (channels == 1)
+ SetPixelChannelMask(destination_image,channel_mask);
+ if ((channel_op == ExtractChannelOp) && (destination_channel == 1))
+ (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
+ status=SetImageStorageClass(destination_image,DirectClass,exception);
+ if (status == MagickFalse)
{
- destination_image->colorspace=GRAYColorspace;
- InitializePixelChannelMap(destination_image);
+ destination_image=GetLastImageInList(destination_image);
+ return((Image *) NULL);
}
- return(destination_image);
+ return(GetFirstImageInList(destination_image));
}
\f
/*
%
% The format of the CombineImages method is:
%
-% Image *CombineImages(const Image *image,ExceptionInfo *exception)
+% Image *CombineImages(const Image *images,const ColorspaceType colorspace,
+% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
-% o image: the image.
+% o images: the image sequence.
+%
+% o colorspace: the image colorspace.
%
% o exception: return any errors or warnings in this structure.
%
*/
-MagickExport Image *CombineImages(const Image *image,ExceptionInfo *exception)
+MagickExport Image *CombineImages(const Image *image,
+ const ColorspaceType colorspace,ExceptionInfo *exception)
{
#define CombineImageTag "Combine/Image"
combine_image=DestroyImage(combine_image);
return((Image *) NULL);
}
+ if (IsGrayColorspace(image->colorspace) != MagickFalse)
+ (void) SetImageColorspace(combine_image,RGBColorspace,exception);
if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
- combine_image->matte=MagickTrue;
+ combine_image->alpha_trait=BlendPixelTrait;
/*
Combine images.
*/
status=MagickTrue;
progress=0;
- combine_view=AcquireCacheView(combine_image);
+ combine_view=AcquireAuthenticCacheView(combine_image,exception);
for (y=0; y < (ssize_t) combine_image->rows; y++)
{
CacheView
continue;
}
next=image;
- for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+ for (i=0; i < (ssize_t) GetPixelChannels(combine_image); i++)
{
PixelChannel
channel;
PixelTrait
- combine_traits,
traits;
register ssize_t
if (next == (Image *) NULL)
continue;
- channel=GetPixelChannelMapChannel(image,i);
- traits=GetPixelChannelMapTraits(image,channel);
- combine_traits=GetPixelChannelMapTraits(combine_image,channel);
- if ((traits == UndefinedPixelTrait) ||
- (combine_traits == UndefinedPixelTrait))
+ channel=GetPixelChannelChannel(combine_image,i);
+ traits=GetPixelChannelTraits(combine_image,channel);
+ if (traits == UndefinedPixelTrait)
continue;
- image_view=AcquireCacheView(next);
+ image_view=AcquireVirtualCacheView(next,exception);
p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
if (p == (const Quantum *) NULL)
continue;
q=pixels;
for (x=0; x < (ssize_t) combine_image->columns; x++)
{
- if (x < (ssize_t) image->columns)
+ if (x < (ssize_t) next->columns)
{
- q[i]=GetPixelGray(image,p);
- p+=GetPixelChannels(image);
+ q[i]=GetPixelGray(next,p);
+ p+=GetPixelChannels(next);
}
q+=GetPixelChannels(combine_image);
}
image_view=DestroyCacheView(image_view);
next=GetNextImageInList(next);
- if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
- status=MagickFalse;
- if (image->progress_monitor != (MagickProgressMonitor) NULL)
- {
- MagickBooleanType
- proceed;
-
- proceed=SetImageProgress(image,CombineImageTag,progress++,
- combine_image->rows);
- if (proceed == MagickFalse)
- status=MagickFalse;
- }
}
+ if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
+ status=MagickFalse;
+ if (image->progress_monitor != (MagickProgressMonitor) NULL)
+ {
+ MagickBooleanType
+ proceed;
+
+ proceed=SetImageProgress(image,CombineImageTag,progress++,
+ combine_image->rows);
+ if (proceed == MagickFalse)
+ status=MagickFalse;
+ }
}
combine_view=DestroyCacheView(combine_view);
if (status == MagickFalse)
combine_image=DestroyImage(combine_image);
+ (void) TransformImageColorspace(combine_image,colorspace,exception);
return(combine_image);
}
\f
separate_image=DestroyImage(separate_image);
return((Image *) NULL);
}
- separate_image->colorspace=GRAYColorspace;
+ separate_image->alpha_trait=UndefinedPixelTrait;
+ (void) SetImageColorspace(separate_image,GRAYColorspace,exception);
/*
Separate image.
*/
status=MagickTrue;
progress=0;
- image_view=AcquireCacheView(image);
- separate_view=AcquireCacheView(separate_image);
+ image_view=AcquireVirtualCacheView(image,exception);
+ separate_view=AcquireAuthenticCacheView(separate_image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static) shared(progress,status)
+ #pragma omp parallel for schedule(static,4) shared(progress,status) \
+ dynamic_number_threads(image,image->columns,image->rows,1)
#endif
for (y=0; y < (ssize_t) image->rows; y++)
{
SetPixelChannel(separate_image,GrayPixelChannel,0,q);
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
{
+ double
+ pixel;
+
PixelChannel
channel;
PixelTrait
traits;
- channel=GetPixelChannelMapChannel(image,i);
- traits=GetPixelChannelMapTraits(image,channel);
+ channel=GetPixelChannelChannel(image,i);
+ traits=GetPixelChannelTraits(image,channel);
if ((traits == UndefinedPixelTrait) ||
(GetChannelBit(channel_type,channel) == 0))
continue;
- SetPixelChannel(separate_image,GrayPixelChannel,p[i],q);
+ pixel=p[i];
+ if (IssRGBColorspace(image->colorspace) != MagickFalse)
+ pixel=DecodesRGBGamma(pixel);
+ SetPixelChannel(separate_image,GrayPixelChannel,ClampToQuantum(pixel),
+ q);
}
p+=GetPixelChannels(image);
q+=GetPixelChannels(separate_image);
proceed;
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp critical (MagickCore_SeparateImage)
+ #pragma omp critical (MagickCore_SeparateImage)
#endif
proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
if (proceed == MagickFalse)
%
% The format of the SeparateImages method is:
%
-% MagickBooleanType SeparateImages(const Image *image,
-% ExceptionInfo *exception)
+% Image *SeparateImages(const Image *image,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
PixelTrait
traits;
- channel=GetPixelChannelMapChannel(image,i);
- traits=GetPixelChannelMapTraits(image,channel);
+ channel=GetPixelChannelChannel(image,i);
+ traits=GetPixelChannelTraits(image,channel);
if ((traits == UndefinedPixelTrait) ||
((traits & UpdatePixelTrait) == 0))
continue;
if (separate_image != (Image *) NULL)
AppendImageToList(&images,separate_image);
}
+ if (images == (Image *) NULL)
+ images=SeparateImage(image,UndefinedChannel,exception);
return(images);
}