Thomas Lübking wrote:
After checking the i18n files i now know that "nachbelichten" is supposed to be burn.
However, the appropriate function in app/coposite-generic.c does not seem to behave as expected.
afaik the burn function should do nothing if the the upper (the burning) color is white.
also a black pixel of the lower layer should remain black - whatever the upper layer is colored.
However, this function:

  while (length--)
      for (b = 0; b < alpha; b++)
          tmp = (255 - src1[b]) << 8;
          tmp /= src2[b] + 1;
          dest[b] = (guchar) CLAMP(255 - tmp, 0, 255);
      if (has_alpha1 && has_alpha2)
        dest[alpha] = MIN(src1[alpha], src2[alpha]);
      else if (has_alpha2)
        dest[alpha] = src2[alpha];

      src1 += bytes1;
      src2 += bytes2;
      dest += bytes2;

cannot provide this.
(e.g. upper (src1) is white (255) -> tmp = 0 << 8 = 0; => 0 / ? + 1 = 0; CLAMP(255 - 0, 0, 255) = 255 = white - so white will flatten anything instead of leaving it as it is.
as a consequence, black won't remain, as soon as one of the components r,g,b = 255.
i tried to weight the effect (255-0)/255*burn + (1-(255-0)/255)*original... but the result wasn't like what i expected.

Ok. First off you need to realize that your constants (8, 255, 0, 1) are all integers (since they don't have a type specification after them). Also tmp is an int. This means the chars get promoted and are not doing 8 bit math: we are doing at least 32 bit math. This means that 255 << 8 is not 0, but 65280. This also means that a black second layer stays black and a white first layer leaves the original pixel untouched.

Second, lets do our math in normalized RGB space so that RGB vary from (0,0,0) (black) to (1,1,1). Lets convert the above equation to normalized space.

tmp = (255 - src1) << 8 / (src2 + 1).
dest = CLAMP (255 - tmp).

IF you want to convert to normalized form, you divide src1 by 255. Lets call that src1'. Derive src2', tmp' and dest' in the same way. Then, turning the bit shift into a multiply, and ignoring the clamp for a moment:

tmp' * 255 = (255 - 255 * src1') * 256 / (src2' * 255 + 1)
dest' * 255 = 255 - tmp' * 255

Factoring out 255 everywhere gives us:

tmp' = (1 - src1') * 256 /((src2' + 1/255) * 255)
dest' = 1 - tmp'
tmp' = (1 - src1')/(src2' + 1/255) * (256 / 255).
dest' = 1 - tmp'

I am sure that the original formula assumes 1/255 is aprox. 0 and 256/255 is 1 (since this saves a multiply, and prevents 1/src2 from being evaluated as zero).

thus, the original formula, in normalized RGB space is:

tmp' = (1 - src1')/(src2')
dest' = 1 - tmp'
dest' = 1 - (1-src1')/(src2')
Also, with the condition that if src2' = 0, dest' = 0;
This is much more sane.

Now for the theory of burning.

Burning is a term from photography (the chemical and paper kind). A burn is when you expose a portion of the paper beyond the normal exposure time. Let me derive the formula of a real, physical exposure burn.

The aparent change in darkness of a photo as you add more light is of a is propotional amount of light, exposure (Intensity * time), and the current darkness of the photo. Lets make a simplification from the begining. There is an inversion here. Bright light is a dark spot on the photo, and dim light is a light spot on the photo, so we are going to reverse our lights levels, so that we are referring to the corresponding shade the light will produce on the photo. This forces all discussion to happen in the photo colorspace. Lets call the original photo brigness p, the new photo brightness p', and the inverted exposure be I times delta t. The formula for the differential change in brightness is thus:

- delta p = p * I * delta t;

Which is, once solve in closed form, an exponential decay. Exactly what I would expect. At the very least, it is obvious that the above equation qualitatily reflects the properties of an exponential exposure time, assuming that a single interation represents some fixed (short) extra exporsure time. I am not sure if this represents an actual approximation. I don't acutally have any source material for burn, except for the knowledge of want the process is.

On a related noted, I notice that a brush in burn mode won't burn white, no matter how hard I try. That doesn't seem correct to me. Shouldn't a burn darker a white area (it will darken everything up to 255)? Also, same for dodge and black. Shouldn't a dodge lighten a black area?

Gimp-developer mailing list

Reply via email to