#include "MagickCore/resource_.h"
#include "MagickCore/string_.h"
#include "MagickCore/thread-private.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/token.h"
#include "MagickCore/utility.h"
#include "MagickCore/utility-private.h"
#include "MagickCore/version.h"
% The format of the CompositeImage method is:
%
% MagickBooleanType CompositeImage(Image *image,
-% const CompositeOperator compose,Image *composite_image,
-% const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
+% const Image *composite_image,const CompositeOperator compose,
+% const MagickBooleanType clip_to_self,const ssize_t x_offset,
+% const ssize_t y_offset,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: the destination image, modified by he composition
%
+% o composite_image: the composite (source) image.
+%
% o compose: This operator affects how the composite is applied to
% the image. The operators and how they are utilized are listed here
% http://www.w3.org/TR/SVG12/#compositing.
%
-% o composite_image: the composite (source) image.
+% o clip_to_self: set to MagickTrue to limit composition to area composed.
%
% o x_offset: the column offset of the composited image.
%
% Compose methods needing such arguments include "BlendCompositeOp" and
% "DisplaceCompositeOp".
%
-% o "compose:outside-overlay"
-% Modify how the composition is to effect areas not directly covered
-% by the 'composite_image' at the offset given. Normally this is
-% dependant on the 'compose' method, especially Duff-Porter methods.
-%
-% If set to "false" then disable all normal handling of pixels not
-% covered by the composite_image. Typically used for repeated tiling
-% of the composite_image by the calling API.
-%
-% Previous to IM v6.5.3-3 this was called "modify-outside-overlay"
-%
% o exception: return any errors or warnings in this structure.
%
*/
-static void CompositeHSB(const Quantum red,const Quantum green,
- const Quantum blue,double *hue,double *saturation,double *brightness)
+/*
+ Composition based on the SVG specification:
+
+ A Composition is defined by...
+ Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
+ Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
+ Y = 1 for source preserved
+ Z = 1 for destination preserved
+
+ Conversion to transparency (then optimized)
+ Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
+ Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
+
+ Where...
+ Sca = Sc*Sa normalized Source color divided by Source alpha
+ Dca = Dc*Da normalized Dest color divided by Dest alpha
+ Dc' = Dca'/Da' the desired color value for this channel.
+
+ Da' in in the follow formula as 'gamma' The resulting alpla value.
+
+ Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
+ the following optimizations...
+ gamma = Sa+Da-Sa*Da;
+ gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
+ opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
+
+ The above SVG definitions also definate that Mathematical Composition
+ methods should use a 'Over' blending mode for Alpha Channel.
+ It however was not applied for composition modes of 'Plus', 'Minus',
+ the modulus versions of 'Add' and 'Subtract'.
+
+ Mathematical operator changes to be applied from IM v6.7...
+
+ 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
+ 'ModulusAdd' and 'ModulusSubtract' for clarity.
+
+ 2) All mathematical compositions work as per the SVG specification
+ with regard to blending. This now includes 'ModulusAdd' and
+ 'ModulusSubtract'.
+
+ 3) When the special channel flag 'sync' (syncronize channel updates)
+ is turned off (enabled by default) then mathematical compositions are
+ only performed on the channels specified, and are applied
+ independantally of each other. In other words the mathematics is
+ performed as 'pure' mathematical operations, rather than as image
+ operations.
+*/
+
+static inline double MagickMin(const double x,const double y)
{
- double
- delta;
+ if (x < y)
+ return(x);
+ return(y);
+}
- Quantum
- max,
- min;
+static inline double MagickMax(const double x,const double y)
+{
+ if (x > y)
+ return(x);
+ return(y);
+}
- /*
- Convert RGB to HSB colorspace.
- */
- assert(hue != (double *) NULL);
- assert(saturation != (double *) NULL);
- assert(brightness != (double *) NULL);
- max=(red > green ? red : green);
- if (blue > max)
- max=blue;
- min=(red < green ? red : green);
- if (blue < min)
- min=blue;
- *hue=0.0;
- *saturation=0.0;
- *brightness=(double) (QuantumScale*max);
- if (fabs((double) max) < MagickEpsilon)
- return;
- *saturation=(double) (1.0-min/max);
- delta=(MagickRealType) max-min;
- if (fabs(delta) < MagickEpsilon)
- return;
- if (fabs((double) red-max) < MagickEpsilon)
- *hue=(double) ((green-blue)/delta);
- else
- if (fabs((double) green-max) < MagickEpsilon)
- *hue=(double) (2.0+(blue-red)/delta);
- else
- if (fabs((double) blue-max) < MagickEpsilon)
- *hue=(double) (4.0+(red-green)/delta);
- *hue/=6.0;
- if (*hue < 0.0)
- *hue+=1.0;
+static inline double ConvertHueToRGB(double m1,
+ double m2,double hue)
+{
+ if (hue < 0.0)
+ hue+=1.0;
+ if (hue > 1.0)
+ hue-=1.0;
+ if ((6.0*hue) < 1.0)
+ return(m1+6.0*(m2-m1)*hue);
+ if ((2.0*hue) < 1.0)
+ return(m2);
+ if ((3.0*hue) < 2.0)
+ return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
+ return(m1);
}
-static void HSBComposite(const double hue,const double saturation,
- const double brightness,double *red,double *green,double *blue)
+static void HCLComposite(const double hue,const double chroma,const double luma,
+ double *red,double *green,double *blue)
{
double
- f,
+ b,
+ c,
+ g,
h,
- p,
- q,
- t;
+ m,
+ r,
+ x,
+ z;
/*
- Convert HSB to RGB colorspace.
+ Convert HCL to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
- if (saturation == 0.0)
- {
- *red=(double) QuantumRange*brightness;
- *green=(*red);
- *blue=(*red);
- return;
- }
- h=6.0*(hue-floor(hue));
- f=h-floor((double) h);
- p=brightness*(1.0-saturation);
- q=brightness*(1.0-saturation*f);
- t=brightness*(1.0-saturation*(1.0-f));
- switch ((int) h)
- {
- case 0:
- default:
- {
- *red=(double) QuantumRange*brightness;
- *green=(double) QuantumRange*t;
- *blue=(double) QuantumRange*p;
- break;
- }
- case 1:
- {
- *red=(double) QuantumRange*q;
- *green=(double) QuantumRange*brightness;
- *blue=(double) QuantumRange*p;
- break;
- }
- case 2:
- {
- *red=(double) QuantumRange*p;
- *green=(double) QuantumRange*brightness;
- *blue=(double) QuantumRange*t;
- break;
- }
- case 3:
- {
- *red=(double) QuantumRange*p;
- *green=(double) QuantumRange*q;
- *blue=(double) QuantumRange*brightness;
- break;
- }
- case 4:
+ h=6.0*hue;
+ c=chroma;
+ x=c*(1.0-fabs(fmod(h,2.0)-1.0));
+ r=0.0;
+ g=0.0;
+ b=0.0;
+ if ((0.0 <= h) && (h < 1.0))
{
- *red=(double) QuantumRange*t;
- *green=(double) QuantumRange*p;
- *blue=(double) QuantumRange*brightness;
- break;
+ r=c;
+ g=x;
}
- case 5:
+ else
+ if ((1.0 <= h) && (h < 2.0))
+ {
+ r=x;
+ g=c;
+ }
+ else
+ if ((2.0 <= h) && (h < 3.0))
+ {
+ g=c;
+ b=x;
+ }
+ else
+ if ((3.0 <= h) && (h < 4.0))
+ {
+ g=x;
+ b=c;
+ }
+ else
+ if ((4.0 <= h) && (h < 5.0))
+ {
+ r=x;
+ b=c;
+ }
+ else
+ if ((5.0 <= h) && (h < 6.0))
+ {
+ r=c;
+ b=x;
+ }
+ m=luma-(0.298839*r+0.586811*g+0.114350*b);
+ /*
+ Choose saturation strategy to clip it into the RGB cube; hue and luma are
+ preserved and chroma may be changed.
+ */
+ z=1.0;
+ if (m < 0.0)
{
- *red=(double) QuantumRange*brightness;
- *green=(double) QuantumRange*p;
- *blue=(double) QuantumRange*q;
- break;
+ z=luma/(luma-m);
+ m=0.0;
}
- }
+ else
+ if (m+c > 1.0)
+ {
+ z=(1.0-luma)/(m+c-luma);
+ m=1.0-z*c;
+ }
+ *red=QuantumRange*(z*r+m);
+ *green=QuantumRange*(z*g+m);
+ *blue=QuantumRange*(z*b+m);
}
-static inline double MagickMin(const double x,const double y)
-{
- if (x < y)
- return(x);
- return(y);
-}
-static inline double MagickMax(const double x,const double y)
+static void CompositeHCL(const double red,const double green,const double blue,
+ double *hue,double *chroma,double *luma)
{
- if (x > y)
- return(x);
- return(y);
+ double
+ b,
+ c,
+ g,
+ h,
+ max,
+ r;
+
+ /*
+ Convert RGB to HCL colorspace.
+ */
+ assert(hue != (double *) NULL);
+ assert(chroma != (double *) NULL);
+ assert(luma != (double *) NULL);
+ r=red;
+ g=green;
+ b=blue;
+ max=MagickMax(r,MagickMax(g,b));
+ c=max-(double) MagickMin(r,MagickMin(g,b));
+ h=0.0;
+ if (c == 0)
+ h=0.0;
+ else
+ if (red == max)
+ h=fmod(6.0+(g-b)/c,6.0);
+ else
+ if (green == max)
+ h=((b-r)/c)+2.0;
+ else
+ if (blue == max)
+ h=((r-g)/c)+4.0;
+ *hue=(h/6.0);
+ *chroma=QuantumScale*c;
+ *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
}
static MagickBooleanType CompositeOverImage(Image *image,
- const Image *composite_image,const ssize_t x_offset,const ssize_t y_offset,
- ExceptionInfo *exception)
+ const Image *composite_image,const MagickBooleanType clip_to_self,
+ const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
{
#define CompositeImageTag "Composite/Image"
*composite_view,
*image_view;
- const char
- *value;
-
MagickBooleanType
- modify_outside_overlay,
status;
MagickOffsetType
ssize_t
y;
- size_t
- channels;
-
- /*
- Prepare composite image.
- */
- modify_outside_overlay=MagickFalse;
- value=GetImageArtifact(composite_image,"compose:outside-overlay");
- if (value != (const char *) NULL)
- modify_outside_overlay=IsMagickTrue(value);
/*
Composite image.
*/
status=MagickTrue;
progress=0;
- image_view=AcquireCacheView(image);
- composite_view=AcquireCacheView(composite_image);
+ composite_view=AcquireVirtualCacheView(composite_image,exception);
+ image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,4) 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++)
{
register ssize_t
x;
+ size_t
+ channels;
+
if (status == MagickFalse)
continue;
- if (modify_outside_overlay == MagickFalse)
+ if (clip_to_self != MagickFalse)
{
if (y < y_offset)
continue;
}
for (x=0; x < (ssize_t) image->columns; x++)
{
- MagickRealType
+ double
alpha,
Da,
Dc,
register ssize_t
i;
- if (modify_outside_overlay == MagickFalse)
+ if (clip_to_self != MagickFalse)
{
if (x < x_offset)
{
Sc: source color.
Dc: destination color.
*/
+ if (GetPixelMask(image,q) != 0)
+ {
+ q+=GetPixelChannels(image);
+ continue;
+ }
(void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
source,exception);
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
composite_traits,
traits;
- channel=GetPixelChannelMapChannel(image,i);
- traits=GetPixelChannelMapTraits(image,channel);
- composite_traits=GetPixelChannelMapTraits(composite_image,
- channel);
+ channel=GetPixelChannelChannel(image,i);
+ traits=GetPixelChannelTraits(image,channel);
+ composite_traits=GetPixelChannelTraits(composite_image,channel);
if ((traits == UndefinedPixelTrait) ||
(composite_traits == UndefinedPixelTrait))
continue;
Sa: normalized source alpha.
Da: normalized destination alpha.
*/
+ if (GetPixelMask(composite_image,p) != 0)
+ {
+ p+=GetPixelChannels(composite_image);
+ channels=GetPixelChannels(composite_image);
+ if (p >= (pixels+channels*composite_image->columns))
+ p=pixels;
+ q+=GetPixelChannels(image);
+ continue;
+ }
Sa=QuantumScale*GetPixelAlpha(composite_image,p);
Da=QuantumScale*GetPixelAlpha(image,q);
alpha=Sa*(-Da)+Sa+Da;
composite_traits,
traits;
- channel=GetPixelChannelMapChannel(image,i);
- traits=GetPixelChannelMapTraits(image,channel);
- composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+ channel=GetPixelChannelChannel(image,i);
+ traits=GetPixelChannelTraits(image,channel);
+ composite_traits=GetPixelChannelTraits(composite_image,channel);
if ((traits == UndefinedPixelTrait) ||
(composite_traits == UndefinedPixelTrait))
continue;
Sc: source color.
Dc: destination color.
*/
- Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
- Dc=(MagickRealType) q[i];
- gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+ Sc=(double) GetPixelChannel(composite_image,channel,p);
+ Dc=(double) q[i];
+ gamma=MagickEpsilonReciprocal(alpha);
q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
}
p+=GetPixelChannels(composite_image);
proceed;
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp critical (MagickCore_CompositeImage)
+ #pragma omp critical (MagickCore_CompositeImage)
#endif
proceed=SetImageProgress(image,CompositeImageTag,progress++,
image->rows);
}
MagickExport MagickBooleanType CompositeImage(Image *image,
- const CompositeOperator compose,const Image *composite_image,
- const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
+ const Image *composite,const CompositeOperator compose,
+ const MagickBooleanType clip_to_self,const ssize_t x_offset,
+ const ssize_t y_offset,ExceptionInfo *exception)
{
#define CompositeImageTag "Composite/Image"
*composite_view,
*image_view;
- const char
- *value;
-
- double
- sans;
-
GeometryInfo
geometry_info;
Image
+ *composite_image,
*destination_image;
MagickBooleanType
- modify_outside_overlay,
status;
MagickOffsetType
progress;
- MagickRealType
+ double
amount,
destination_dissolve,
midpoint,
- percent_brightness,
- percent_saturation,
+ percent_luma,
+ percent_chroma,
source_dissolve,
threshold;
ssize_t
y;
- size_t
- channels;
-
- /*
- Composition based on the SVG specification:
-
- A Composition is defined by...
- Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
- Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
- Y = 1 for source preserved
- Z = 1 for destination preserved
-
- Conversion to transparency (then optimized)
- Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
- Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
-
- Where...
- Sca = Sc*Sa normalized Source color divided by Source alpha
- Dca = Dc*Da normalized Dest color divided by Dest alpha
- Dc' = Dca'/Da' the desired color value for this channel.
-
- Da' in in the follow formula as 'gamma' The resulting alpla value.
-
- Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
- the following optimizations...
- gamma = Sa+Da-Sa*Da;
- gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
- opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
-
- The above SVG definitions also definate that Mathematical Composition
- methods should use a 'Over' blending mode for Alpha Channel.
- It however was not applied for composition modes of 'Plus', 'Minus',
- the modulus versions of 'Add' and 'Subtract'.
-
- Mathematical operator changes to be applied from IM v6.7...
-
- 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
- 'ModulusAdd' and 'ModulusSubtract' for clarity.
-
- 2) All mathematical compositions work as per the SVG specification
- with regard to blending. This now includes 'ModulusAdd' and
- 'ModulusSubtract'.
-
- 3) When the special channel flag 'sync' (syncronize channel updates)
- is turned off (enabled by default) then mathematical compositions are
- only performed on the channels specified, and are applied
- independantally of each other. In other words the mathematics is
- performed as 'pure' mathematical operations, rather than as image
- operations.
- */
-
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- assert(composite_image != (Image *) NULL);
- assert(composite_image->signature == MagickSignature);
+ assert(composite!= (Image *) NULL);
+ assert(composite->signature == MagickSignature);
if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
return(MagickFalse);
+ composite_image=CloneImage(composite,0,0,MagickTrue,exception);
+ if (composite_image == (const Image *) NULL)
+ return(MagickFalse);
+ (void) SetImageColorspace(composite_image,image->colorspace,exception);
if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
{
- status=CompositeOverImage(image,composite_image,x_offset,y_offset,
- exception);
+ status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
+ y_offset,exception);
+ composite_image=DestroyImage(composite_image);
return(status);
}
destination_image=(Image *) NULL;
amount=0.5;
destination_dissolve=1.0;
- modify_outside_overlay=MagickFalse;
- percent_brightness=100.0;
- percent_saturation=100.0;
+ percent_luma=100.0;
+ percent_chroma=100.0;
source_dissolve=1.0;
threshold=0.05f;
switch (compose)
{
- case ClearCompositeOp:
- case DstAtopCompositeOp:
- case DstInCompositeOp:
- case InCompositeOp:
- case OutCompositeOp:
- case SrcCompositeOp:
- case SrcInCompositeOp:
- case SrcOutCompositeOp:
- {
- /*
- Modify destination outside the overlaid region.
- */
- modify_outside_overlay=MagickTrue;
- break;
- }
case CopyCompositeOp:
{
if ((x_offset < 0) || (y_offset < 0))
if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
break;
status=MagickTrue;
- image_view=AcquireCacheView(image);
- composite_view=AcquireCacheView(composite_image);
+ composite_view=AcquireVirtualCacheView(composite_image,exception);
+ image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,4) shared(status)
+ #pragma omp parallel for schedule(static,4) shared(status) \
+ dynamic_number_threads(image,image->columns,image->rows,1)
#endif
for (y=0; y < (ssize_t) composite_image->rows; y++)
{
register ssize_t
i;
+ if (GetPixelMask(composite_image,p) != 0)
+ {
+ p+=GetPixelChannels(composite_image);
+ q+=GetPixelChannels(image);
+ continue;
+ }
for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
{
PixelChannel
composite_traits,
traits;
- channel=GetPixelChannelMapChannel(composite_image,i);
- composite_traits=GetPixelChannelMapTraits(composite_image,channel);
- traits=GetPixelChannelMapTraits(image,channel);
+ channel=GetPixelChannelChannel(composite_image,i);
+ composite_traits=GetPixelChannelTraits(composite_image,channel);
+ traits=GetPixelChannelTraits(image,channel);
if ((traits == UndefinedPixelTrait) ||
(composite_traits == UndefinedPixelTrait))
continue;
}
composite_view=DestroyCacheView(composite_view);
image_view=DestroyCacheView(image_view);
+ composite_image=DestroyImage(composite_image);
return(status);
}
case CopyAlphaCompositeOp:
Modify destination outside the overlaid region and require an alpha
channel to exist, to add transparency.
*/
- if (image->matte == MagickFalse)
+ if (image->alpha_trait != BlendPixelTrait)
(void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
- modify_outside_overlay=MagickTrue;
break;
}
case BlurCompositeOp:
*composite_view,
*destination_view;
+ const char
+ *value;
+
PixelInfo
pixel;
- MagickRealType
+ double
angle_range,
angle_start,
height,
blur;
/*
+ Blur Image by resampling.
+
Blur Image dictated by an overlay gradient map: X = red_channel;
Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
*/
destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
exception);
if (destination_image == (Image *) NULL)
- return(MagickFalse);
+ {
+ composite_image=DestroyImage(composite_image);
+ return(MagickFalse);
+ }
/*
- Determine the horizontal and vertical maximim blur.
+ Gather the maximum blur sigma values from user.
*/
SetGeometryInfo(&geometry_info);
flags=NoValue;
value=GetImageArtifact(composite_image,"compose:args");
if (value != (char *) NULL)
flags=ParseGeometry(value,&geometry_info);
- if ((flags & WidthValue) == 0 )
- {
+ if ((flags & WidthValue) == 0 ) {
+ (void) ThrowMagickException(exception,GetMagickModule(),
+ OptionWarning,"InvalidSetting","'%s' '%s'",
+ "compose:args",value);
+ composite_image=DestroyImage(composite_image);
destination_image=DestroyImage(destination_image);
return(MagickFalse);
}
- width=geometry_info.rho;
- height=geometry_info.sigma;
- blur.x1=geometry_info.rho;
+ /*
+ Users input sigma now needs to be converted to the EWA ellipse size.
+ The filter defaults to a sigma of 0.5 so to make this match the
+ users input the ellipse size needs to be doubled.
+ */
+ width=height=geometry_info.rho*2.0;
+ if ((flags & HeightValue) != 0 )
+ height=geometry_info.sigma*2.0;
+
+ /* default the unrotated ellipse width and height axis vectors */
+ blur.x1=width;
blur.x2=0.0;
blur.y1=0.0;
- blur.y2=geometry_info.sigma;
- angle_start=0.0;
- angle_range=0.0;
- if ((flags & HeightValue) == 0)
- blur.y2=blur.x1;
+ blur.y2=height;
+ /* rotate vectors if a rotation angle is given */
if ((flags & XValue) != 0 )
{
- MagickRealType
+ double
angle;
angle=DegreesToRadians(geometry_info.xi);
blur.y1=(-height*sin(angle));
blur.y2=height*cos(angle);
}
+ /* Otherwise lets set a angle range and calculate in the loop */
+ angle_start=0.0;
+ angle_range=0.0;
if ((flags & YValue) != 0 )
{
angle_start=DegreesToRadians(geometry_info.xi);
angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
}
/*
- Blur Image by resampling.
+ Set up a gaussian cylindrical filter for EWA Bluring.
+
+ As the minimum ellipse radius of support*1.0 the EWA algorithm
+ can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
+ This means that even 'No Blur' will be still a little blurry!
+
+ The solution (as well as the problem of preventing any user
+ expert filter settings, is to set our own user settings, then
+ restore them afterwards.
*/
resample_filter=AcquireResampleFilter(image,exception);
- SetResampleFilter(resample_filter,CubicFilter,2.0);
- destination_view=AcquireCacheView(destination_image);
- composite_view=AcquireCacheView(composite_image);
+ SetResampleFilter(resample_filter,GaussianFilter);
+
+ /* do the variable blurring of each pixel in image */
+ GetPixelInfo(image,&pixel);
+ composite_view=AcquireVirtualCacheView(composite_image,exception);
+ destination_view=AcquireAuthenticCacheView(destination_image,exception);
for (y=0; y < (ssize_t) composite_image->rows; y++)
{
MagickBooleanType
}
if (fabs(angle_range) > MagickEpsilon)
{
- MagickRealType
+ double
angle;
angle=angle_start+angle_range*QuantumScale*
blur.y1=(-height*sin(angle));
blur.y2=height*cos(angle);
}
- ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
- GetPixelRed(composite_image,p),blur.y1*QuantumScale*
- GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
- GetPixelRed(composite_image,p),blur.y2*QuantumScale*
- GetPixelGreen(composite_image,p));
+#if 0
+ if ( x == 10 && y == 60 ) {
+ fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",
+ blur.x1, blur.x2, blur.y1, blur.y2);
+ fprintf(stderr, "scaled by=%lf,%lf\n",
+ QuantumScale*GetPixelRed(p), QuantumScale*GetPixelGreen(p));
+#endif
+ ScaleResampleFilter(resample_filter,
+ blur.x1*QuantumScale*GetPixelRed(composite_image,p),
+ blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
+ blur.x2*QuantumScale*GetPixelRed(composite_image,p),
+ blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
(void) ResamplePixelColor(resample_filter,(double) x_offset+x,
- (double) y_offset+y,&pixel);
+ (double) y_offset+y,&pixel,exception);
SetPixelInfoPixel(destination_image,&pixel,q);
p+=GetPixelChannels(composite_image);
q+=GetPixelChannels(destination_image);
resample_filter=DestroyResampleFilter(resample_filter);
composite_view=DestroyCacheView(composite_view);
destination_view=DestroyCacheView(destination_view);
+ composite_image=DestroyImage(composite_image);
composite_image=destination_image;
break;
}
*destination_view,
*image_view;
+ const char
+ *value;
+
PixelInfo
pixel;
- MagickRealType
+ double
horizontal_scale,
vertical_scale;
destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
exception);
if (destination_image == (Image *) NULL)
- return(MagickFalse);
+ {
+ composite_image=DestroyImage(composite_image);
+ return(MagickFalse);
+ }
SetGeometryInfo(&geometry_info);
flags=NoValue;
value=GetImageArtifact(composite_image,"compose:args");
{
if ((flags & AspectValue) == 0)
{
- horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
+ horizontal_scale=(double) (composite_image->columns-1.0)/
2.0;
- vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
+ vertical_scale=(double) (composite_image->rows-1.0)/2.0;
}
else
{
- horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
- vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
+ horizontal_scale=(double) (image->columns-1.0)/2.0;
+ vertical_scale=(double) (image->rows-1.0)/2.0;
}
}
else
default = center of overlay image
arg flag '!' = locations/percentage relative to background image
*/
- center.x=(MagickRealType) x_offset;
- center.y=(MagickRealType) y_offset;
+ center.x=(double) x_offset;
+ center.y=(double) y_offset;
if (compose == DistortCompositeOp)
{
if ((flags & XValue) == 0)
if ((flags & AspectValue) == 0)
- center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
+ center.x=(double) x_offset+(composite_image->columns-1)/
2.0;
else
- center.x=((MagickRealType) image->columns-1)/2.0;
+ center.x=((double) image->columns-1)/2.0;
else
if ((flags & AspectValue) == 0)
- center.x=(MagickRealType) x_offset+geometry_info.xi;
+ center.x=(double) x_offset+geometry_info.xi;
else
center.x=geometry_info.xi;
if ((flags & YValue) == 0)
if ((flags & AspectValue) == 0)
- center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
+ center.y=(double) y_offset+(composite_image->rows-1)/2.0;
else
- center.y=((MagickRealType) image->rows-1)/2.0;
+ center.y=((double) image->rows-1)/2.0;
else
if ((flags & AspectValue) == 0)
- center.y=(MagickRealType) y_offset+geometry_info.psi;
+ center.y=(double) y_offset+geometry_info.psi;
else
center.y=geometry_info.psi;
}
displacement/distortion map. -- Like a lens...
*/
GetPixelInfo(image,&pixel);
- image_view=AcquireCacheView(image);
- destination_view=AcquireCacheView(destination_image);
- composite_view=AcquireCacheView(composite_image);
+ image_view=AcquireVirtualCacheView(image,exception);
+ composite_view=AcquireVirtualCacheView(composite_image,exception);
+ destination_view=AcquireAuthenticCacheView(destination_image,exception);
for (y=0; y < (ssize_t) composite_image->rows; y++)
{
MagickBooleanType
Displace the offset.
*/
offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
- (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
+ (((double) QuantumRange+1.0)/2.0)))/(((double)
QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
x : 0);
offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
- (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
+ (((double) QuantumRange+1.0)/2.0)))/(((double)
QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
y : 0);
(void) InterpolatePixelInfo(image,image_view,
/*
Mask with the 'invalid pixel mask' in alpha channel.
*/
- pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
+ pixel.alpha=(double) QuantumRange*(1.0-(1.0-QuantumScale*
pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
SetPixelInfoPixel(destination_image,&pixel,q);
p+=GetPixelChannels(composite_image);
destination_view=DestroyCacheView(destination_view);
composite_view=DestroyCacheView(composite_view);
image_view=DestroyCacheView(image_view);
+ composite_image=DestroyImage(composite_image);
composite_image=destination_image;
break;
}
case DissolveCompositeOp:
{
+ const char
+ *value;
+
/*
Geometry arguments to dissolve factors.
*/
destination_dissolve=geometry_info.sigma/100.0;
if ((destination_dissolve-MagickEpsilon) < 0.0)
destination_dissolve=0.0;
- modify_outside_overlay=MagickTrue;
+ /* posible speed up? -- from IMv6 update
+ clip_to_self=MagickFalse;
if ((destination_dissolve+MagickEpsilon) > 1.0 )
{
destination_dissolve=1.0;
- modify_outside_overlay=MagickFalse;
+ clip_to_self=MagickTrue;
}
+ */
}
break;
}
case BlendCompositeOp:
{
+ const char
+ *value;
+
value=GetImageArtifact(composite_image,"compose:args");
if (value != (char *) NULL)
{
destination_dissolve=1.0-source_dissolve;
if ((flags & SigmaValue) != 0)
destination_dissolve=geometry_info.sigma/100.0;
- modify_outside_overlay=MagickTrue;
- if ((destination_dissolve+MagickEpsilon) > 1.0)
- modify_outside_overlay=MagickFalse;
}
break;
}
case MathematicsCompositeOp:
{
+ const char
+ *value;
+
/*
Just collect the values from "compose:args", setting.
Unused values are set to zero automagically.
}
case ModulateCompositeOp:
{
+ const char
+ *value;
+
/*
- Determine the brightness and saturation scale.
+ Determine the luma and chroma scale.
*/
value=GetImageArtifact(composite_image,"compose:args");
if (value != (char *) NULL)
{
flags=ParseGeometry(value,&geometry_info);
- percent_brightness=geometry_info.rho;
+ percent_luma=geometry_info.rho;
if ((flags & SigmaValue) != 0)
- percent_saturation=geometry_info.sigma;
+ percent_chroma=geometry_info.sigma;
}
break;
}
case ThresholdCompositeOp:
{
+ const char
+ *value;
+
/*
Determine the amount and threshold.
*/
default:
break;
}
- value=GetImageArtifact(composite_image,"compose:outside-overlay");
- if (value != (const char *) NULL)
- modify_outside_overlay=IsMagickTrue(value);
/*
Composite image.
*/
status=MagickTrue;
progress=0;
- midpoint=((MagickRealType) QuantumRange+1.0)/2;
- image_view=AcquireCacheView(image);
- composite_view=AcquireCacheView(composite_image);
+ midpoint=((double) QuantumRange+1.0)/2;
+ composite_view=AcquireVirtualCacheView(composite_image,exception);
+ image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,4) 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++)
{
double
blue,
- brightness,
+ luma,
green,
hue,
red,
- saturation;
+ chroma;
+
+ PixelInfo
+ destination_pixel,
+ source_pixel;
register const Quantum
*restrict p;
if (status == MagickFalse)
continue;
- if (modify_outside_overlay == MagickFalse)
+ if (clip_to_self != MagickFalse)
{
if (y < y_offset)
continue;
continue;
}
hue=0.0;
- saturation=0.0;
- brightness=0.0;
+ chroma=0.0;
+ luma=0.0;
+ GetPixelInfo(image,&destination_pixel);
+ GetPixelInfo(composite_image,&source_pixel);
for (x=0; x < (ssize_t) image->columns; x++)
{
- MagickRealType
+ double
alpha,
Da,
Dc,
register ssize_t
i;
- if (modify_outside_overlay == MagickFalse)
+ size_t
+ channels;
+
+ if (clip_to_self != MagickFalse)
{
if (x < x_offset)
{
*/
(void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
source,exception);
+ if (GetPixelMask(image,q) != 0)
+ {
+ q+=GetPixelChannels(image);
+ continue;
+ }
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
{
- MagickRealType
+ double
pixel;
PixelChannel
composite_traits,
traits;
- channel=GetPixelChannelMapChannel(image,i);
- traits=GetPixelChannelMapTraits(image,channel);
- composite_traits=GetPixelChannelMapTraits(composite_image,
- channel);
+ channel=GetPixelChannelChannel(image,i);
+ traits=GetPixelChannelTraits(image,channel);
+ composite_traits=GetPixelChannelTraits(composite_image,channel);
if ((traits == UndefinedPixelTrait) ||
(composite_traits == UndefinedPixelTrait))
continue;
case SrcInCompositeOp:
case SrcOutCompositeOp:
{
- pixel=(MagickRealType) q[i];
+ pixel=(double) q[i];
if (channel == AlphaPixelChannel)
- pixel=(MagickRealType) TransparentAlpha;
+ pixel=(double) TransparentAlpha;
break;
}
case ClearCompositeOp:
{
if (channel == AlphaPixelChannel)
{
- pixel=(MagickRealType) TransparentAlpha;
+ pixel=(double) TransparentAlpha;
break;
}
pixel=0.0;
source);
break;
}
- pixel=(MagickRealType) source[channel];
+ pixel=(double) source[channel];
break;
}
default:
{
- pixel=(MagickRealType) source[channel];
+ pixel=(double) source[channel];
break;
}
}
break;
}
}
+ if (GetPixelMask(image,p) != 0)
+ {
+ p+=GetPixelChannels(composite_image);
+ q+=GetPixelChannels(image);
+ continue;
+ }
+ switch (compose)
+ {
+ case ColorizeCompositeOp:
+ case HueCompositeOp:
+ case LuminizeCompositeOp:
+ case ModulateCompositeOp:
+ case SaturateCompositeOp:
+ {
+ GetPixelInfoPixel(composite_image,p,&source_pixel);
+ GetPixelInfoPixel(image,q,&destination_pixel);
+ break;
+ }
+ default:
+ break;
+ }
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
{
- MagickRealType
+ double
+ sans;
+
+ double
pixel;
PixelChannel
composite_traits,
traits;
- channel=GetPixelChannelMapChannel(image,i);
- traits=GetPixelChannelMapTraits(image,channel);
- composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+ channel=GetPixelChannelChannel(image,i);
+ traits=GetPixelChannelTraits(image,channel);
+ composite_traits=GetPixelChannelTraits(composite_image,channel);
if (traits == UndefinedPixelTrait)
continue;
if ((compose != IntensityCompositeOp) &&
Sc: source color.
Dc: destination color.
*/
- Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
- Dc=(MagickRealType) q[i];
+ Sc=(double) GetPixelChannel(composite_image,channel,p);
+ Dc=(double) q[i];
if ((traits & CopyPixelTrait) != 0)
{
if (channel != AlphaPixelChannel)
MagickBooleanType
equivalent;
- if (Da > ((MagickRealType) QuantumRange/2.0))
+ if (Da > ((double) QuantumRange/2.0))
{
- pixel=(MagickRealType) TransparentAlpha;
+ pixel=(double) TransparentAlpha;
break;
}
equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
if (equivalent != MagickFalse)
{
- pixel=(MagickRealType) TransparentAlpha;
+ pixel=(double) TransparentAlpha;
break;
}
- pixel=(MagickRealType) OpaqueAlpha;
+ pixel=(double) OpaqueAlpha;
break;
}
case ClearCompositeOp:
{
- pixel=(MagickRealType) TransparentAlpha;
+ pixel=(double) TransparentAlpha;
break;
}
case ColorizeCompositeOp:
pixel=QuantumRange*Sa;
break;
}
- case CopyCompositeOp:
case CopyAlphaCompositeOp:
+ {
+ pixel=QuantumRange*Sa;
+ if (composite_image->alpha_trait != BlendPixelTrait)
+ pixel=GetPixelIntensity(composite_image,p);
+ break;
+ }
+ case CopyCompositeOp:
case DisplaceCompositeOp:
case DistortCompositeOp:
case DstAtopCompositeOp:
}
case IntensityCompositeOp:
{
- pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
+ pixel=GetPixelIntensity(composite_image,p);
break;
}
case LightenIntensityCompositeOp:
default:
break;
}
- gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+ gamma=MagickEpsilonReciprocal(alpha);
+ pixel=Dc;
switch (compose)
{
case AlphaCompositeOp:
pixel=Sc;
break;
}
- CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
- GetPixelBlue(image,q),&sans,&sans,&brightness);
- CompositeHSB(GetPixelRed(composite_image,p),
- GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
- &hue,&saturation,&sans);
- HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+ CompositeHCL(destination_pixel.red,destination_pixel.green,
+ destination_pixel.blue,&sans,&sans,&luma);
+ CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
+ &hue,&chroma,&sans);
+ HCLComposite(hue,chroma,luma,&red,&green,&blue);
switch (channel)
{
case RedPixelChannel: pixel=red; break;
}
case CopyBlackCompositeOp:
{
- pixel=(MagickRealType) GetPixelBlack(composite_image,p);
+ if (channel == BlackPixelChannel)
+ pixel=(double) GetPixelBlack(composite_image,p);
break;
}
case CopyBlueCompositeOp:
case CopyYellowCompositeOp:
{
- pixel=(MagickRealType) GetPixelBlue(composite_image,p);
+ if (channel == BluePixelChannel)
+ pixel=(double) GetPixelBlue(composite_image,p);
break;
}
case CopyGreenCompositeOp:
case CopyMagentaCompositeOp:
{
- pixel=(MagickRealType) GetPixelGreen(composite_image,p);
+ if (channel == GreenPixelChannel)
+ pixel=(double) GetPixelGreen(composite_image,p);
break;
}
case CopyRedCompositeOp:
case CopyCyanCompositeOp:
{
- pixel=(MagickRealType) GetPixelRed(composite_image,p);
+ if (channel == RedPixelChannel)
+ pixel=(double) GetPixelRed(composite_image,p);
break;
}
case DarkenCompositeOp:
pixel=Sc;
break;
}
- CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
- GetPixelBlue(image,q),&hue,&saturation,&brightness);
- CompositeHSB(GetPixelRed(composite_image,p),
- GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
+ CompositeHCL(destination_pixel.red,destination_pixel.green,
+ destination_pixel.blue,&hue,&chroma,&luma);
+ CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
&hue,&sans,&sans);
- HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+ HCLComposite(hue,chroma,luma,&red,&green,&blue);
switch (channel)
{
case RedPixelChannel: pixel=red; break;
{
if (Sc > Dc)
{
- pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
+ pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
break;
}
- pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
+ pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
break;
}
case LightenIntensityCompositeOp:
pixel=Sc;
break;
}
- CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
- GetPixelBlue(image,q),&hue,&saturation,&brightness);
- CompositeHSB(GetPixelRed(composite_image,p),
- GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
- &sans,&sans,&brightness);
- HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+ CompositeHCL(destination_pixel.red,destination_pixel.green,
+ destination_pixel.blue,&hue,&chroma,&luma);
+ CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
+ &sans,&sans,&luma);
+ HCLComposite(hue,chroma,luma,&red,&green,&blue);
switch (channel)
{
case RedPixelChannel: pixel=red; break;
pixel=Dc;
break;
}
- CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
- GetPixelBlue(image,q),&hue,&saturation,&brightness);
- brightness+=(0.01*percent_brightness*offset)/midpoint;
- saturation*=0.01*percent_saturation;
- HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+ CompositeHCL(destination_pixel.red,destination_pixel.green,
+ destination_pixel.blue,&hue,&chroma,&luma);
+ luma+=(0.01*percent_luma*offset)/midpoint;
+ chroma*=0.01*percent_chroma;
+ HCLComposite(hue,chroma,luma,&red,&green,&blue);
switch (channel)
{
case RedPixelChannel: pixel=red; break;
}
case PlusCompositeOp:
{
- pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
+ pixel=gamma*(Sa*Sc+Da*Dc);
break;
}
case SaturateCompositeOp:
pixel=Sc;
break;
}
- CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
- GetPixelBlue(image,q),&hue,&saturation,&brightness);
- CompositeHSB(GetPixelRed(composite_image,p),
- GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
- &sans,&saturation,&sans);
- HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+ CompositeHCL(destination_pixel.red,destination_pixel.green,
+ destination_pixel.blue,&hue,&chroma,&luma);
+ CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
+ &sans,&chroma,&sans);
+ HCLComposite(hue,chroma,luma,&red,&green,&blue);
switch (channel)
{
case RedPixelChannel: pixel=red; break;
}
case ThresholdCompositeOp:
{
- MagickRealType
+ double
delta;
delta=Sc-Dc;
- if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
+ if ((double) fabs((double) (2.0*delta)) < threshold)
{
pixel=gamma*Dc;
break;
image_view=DestroyCacheView(image_view);
if (destination_image != (Image * ) NULL)
destination_image=DestroyImage(destination_image);
+ else
+ composite_image=DestroyImage(composite_image);
+ if (status != MagickFalse)
+ (void) ClampImage(image,exception);
return(status);
}
\f
%
% The format of the TextureImage method is:
%
-% MagickBooleanType TextureImage(Image *image,const Image *texture_image,
+% MagickBooleanType TextureImage(Image *image,const Image *texture,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
% o texture_image: This image is the texture to layer on the background.
%
*/
-MagickExport MagickBooleanType TextureImage(Image *image,
- const Image *texture_image,ExceptionInfo *exception)
+MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
+ ExceptionInfo *exception)
{
#define TextureImageTag "Texture/Image"
*image_view,
*texture_view;
+ Image
+ *texture_image;
+
MagickBooleanType
status;
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(image->signature == MagickSignature);
- if (texture_image == (const Image *) NULL)
+ if (texture == (const Image *) NULL)
return(MagickFalse);
- (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
return(MagickFalse);
+ texture_image=CloneImage(texture,0,0,MagickTrue,exception);
+ if (texture_image == (const Image *) NULL)
+ return(MagickFalse);
+ (void) TransformImageColorspace(texture_image,image->colorspace,exception);
+ (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
+ exception);
status=MagickTrue;
if ((image->compose != CopyCompositeOp) &&
- ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
- (texture_image->matte != MagickFalse)))
+ ((image->compose != OverCompositeOp) || (image->alpha_trait == BlendPixelTrait) ||
+ (texture_image->alpha_trait == BlendPixelTrait)))
{
/*
Tile texture onto the image background.
*/
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,1) shared(status)
+ #pragma omp parallel for schedule(static) shared(status) \
+ dynamic_number_threads(image,image->columns,image->rows,1)
#endif
for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
{
MagickBooleanType
thread_status;
- thread_status=CompositeImage(image,image->compose,texture_image,x+
- texture_image->tile_offset.x,y+texture_image->tile_offset.y,
- exception);
+ thread_status=CompositeImage(image,texture_image,image->compose,
+ MagickFalse,x+texture_image->tile_offset.x,y+
+ texture_image->tile_offset.y,exception);
if (thread_status == MagickFalse)
{
status=thread_status;
}
(void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
image->rows,image->rows);
+ texture_image=DestroyImage(texture_image);
return(status);
}
/*
Tile texture onto the image background (optimized).
*/
status=MagickTrue;
- image_view=AcquireCacheView(image);
- texture_view=AcquireCacheView(texture_image);
+ texture_view=AcquireVirtualCacheView(texture_image,exception);
+ image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,1) shared(status)
+ #pragma omp parallel for schedule(static) shared(status) \
+ dynamic_number_threads(image,image->columns,image->rows,1)
#endif
for (y=0; y < (ssize_t) image->rows; y++)
{
register ssize_t
i;
+ if (GetPixelMask(image,p) != 0)
+ {
+ p+=GetPixelChannels(texture_image);
+ q+=GetPixelChannels(image);
+ continue;
+ }
for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
{
PixelChannel
texture_traits,
traits;
- channel=GetPixelChannelMapChannel(texture_image,i);
- texture_traits=GetPixelChannelMapTraits(texture_image,channel);
- traits=GetPixelChannelMapTraits(image,channel);
+ channel=GetPixelChannelChannel(texture_image,i);
+ texture_traits=GetPixelChannelTraits(texture_image,channel);
+ traits=GetPixelChannelTraits(image,channel);
if ((traits == UndefinedPixelTrait) ||
(texture_traits == UndefinedPixelTrait))
continue;
}
texture_view=DestroyCacheView(texture_view);
image_view=DestroyCacheView(image_view);
+ texture_image=DestroyImage(texture_image);
return(status);
}