Commit 0d84dc79f for imagemagick.org
commit 0d84dc79f6e049363af431eacd422cf11b289469
Author: tomotomo <tomoppeko@gmail.com>
Date: Fri Oct 30 00:00:40 2026 +0900
Divide by alpha in LinearBurn, Screen, Exclusion and Difference compose (#9074)
Since 49e5a1114 these operators return the premultiplied color without
dividing it by the result alpha, so semi-transparent destination pixels
come out darker by their alpha, even under a fully transparent source.
Multiply had the same problem and was fixed in d81304839.
Use the form that LinearDodge, LinearLight, PinLight, HardMix and Multiply
already use: gamma*RoundToUnity(Sa*Da*blend+Sca*(1-Da)+Dca*(1-Sa)).
Difference also composites |S-D| with the alphas again instead of
returning it as is.
diff --git a/MagickCore/composite.c b/MagickCore/composite.c
index 1761775cf..40f3d2924 100644
--- a/MagickCore/composite.c
+++ b/MagickCore/composite.c
@@ -2923,9 +2923,11 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
(double) Dc));
break;
}
- S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
- D=(Da > 0.0) ? (Dca/Da) : 0.0;
- pixel=(double) QuantumRange*RoundToUnity(fabs(S-D));
+ S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
+ D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
+ blend=fabs(S-D);
+ pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*blend+Sca*
+ (1.0-Da)+Dca*(1.0-Sa));
break;
}
case DissolveCompositeOp:
@@ -3003,8 +3005,8 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
D=(Da > 0.0) ? RoundToUnity(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));
+ pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*blend+Sca*
+ (1.0-Da)+Dca*(1.0-Sa));
break;
}
case FreezeCompositeOp:
@@ -3107,8 +3109,8 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
blend=RoundToUnity(S+D-1.0);
- pixel=(double) QuantumRange*RoundToUnity(Sa*Da*blend+Sca*(1.0-Da)+
- Dca*(1.0-Sa));
+ pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*blend+Sca*
+ (1.0-Da)+Dca*(1.0-Sa));
break;
}
case LinearDodgeCompositeOp:
@@ -3485,8 +3487,8 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
blend=RoundToUnity(S+D-S*D);
- pixel=(double) QuantumRange*RoundToUnity(Sa*Da*blend+Sca*(1.0-Da)+
- Dca*(1.0-Sa));
+ pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*blend+Sca*
+ (1.0-Da)+Dca*(1.0-Sa));
break;
}
case SoftBurnCompositeOp: