GDI+ help image with rounded corners Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
grimboto
Posts: 53
Joined: 09 Jul 2014, 19:20

GDI+ help image with rounded corners

20 Jun 2017, 17:25

hey

I'm trying to create an image from a control in a program i use and save it as a rounded rectangle image but i can't figure out how to remove the excess from the corners. see image below
test2.png
test2.png (27.66 KiB) Viewed 2375 times
below is the current code im using to get me to the image above.

Code: Select all

			
			pToken := Gdip_Startup()
			ControlGet, DrawingHWND, Hwnd, , TC25Drawing1, ahk_id %TCADHWND%
			ImageName := A_ScriptDir "\test" a_index ".png"
			;create BMP image from Google HWND

			pBitmap := Gdip_BitmapFromHWND(DrawingHWND)
			
			; Get a pointer to the graphics of the bitmap, for use with drawing functions
			G := Gdip_GraphicsFromImage(pBitmap)
			W := Gdip_GetImageWidth(pBitmap)
			H := Gdip_GetImageHeight(pBitmap)
			
			pPen := Gdip_CreatePen(0xff000000, 8)
			
			Gdip_DrawRoundedRectangle(G, pPen, 4, 4, w-8, h-8, 50)
			
			Gdip_SaveBitmapToFile(pBitmap, ImageName)

			Gdip_DisposeImage(pBitmap)
			Gdip_Shutdown(pToken)
			
any help would be appreciated

thanks
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: GDI+ help image with rounded corners

21 Jun 2017, 02:13

Image



One way is to create an alphamask , you can find an interesting discussing here: https://autohotkey.com/board/topic/1034 ... i-aliasing

example using modified mcode from Tic:

Code: Select all

SetWorkingDir, %A_ScriptDir%
SetBatchLines, -1

ofile=screengrab.png

If !pToken := Gdip_Startup()
{
   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
   ExitApp
}

bmap:=Gdip_BitmapFromScreen("100|100|300|200")
pBitmap :=Gdip_AlphaMask_rectangle(bmap,30,1)
Gdip_SaveBitmapToFile(pBitmap,oFile)
return 



Gdip_AlphaMask_rectangle(source,r,bm) ; r radius rounded rectangle / set bm  for bitmap=1 file=1
  {

    x:=y:=0
    static _AlphaMask
    If !_AlphaMask
      {
        MCode_AlphaMask := "518B4424249983E20303C28BC88B442428995383E20303C28B5424245556C1F902C1F802837C24400057757E85D20F8E0E01000"
        . "08B5C241C8B74242C03C003C0894424388D048D000000000FAF4C2440034C243C894424348B4424208D3C888954244485F67E2C8B5424182B5424208"
        . "BCF8BC38B2C0A332883C00481E5FFFFFF003368FC83C10483EE018969FC75E48B74242C037C2434035C2438836C24440175C15F5E5D33C05B59C385D"
        . "20F8E900000008B5C241C8B74242C03C003C0894424388D048D000000000FAF4C2440034C243C894424348B442420895C24448D3C888954241085F67"
        . "E428B5424182B5424208BC78BCBEB098DA424000000008BFF8B1981E3000000FFBD000000FF2BEB8B1C1081E3FFFFFF000BEB892883C10483C00483E"
        . "E0175D98B74242C8B5C2444035C2438037C2434836C241001895C244475A35F5E5D33C05B59C3"

        VarSetCapacity(_AlphaMask, StrLen(MCode_AlphaMask)//2)
        Loop % StrLen(MCode_AlphaMask)//2      ;%
            NumPut("0x" SubStr(MCode_AlphaMask, (2*A_Index)-1, 2), _AlphaMask, A_Index-1, "char")
      }
      
    if !bm 
    pBitmap_:=Gdip_CreateBitmapFromFile(source)
    else
    pBitmap_:=source
    Gdip_GetDimensions(pBitmap_, w,h )
w1:=w+1
h1:=h+1
    pBitmap := Gdip_CreateBitmap(w1,h1)
    G_:= Gdip_GraphicsFromImage(pBitmap), Gdip_SetSmoothingMode(G_, 4), Gdip_SetInterpolationMode(G_, 7)
    Gdip_DrawImage(G_, pBitmap_, 0, 0, w1,h1,0,0,w1,h1)
    Gdip_DeleteGraphics(G_)
    Gdip_DisposeImage(pBitmap_)

    pBitmapMask := Gdip_CreateBitmap(w1, h1), G2 := Gdip_GraphicsFromImage(pBitmapMask),Gdip_SetSmoothingMode(G2, 4)
    pBrush := Gdip_BrushCreateSolid(0xff00ff00)
    Gdip_FillRoundedRectangle(G2, pBrush, 0, 0, w1, h1, r)

    Gdip_DeleteBrush(pBrush)
    Gdip_DeleteGraphics(G2)


    pBitmapNew := Gdip_CreateBitmap(w1, h1)
    If !pBitmapNew
        Return -1

    E1 := Gdip_LockBits(pBitmap, 0, 0, w1, h1, Stride1, Scan01, BitmapData1)
    E2 := Gdip_LockBits(pBitmapMask, 0, 0, w1, h1, Stride2, Scan02, BitmapData2)
    E3 := Gdip_LockBits(pBitmapNew, 0, 0, w1, h1, Stride3, Scan03, BitmapData3)
    If (E1 || E2 || E3)
        Return -2

    E := DllCall(&_AlphaMask, "ptr", Scan01, "ptr", Scan02, "ptr", Scan03, "int", w, "int", h, "int", w, "int", h, "int", Stride1, "int", Stride2, "int", x, "int", y, "int", invert)

    Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapMask, BitmapData2), Gdip_UnlockBits(pBitmapNew, BitmapData3)
    Gdip_DisposeImage(pBitmap)
    Gdip_DisposeImage(pBitmapMask)
    Return (E = "") ? -3 : pBitmapNew
  }
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: GDI+ help image with rounded corners  Topic is solved

