News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

TransparentBlt Example

Started by zedd151, March 09, 2025, 05:41:18 AM

Previous topic - Next topic

zedd151

TransparentBlt example:  Another example that others might find useful.
Source code fully commented.  :tongue:

    include \masm32\include\masm32rt.inc

    include \masm32\include\msimg32.inc        ; needed for TransparentBlt
    includelib \masm32\lib\msimg32.lib          ; needed for TransparentBlt
       
    DlgProc proto :dword, :dword, :dword, :dword

        cwidth        equ 240                  ; desired client area width
        cheight      equ 140                  ; desired client area height

    .data?
   
        hBmp_red      dd ?                      ; handle of bitmap loaded from resource

    .code

    start proc
    local hInstance:dword
        invoke GetModuleHandle, NULL
        mov hInstance, eax

        invoke DialogBoxParam, hInstance, 100, 0, addr DlgProc, 0  ;; create dialog box, from resource dilalog

        invoke ExitProcess, eax
    start endp

    DlgProc proc hWin:dword, uMsg:dword, wParam:dword, lParam:dword
    local hDC:dword, ps:PAINTSTRUCT, rct:RECT, hBrush:dword, hBrush_old:dword
    local mDC:dword, hBmp:dword, hBmp_old:dword, hPen:dword, hPen_old:dword
    local x:dword, y:dword, wwid:dword, whgt:dword, cwid:dword, chgt:dword
   
        .if uMsg == WM_INITDIALOG

          ;; resizing Client Area to exact dimensions, specified by cwidth and cheight

          invoke GetWindowRect, hWin, addr rct ;; get window current dimensions.
          mov eax, rct.right                  ;; obtain current window width by subtracting left boundary
          sub eax, rct.left                    ;; from the right boundary
          mov wwid, eax                        ;; store current window width
          mov eax, rct.bottom                  ;; obtain current window height by subtracting top boundary
          sub eax, rct.top                    ;; from the bottom boundary
          mov whgt, eax                        ;; store current window height

          invoke GetClientRect, hWin, addr rct ;; get client area current dimensions.
          mov eax, rct.right                  ;; obtain current client width by subtracting left boundary
          sub eax, rct.left                    ;; from the right boundary
          mov cwid, eax                        ;; store current client area width
          mov eax, rct.bottom                  ;; obtain current client height by subtracting top boundary
          sub eax, rct.top                    ;; from the bottom boundary
          mov chgt, eax                        ;; store client area height

          ;; calculate the difference between desired client area width and current client area width
          mov eax, cwidth
          sub eax, cwid

          ;; adjust the window width according to the difference calculated above
          add wwid, eax

          ;; calculate the difference between desired client area height and current client area height
          mov eax, cheight
          sub eax, chgt
          ;; adjust the window height according to the difference calculated height
          add whgt, eax

          ;; center the main window
          ;; obtain client area of the desktop, not including the task bar
          invoke SystemParametersInfoA, SPI_GETWORKAREA, 0, addr rct, 0

          ;; center window width
          mov eax, rct.right
          sub eax, wwid
          sar eax, 1
          mov x, eax

          ;; center window height
          mov eax, rct.bottom
          sub eax, whgt
          sar eax, 1
          mov y, eax

          ;; implement the centering of the resized main window
          invoke MoveWindow, hWin, x, y, wwid, whgt, TRUE
         
          invoke GetModuleHandle, 0
          invoke LoadBitmap, eax, 100                          ; load bitmap from resource
          mov hBmp_red, eax

        .elseif uMsg == WM_PAINT
          invoke BeginPaint, hWin, addr ps
          mov hDC, eax                                          ; window client area DC
         
          ;; get client area rectangle
          invoke GetClientRect, hWin, addr rct                  ; client rectangle of dialog box

          invoke CreateCompatibleDC, hDC
          mov mDC, eax                                          ; memory DC

          invoke CreateCompatibleBitmap, hDC, rct.right, rct.bottom
          mov hBmp, eax                                        ; compatible bitmap handle
         
          invoke SelectObject, mDC, hBmp
          mov hBmp_old, eax

          ;; ###########################################################

          ;; Here I change the background color of the main window
          invoke CreateSolidBrush, 0000FFFFh                    ; color yellow
          mov hBrush, eax  ;; save the brush handle

          ;; fill the client area rectangle with chosen color
          invoke FillRect, mDC, addr rct, hBrush                ; fill rectangle in memory DC

          ;; delete the brush, as it is no longer needed
          invoke DeleteObject, hBrush
         
          invoke SelectObject, mDC, hBmp                        ; select memory bitmap object
          mov hBmp_old, eax
          invoke BitBlt, hDC, 0, 0, rct.right, rct.bottom, mDC, 0, 0, SRCCOPY
         
          ;; ###########################################################
         
          invoke SelectObject, mDC, hBmp_red                    ; select resource bitmap object
         
                                                                ; transparent blit, exclude color 0000FF00h
          invoke TransparentBlt, hDC,  0, 0, 120, 120, mDC, 0, 0, 120, 120, 0000FF00h
         
                                                                ; mormal blit resource bitmap
          invoke BitBlt, hDC,        120, 0, 120, 120, mDC, 0, 0, SRCCOPY

          ;; ###########################################################
          invoke SelectObject, mDC, hBmp_old
          invoke DeleteObject, hBmp                            ; delete DC bitmap object
          invoke DeleteDC, mDC                                  ; delete memory DC

          invoke EndPaint, hWin, addr ps
        .elseif uMsg == WM_CLOSE
          invoke DeleteObject, hBmp_red                        ; delete resource bitmap object
          invoke EndDialog, hWin, 0                            ; clode dialog box
        .endif
        xor eax, eax
        ret
    DlgProc endp

    end

