Page 1 of 1

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

Posted: Tue May 08, 2012 2:22 pm
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

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

Posted: Wed May 09, 2012 8:45 am
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


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

Posted: Wed May 09, 2012 11:25 am
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?

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

Posted: Wed May 09, 2012 11:45 am
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. ;)

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

Posted: Wed May 09, 2012 12:49 pm
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.