21 Jun 2017, 03:41

The best solution is probably using a Clip on the target graphics:
If you check the source for Gdip_FillRoundedRectangle you will see a similar function.

Code: Select all

#Include <Gdip_All>
#NoEnv

roundSize := 100

pToken  := Gdip_Startup()
pBitmap := Gdip_CreateBitmapFromFile( "test.jpg" )
pTarget := Gdip_CreateBitmap( w := Gdip_getImageWidth( pBitmap ), h := Gdip_getImageHeight( pBitmap ) )
pGraphics := Gdip_GraphicsFromImage( pTarget )

pPath   := Gdip_CreatePath()

Gdip_AddPathEllipse( pPath, 0, 0, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, 0, h - roundSize * 2, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, w - roundSize * 2, 0, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, w - roundSize * 2, h - roundSize * 2, roundSize * 2, roundSize * 2 )

Gdip_SetClipRect( pGraphics, roundSize, 0, w - roundSize * 2, h )
Gdip_SetClipRect( pGraphics, 0, roundSize, w, h - roundSize * 2, 2 )
Gdip_SetClipPath( pGraphics, pPath, 2 )

Gdip_DrawImage( pGraphics, pBitmap )
Gdip_SaveBitmapToFile( pTarget, "out2.png" )


Gdip_DeletePath( pPath )
Gdip_DeleteGraphics( pGraphics )
Gdip_DisposeImage( pBitmap )
Gdip_DisposeImage( pTarget )
Recommends AHK Studio
william_ahk
Posts: 482
Joined: 03 Dec 2018, 20:02

Re: GDI+ help image with rounded corners

09 Apr 2021, 19:11

@noname I tried this code but no file was being outputted? Do I have to use an alternate version of Gdip lib? I'm using Gdip_All 1.45 by tic.
User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: GDI+ help image with rounded corners

09 Apr 2021, 19:21

It worked in my test.

Code: Select all

#Include q:\vis2\lib\Gdip_All.ahk
dir := A_ScriptDir,  source := dir "\NZflag.png", target := dir "\out2.png", roundSize := 100
URLDownloadToFile, https://www.autohotkey.com/boards/download/file.php?id=12780, %source%
pToken  := Gdip_Startup(), pBitmap := Gdip_CreateBitmapFromFile(source)
pTarget := Gdip_CreateBitmap( w := Gdip_getImageWidth( pBitmap ), h := Gdip_getImageHeight( pBitmap ) )
pGraphics := Gdip_GraphicsFromImage( pTarget ), pPath   := Gdip_CreatePath()
Gdip_AddPathEllipse( pPath, 0, 0, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, 0, h - roundSize * 2, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, w - roundSize * 2, 0, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, w - roundSize * 2, h - roundSize * 2, roundSize * 2, roundSize * 2 )
Gdip_SetClipRect( pGraphics, roundSize, 0, w - roundSize * 2, h )
Gdip_SetClipRect( pGraphics, 0, roundSize, w, h - roundSize * 2, 2 ), Gdip_SetClipPath( pGraphics, pPath, 2 )
Gdip_DrawImage( pGraphics, pBitmap ), Gdip_SaveBitmapToFile(pTarget, target)
Gdip_DeletePath( pPath ), Gdip_DeleteGraphics( pGraphics ), Gdip_DisposeImage( pBitmap )
Gdip_DisposeImage( pTarget )
Run, %target%
Attachments
NZflag.png
NZflag.png (10 KiB) Viewed 1549 times
william_ahk
Posts: 482
Joined: 03 Dec 2018, 20:02

