Comments about the function WindowTransformImage

Posted by Nick Gammon on Fri 27 Aug 2010 03:00 AM — 19 posts, 64,910 views.

Australia Forum Administrator #0
Further on from this thread:

http://www.gammon.com.au/forum/bbshowpost.php?id=10527
USA #1
How might I use this with WindowMergeImageAlpha, if I have a transparency mask I'd like to use?

And is there any way I use this with WindowImageOp so I can clip the image within a fancy, non-rectangular border?

Thanks for the help, Nick.
Australia Forum Administrator #2
Twisol said:

How might I use this with WindowMergeImageAlpha, if I have a transparency mask I'd like to use?


You don't, bad luck. If you look at the source you see it does a heap of complex calculations to make it work. There isn't some easy way of achieving it (or at least, I don't know of it).

Twisol said:

And is there any way I use this with WindowImageOp so I can clip the image within a fancy, non-rectangular border?


Make a temporary window with a purple background. Then use that as the transparency when copying and translating.
USA #3
Nick Gammon said:
Twisol said:

How might I use this with WindowMergeImageAlpha, if I have a transparency mask I'd like to use?


You don't, bad luck. If you look at the source you see it does a heap of complex calculations to make it work. There isn't some easy way of achieving it (or at least, I don't know of it).

I Googled and found this, maybe it'll help?

http://www.mvps.org/user32/gditutorial.html

I found the source download for the transparency tutorial to be easier to glance over than the tutorial itself, for some reason.

Nick Gammon said:
Twisol said:

And is there any way I use this with WindowImageOp so I can clip the image within a fancy, non-rectangular border?


Make a temporary window with a purple background. Then use that as the transparency when copying and translating.

I don't like color-based transparency. :S If I could use WindowMergeImageAlpha, I could render it into a scratch window and then draw that rotated.
Australia Forum Administrator #4
Twisol said:

I don't like color-based transparency. :S If I could use WindowMergeImageAlpha, I could render it into a scratch window and then draw that rotated.


You can. Rotate the image. Rotate the mask. Then merge the rotated image with the rotated mask into the miniwindow.
Australia Forum Administrator #5
Twisol said:

I Googled and found this, maybe it'll help?

http://www.mvps.org/user32/gditutorial.html


From that page: "GDI has no built in transparency support - you have to implement transparency in bitmaps yourself.".

Now maybe later versions of the GDI do support it, but we will get to the stage where MUSHclient only runs under Windows Vista or onwards, because of pressure to implement features that no-one has wanted so far, to do obscure things like rotating a loaded image and merge it with an alpha mask in order to give an inventory window a slightly better looking shadow that no-one will really care about.
USA #6
Nick Gammon said:

Twisol said:

I don't like color-based transparency. :S If I could use WindowMergeImageAlpha, I could render it into a scratch window and then draw that rotated.


You can. Rotate the image. Rotate the mask. Then merge the rotated image with the rotated mask into the miniwindow.


So you're saying I'd rotate the image and mask into new scratch windows, which would have to be large enough to fit the whole of the rotated image (and with the new area of the alpha mask filled with the transparency color), then apply them to the target window?

I guess that works. Feels awful though.
USA #7
Nick Gammon said:

Twisol said:

I Googled and found this, maybe it'll help?

http://www.mvps.org/user32/gditutorial.html


From that page: "GDI has no built in transparency support - you have to implement transparency in bitmaps yourself.".

Now maybe later versions of the GDI do support it, but we will get to the stage where MUSHclient only runs under Windows Vista or onwards, because of pressure to implement features that no-one has wanted so far, to do obscure things like rotating a loaded image and merge it with an alpha mask in order to give an inventory window a slightly better looking shadow that no-one will really care about.


Did you look at what it does? It just uses two modes of BitBlt, first applying the trasparency mask and then the image itself. It said it has no built-in, widely-compatible support as a segue for how to do it properly yourself. And I think it might simplify your implementation, too.

Granted, I still don't know if it's exactly what you need, but you haven't said otherwise yet.
Amended on Fri 27 Aug 2010 04:54 AM by Twisol
Australia Forum Administrator #8
Twisol said:

Did you look at what it does? It just uses two modes of BitBlt, first applying the trasparency mask and then the image itself. It said it has no built-in, widely-compatible support as a segue for how to do it properly yourself. And I think it might simplify your implementation, too.


The current code does exactly that:


	    // Build mask based on transparent colour at location 0, 0
	    dcTrans.BitBlt (0, 0, iWidth, iHeight, &bmDC, 0, 0, SRCCOPY);

	    // Do the work 
	    dc.BitBlt (0, 0, iWidth, iHeight, &bmDC,    0, 0, SRCINVERT);
	    dc.BitBlt (0, 0, iWidth, iHeight, &dcTrans, 0, 0, SRCAND);
	    dc.BitBlt (0, 0, iWidth, iHeight, &bmDC,    0, 0, SRCINVERT);


However, as he says "One bitmap specifies the image - and all the "transparent" areas are set to black. The other bitmap is monochrome / black and white.".

That is, this is a on/off sort of transparency, the exact thing that is now implemented. Not a 0-255 levels of transparency.
Australia Forum Administrator #9
Twisol said:

So you're saying I'd rotate the image and mask into new scratch windows, which would have to be large enough to fit the whole of the rotated image (and with the new area of the alpha mask filled with the transparency color), then apply them to the target window?


There is no transparency colour in this particular case. The WindowTranslateImage uses a grayscale image to control the transparency with 256 levels of transparency. That is the thing you have to rotate.
USA #10
Nick Gammon said:

Twisol said:

Did you look at what it does? It just uses two modes of BitBlt, first applying the trasparency mask and then the image itself. It said it has no built-in, widely-compatible support as a segue for how to do it properly yourself. And I think it might simplify your implementation, too.


The current code does exactly that:


	    // Build mask based on transparent colour at location 0, 0
	    dcTrans.BitBlt (0, 0, iWidth, iHeight, &bmDC, 0, 0, SRCCOPY);

	    // Do the work 
	    dc.BitBlt (0, 0, iWidth, iHeight, &bmDC,    0, 0, SRCINVERT);
	    dc.BitBlt (0, 0, iWidth, iHeight, &dcTrans, 0, 0, SRCAND);
	    dc.BitBlt (0, 0, iWidth, iHeight, &bmDC,    0, 0, SRCINVERT);


However, as he says "One bitmap specifies the image - and all the "transparent" areas are set to black. The other bitmap is monochrome / black and white.".

That is, this is a on/off sort of transparency, the exact thing that is now implemented. Not a 0-255 levels of transparency.


The issue was that your implementation is difficult, so I found another. Does the other implementation make it any easier? It seems like it only needs two blits.

Also, I was talking about WindowMergeImageAlpha; why is your code snippet taken from Draw/TranslateImage? :S

Nick Gammon said:
There is no transparency colour in this particular case. The WindowTranslateImage uses a grayscale image to control the transparency with 256 levels of transparency. That is the thing you have to rotate.

The full transparency color, I meant. Fully see-through. Otherwise the space created around the rotation (since I need a bigger canvas) would be visible when it's merged into the target.
Australia Forum Administrator #11
Twisol said:

The issue was that your implementation is difficult, so I found another. Does the other implementation make it any easier? It seems like it only needs two blits.


I count four in the code. Two in the setup (to set up the mask) and two in the painting area.

My four are all done at once, because I don't know in advance which bitmap you are doing to do it with.
Australia Forum Administrator #12
Twisol said:

The full transparency color, I meant. Fully see-through. Otherwise the space created around the rotation (since I need a bigger canvas) would be visible when it's merged into the target.


See this:

http://www.gammon.com.au/forum/bbshowpost.php?id=9568

The mask (the black blobby thing) is the thing you would have to copy and rotate. Naturally you need a large enough place to rotate it into, and the background of that larger "canvas" would be white.
Australia Forum Administrator #13
Twisol said:

I guess that works. Feels awful though.


It works for the hypothetical situation you are proposing. I am waiting for a concrete example of where many people need to rotate and blend in bitmaps with alpha channels, and how the existing system will fail them.
USA #14
Nick Gammon said:

Twisol said:

I guess that works. Feels awful though.


It works for the hypothetical situation you are proposing. I am waiting for a concrete example of where many people need to rotate and blend in bitmaps with alpha channels, and how the existing system will fail them.

Yes, it does work. I have no serious complaints now except for the orthogonality and the feels-awful (which are unsurprisingly linked).
USA #15
Nick Gammon said:

Twisol said:

The issue was that your implementation is difficult, so I found another. Does the other implementation make it any easier? It seems like it only needs two blits.


I count four in the code. Two in the setup (to set up the mask) and two in the painting area.

My four are all done at once, because I don't know in advance which bitmap you are doing to do it with.


Huh, sorry about the noise then. (It does seem to use SRCCOPY, SRCAND, and SRCPAINT, where you use SRCCOPY, SRCAND, and SRCINVERT, but I guess there's no difference here.)
USA Global Moderator #16
1) The name should be WindowTransformImage, not WindowTranslateImage, since translation is just one class of transformation.
2) The transformation results would benefit from bilinear or bicubic interpolation. The shear and rotate examples are super jaggy.
Amended on Fri 27 Aug 2010 06:28 PM by Fiendish
Australia Forum Administrator #17
Fiendish said:

1) The name should be WindowTransformImage, not WindowTranslateImage, since translation is just one class of transformation.


OK good idea. Did that and revised various documentation and forum posts.
Australia Forum Administrator #18
Fiendish said:

2) The transformation results would benefit from bilinear or bicubic interpolation. The shear and rotate examples are super jaggy.


This isn't Photoshop, as I was trying to explain to Twisol. Interpolation is not supported by the underlying Windows API.

The client is not intended to be rendering and rotating images on-the-fly like a shoot-em-up game.

I can understand it would be useful to have rotated text (say) for tabbed windows. This can be accomplished now by pre-rendering the tabs (in a scratch miniwindow), converting to an image, and then rotating them. The rotations of 90, 180 and 270 degrees look fine.

You also have the option of pre-rotating an image in Photoshop or other program of your choice, and then rendering the pre-rotated image in the miniwindow.