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

Post by grimboto » 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 2410 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: 516
Joined: 19 Nov 2013, 09:15

Re: GDI+ help image with rounded corners

Post by noname » 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

Post by nnnik » 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: 499
Joined: 03 Dec 2018, 20:02

Re: GDI+ help image with rounded corners

Post by william_ahk » 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: 27099
Joined: 09 Sep 2014, 18:38

Re: GDI+ help image with rounded corners

Post by mikeyww » 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 1584 times

william_ahk
Posts: 499
Joined: 03 Dec 2018, 20:02

Re: GDI+ help image with rounded corners

Post by william_ahk » 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: 2750
Joined: 02 Oct 2015, 12:15

Re: GDI+ help image with rounded corners

Post by Xtra » 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: 499
Joined: 03 Dec 2018, 20:02

Re: GDI+ help image with rounded corners

Post by william_ahk » 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: 4349
Joined: 29 Mar 2015, 09:41
Contact:

Re: GDI+ help image with rounded corners

Post by teadrinker » 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: 499
Joined: 03 Dec 2018, 20:02

Re: GDI+ help image with rounded corners

Post by william_ahk » 11 Apr 2021, 04:45

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

sooyke_
Posts: 25
Joined: 18 Nov 2020, 10:27

Re: GDI+ help image with rounded corners

Post by sooyke_ » 11 Apr 2021, 07:49

You can find a 64bit version here thanks to Linearspoon :

https://www.autohotkey.com/boards/viewtopic.php?f=5&t=39077

Post Reply

Return to “Ask for Help (v1)”