Re: GDI+ help image with rounded corners

09 Apr 2021, 21:14

@mikeyww Sorry for the misunderstanding, I was referring to this code by @noname using alphamask, which supports anti-aliasing.
noname wrote:
21 Jun 2017, 02:13
Image



One way is to create an alphamask , you can find an interesting discussing here: https://autohotkey.com/board/topic/103475-gdi-cutting-anti-aliasing

example using modified mcode from Tic:

Code: Select all

SetWorkingDir, %A_ScriptDir%
SetBatchLines, -1

ofile=screengrab.png

If !pToken := Gdip_Startup()
{
   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
   ExitApp
}

bmap:=Gdip_BitmapFromScreen("100|100|300|200")
pBitmap :=Gdip_AlphaMask_rectangle(bmap,30,1)
Gdip_SaveBitmapToFile(pBitmap,oFile)
return 



Gdip_AlphaMask_rectangle(source,r,bm) ; r radius rounded rectangle / set bm  for bitmap=1 file=1
  {

    x:=y:=0
    static _AlphaMask
    If !_AlphaMask
      {
        MCode_AlphaMask := "518B4424249983E20303C28BC88B442428995383E20303C28B5424245556C1F902C1F802837C24400057757E85D20F8E0E01000"
        . "08B5C241C8B74242C03C003C0894424388D048D000000000FAF4C2440034C243C894424348B4424208D3C888954244485F67E2C8B5424182B5424208"
        . "BCF8BC38B2C0A332883C00481E5FFFFFF003368FC83C10483EE018969FC75E48B74242C037C2434035C2438836C24440175C15F5E5D33C05B59C385D"
        . "20F8E900000008B5C241C8B74242C03C003C0894424388D048D000000000FAF4C2440034C243C894424348B442420895C24448D3C888954241085F67"
        . "E428B5424182B5424208BC78BCBEB098DA424000000008BFF8B1981E3000000FFBD000000FF2BEB8B1C1081E3FFFFFF000BEB892883C10483C00483E"
        . "E0175D98B74242C8B5C2444035C2438037C2434836C241001895C244475A35F5E5D33C05B59C3"

        VarSetCapacity(_AlphaMask, StrLen(MCode_AlphaMask)//2)
        Loop % StrLen(MCode_AlphaMask)//2      ;%
            NumPut("0x" SubStr(MCode_AlphaMask, (2*A_Index)-1, 2), _AlphaMask, A_Index-1, "char")
      }
      
    if !bm 
    pBitmap_:=Gdip_CreateBitmapFromFile(source)
    else
    pBitmap_:=source
    Gdip_GetDimensions(pBitmap_, w,h )
w1:=w+1
h1:=h+1
    pBitmap := Gdip_CreateBitmap(w1,h1)
    G_:= Gdip_GraphicsFromImage(pBitmap), Gdip_SetSmoothingMode(G_, 4), Gdip_SetInterpolationMode(G_, 7)
    Gdip_DrawImage(G_, pBitmap_, 0, 0, w1,h1,0,0,w1,h1)
    Gdip_DeleteGraphics(G_)
    Gdip_DisposeImage(pBitmap_)

    pBitmapMask := Gdip_CreateBitmap(w1, h1), G2 := Gdip_GraphicsFromImage(pBitmapMask),Gdip_SetSmoothingMode(G2, 4)
    pBrush := Gdip_BrushCreateSolid(0xff00ff00)
    Gdip_FillRoundedRectangle(G2, pBrush, 0, 0, w1, h1, r)

    Gdip_DeleteBrush(pBrush)
    Gdip_DeleteGraphics(G2)


    pBitmapNew := Gdip_CreateBitmap(w1, h1)
    If !pBitmapNew
        Return -1

    E1 := Gdip_LockBits(pBitmap, 0, 0, w1, h1, Stride1, Scan01, BitmapData1)
    E2 := Gdip_LockBits(pBitmapMask, 0, 0, w1, h1, Stride2, Scan02, BitmapData2)
    E3 := Gdip_LockBits(pBitmapNew, 0, 0, w1, h1, Stride3, Scan03, BitmapData3)
    If (E1 || E2 || E3)
        Return -2

    E := DllCall(&_AlphaMask, "ptr", Scan01, "ptr", Scan02, "ptr", Scan03, "int", w, "int", h, "int", w, "int", h, "int", Stride1, "int", Stride2, "int", x, "int", y, "int", invert)

    Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapMask, BitmapData2), Gdip_UnlockBits(pBitmapNew, BitmapData3)
    Gdip_DisposeImage(pBitmap)
    Gdip_DisposeImage(pBitmapMask)
    Return (E = "") ? -3 : pBitmapNew
  }
