#include "MagickCore/image.h"
#include "MagickCore/list.h"
#include "MagickCore/log.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
#include "MagickCore/token.h"
#include "MagickCore/utility.h"
#include "MagickCore/version.h"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ChannelOperationImage() applies a channel expression to the specified image.
+% The expression consists of one or more channels, either mnemonic or numeric
+% (e.g. red, 1), separated by certain operation symbols as follows:
+%
+% <=> exchange two channels (e.g. red<=>blue)
+% => transfer a channel to another (e.g. red=>green)
+% , 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)
+%
+% 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:
+%
+% -channel-ops "red; green; blue"
%
% The format of the ChannelOperationImage method is:
%
-% Image *ChannelOperationImage(const Image *images,
+% Image *ChannelOperationImage(const Image *image,
% const char *expression,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
-% o images: the images.
+% o image: the image.
%
% o expression: A channel expression.
%
TransferChannelOp
} ChannelOperation;
-static MagickBooleanType ChannelImage(Image *channel_image,const Image *image,
- const ChannelOperation channel_op,const PixelChannel p_channel,
- const PixelChannel q_channel,ExceptionInfo *exception)
+static inline size_t MagickMin(const size_t x,const size_t y)
{
- return(MagickTrue);
+ if (x < y)
+ return(x);
+ return(y);
}
-MagickExport Image *ChannelOperationImage(const Image *images,
+static MagickBooleanType ChannelImage(Image *destination_image,
+ const Image *source_image,const ChannelOperation channel_op,
+ const PixelChannel source_channel,const PixelChannel destination_channel,
+ ExceptionInfo *exception)
+{
+ CacheView
+ *source_view,
+ *destination_view;
+
+ MagickBooleanType
+ status;
+
+ size_t
+ height;
+
+ ssize_t
+ y;
+
+ status=MagickTrue;
+ source_view=AcquireCacheView(source_image);
+ destination_view=AcquireCacheView(destination_image);
+ height=MagickMin(source_image->rows,destination_image->rows);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(static) shared(status)
+#endif
+ for (y=0; y < (ssize_t) height; y++)
+ {
+ register const Quantum
+ *restrict p;
+
+ register Quantum
+ *restrict q;
+
+ 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,
+ destination_image->columns,1,exception);
+ if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+ {
+ status=MagickFalse;
+ continue;
+ }
+ width=MagickMin(source_image->columns,destination_image->columns);
+ for (x=0; x < (ssize_t) width; x++)
+ {
+ PixelTrait
+ destination_traits,
+ source_traits;
+
+ ssize_t
+ offset;
+
+ source_traits=GetPixelChannelMapTraits(source_image,source_channel);
+ destination_traits=GetPixelChannelMapTraits(destination_image,
+ destination_channel);
+ if ((source_traits == UndefinedPixelTrait) ||
+ (destination_traits == UndefinedPixelTrait))
+ continue;
+ offset=GetPixelChannelMapOffset(source_image,source_channel);
+ SetPixelChannel(destination_image,destination_channel,p[offset],q);
+ p+=GetPixelChannels(source_image);
+ q+=GetPixelChannels(destination_image);
+ }
+ if (SyncCacheViewAuthenticPixels(destination_view,exception) == MagickFalse)
+ status=MagickFalse;
+ }
+ destination_view=DestroyCacheView(destination_view);
+ source_view=DestroyCacheView(source_view);
+ return(status);
+}
+
+MagickExport Image *ChannelOperationImage(const Image *image,
const char *expression,ExceptionInfo *exception)
{
+#define ChannelOperationImageTag "ChannelOperation/Image"
+
char
token[MaxTextExtent];
const char
*p;
+ const Image
+ *source_image;
+
Image
- *channel_images;
+ *destination_image;
PixelChannel
- p_channel,
- q_channel;
-
- assert(images != (Image *) NULL);
- assert(images->signature == MagickSignature);
- if (images->debug != MagickFalse)
- (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
- channel_images=CloneImage(images,images->columns,images->columns,MagickTrue,
- exception);
+ source_channel,
+ destination_channel;
+
+ ssize_t
+ channels;
+
+ assert(image != (Image *) NULL);
+ assert(image->signature == MagickSignature);
+ if (image->debug != MagickFalse)
+ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+ assert(exception != (ExceptionInfo *) NULL);
+ assert(exception->signature == MagickSignature);
+ source_image=image;
+ 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 (expression == (const char *) NULL)
+ return(destination_image);
+ destination_channel=RedPixelChannel;
p=(char *) expression;
GetMagickToken(p,&p,token);
- for (q_channel=RedPixelChannel; *p != '\0'; )
+ for (channels=0; *p != '\0'; )
{
MagickBooleanType
status;
*/
if (*token == ',')
{
- q_channel=(PixelChannel) ((ssize_t) q_channel+1);
+ destination_channel=(PixelChannel) ((ssize_t) destination_channel+1);
GetMagickToken(p,&p,token);
}
if (*token == '|')
{
- if (GetNextImageInList(images) != (Image *) NULL)
- images=GetNextImageInList(images);
+ if (GetNextImageInList(source_image) != (Image *) NULL)
+ source_image=GetNextImageInList(source_image);
else
- images=GetFirstImageInList(images);
+ source_image=GetFirstImageInList(source_image);
GetMagickToken(p,&p,token);
}
if (*token == ';')
{
- AppendImageToList(&channel_images,CloneImage(images,
- channel_images->columns,channel_images->rows,MagickTrue,exception));
- channel_images=GetLastImageInList(channel_images);
+ Image
+ *canvas;
+
+ if (channels == 1)
+ destination_image->colorspace=GRAYColorspace;
+ canvas=CloneImage(source_image,0,0,MagickTrue,exception);
+ if (canvas == (Image *) NULL)
+ {
+ destination_image=GetLastImageInList(destination_image);
+ return((Image *) NULL);
+ }
+ 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;
}
i=ParsePixelChannelOption(token);
if (i < 0)
{
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
"UnableToParseExpression","`%s'",p);
- channel_images=DestroyImageList(channel_images);
+ destination_image=DestroyImageList(destination_image);
break;
}
- p_channel=(PixelChannel) i;
+ source_channel=(PixelChannel) i;
channel_op=ExtractChannelOp;
GetMagickToken(p,&p,token);
if (*token == '<')
{
(void) ThrowMagickException(exception,GetMagickModule(),OptionError,
"UnableToParseExpression","`%s'",p);
- channel_images=DestroyImageList(channel_images);
+ destination_image=DestroyImageList(destination_image);
break;
}
- q_channel=(PixelChannel) i;
+ destination_channel=(PixelChannel) i;
}
- status=ChannelImage(channel_images,images,channel_op,p_channel,q_channel,
- exception);
+ status=ChannelImage(destination_image,source_image,channel_op,
+ source_channel,destination_channel,exception);
if (status == MagickFalse)
{
- channel_images=DestroyImageList(channel_images);
+ destination_image=DestroyImageList(destination_image);
break;
}
+ channels++;
+ status=SetImageProgress(source_image,ChannelOperationImageTag,p-expression,
+ strlen(expression));
+ if (status == MagickFalse)
+ break;
}
- return(channel_images);
+ if (channels == 1)
+ destination_image->colorspace=GRAYColorspace;
+ return(destination_image);
}
FcPatternAddBool(pattern,FC_AUTOHINT,LocaleCompare(option,"auto") == 0);
}
-static Image *ReadCAPTIONImage(const ImageInfo *image_info,
- ExceptionInfo *exception)
+static MagickBooleanType PangoImage(const ImageInfo *image_info,Image *image,
+ const DrawInfo *draw_info,ExceptionInfo *exception)
{
char
*caption,
const char
*option;
- DrawInfo
- *draw_info;
-
FT_Bitmap
*canvas;
- Image
- *image;
-
PangoAlignment
align;
ssize_t
y;
- /*
- Initialize Image structure.
- */
- assert(image_info != (const ImageInfo *) NULL);
- assert(image_info->signature == MagickSignature);
- if (image_info->debug != MagickFalse)
- (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
- image_info->filename);
- assert(exception != (ExceptionInfo *) NULL);
- assert(exception->signature == MagickSignature);
- image=AcquireImage(image_info,exception);
- (void) ResetImagePage(image,"0x0+0+0");
/*
Get context.
*/
option=GetImageOption(image_info,"caption:language");
if (option != (const char *) NULL)
pango_context_set_language(context,pango_language_from_string(option));
- draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL);
pango_context_set_base_dir(context,draw_info->direction ==
RightToLeftDirection ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR);
switch (draw_info->gravity)
pango_layout_set_alignment(layout,align);
description=pango_font_description_from_string(draw_info->font ==
(char *) NULL ? "helvetica" : draw_info->font);
- pango_font_description_set_size(description,PANGO_SCALE*draw_info->pointsize);
+ pango_font_description_set_size(description,(int) (0.9*PANGO_SCALE*
+ draw_info->pointsize+0.5));
pango_layout_set_font_description(layout,description);
pango_font_description_free(description);
option=GetImageOption(image_info,"filename");
*/
canvas=(FT_Bitmap *) AcquireMagickMemory(sizeof(*canvas));
if (canvas == (FT_Bitmap *) NULL)
- {
- draw_info=DestroyDrawInfo(draw_info);
- ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
- }
+ ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+ image->filename);
canvas->width=image->columns;
canvas->pitch=(canvas->width+3) & ~3;
canvas->rows=image->rows;
canvas->rows*sizeof(*canvas->buffer));
if (canvas->buffer == (unsigned char *) NULL)
{
- draw_info=DestroyDrawInfo(draw_info);
canvas=(FT_Bitmap *) RelinquishMagickMemory(canvas);
- ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+ ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+ image->filename);
}
canvas->num_grays=256;
canvas->pixel_mode=ft_pixel_mode_grays;
image->rows+=2*page.y;
if (SetImageBackgroundColor(image,exception) == MagickFalse)
{
- draw_info=DestroyDrawInfo(draw_info);
canvas->buffer=(unsigned char *) RelinquishMagickMemory(canvas->buffer);
canvas=(FT_Bitmap *) RelinquishMagickMemory(canvas);
caption=DestroyString(caption);
image=DestroyImageList(image);
- return((Image *) NULL);
+ return(MagickFalse);
}
GetPixelInfo(image,&fill_color);
p=canvas->buffer;
/*
Relinquish resources.
*/
- draw_info=DestroyDrawInfo(draw_info);
canvas->buffer=(unsigned char *) RelinquishMagickMemory(canvas->buffer);
canvas=(FT_Bitmap *) RelinquishMagickMemory(canvas);
caption=DestroyString(caption);
- return(GetFirstImageInList(image));
+ return(MagickTrue);
}
-#else
+#endif
+
static Image *ReadCAPTIONImage(const ImageInfo *image_info,
ExceptionInfo *exception)
{
*property;
const char
- *gravity;
+ *gravity,
+ *option;
DrawInfo
*draw_info;
*/
property=InterpretImageProperties(image_info,image,image_info->filename,
exception);
+ option=GetImageOption(image_info,"filename");
+ if (option == (const char *) NULL)
+ property=InterpretImageProperties(image_info,image,image_info->filename,
+ exception);
+ else
+ if (LocaleNCompare(option,"caption:",8) == 0)
+ property=InterpretImageProperties(image_info,image,option+8,exception);
+ else
+ property=InterpretImageProperties(image_info,image,option,exception);
(void) SetImageProperty(image,"caption",property,exception);
property=DestroyString(property);
caption=ConstantString(GetImageProperty(image,"caption",exception));
metrics.ascent+draw_info->stroke_width/2.0);
draw_info->geometry=AcquireString(geometry);
}
- (void) AnnotateImage(image,draw_info,exception);
+#if defined(MAGICKCORE_PANGOFT2_DELEGATE)
+ status=PangoImage(image_info,image,draw_info,exception);
+#else
+ status=AnnotateImage(image,draw_info,exception);
+#endif
draw_info=DestroyDrawInfo(draw_info);
caption=DestroyString(caption);
+ if (status == MagickFalse)
+ {
+ image=DestroyImageList(image);
+ return((Image *) NULL);
+ }
return(GetFirstImageInList(image));
}
-#endif
\f
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%