Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
gubach
Posts: 45
Joined: 2013-12-13T11:13:29-07:00
Authentication code: 6789

I am trying to formalize ModulusAdd and ModulusSubtract (see http://www.imagemagick.org/Usage/compose/#modulus_add and the discussion https://www.imagemagick.org/discourse-s ... dd#p124698) with the known image symbols Sca, Dca, Sa, Da (from http://www.w3.org/TR/2014/CR-compositing-1-20140220/) which represents here 1-channel arrays (gray scale images respective alphas) all as double. Are the following hypothesis correct and what about transforming the corresponding alpha?

Code: Select all

``````        if (Sca + Dca) <= 1
Dca = Sca + Dca;
else
Dca = (Sca + Dca) - 1;
end``````
Alpha channel:
Da = Sa + Da or the same procedure:
if (Sa + Da) <= 1; Da = Sa + Da; else; Da = (Sa + Da) - 1; end

ModulusSubtract:

Code: Select all

``````       if (Sca - Dca) >= 0
Dca = Sca - Dca;
else
Dca = (Sca - Dca) + 1;
end``````
Alpha channel:
Da = Sa - Da or the same procedure:
if (Sa - Da) >= 0; Da = Sa - Da; else; Da = (Sa - Da) + 1; end

magick
Posts: 11254
Joined: 2003-05-31T11:32:55-07:00

### Re: Formalizing ModulusAdd and ModulusSubtract

Let's go to the authoritative source, IMv7:

Alpha:

Code: Select all

``  alpha=RoundToUnity(Sa+Da-Sa*Da);``
Gray:

Code: Select all

`````` case ModulusAddCompositeOp:
{
pixel=Sc+Dc;
while (pixel > QuantumRange)
pixel-=QuantumRange;
while (pixel < 0.0)
pixel+=QuantumRange;
pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
break;
}
case ModulusSubtractCompositeOp:
{
pixel=Sc-Dc;
while (pixel > QuantumRange)
pixel-=QuantumRange;
while (pixel < 0.0)
pixel+=QuantumRange;
pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
break;
}
``````

snibgo
Posts: 13034
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

### Re: Formalizing ModulusAdd and ModulusSubtract

As magick says.

Also note that with HDRI, input values can be outside the range 0.0 to 1.0 (as a fraction of QuantumRange).

Formalisations (and the source code) can be verified, eg (Windows CMD syntax):

Code: Select all

``````magick xc:srgba(10%,20%,30%,0.3) xc:srgba(60%,70%,380%,0.4) ^
-define compose:clamp=off ^
-compose ModulusSubtract -composite ^
txt:

# ImageMagick pixel enumeration: 1,1,65535,srgba
0,0: (16121.6,19136.2,77200.2,38010.3)  #3EFA4AC0FFFF947A  srgba(24.6%,29.2%,117.8%,0.58)``````
And:

Code: Select all

``result.a = 1 - ((1 - dest.a) * (1 - src.a)) = 1 - (1 - src.a - dest.a + src.a * dest.a) = scr.a + dest.a - src.a * dest.a``
snibgo's IM pages: im.snibgo.com

gubach
Posts: 45
Joined: 2013-12-13T11:13:29-07:00
Authentication code: 6789

### Re: Formalizing ModulusAdd and ModulusSubtract

Is the interpretion of the code in "case ModulusAddCompositeOp" correct, that if pixel (= Sc + Dc; why not Sca + Dca like in the SVG specification?) is larger than QuantumRange (= 1) or smaller than 0 (which is equivalent to pixel is in the interval [0 1]) the equation

Code: Select all

``pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa))``
holds?

Correct me if I am wrong but

Code: Select all

``````pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa))

<=> Sc + Dc = Sa * Da * (Sc+Dc) + Sa * Sc * (1.0-Da) + Da * Dc * (1.0-Sa)

<=> Sc + Dc = Sa * Da * (Sc+Dc) + Sca * (1.0-Da) + Dca * (1.0-Sa)

<=> Sc + Dc = Sa * Da * Sc + Sa * Da * Dc + Sca - Sca * Da + Dca - Dca * Sa

<=> Sc + Dc = Sca * Da + Sa * Dca + Sca - Sca * Da + Dca - Dca * Sa

<=> Sc + Dc = Sca + Dca         #which holds only in the special case that Sa = Da = 1

<=> Dca = Sc + Dc - Sca``````
which looks different from the expected plus-equation Dca = Sca + Dca that should be applied within [0 1]; according to the SVG specification for plus:

Code: Select all

``Dca' = Sca × Da + Dca × Sa + Sca × (1 - Da) + Dca × (1 - Sa) = Sca + Dca.``

magick