image-js / image-js-typescript

Temporary repository to work on the migration of image-js to TypeScript
https://image-js.github.io/image-js-typescript/
MIT License
5 stars 5 forks source link

Add copyTo #19

Closed lpatiny closed 2 years ago

lpatiny commented 2 years ago

We could try to make a code that allows to create a mosaic of grey images

const small = new Image(50, 50);

const target = new Image(250, 250);

for (let i=0; i<25; i++) {
  const temp = small.fill( [i*10, i*10, i*10] );
  temp.copyTo(target, {
    columnOffset: i%5,
    rowOffset: Math.floor(i/5),
  }
}
opatiny commented 2 years ago

Goal: create the copyTo() method.

lpatiny commented 2 years ago

What about alpha ?

Well if there is no alpha the problem is easy, we just copy all the values.

If there is an alpha, the goal is by default to 'mergeAlpha' even if there will be no option currently (it will be the default behaviour).

targos commented 2 years ago

Shouldn't the alpha value of the target image also be in the formula ?

targos commented 2 years ago

Reference: https://en.wikipedia.org/wiki/Alpha_compositing

lpatiny commented 2 years ago

Because we don't touch the alpha channel of the target image it is indirectly used. If there is a zone in the target image that is transparent the copyTo will have no visual effect.

targos commented 2 years ago

I'm not convinced it will give the same result...

targos commented 2 years ago

I mean, if the image that you copy is entirely transparent (all alpha = 0), the result should be the same image as before. With your algorithm, the result is to copy the value of the small image.

lpatiny commented 2 years ago

If the image I copy (called small) is completely transparent (A=0) the contribution in the final image of the small image is 0 with the proposed formula:

small.pixel.R * small.pixel.A / small.maxValue + target.pixel.R * (small.maxValue - small.pixel.A) / small.maxValue

And the pixels of the target image stays untouched (small.maxValue - small.pixelA) / small.maxValue is in fact 1.

targos commented 2 years ago

Here are two simple examples that can be turned into test cases: All images are 1x1, grey with alpha Source = image to copy Target = "background" where source is copied

  1. Transparent source, opaque target. Source: [100, 0] Target: [50, 255] Expected result: [50, 255] With your formula: [50, 255]

  2. Opaque source, transparent target Source: [100, 255] Target: [50, 0] Expected result: [100, 255] With your formula: [100, 0] It's impossible to get the correct result without changing the alpha value of the target.

Edit: of course, it becomes interesting when the alpha value in source and target is between 0 and 255.

targos commented 2 years ago

Maybe my expectations are wrong, but I surely don't agree that the target is the only one that can contribute to the opacity of the final image.

lpatiny commented 2 years ago

Indeed this is something we didn't see in the same way. For the second case I was keeping the transparency of the target picture so the copy had no effect. Wonder what is the 'expected' real case behaviour.

Opaque source, transparent target Source: [100, 255] Target: [50, 0] Expected result: [100, 255] With your formula: [100, 0]

targos commented 2 years ago

I think we should try to implement the formula for the "over" operator given by Wikipedia and see what that gives.