1. ## VG_DRAW_IMAGE_STENCIL confusion, urgent.

Oh well. I tried to implement the stencil draw mode, but I have lots of troubles to get anything usefull output. What I get (my implementation), and what I get when I run test codes on the reference implementation differ a lot!

These are some tests, and I was able to break down the problem to a single pixel blend. Here are some colors:

[0.2, 0.4, 0.6, 1.0] -> Dest-Color (some nice blue)
[0.0, 1.0, 0.0, 1.0] -> Image-Color (Pure Green)
[0.0, 0.0, 0.0, 1.0] -> Paint Color (e.g. Black)

Note: All alpha values are 1, so it does not matter if we're talking about premultiplied colors or not (at least for now).

Now I take the equation from chapter 10.8 (the one that shows the stencil mode in combination with SRC_OVER). I leave out the division by AlphaTemp. it's 1 in any case, and the equations are already confusing enough.

For the case of a single color channel (in this case green):

Gdst = ((Aimg * Apaint * Gimg * Gpaint) + Adst * Gdst * (1- Aimg * Apaint * Gimg).

I plug in the constants (e.g. anything that does not change per channel, like dest-alpha and Paint Alpha ect:

Gdst = ((1 * 1 * Gimg * Gpaint) + 1 * Gdst * (1- 1*1* Gimg).

Simplify:

Gdst = ((Gimg * Gpaint) + Gdst * (1- Gimg).

So it will do simple linear interpolation between Paint-color and Dest-color based on the image color channel, at least for this simplified case, where all Alpha values are one.

If I apply this equations to the test colors I've listed above I ought to get:

[0, 0.4, 0, 1.0] -> Output-Color (some medium green)

However, the reference implementation gives me this color:

[0.2, 0.13, 0.6, 1.0]. That's a totally different result. Not even close..

Could anyone please help me and give a detailes answer what the stencil draw mode is supposed to do? For the reference, I also attached the test code I've used:

Code :
```void printcolor (char * name, unsigned char * buffer)
{
float r = buffer[3] / 255.0f;
float g = buffer[2] / 255.0f;
float b = buffer[1] / 255.0f;
float a = buffer[0] / 255.0f;
printf ("%s [%f, %f, %f, %f]\n", name, r,g,b,a);
}

void stenciltest2 (void)
{
unsigned char buffer[4]; // to read back colors:

VGuint testdata[] = {
0x00ff00ff // Full alpha Green
};

VGfloat clearColor[4] = {0.2,0.4,0.6,1};

// Create the Image:
VGImage stencil = vgCreateImage (VG_sRGBA_8888, 1,1, VG_IMAGE_QUALITY_NONANTIALIASED);
vgImageSubData (stencil, testdata, 1, VG_sRGBA_8888, 0,0,1,1);

// Create the Paint:
VGImage paint = vgCreatePaint ();
vgSetPaint (paint, VG_FILL_PATH);
vgSetColor (paint, 0x000000ff); // Full alpha black:

// set a known destination color:
vgSetfv (VG_CLEAR_COLOR, 4, clearColor);
vgClear (0,0,10,10);

vgReadPixels  (buffer, 4, VG_sRGBA_8888_PRE, 0, 0, 1, 1);
printcolor ("Destination = ", buffer);

vgSeti (VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
vgSeti (VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
vgScale (10,10);
vgSeti (VG_BLEND_MODE, VG_BLEND_SRC_OVER);
vgDrawImage (stencil);

vgReadPixels  (buffer, 4, VG_sRGBA_8888_PRE, 0, 0, 1, 1);
printcolor ("Output  = ", buffer);

vgDestroyImage (stencil);
vgDestroyPaint (paint);
}```

2. ## Re: VG_DRAW_IMAGE_STENCIL confusion, urgent.

Originally Posted by Nils Pipenbrinck
Oh well. I tried to implement the stencil draw mode, but I have lots of troubles to get anything usefull output. What I get (my implementation), and what I get when I run test codes on the reference implementation differ a lot!

These are some tests, and I was able to break down the problem to a single pixel blend. Here are some colors:

[0.2, 0.4, 0.6, 1.0] -> Dest-Color (some nice blue)
[0.0, 1.0, 0.0, 1.0] -> Image-Color (Pure Green)
[0.0, 0.0, 0.0, 1.0] -> Paint Color (e.g. Black)

Note: All alpha values are 1, so it does not matter if we're talking about premultiplied colors or not (at least for now).

Now I take the equation from chapter 10.8 (the one that shows the stencil mode in combination with SRC_OVER). I leave out the division by AlphaTemp. it's 1 in any case, and the equations are already confusing enough.

For the case of a single color channel (in this case green):

Gdst = ((Aimg * Apaint * Gimg * Gpaint) + Adst * Gdst * (1- Aimg * Apaint * Gimg).

I plug in the constants (e.g. anything that does not change per channel, like dest-alpha and Paint Alpha ect:

Gdst = ((1 * 1 * Gimg * Gpaint) + 1 * Gdst * (1- 1*1* Gimg).

Simplify:

Gdst = ((Gimg * Gpaint) + Gdst * (1- Gimg).

So it will do simple linear interpolation between Paint-color and Dest-color based on the image color channel, at least for this simplified case, where all Alpha values are one.

If I apply this equations to the test colors I've listed above I ought to get:

[0, 0.4, 0, 1.0] -> Output-Color (some medium green)

However, the reference implementation gives me this color:

[0.2, 0.13, 0.6, 1.0]. That's a totally different result. Not even close..

Could anyone please help me and give a detailes answer what the stencil draw mode is supposed to do? For the reference, I also attached the test code I've used:
Judging from just the Red* value, the reference implementation and your equation simplification look correct.

[0.2, 0.4, 0.6, 1.0] -> Dest-Color (some nice blue)
[0.0, 1.0, 0.0, 1.0] -> Image-Color (Pure Green)
[0.0, 0.0, 0.0, 1.0] -> Paint Color (e.g. Black)

Gdst = ((Gimg * Gpaint) + Gdst * (1- Gimg).

Gives a red* of:

Gdst = ((0 * 0) + 0.2*(1 - 0) = 0.2

(* edit I originally said 'green' for some reason - I don't know what I was thinking...)

3. Hi Ivo,

Yes, I messed up something. Guess I worked, thought and tried to long on the same problem. :P

I made a little test program that just blends the colors and prints them out. Straight forward, without any simplifications.

Code :
```float testblend (float Aimg, float Apaint, float Adst, float Cimg, float Cpaint, float Cdst)
{
float Atmp = (Aimg * Apaint + Adst*(1.0f-Aimg*Apaint));
float  c = (Aimg * Apaint * Cimg * Cpaint) + Adst * Cdst * (1.0f - Aimg * Apaint * Cimg);
return c /Atmp;
}

void main (void)
{
float r = testblend (1, 1, 1, 0, 0, 0.2);
float g = testblend (1, 1, 1, 1, 0, 0.4);
float b = testblend (1, 1, 1, 0, 0, 0.6);
printf ("r=%f g=%f b=%f\n", r,g,b);
}```

That gives, with my test colors:

r = 0.2 g = 0 b = 0.6

(as expected.. the image color becomes source alpha per channel, and the blend equation just lerps between paint-color and dest-color)

The reference implementation still gives:

r = 0.2 g = 0.13 b = 0.6

That is is way off, and I have no idea how they derive their 0.13 value...

So, anyone has an idea if the reference implementation is simply broken, or if I still don't got the equations?

Nils

4. I'm still thinking:

I took the original equations, assumed all variables are assumed to be in non premultiplied format and restated the equations with premultiplied input and output.

Equations from the spec:

tmp = (Aimg * Apaint + Adst*(1.0f-Aimg*Apaint))
Cout = ((Aimg * Apaint * Cimg * Cpaint) + Adst * Cdst * (1.0f - Aimg * Apaint * Cimg)) / tmp
Aout = tmp

-> with premultiplied output: division is obsolete now:

Cout = ((Aimg * Apaint * Cimg * Cpaint) + Adst * Cdst * (1.0f - Aimg * Apaint * Cimg))

-> with premultiplied paint: Cpaint = Cpaint * Apaint

Cout = ((Aimg * Cimg * Cpaint) + Adst * Cdst * (1.0f - Aimg * Apaint * Cimg))

-> with premultiplied Destination: Cdst = Cdst * Adst

Cout = ((Aimg * Cimg * Cpaint) + Cdst * (1.0f - Aimg * Apaint * Cimg))

-> with premultiplied Image Cimg = Cimg * Aimg

This gives the really nice equations (all inputs an output are now premultiplied):

Cout = Cimg * Cpaint + Cdst * (1.0f - Apaint * Cimg)
Aout = Aimg * Apaint + Adst * (1.0f - Apaint * Aimg)

The equations look almost like the SRC_OVER Porter-Duff blending. Just the AlphaSrc used in the Porter-Duff equations is multiplied with the corresponding image color channel. This even makes sense! The image becomes a per channel alpha source that is just multiplied into the equations.

Is it really *that* simple?

5. Noone?

6. ## Some clarfication about stencil image mode.

Public specifications are not so clear, as in other cases...anyway i'll try to write down a simple example. Lets say to have:

- Drawing surface in premultiplied non-linear color space, cleared with rs = 0.2, gs = 0.2, bs = 0.2, as = 0.6
- A paint color in unpremultiplied non-linear color space of rp = 0.1, gp = 0.4, bp = 0.3, ap = 0.5
- An image pixel in unpremultiplied non-linear color space of ri = 0.4, gi = 0.3, bi = 0.1, ai = 0.5
- A source over blend mode, expressed in SourceOver(SrcColorPremultiplied, SrcAlpha, DstColorPremultiplied, DstAlpha)

Now, if you draw the image in stencil mode, the resulting color will be:

rs' = SourceOver(rp * ap * ri * ai, ap * ri * ai, rs, as)
gs' = SourceOver(gp * ap * gi * ai, ap * gi * ai, gs, as)
bs' = SourceOver(bp * ap * bi * ai, ap * bi * ai, bs, as)
as' = SourceOver(ai * ap, as)

rs' = SourceOver(0.1 * 0.5 * 0.4 * 0.5, 0.5 * 0.4 * 0.5, 0.2, 0.6)
gs' = SourceOver(0.4 * 0.5 * 0.3 * 0.5, 0.5 * 0.3 * 0.5, 0.2, 0.6)
bs' = SourceOver(0.3 * 0.5 * 0.1 * 0.5, 0.5 * 0.1 * 0.5, 0.2, 0.6)
as' = SourceOver(0.5 * 0.5, 0.6)

rs' = SourceOver(0.01, 0.1, 0.2, 0.6)
gs' = SourceOver(0.03, 0.075, 0.2, 0.6)
bs' = SourceOver(0.0075, 0.025, 0.2, 0.6)
as' = SourceOver(0.25, 0.6)

Applying source over equations:

rs' = 0.01 + 0.2 * (1 - 0.1) = 0.19
gs' = 0.03 + 0.2 * (1 - 0.075) = 0.215
bs' = 0.0075 + 0.2 * (1 - 0.025) = 0.2025
as' = 0.25 + 0.6 * (1 - 0.25) = 0.7

I wish this example could be of help.
Regards,
Matteo - AmanithVG Team

7. *exactly* what I was looking for, thanks matteo.

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•