User avatar
Xtra
Posts: 2744
Joined: 02 Oct 2015, 12:15

Re: GDI+ help image with rounded corners

09 Apr 2021, 21:24

william_ahk wrote:
09 Apr 2021, 19:11
@noname I tried this code but no file was being outputted?.
If the mcode is 32bit you would need to run ahk as 32bit.
Give it a try if you are currently running ahk as 64bit.

HTH
william_ahk
Posts: 482
Joined: 03 Dec 2018, 20:02

Re: GDI+ help image with rounded corners

09 Apr 2021, 22:56

Xtra wrote:
09 Apr 2021, 21:24

If the mcode is 32bit you would need to run ahk as 32bit.
Give it a try if you are currently running ahk as 64bit.

HTH
Thanks! Running the code with 32bit ahk successfully created the image file. Is there any way to convert the mcode to 64bit though?
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: GDI+ help image with rounded corners

10 Apr 2021, 01:39

william_ahk wrote: Is there any way to convert the mcode to 64bit though?
No, you have to create new one.
I found another approach. Perhaps it's overhead, but funny. I used a rounded rectangle as a mask.

Code: Select all

if !FileExist("source.png") {
   pToken := Gdip_Startup()
   pBitmap := Gdip_BitmapFromScreen("0|0|400|220")
   Gdip_SaveBitmapToFile(pBitmap, "source.png")
   Gdip_DisposeImage(pBitmap)
   Gdip_Shutdown(pToken)
}
RoundImageCorners("source.png", "rounded.png", 20)
Gui, Margin, 20, 20
Gui, Add, Pic,, rounded.png
Gui, Show
Return

GuiClose:
   ExitApp

RoundImageCorners(sourceFile, destFile, roundSize) {
   static AntiAlias := 4, SRCAND := 0x008800C6
   
   pToken := Gdip_Startup()
   pBitmap := Gdip_CreateBitmapFromFile(sourceFile)
   hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   hDcImage := CreateCompatibleDC()
   oBmImage := SelectObject(hDcImage, hBitmap)
   
   Gdip_GetImageDimensions(pBitmap, W, H)
   
   hBmMask := CreateDIBSection(W, H)
   hDcMask := CreateCompatibleDC()
   oBmMask := SelectObject(hDcMask, hBmMask)
   G := Gdip_GraphicsFromHDC(hDcMask)
   Gdip_SetSmoothingMode(G, AntiAlias)
   pBrush := Gdip_BrushCreateSolid(0xFFFFFFFF)
   Gdip_FillRoundedRectangle(G, pBrush, 0, 0, W - 1, H - 1, roundSize)
   Gdip_DeleteBrush(pBrush), Gdip_DeleteGraphics(G)

   BitBlt(hDcImage, 0, 0, W, H, hDcMask, 0, 0, SRCAND)
   
   SelectObject(hDcImage, oBmImage), SelectObject(hDcMask, oBmMask)
   DeleteDC(hDcImage), DeleteDC(hDcMask), DeleteObject(hBmMask)
   Gdip_DisposeImage(pBitmap)
   
   VarSetCapacity(BITMAP, size := 16 + A_PtrSize*2, 0)
   DllCall("GetObject", "Ptr", hBitmap, "UInt", size, "Ptr", &BITMAP)
   pPix := NumGet(BITMAP, 16 + A_PtrSize)

   pNewBimap := Gdip_CreateBitmap(W, H)
   Gdip_LockBits(pNewBimap, 0, 0, W, H, Stride, Scan0, data)
   Loop % H
      DllCall("RtlMoveMemory", "Ptr", Scan0 + Stride*(H - A_Index), "Ptr", pPix + Stride*(A_Index - 1), "Ptr", Stride)
   Gdip_UnlockBits(pNewBimap, data)
   Gdip_SaveBitmapToFile(pNewBimap, destFile)
   
   Gdip_DisposeImage(pNewBimap), DeleteObject(hBitmap), Gdip_Shutdown(pToken)
}
william_ahk
Posts: 482
Joined: 03 Dec 2018, 20:02

Re: GDI+ help image with rounded corners

11 Apr 2021, 04:45

@teadrinker This method could produce really smooth round corners (although with some subpixels at the edge), thanks for sharing!

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Auntiejack56, Xtra and 147 guests