Commit 49e5a1114 for imagemagick.org
commit 49e5a11140d4b837475d4d21ce993d33f3558f12
Author: Cristy <urban-warrior@imagemagick.org>
Date: Sat Feb 28 09:34:56 2026 -0500
https://github.com/ImageMagick/ImageMagick/issues/8579
diff --git a/MagickCore/composite.c b/MagickCore/composite.c
index 5039fdb7c..54296c2e5 100644
--- a/MagickCore/composite.c
+++ b/MagickCore/composite.c
@@ -71,6 +71,8 @@
#include "MagickCore/pixel-accessor.h"
#include "MagickCore/property.h"
#include "MagickCore/quantum.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/random-private.h"
#include "MagickCore/resample.h"
#include "MagickCore/resource_.h"
#include "MagickCore/string_.h"
@@ -1459,6 +1461,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
MagickStatusType
flags;
+ RandomInfo
+ *random_info;
+
ssize_t
y;
@@ -2087,7 +2092,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
residual_threshold = 0.0002,
iterations = 400.0;
- size_t
+ size_t
tick = 100;
artifact=GetImageArtifact(image,"compose:args");
@@ -2191,6 +2196,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
status=MagickTrue;
progress=0;
midpoint=((MagickRealType) QuantumRange+1.0)/2;
+ random_info=AcquireRandomInfo();
source_view=AcquireVirtualCacheView(source_image,exception);
image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
@@ -2200,6 +2206,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
for (y=0; y < (ssize_t) image->rows; y++)
{
const Quantum
+ *magick_restrict p,
*pixels;
MagickRealType
@@ -2214,9 +2221,6 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
canvas_pixel,
source_pixel;
- const Quantum
- *magick_restrict p;
-
Quantum
*magick_restrict q;
@@ -2268,13 +2272,14 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
MagickRealType
alpha = 0.0,
+ blend = 0.0,
+ D = 0.0,
Da = 0.0,
Dc = 0.0,
Dca = 0.0,
- DcaDa = 0.0,
Di = 0.0,
+ S = 0.0,
Sa = 0.0,
- SaSca = 0.0,
Sc = 0.0,
Sca = 0.0,
Si = 0.0;
@@ -2593,10 +2598,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
case CopyAlphaCompositeOp:
{
- if (source_image->alpha_trait == UndefinedPixelTrait)
- pixel=Si;
- else
- pixel=(double) QuantumRange*Sa;
+ pixel=Si;
break;
}
case BlurCompositeOp:
@@ -2614,7 +2616,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
{
if (compose_sync == MagickFalse)
{
- pixel=Si < Di? Sa : Da;
+ pixel=Si < Di ? Sa : Da;
break;
}
pixel=Sa*Si < Da*Di ? Sa : Da;
@@ -2720,8 +2722,6 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
*/
Sca=QuantumScale*Sa*Sc;
Dca=QuantumScale*Da*Dc;
- SaSca=Sa*MagickSafeReciprocal(Sca);
- DcaDa=Dca*MagickSafeReciprocal(Da);
switch (compose)
{
case DarkenCompositeOp:
@@ -2777,7 +2777,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
pixel=Dc;
break;
}
- pixel=(double) QuantumScale*Si*Dc;
+ pixel=Dc+(QuantumScale*Si-0.5)*Dc;
break;
}
case ChangeMaskCompositeOp:
@@ -2792,28 +2792,40 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
case ColorBurnCompositeOp:
{
- if ((Sca == 0.0) && (Dca == Da))
- {
- pixel=(double) QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
- break;
- }
- if (Sca == 0.0)
- {
- pixel=(double) QuantumRange*gamma*(Dca*(1.0-Sa));
- break;
- }
- pixel=(double) QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,
- (1.0-DcaDa)*SaSca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
+ D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
+ S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
+ if (S <= 0.0)
+ blend=0.0;
+ else
+ blend=1.0-(1.0-D)/S;
+ pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*
+ RoundToUnity(blend)+Sa*(1.0-Da)*S+Da*(1.0-Sa)*D);
break;
}
case ColorDodgeCompositeOp:
{
- if ((Sca*Da+Dca*Sa) >= Sa*Da)
- pixel=(double) QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*
- (1.0-Sa));
+ if (Sa > 0.0)
+ S=RoundToUnity(Sca/Sa);
+ else
+ S=0.0;
+ if (Da > 0.0)
+ D=RoundToUnity(Dca/Da);
+ else
+ D=0.0;
+ if (S >= 1.0)
+ blend=1.0;
else
- pixel=(double) QuantumRange*gamma*(Dca*Sa*Sa*
- MagickSafeReciprocal(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
+ if (D <= 0.0)
+ blend=0.0;
+ else
+ {
+ if ((1.0-S) <= 0.0)
+ blend=1.0;
+ else
+ blend=MagickMin(1.0,D/(1.0-S));
+ }
+ pixel=(double) QuantumRange*gamma*(Sa*Da*blend+Sca*(1.0-Da)+Dca*
+ (1.0-Sa));
break;
}
case ColorizeCompositeOp:
@@ -2880,95 +2892,71 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
case DarkenCompositeOp:
{
- /*
- Darken is equivalent to a 'Minimum' method
- OR a greyscale version of a binary 'Or'
- OR the 'Intersection' of pixel sets.
- */
if (compose_sync == MagickFalse)
{
- pixel=MagickMin(Sc,Dc);
- break;
- }
- if ((Sca*Da) < (Dca*Sa))
- {
- pixel=(double) QuantumRange*(Sca+Dca*(1.0-Sa));
+ pixel=RoundToUnity(MagickMin(Sca,Dca)+Sca*(1.0-Da)+Dca*
+ (1.0-Sa));
break;
}
- pixel=(double) QuantumRange*(Dca+Sca*(1.0-Da));
+ pixel=(double) QuantumRange*RoundToUnity(MagickMin(Sca,Dca)+Sca*
+ (1.0-Da)+Dca*(1.0-Sa));
break;
}
case DarkenIntensityCompositeOp:
{
if (compose_sync == MagickFalse)
{
- pixel=Si < Di ? Sc : Dc;
+ pixel=RoundToUnity(MagickMin(Sca,Dca)+Sca*(1.0-Di)+Dca*
+ (1.0-Si));
break;
}
- pixel=Sa*Si < Da*Di ? Sc : Dc;
+ pixel=(double) QuantumRange*RoundToUnity(MagickMin(Sca,Dca)+Sca*
+ (1.0-Di)+Dca*(1.0-Si));
break;
}
case DifferenceCompositeOp:
{
if (compose_sync == MagickFalse)
{
- pixel=fabs((double) Sc-Dc);
- break;
+ pixel=(double) QuantumRange*RoundToUnity(fabs((double) Sc-
+ (double) Dc));
+ break;
}
- pixel=(double) QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,
- Dca*Sa));
+ S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
+ D=(Da > 0.0) ? (Dca/Da) : 0.0;
+ pixel=(double) QuantumRange*RoundToUnity(fabs(S-D));
break;
}
case DissolveCompositeOp:
{
- pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
- canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
+ if (GetPseudoRandomValue(random_info) < (source_dissolve*Sa))
+ pixel=Sc;
+ else
+ pixel=Dc;
break;
}
case DivideDstCompositeOp:
{
- if (compose_sync == MagickFalse)
- {
- pixel=(double) QuantumRange*(Sc/MagickSafeReciprocal(Dc));
- break;
- }
- if ((fabs((double) Sca) < MagickEpsilon) &&
- (fabs((double) Dca) < MagickEpsilon))
- {
- pixel=(double) QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
- break;
- }
- if (fabs((double) Dca) < MagickEpsilon)
- {
- pixel=(double) QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*
- (1.0-Sa));
- break;
- }
- pixel=(double) QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*
- (1.0-Sa));
+ S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
+ D=(Da > 0.0) ? (Dca/Da) : 0.0;
+ if (S <= 0.0)
+ blend=1.0;
+ else
+ blend=MagickMin(1.0,D/S);
+ pixel=(double) QuantumRange*RoundToUnity(Sca*(1.0-Da)+Dca*(1.0-Sa)+
+ Sa*Da*blend);
break;
}
case DivideSrcCompositeOp:
{
- if (compose_sync == MagickFalse)
- {
- pixel=(double) QuantumRange*(Dc/MagickSafeReciprocal(Sc));
- break;
- }
- if ((fabs((double) Dca) < MagickEpsilon) &&
- (fabs((double) Sca) < MagickEpsilon))
- {
- pixel=(double) QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
- break;
- }
- if (fabs((double) Sca) < MagickEpsilon)
- {
- pixel=(double) QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*
- (1.0-Da));
- break;
- }
- pixel=(double) QuantumRange*gamma*(Dca*Sa*SaSca+Dca*(1.0-Sa)+Sca*
- (1.0-Da));
+ S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
+ D=(Da > 0.0) ? (Dca/Da) : 0.0;
+ if (D <= 0.0)
+ blend=1.0;
+ else
+ blend=MagickMin(1.0,S/D);
+ pixel=(double) QuantumRange*RoundToUnity(Sca*(1.0-Da)+Dca*(1.0-Sa)+
+ Sa*Da*blend);
break;
}
case DstAtopCompositeOp:
@@ -2993,33 +2981,51 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
case ExclusionCompositeOp:
{
- pixel=(double) QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*
- (1.0-Da)+Dca*(1.0-Sa));
+ S=(Sa > 0.0) ? Sca/Sa : 0.0;
+ D=(Da > 0.0) ? Dca/Da : 0.0;
+ blend=RoundToUnity(S+D-2.0*S*D);
+ pixel=(double) QuantumRange*RoundToUnity((blend*Sa+D*(1.0-Sa))*
+ (Sa+Da-Sa*Da));
break;
}
case FreezeCompositeOp:
- {
- pixel=(double) QuantumRange*gamma*(1.0-(1.0-Sca)*(1.0-Sca)*
- MagickSafeReciprocal(Dca));
- if (pixel < 0.0)
- pixel=0.0;
+ {
+ if (Dca != 0.0)
+ blend=1.0-(1.0-Sca)*(1.0-Sca)/Dca;
+ else
+ blend=0.0;
+ pixel=(double) QuantumRange*gamma*RoundToUnity(blend);
break;
}
case HardLightCompositeOp:
{
- if ((2.0*Sca) < Sa)
- {
- pixel=(double) QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
- (1.0-Sa));
- break;
- }
- pixel=(double) QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*
- (1.0-Da)+Dca*(1.0-Sa));
+ D=(Da > 0.0) ? (Dca/Da) : 0.0;
+ S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
+ if (S <= 0.5)
+ blend=2.0*S*D;
+ else
+ blend=1.0-2.0*(1.0-S)*(1.0-D);
+ pixel=(double) QuantumRange*gamma*RoundToUnity((1.0-Da)*Sca+
+ (1.0-Sa)*Dca+blend*Sa*Da);
break;
}
case HardMixCompositeOp:
{
- pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : (double) QuantumRange);
+ if (Sca < 0.5)
+ {
+ if ((2.0*Sca) == 0.0)
+ blend=0.0;
+ else
+ blend=1.0-(1.0-Dca)/(2.0*Sca);
+ }
+ else
+ {
+ if ((1.0-((2.0*Sca)-1.0)) == 0.0)
+ blend=1.0;
+ else
+ blend=Dca/(1.0-(2.0*Sca-1.0));
+ }
+ pixel=gamma*((blend < 0.5) ? 0.0 : (double) QuantumRange);
break;
}
case HueCompositeOp:
@@ -3071,7 +3077,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
f(Sc,Dc) = Sc + Dc - 1
*/
- pixel=(double) QuantumRange*gamma*(Sca+Dca-Sa*Da);
+ pixel=(double) QuantumRange*(Sca+Dca-Sa*Da);
break;
}
case LinearDodgeCompositeOp:
@@ -3082,12 +3088,13 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
case LinearLightCompositeOp:
{
/*
- LinearLight: as defined by Abode Photoshop, according to
- http://www.simplefilter.de/en/basics/mixmods.html is:
-
- f(Sc,Dc) = Dc + 2*Sc - 1
+ Linear Light (Adobe standard):
+ f(Sc, Dc) = Dc + 2*Sc - 1
+ Applied in linear (HDRI) space with clamping.
*/
- pixel=(double) QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
+ D=(Da > 0.0) ? Dca/Da : 0.0,
+ S=(Sa > 0.0) ? Sca/Sa : 0.0;
+ pixel=(double) QuantumRange*gamma*(RoundToUnity(D+2.0*S-1.0)*Da);
break;
}
case LightenCompositeOp:
@@ -3097,27 +3104,15 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
pixel=MagickMax(Sc,Dc);
break;
}
- if ((Sca*Da) > (Dca*Sa))
- {
- pixel=(double) QuantumRange*(Sca+Dca*(1.0-Sa));
- break;
- }
- pixel=(double) QuantumRange*(Dca+Sca*(1.0-Da));
+ S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
+ D=(Da > 0.0) ? (Dca/Da) : 0.0;
+ pixel=(double) QuantumRange*RoundToUnity(Sca*(1.0-Da)+Dca*(1.0-Sa)+
+ MagickMax(S,D)*Sa*Da);
break;
}
case LightenIntensityCompositeOp:
{
- /*
- Lighten is equivalent to a 'Maximum' method
- OR a greyscale version of a binary 'And'
- OR the 'Union' of pixel sets.
- */
- if (compose_sync == MagickFalse)
- {
- pixel=Si > Di ? Sc : Dc;
- break;
- }
- pixel=Sa*Si > Da*Di ? Sc : Dc;
+ pixel=Si > Di ? Sc : Dc;
break;
}
case LuminizeCompositeOp:
@@ -3188,22 +3183,12 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
pixel=Dc-Sc;
break;
}
- pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
+ pixel=gamma*(Da*Dc-Sa*Sc);
break;
}
case MinusSrcCompositeOp:
{
- /*
- Minus source from canvas.
-
- f(Sc,Dc) = Sc - Dc
- */
- if (compose_sync == MagickFalse)
- {
- pixel=Sc-Dc;
- break;
- }
- pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
+ pixel=Sc-Dc;
break;
}
case ModulateCompositeOp:
@@ -3240,48 +3225,39 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
case ModulusAddCompositeOp:
{
- if (compose_sync == MagickFalse)
- {
- pixel=(Sc+Dc);
- break;
- }
- if ((Sca+Dca) <= 1.0)
- {
- pixel=(double) QuantumRange*(Sca+Dca);
- break;
- }
- pixel=(double) QuantumRange*((Sca+Dca)-1.0);
+ pixel=(double) QuantumRange*(Sc+Dc-floor(Sc+Dc));
break;
}
case ModulusSubtractCompositeOp:
{
+ D=(Da > 0.0) ? (Dc/Da) : 0.0;
+ S=(Sa > 0.0) ? (Sc/Sa) : 0.0;
+ blend=S-D;
+ if (blend < 0.0)
+ blend+=1.0;
if (compose_sync == MagickFalse)
{
- pixel=(Sc-Dc);
- break;
- }
- if ((Sca-Dca) >= 0.0)
- {
- pixel=(double) QuantumRange*(Sca-Dca);
+ pixel=(double) QuantumRange*(blend*Sa);
break;
}
- pixel=(double) QuantumRange*((Sca-Dca)+1.0);
+ pixel=(double) QuantumRange*(blend*Sa);
break;
}
case MultiplyCompositeOp:
{
if (compose_sync == MagickFalse)
{
- pixel=(double) QuantumScale*Dc*Sc;
+ pixel=(double) QuantumRange*Sc*Dc;
break;
}
- pixel=(double) QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*
- (1.0-Sa));
+ pixel=(double) QuantumRange*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
break;
}
case NegateCompositeOp:
{
- pixel=(double) QuantumRange*(1.0-fabs(1.0-Sca-Dca));
+ D=(Da > 0.0) ? Dca/Da : 0.0;
+ S=(Sa > 0.0) ? Sca/Sa : 0.0;
+ pixel=(double) QuantumRange*((1.0-fabs(1.0-S-D))*Da);
break;
}
case NoCompositeOp:
@@ -3298,7 +3274,11 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
case OverCompositeOp:
case SrcOverCompositeOp:
{
- pixel=(double) QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
+ if ((Sa+Da*(1.0-Sa)) <= MagickEpsilon)
+ pixel=0.0;
+ else
+ pixel=(double) QuantumRange*gamma*((Sca+Dca*(1.0-Sa))/
+ (Sa+Da*(1.0-Sa)));
break;
}
case OverlayCompositeOp:
@@ -3315,61 +3295,79 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
case PegtopLightCompositeOp:
{
- /*
- PegTop: A Soft-Light alternative: A continuous version of the
- Softlight function, producing very similar results.
-
- f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
-
- http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
- */
if (fabs((double) Da) < MagickEpsilon)
{
pixel=(double) QuantumRange*gamma*Sca;
break;
}
- pixel=(double) QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*
- (2.0*Dca+1.0-Da)+Dca*(1.0-Sa));
+ if (RoundToUnity(Sca) <= 0.5)
+ blend=RoundToUnity(Dca/Da)-(1.0-2.0*RoundToUnity(Sca))*
+ RoundToUnity(Dca/Da)*(1.0-RoundToUnity(Dca/Da));
+ else
+ {
+ if (RoundToUnity(Dca/Da) <= 0.25)
+ blend=((16.0*RoundToUnity(Dca/Da)-12.0)*RoundToUnity(Dca/Da)+
+ 4.0)*RoundToUnity(Dca/Da);
+ else
+ blend=sqrt(RoundToUnity(Dca/Da));
+ blend=RoundToUnity(Dca/Da)+(2.0*RoundToUnity(Sca)-1.0)*
+ (blend-RoundToUnity(Dca/Da));
+ }
+ pixel=(double) QuantumRange*gamma*(RoundToUnity(blend)*Da*Sa+Dca*
+ (1.0-Sa));
break;
}
case PinLightCompositeOp:
{
/*
- PinLight: A Photoshop 7 composition method
- http://www.simplefilter.de/en/basics/mixmods.html
+ Adobe Pin Light (colors in [0,1]):
- f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
+ if (Cs <= 0.5)
+ f = min(Cd, 2*Cs);
+ else
+ f = max(Cd, 2*Cs - 1);
*/
- if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
- {
- pixel=(double) QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*
- (1.0-Sa));
- break;
- }
- if ((Dca*Sa) > (2.0*Sca*Da))
- {
- pixel=(double) QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
- break;
- }
- pixel=(double) QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
+ D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
+ S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
+ if (S <= 0.5)
+ blend=MagickMin(D,2.0*S);
+ else
+ blend=MagickMax(D,2.0*S-1.0);
+ pixel=(double) QuantumRange*gamma*(blend*RoundToUnity(Sa+Da-Sa*Da));
break;
}
case PlusCompositeOp:
{
- if (compose_sync == MagickFalse)
- {
- pixel=(Dc+Sc);
- break;
- }
- pixel=(double) QuantumRange*(Sca+Dca);
+ D=(Da > 0.0) ? Dca/Da : 0.0;
+ S=(Sa > 0.0) ? Sca/Sa : 0.0;
+ pixel=(double) QuantumRange*(RoundToUnity(Sa+Da-Sa*Da)*
+ RoundToUnity(S+D));
break;
}
case ReflectCompositeOp:
{
- pixel=(double) QuantumRange*gamma*(Sca*Sca*
- MagickSafeReciprocal(1.0-Dca));
- if (pixel > (double) QuantumRange)
- pixel=(double) QuantumRange;
+ if (compose_sync == MagickFalse)
+ {
+ if (Dc < 1.0)
+ blend=(Sc*Sc)/(1.0-Dc);
+ else
+ blend=1.0;
+ pixel=(double) QuantumRange*RoundToUnity(blend);
+ break;
+ }
+ if (Sa > 0.0)
+ S=Sca/Sa;
+ else
+ S=0.0;
+ if (Da > 0.0)
+ D=Dca/Da;
+ else
+ D=0.0;
+ if (D < 1.0)
+ blend=(S*S)/(1.0-D);
+ else
+ blend=1.0;
+ pixel=(double) QuantumRange*RoundToUnity((Sa+Da-Sa*Da)*blend);
break;
}
case RMSECompositeOp:
@@ -3434,61 +3432,74 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
case ScreenCompositeOp:
{
- /*
- Screen: a negated multiply:
-
- f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
- */
if (compose_sync == MagickFalse)
{
- pixel=Sc+Dc-Sc*Dc;
+ pixel=(double) QuantumRange*RoundToUnity(Sc+Dc-Sc*Dc);
break;
}
- pixel=(double) QuantumRange*gamma*(Sca+Dca-Sca*Dca);
+ if (Sa > 0.0)
+ S=Sca/Sa;
+ else
+ S=0.0;
+ if (Da > 0.0)
+ D=Dca/Da;
+ else
+ D=0.0;
+ if ((Sa+Da-Sa*Da) > 0.0)
+ pixel=(double) QuantumRange*RoundToUnity((Sa+Da-Sa*Da)*(S+D-S*D));
+ else
+ pixel=0.0;
break;
}
case SoftBurnCompositeOp:
{
- if ((Sca+Dca) < 1.0)
- pixel=(double) QuantumRange*gamma*(0.5*Dca*
- MagickSafeReciprocal(1.0-Sca));
+ if (RoundToUnity(Dca) <= 0.0)
+ blend = 0.0;
else
- pixel=(double) QuantumRange*gamma*(1.0-0.5*(1.0-Sca)*
- MagickSafeReciprocal(Dca));
+ if (RoundToUnity(Sca) >= 1.0)
+ blend = 1.0;
+ else
+ blend=1.0-MagickMin(1.0,(1.0-RoundToUnity(Dca))/
+ RoundToUnity(Sca));
+ pixel=(double) QuantumRange*gamma*RoundToUnity(blend);
break;
}
case SoftDodgeCompositeOp:
{
- if ((Sca+Dca) < 1.0)
- pixel=(double) QuantumRange*gamma*(0.5*Sca*
- MagickSafeReciprocal(1.0-Dca));
+ if (RoundToUnity(Sca) <= 0.0)
+ blend=RoundToUnity(Dca);
else
- pixel=(double) QuantumRange*gamma*(1.0-0.5*(1.0-Dca)*
- MagickSafeReciprocal(Sca));
+ if (RoundToUnity(Dca) >= 1.0)
+ blend=1.0;
+ else
+ blend=MagickMin(1.0,RoundToUnity(Dca)/(1.0-RoundToUnity(Sca)));
+ pixel=(double) QuantumRange*gamma*RoundToUnity(blend);
break;
}
case SoftLightCompositeOp:
{
- if ((2.0*Sca) < Sa)
- {
- pixel=(double) QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*
- (1.0-DcaDa))+Sca*(1.0-Da)+Dca*(1.0-Sa));
- break;
- }
- if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
+ if (RoundToUnity(Sca) <= 0.5)
{
- pixel=(double) QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*
- (4.0*DcaDa*(4.0*DcaDa+1.0)*(DcaDa-1.0)+7.0*DcaDa)+Sca*
- (1.0-Da)+Dca*(1.0-Sa));
+ pixel=(double) QuantumRange*gamma*(RoundToUnity(Dca)*Sa+Da*
+ (RoundToUnity(Dca)-(1.0-2.0*RoundToUnity(Sca))*
+ RoundToUnity(Dca)*(1.0-RoundToUnity(Dca)))+RoundToUnity(Sca)*
+ (1.0-Da)+RoundToUnity(Dca)*(1.0-Sa));
break;
}
- pixel=(double) QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*
- (pow(DcaDa,0.5)-DcaDa)+Sca*(1.0-Da)+Dca*(1.0-Sa));
+ if (RoundToUnity(Dca) > 0.25)
+ blend=sqrt(RoundToUnity(Dca));
+ else
+ blend=((16.0*RoundToUnity(Dca)-12.0)*RoundToUnity(Dca)+4.0)*
+ RoundToUnity(Dca);
+ pixel=(double) QuantumRange*gamma*(RoundToUnity(Dca)*Sa+Da*
+ (RoundToUnity(Dca)+(2.0*RoundToUnity(Sca)-1.0)*
+ (RoundToUnity(blend)-RoundToUnity(Dca)))+RoundToUnity(Sca)*
+ (1.0-Da)+RoundToUnity(Dca)*(1.0-Sa));
break;
}
case StampCompositeOp:
{
- pixel=(double) QuantumRange*(Sca+Dca*Dca-1.0);
+ pixel=(double) QuantumRange*RoundToUnity(Sca+Dca-1.0);
break;
}
case StereoCompositeOp:
@@ -3499,41 +3510,37 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
case ThresholdCompositeOp:
{
- MagickRealType
- delta;
-
- delta=Sc-Dc;
- if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
- {
- pixel=gamma*Dc;
- break;
- }
- pixel=gamma*(Dc+delta*amount);
+ S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
+ D=(Da > 0.0) ? (Dca/Da) : 0.0;
+ if (fabs(2.0*(S-D)) < threshold)
+ blend=D;
+ else
+ blend=D+(S-D)*amount;
+ pixel=(double) QuantumRange*(Sa*Da*RoundToUnity(blend)+Sca*
+ (1.0-Da)+Dca*(1.0-Sa));
break;
}
case VividLightCompositeOp:
{
- /*
- VividLight: A Photoshop 7 composition method. See
- http://www.simplefilter.de/en/basics/mixmods.html.
-
- f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
- */
if ((fabs((double) Sa) < MagickEpsilon) ||
- (fabs((double) (Sca-Sa)) < MagickEpsilon))
+ (fabs((double) Da) < MagickEpsilon))
{
pixel=(double) QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*
(1.0-Sa));
break;
}
- if ((2.0*Sca) <= Sa)
- {
- pixel=(double) QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)*
- MagickSafeReciprocal(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
- break;
- }
- pixel=(double) QuantumRange*gamma*(Dca*Sa*Sa*
- MagickSafeReciprocal(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
+ if (RoundToUnity(Sca/Sa) <= 0.0)
+ blend=0.0;
+ else
+ if (RoundToUnity(Sca/Sa) < 0.5)
+ blend=1.0-(1.0-RoundToUnity(Dca/Da))/(2.0*RoundToUnity(Sca/Sa));
+ else
+ if (RoundToUnity(Sca/Sa) < 1.0)
+ blend=RoundToUnity(Dca/Da)/(2.0*(1.0-RoundToUnity(Sca/Sa)));
+ else
+ blend=1.0;
+ pixel=(double) QuantumRange*gamma*(Sa*Da*RoundToUnity(blend)+Sca*
+ (1.0-Da)+Dca*(1.0-Sa));
break;
}
case XorCompositeOp:
@@ -3573,6 +3580,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
}
source_view=DestroyCacheView(source_view);
image_view=DestroyCacheView(image_view);
+ random_info=DestroyRandomInfo(random_info);
if (canvas_image != (Image * ) NULL)
canvas_image=DestroyImage(canvas_image);
else
diff --git a/PerlMagick/Magick.xs b/PerlMagick/Magick.xs
index cb7f8feaf..463bc3479 100644
--- a/PerlMagick/Magick.xs
+++ b/PerlMagick/Magick.xs
@@ -8886,8 +8886,8 @@ Mogrify(ref,...)
*/
mask_image=CloneImage(argument_list[10].image_reference,0,0,
MagickTrue,exception);
- (void) SetImageMask(composite_image,ReadPixelMask,mask_image,
- exception);
+ (void) CompositeImage(composite_image,mask_image,
+ CopyAlphaCompositeOp,clip_to_self,0,0,exception);
mask_image=DestroyImage(mask_image);
}
}
diff --git a/PerlMagick/quantum/quantum.xs.in b/PerlMagick/quantum/quantum.xs.in
index f6b3352e7..18bcf7251 100644
--- a/PerlMagick/quantum/quantum.xs.in
+++ b/PerlMagick/quantum/quantum.xs.in
@@ -8907,8 +8907,8 @@ Mogrify(ref,...)
*/
mask_image=CloneImage(argument_list[10].image_reference,0,0,
MagickTrue,exception);
- (void) SetImageMask(composite_image,ReadPixelMask,mask_image,
- exception);
+ (void) CompositeImage(composite_image,mask_image,
+ CopyAlphaCompositeOp,clip_to_self,0,0,exception);
mask_image=DestroyImage(mask_image);
}
}