The image on the left uses TranparentBlt to draw the bitmap. Color for transparent parts (color to not copy) is 0000FF00h.
The image on the right used BitBlt to draw the bitmap, and represents what the actual bitmap looks like.



:smiley:
Slight change to the source code, also in the attachment.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

NoCforMe

Yes, TransparentBlt() is an excellent tool to have in one's toolbox.
The one limitation I found with it is that (if I remember correctly) you can't resize the image between the source and destination DCs as you can with BitBlt(); the destination has to be the same size as the source. (Maybe someone can confirm or deny this.)

Hey, Zedd, maybe next you might want to try StretchBlt() to round out your GDI methods.
Assembly language programming should be fun. That's why I do it.

zedd151

#2
Quote from: NoCforMe on March 09, 2025, 07:28:03 AM(if I remember correctly) you can't resize the image between the source and destination DCs as you can with BitBlt()

Like this:  :biggrin:


TransparentBlt with stretching!!  :cool:
                                                                ; transparent blit, exclude color 0000FF00h
          invoke TransparentBlt, hDC,  0, 0, 240, 240, mDC, 0, 0, 120, 120, 0000FF00h

I had seen your comment about not able to stretch while using TransparentBlt, btw. I almost posted there today, while checking if an example was already posted somewhere on the forum for how to use TransparentBlt - before posting mine.

Found it. Again:
Quote from: NoCforMe on December 09, 2023, 07:44:47 AMAnd stretching does not work. Don't believe me? Try it.
That might have had something to do with your custom pallete?.

Quote from: NoCforMe on March 09, 2025, 07:28:03 AMHey, Zedd, maybe next you might want to try StretchBlt() to round out your GDI methods.
I generally don't like the appearance of stretched images. It is bad enough that some have to look blocky because of reducing the # of colors used. Stretching amplifies the blockiness. If I could "stretch B.L.T." that would be alright.  :biggrin:
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

sinsi

If you want to get a particular client size try using AdjustWindowRect.

zedd151

