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: