[SOLVED] DrawText() & TextOut() WinAPI on Layered Window

Just starting out? Need help? Post your questions and find answers here.
User avatar
TI-994A
Addict
Addict
Posts: 2741
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

[SOLVED] DrawText() & TextOut() WinAPI on Layered Window

Post by TI-994A »

[This issue has been solved by PureBasic expert Danilo] (linked)

Image

In the following code, which creates a layered window, I'm able to draw text on it using PureBasic's DrawText() function, but get this cut-out effect (illustrated above) if the WinAPI DrawText() or TextOut() functions are used.

Does anyone know what causes this behaviour?

NOTE: You'll need a PNG image to test this code (or just download this one):

Code: Select all

; modified from original code by Le Soldat Inconnu - Thank You!
; http://forum.purebasic.com/english/viewtopic.php?f=12&t=39079&hilit=transparency

UsePNGImageDecoder()

Enumeration
  #MainWindow
  #imageFile
EndEnumeration

Global.l appQuit

Procedure WndProc(hWnd, uMsg, wParam, lParam)
  Shared sysProc
  result = CallWindowProc_(sysProc, hWnd, uMsg, wParam, lParam)  
  Select uMsg
    Case #WM_NCHITTEST
      SendMessage_(hWnd, #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
    Case #WM_LBUTTONDOWN
      If WindowMouseX(#MainWindow)>0 And WindowMouseX(#MainWindow)<60
        If WindowMouseY(#MainWindow)>0 And WindowMouseY(#MainWindow)<60
          appQuit = 1
          ProcedureReturn 0 
        EndIf
      EndIf      
  EndSelect
  ProcedureReturn result
EndProcedure

Procedure AlphaImageWindow(WindowID, ImageID, Alpha)
  Protected Image_HDC, Image_Bitmap.BITMAP, Image_BitmapInfo.BITMAPINFO, ContextOffset.POINT, Blend.BLENDFUNCTION
  Protected xx, yy, x, y, Rouge, Vert, Bleu, AlphaChannel
  Protected Dim Echelle.f($FF)
  For x = 0 To $FF
    Echelle(x) = x / $FF
  Next
   
  Image_HDC = CreateCompatibleDC_(#Null)
  Image_Ancienne = SelectObject_(Image_HDC, ImageID)
   
  GetObject_(ImageID, SizeOf(BITMAP), @Image_Bitmap)
  Image_BitmapInfo\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
  Image_BitmapInfo\bmiHeader\biWidth = Image_Bitmap\bmWidth
  Image_BitmapInfo\bmiHeader\biHeight = Image_Bitmap\bmHeight
  Image_BitmapInfo\bmiHeader\biPlanes = 1
  Image_BitmapInfo\bmiHeader\biBitCount = 32
   
  xx = Image_Bitmap\bmWidth - 1
  yy = Image_Bitmap\bmHeight - 1
  Protected Dim Image.l(xx, yy)
   
  GetDIBits_(Image_HDC, ImageID, 0, Image_Bitmap\bmHeight, @Image(), @Image_BitmapInfo, #DIB_RGB_COLORS)
   
  For x = 0 To xx
    For y = 0 To yy
      Couleur = Image(x, y)
      AlphaChannel = Couleur >> 24 & $FF
      If AlphaChannel < $FF
        Rouge = (Couleur & $FF) * Echelle(AlphaChannel)
        Vert = (Couleur >> 8 & $FF) * Echelle(AlphaChannel)
        Bleu = (Couleur >> 16 & $FF) * Echelle(AlphaChannel)
        Image(x, y) = Rouge | Vert << 8 | Bleu << 16 | AlphaChannel << 24
      EndIf
    Next
  Next
   
  SetDIBits_(Image_HDC, ImageID, 0, Image_Bitmap\bmHeight, @Image(), @Image_BitmapInfo, #DIB_RGB_COLORS)
   
  Blend\AlphaFormat = 1
  Blend\BlendOp = 0
  Blend\BlendFlags = 0
  Blend\SourceConstantAlpha = Alpha
  UpdateLayeredWindow_(WindowID, 0, 0, @Image_BitmapInfo + 4, Image_HDC, @ContextOffset, 0, @Blend, 2)
     
  SelectObject_(Image_HDC, Image_Ancienne)
  DeleteDC_(Image_HDC)
EndProcedure

Define imageFile.s = OpenFileRequester("Select Image:", "", "PNG|*.png", 0)
If imageFile And LoadImage(#imageFile, imageFile)
  wFlags = #PB_Window_BorderLess | #PB_Window_ScreenCentered | #PB_Window_Invisible 
  OpenWindow(#MainWindow, #PB_Any, #PB_Any, ImageWidth(#imageFile), ImageHeight(#imageFile), "Layered Window", wFlags)
  sysProc = SetWindowLong_(WindowID(#MainWindow), #GWL_WNDPROC, @WndProc())
  SetWindowLong_(WindowID(#MainWindow), #GWL_EXSTYLE, GetWindowLong_(WindowID(#MainWindow), #GWL_EXSTYLE) | #WS_EX_LAYERED)
  HideWindow(#MainWindow, 0)
  
  ;PureBasic drawing
  ;==============
  LoadFont(1, "Arial", 20, #PB_Font_Bold)
  StartDrawing(ImageOutput(#imageFile))
  DrawingFont(FontID(1))
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawText(50, 130, "SOLID TEXT...", #Red)
  StopDrawing()
  
  ;Windows drawing
  ;=============
  ddc = StartDrawing(ImageOutput(#imageFile))
    SelectObject_(ddc, FontID(1))
    SetBkMode_(ddc, #TRANSPARENT)
    SetTextColor_(ddc, $FFFF)
    TextOut_(ddc, 50, 180, "CUT-OUT TEXT!", 13)
  StopDrawing()
    
  AlphaImageWindow(WindowID(#MainWindow), ImageID(#imageFile), 255)    

  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        appQuit = 1
    EndSelect
  Until appQuit = 1
EndIf
End
Last edited by TI-994A on Thu May 10, 2012 5:29 am, edited 1 time in total.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
Michael Vogel
Addict
Addict
Posts: 2810
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: DrawText() & TextOut() WinAPI on Layered Window

Post by Michael Vogel »

Maybe you need something like this...

NOTE: You'll don't need a PNG image to test this code :lol:

Code: Select all


#size=640

OpenWindow(0,0,0,#size,#size,"Text out",#PB_Window_ScreenCentered)

LoadFont(0,"Calibri",-160,#PB_Font_Bold)

CreateImage(1,#size,#size,32|#PB_Image_Transparent)
StartDrawing(ImageOutput(1))
DrawingMode(#PB_2DDrawing_AllChannels)
Box(100,100,480,320,#Blue|$FF000000)
DrawingMode(#PB_2DDrawing_AlphaChannel)
DrawingFont(FontID(0))
DrawText(130,180,"PURE",0)
StopDrawing()


CreateImage(0,#size,#size,32)
StartDrawing(ImageOutput(0))
For i=0 To 999
	Circle(Random(#size),Random(#size),Random(20)+20,Random(#White))
Next i
DrawAlphaImage(ImageID(1),0,0)
StopDrawing()


ImageGadget(0,0,0,#size,#size,ImageID(0))

Repeat
	Select WaitWindowEvent()
	Case #PB_Event_CloseWindow,#WM_CHAR
		Break
	EndSelect
ForEver

User avatar
TI-994A
Addict
Addict
Posts: 2741
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: DrawText() & TextOut() WinAPI on Layered Window

Post by TI-994A »

Hi Michael Vogel. Thanks for your reply, and for the great example; really good illustration for DrawAlphaImage().

But actually, I wasn't trying to reproduce the effect, but rather figure out why it was happening. When we draw on a PNG image with PureBasic's DrawText(), it comes out fine; but if we use Windows DrawText() API, it doesn't draw the text, but instead cuts out transparent regions of the text.

Originally, I thought that it had something to do with layered windows; but in fact, we get the same effect on any PNG image. Here's a small snippet to demonstrate this:

Code: Select all

UsePNGImageDecoder()
InitNetwork()

Enumeration
  #MainWindow
  #ImageGadget
  #imageFile
  #drawFont
EndEnumeration

If ReceiveHTTPFile("http://images1.wikia.nocookie.net/__cb20120202174654/central/images/7/71/Tv_series.png", GetTemporaryDirectory() + "image.png")
  LoadImage(#imageFile, GetTemporaryDirectory() + "image.png")
  wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
  OpenWindow(#MainWindow, #PB_Any, #PB_Any, ImageWidth(#imageFile), ImageHeight(#imageFile), "Why does this happen?", wFlags)
  SetWindowColor(#MainWindow, #Magenta)
  
  LoadFont(#drawFont, "Arial", 20, #PB_Font_Bold)
  StartDrawing(ImageOutput(#imageFile))
    DrawingFont(FontID(#drawFont))
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawText(30, 180, "TEXT IS SOLID", #Red)
  StopDrawing()
  
  ddc = StartDrawing(ImageOutput(#imageFile))
    SelectObject_(ddc, FontID(#drawFont))
    SetBkMode_(ddc, #TRANSPARENT)
    SetTextColor_(ddc, $0)   ;<<<====== text should be black
    TextOut_(ddc, 30, 120, "TEXT IS CUT OUT!", 16)
  StopDrawing()
    
  ImageGadget(#ImageGadget, 0, 0, ImageWidth(#imageFile), ImageHeight(#imageFile), ImageID(#imageFile))

  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        appQuit = 1
    EndSelect
  Until appQuit = 1
  
EndIf

End
Any idea why this happens?
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: DrawText() & TextOut() WinAPI on Layered Window

Post by Danilo »

The API functions draw the text, but they set the alpha channel of 32bit images to 0, so it looks transparent.

Just set the alpha channel again after using the API functions.

Code: Select all

UsePNGImageDecoder()
InitNetwork()

Enumeration
  #MainWindow
  #ImageGadget
  #imageFile
  #drawFont
EndEnumeration

If ReceiveHTTPFile("http://images1.wikia.nocookie.net/__cb20120202174654/central/images/7/71/Tv_series.png", GetTemporaryDirectory() + "image.png")
  LoadImage(#imageFile, GetTemporaryDirectory() + "image.png")
  wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
  OpenWindow(#MainWindow, #PB_Any, #PB_Any, ImageWidth(#imageFile), ImageHeight(#imageFile), "Why does this happen?", wFlags)
  SetWindowColor(#MainWindow, #Magenta)
  LoadFont(#drawFont, "Arial", 20, #PB_Font_Bold)
  StartDrawing(ImageOutput(#imageFile))
    DrawingFont(FontID(#drawFont))
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawText(30, 180, "TEXT IS SOLID", #Red)
  StopDrawing()
  
  ddc = StartDrawing(ImageOutput(#imageFile))
    SelectObject_(ddc, FontID(#drawFont))
    SetBkMode_(ddc, #TRANSPARENT)
    SetTextColor_(ddc, 0)   ;<<<====== text should be black
    TextOut_(ddc, 30, 120, "TEXT IS CUT OUT!", 16)

    DrawingMode(#PB_2DDrawing_AlphaChannel) ; set Alpha Channel
    DrawingFont(FontID(#drawFont))
    t.s = "TEXT IS CUT OUT!"
    Box(30,120,TextWidth(t),TextHeight(t),$FFFFFFFF)
  StopDrawing()
    
  ImageGadget(#ImageGadget, 0, 0, ImageWidth(#imageFile), ImageHeight(#imageFile), ImageID(#imageFile))

  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        appQuit = 1
    EndSelect
  Until appQuit = 1
  
EndIf
No need to open more topics for the same issue. ;)
User avatar
TI-994A
Addict
Addict
Posts: 2741
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: DrawText() & TextOut() WinAPI on Layered Window

Post by TI-994A »

Danilo wrote:The API functions draw the text, but they set the alpha channel of 32bit images to 0, so it looks transparent.

Just set the alpha channel again after using the API functions.
Hi Danilo! And thanks a lot for the solution; I wouldn't have figured that out.
Danilo wrote:No need to open more topics for the same issue.
You're right, although my intention was to refine the subject matter to clearly describe the issue. With your solution, I've expunged the last thread.

Thanks again! Truly appreciate your help.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
Post Reply