Quote from: sinsi on March 09, 2025, 07:56:24 AMIf you want to get a particular client size try using AdjustWindowRect.
No, thats too easy.  :biggrin:  Actually I did not know about that api (or if I did, I don't remember it), thanks sinsi. Maybe next time, my solution also works perfectly, and is a lot better than my old one.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

NoCforMe

Quote from: zedd151 on March 09, 2025, 07:33:03 AM
Quote from: NoCforMe on March 09, 2025, 07:28:03 AM(if I remember correctly) you can't resize the image between the source and destination DCs as you can with BitBlt()

Like this:  :biggrin:


TransparentBlt with stretching!!  :cool:
                                                                ; transparent blit, exclude color 0000FF00h
          invoke TransparentBlt, hDC,  0, 0, 240, 240, mDC, 0, 0, 120, 120, 0000FF00h

I had seen your comment about not able to stretch while using TransparentBlt, btw. I almost posted there today, while checking if an example was already posted somewhere on the forum for how to use TransparentBlt - before posting mine.

Found it. Again:
Quote from: NoCforMe on December 09, 2023, 07:44:47 AMAnd stretching does not work. Don't believe me? Try it.
That might have had something to do with your custom pallete?.

So apparently you were able to resize the image using TransparentBlt(), yes?
Happy to be proven wrong here. But it'd be nice to know why I couldn't get it to work. (Believe me, I tried.)
I don't think it would have been on account of my custom palette: Windows doesn't really care what's in that data. However, it could have been because I was using a paletted image in the first place, instead of a non-paletted image (like anything higher than 8BPP).

What is the bit depth of your images? Are they 24-bit images? That might explain it.
Assembly language programming should be fun. That's why I do it.

zedd151

4 bit, Indexed 16 colors... converted with GIMP.
Attach here a bitmap that you could not stretch using TransparentBlt, even if you have to screenshot it from your program or otherwise render it. Is it A custom made bitmap, using your routines?

Side note: when saving indexed .bmp's with GIMP, I have to check "do not save color space information" for it to be compatible with gdi api's. (At least I had not found a way for them to work without doing so).
 I would like to open your bitmap with GIMP, to try a few tricks. Maybe I could find a solution for your particular issue. If I recall correctly, GIMP lets you rearrange the color table (or colormap?).
 Not sure though, if it affects the color placement in the bitmap itself. Experimentation would prolly be necessary.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

NoCforMe

OK, give me a little time to resurrect that project ...
Yes, custom-made bitmap created by code.
Assembly language programming should be fun. That's why I do it.

sinsi

Quote from: NoCforMe on March 09, 2025, 07:28:03 AMThe one limitation I found with it is that (if I remember correctly) you can't resize the image between the source and destination DCs as you can with BitBlt(); the destination has to be the same size as the source. (Maybe someone can confirm or deny this.)

Denied!
From the Microsoft page TransparentBlt
QuoteIf the source and destination rectangles are not the same size, the source bitmap is stretched to match the destination rectangle.

zedd151

Quote from: zedd151 on March 09, 2025, 08:36:25 AMIf I recall correctly, GIMP lets you rearrange the color table (or colormap?).
 Not sure though, if it affects the color placement in the bitmap itself. Experimentation would prolly be necessary.

Rearranging the colormap with GIMP does not alter the appearance of the bitmap in any way.  :biggrin:
I just checked and verified. It changes the colormap as you request, and adjusts the values in the bitmap data according to the changes to the colormap indexing.  :thup:
The GIMP is a great tool, you should try it.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

zedd151

Quote from: NoCforMe on March 09, 2025, 07:28:03 AM(Maybe someone can confirm or deny this.)
Quote from: sinsi on March 09, 2025, 09:15:33 AMDenied!
Ouch! Yes he knows what Microsoft 'says', but he was having trouble with a certain bitmap, which I *think* I can help with.

quote from the thread where NoCforMe was having issues stretching a bitmap while using TransparentBlt...
Quote from: NoCforMe on December 09, 2023, 07:44:47 AMThe point is that TransparentBlt() only works if the transparent color is the first one in the palette. This is not mentioned at all in the Micro$oft documentation.
I think this is not true at all. YOU specify the exact color for the transparent parts, as one of TransparentBlt's arguments. Something else is amiss with your home grown bitmap. I propose opening your rendered bitmap with GIMP, saving it in whatever bit depth you need, then you can compare the bitmap data to see how much it might differ from yours...

Better still, if you wanted 4 bit color depth, examine this one (attached), created with GIMP - with "do not write color space information" checked under "Compatibilty Options" upon exporting (saving) ...

¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

sinsi

According to someone on Stack Overflow, black is not supported as a transparent colour.
Maybe that's the problem?

zedd151

Quote from: sinsi on March 09, 2025, 09:39:45 AMAccording to someone on Stack Overflow, black is not supported as a transparent colour.
Maybe that's the problem?
Yes, I had seen that also during my research. Hey, NoC??? were you using black as transparent??
My money says yes.  Don't ask me why I say this...  :rofl:  Then again, it is a homebrew bitmap made in code not from a .bmp file, so we have to wait and see...

But yes passing colorref for black 00000000h as the transparent colour, would be passing a NULL. Makes sense, actually. Most likely it needs a non-zero  value there.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

NoCforMe

Whoa, whoa; before we get totally corn-fused here:

I had no problems at all with transparency with TransparentBlt(); I was able to use any color, including black, as the transparent color.

What I had problems with was being able to resize the bitmap using that function (despite what Micro$oft claimed in their documentation). Which may or may not be a consequence of the bitmap I was generating programmatically.

I'll try to extract a .bmp from my code that you can experiment with.
Assembly language programming should be fun. That's why I do it.

zedd151

Quote from: NoCforMe on March 09, 2025, 10:59:47 AMWhoa, whoa; before we get totally corn-fused here:

I had no problems at all with transparency with TransparentBlt(); I was able to use any color, including black, as the transparent color.
:biggrin: okay.

QuoteWhat I had problems with was being able to resize the bitmap using that function (despite what Micro$oft claimed in their documentation). Which may or may not be a consequence of the bitmap I was generating programmatically.

I'll try to extract a .bmp from my code that you can experiment with.
okay...  :biggrin:

Once you have a *.bmp file, try it yourself first. Maybe it will work after loading it with LoadBitmap... it's worth a try.
But I'm here if you still need me to try something else.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—