Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
william_ahk
Posts: 471
Joined: 03 Dec 2018, 20:02

Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

19 Sep 2021, 23:36

When I set smoothing mode to anti-alias it produces those subpixels on the sides. But if I set it to none it wouldn't have smooth rounded corners. How not to have those subpixels?

Code: Select all

pBitmapMask := Gdip_CreateBitmap(w, h), G2 := Gdip_GraphicsFromImage(pBitmapMask),Gdip_SetSmoothingMode(G2, 4)
pBrush := Gdip_BrushCreateSolid(0xff00ff00)
cut_offset := 5
Gdip_FillRoundedRectangle(G2, pBrush, cut_offset, cut_offset, w - (cut_offset*2), h - (cut_offset*2), r)
subpixels.png
subpixels.png (1.75 KiB) Viewed 711 times
pBitmapMask.png
pBitmapMask.png (1.1 KiB) Viewed 711 times
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

20 Sep 2021, 09:47

You could rewrite the function to use different smoothing values for the different parts.

Code: Select all

Gdip_FillRoundedRectangle(pGraphics, pBrush, x, y, w, h, r)
{
	Region := Gdip_GetClipRegion(pGraphics)
	Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
	
	
	;change smoothing value
	E := Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h)
	;change smoothing value back
	
	
	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
	Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
	Gdip_FillEllipse(pGraphics, pBrush, x, y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x, y+h-(2*r), 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_DeleteRegion(Region)
	return E
}

I haven't tested it but it looks like it might be the best you will get.
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

20 Sep 2021, 11:33

I tested to see the effect and it looks like you should be able to play around with a few values to get it to look nice.

Code: Select all

#Include <My Altered GDIP lib>
#Include <PopUpWindow Class>
#SingleInstance, Force
SetBatchlines, -1

GDIP_StartUp()

w := 800 , h := 520

Gui1 := New PopUpWindow( { WindowName: "1" , WindowOptions: " -DPIScale +AlwaysOnTop " , WindowSmoothing: 2 , X: "Center" , Y: "Center" , W: w , H: h } )
Gui1.DrawBitmap( HB_BITMAP_MAKER() , { X: 0 , Y: 0 , W: w , H: h } , dispose := 1 )
Gui1.UpdateWindow()
Gui1.ShowWindow()


return
GuiClose:
GuiContextMenu:
*ESC::ExitApp

Numpad3::PopUpWindow.Helper()



HB_BITMAP_MAKER(){
	;Bitmap Created Using: HB Bitmap Maker
	pBitmap := Gdip_CreateBitmap( 200 , 130 ) , G := Gdip_GraphicsFromImage( pBitmap ) , Gdip_SetSmoothingMode( G , 2 )
	Brush := Gdip_BrushCreateSolid( "0xFF3399FF" ) , Gdip_FillRoundedRectangle( G , Brush , 8 , 10 , 180 , 50 , 25 ) , Gdip_DeleteBrush( Brush )
	Brush := Gdip_BrushCreateSolid( "0xFF3399FF" ) , Altered_FillRoundedRectangle( G , Brush , 8 , 70 , 180 , 50 , 25 , 2 ) , Gdip_DeleteBrush( Brush )
	Gdip_DeleteGraphics( G )
	return pBitmap
}

Altered_FillRoundedRectangle(pGraphics, pBrush, x, y, w, h, r , S := 4 ){
	
	Region := Gdip_GetClipRegion(pGraphics)
	Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
	
	
	;change smoothing value
	Gdip_SetSmoothingMode(pGraphics, 3)
	E := Gdip_FillRectangle(pGraphics, pBrush, x+1, y+1, w, h)
	Gdip_SetSmoothingMode(pGraphics, S)
	;change smoothing value back
	
	
	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
	Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
	Gdip_FillEllipse(pGraphics, pBrush, x, y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x, y+h-(2*r), 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_DeleteRegion(Region)
	return E
}


The top rounded rectangle is without any alterations to the functions code.
20210920122857.png
20210920122857.png (36.09 KiB) Viewed 632 times

Alternatively, you could draw the shape on its own layer with the exact width and height for your shape, then draw the layer to your main bitmap.
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

20 Sep 2021, 12:39

Alternatively, you could draw the shape on its own layer with the exact width and height for your shape, then draw the layer to your main bitmap.
Here is an example. The function needs to have a few of the positions tweaked still, but the overall effect is clear.

Top = Before
Bottom = After
20210920133214.png
20210920133214.png (782 Bytes) Viewed 612 times
20210920134059.png
20210920134059.png (1.83 KiB) Viewed 610 times

Code: Select all

#Include <My Altered GDIP lib>
#Include <PopUpWindow Class>
#SingleInstance, Force
SetBatchlines, -1

GDIP_StartUp()

mag := 2 , r := 20
w := 200 * mag , h := 130 * mag

Gui1 := New PopUpWindow( { WindowName: "1" , WindowOptions: " -DPIScale +AlwaysOnTop " , WindowSmoothing: 2 , X: "Center" , Y: "Center" , W: w , H: h } )
Gui1.DrawBitmap( HB_BITMAP_MAKER( r ) , { X: 0 , Y: 0 , W: w , H: h } , dispose := 1 )
Gui1.UpdateWindow()
Gui1.ShowWindow()

return
GuiClose:
GuiContextMenu:
*ESC::ExitApp

Numpad3::PopUpWindow.Helper()

HB_BITMAP_MAKER( r := 25 ){
	;Bitmap Created Using: HB Bitmap Maker
	pBitmap := Gdip_CreateBitmap( 200 , 130 ) , G := Gdip_GraphicsFromImage( pBitmap ) , Gdip_SetSmoothingMode( G , 2 )
	Brush := Gdip_BrushCreateSolid( "0xFF3399FF" ) , Gdip_FillRoundedRectangle( G , Brush , 8 , 10 , 180 , 50 , r ) , Gdip_DeleteBrush( Brush )
	Gdip_SetSmoothingMode( G , 3 )
	Brush := Gdip_BrushCreateSolid( "0xFF3399FF" ) , Altered_FillRoundedRectangle( G , Brush , 8 , 70 , 180 , 50 , r , 2 ) , Gdip_DeleteBrush( Brush )
	Gdip_SetSmoothingMode( G , 2 )
	Gdip_DeleteGraphics( G )
	return pBitmap
}

;************************************************************************************************************************************************8
;************************************************************************************************************************************************8
Altered_FillRoundedRectangle(pGraphics, pBrush, x, y, w, h, r , S := 4 ){
	;*********************************************************************************************
	local pbitmap , G , bx , by 
	bx := x , by := y , x := -1 , y := -1 
	pBitmap := Gdip_CreateBitmap( w -1, h -1) , G := Gdip_GraphicsFromImage( pBitmap ) , Gdip_SetSmoothingMode( G , S )
	;*********************************************************************************************
	Region := Gdip_GetClipRegion(G)
	Gdip_SetClipRect(G, x-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(G, x+w-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(G, x-r, y+h-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(G, x+w-r, y+h-r, 2*r, 2*r, 4)
	E := Gdip_FillRectangle(G, pBrush, x, y, w, h)
	Gdip_SetClipRegion(G, Region, 0)
	Gdip_SetClipRect(G, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
	Gdip_SetClipRect(G, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
	Gdip_FillEllipse(G, pBrush, x, y, 2*r, 2*r)
	Gdip_FillEllipse(G, pBrush, x+w-(2*r), y, 2*r, 2*r)
	Gdip_FillEllipse(G, pBrush, x, y+h-(2*r), 2*r, 2*r)
	Gdip_FillEllipse(G, pBrush, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
	Gdip_SetClipRegion(G, Region, 0)
	Gdip_DeleteRegion(Region)
	;*********************************************************************
	Gdip_DeleteGraphics( G )
	Gdip_DrawImage(pGraphics, pBitmap, bx , by , w-1 , h-1)
	Gdip_DisposeImage(pBitmap)
	;*********************************************************************
	return E
}

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

Re: Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

20 Sep 2021, 19:54

@Hellbent Thank you so much! It's nearly perfect now with your alterations. But (speaking of pixel-perfect XD) I wonder if it's possible to make the corners rounder in this way? Like the one GraphicsMagick generated below:
gm_corner.png
gm_corner.png (1.45 KiB) Viewed 586 times
gdip_corner.png
gdip_corner.png (1.84 KiB) Viewed 586 times
gm_mask.png
gm_mask.png (1017 Bytes) Viewed 586 times
User avatar
boiler
Posts: 16709
Joined: 21 Dec 2014, 02:44

Re: Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

20 Sep 2021, 22:34

Try changing r := 20 near the top of the script to 10, 12 or so.
william_ahk
Posts: 471
Joined: 03 Dec 2018, 20:02

Re: Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

20 Sep 2021, 23:38

@boiler Yes I know but I'm referring to the roundness of the corners, without anti-alias for the sides they look more beveled.
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

21 Sep 2021, 10:05

william_ahk wrote:
20 Sep 2021, 23:38
I'm referring to the roundness of the corners, without anti-alias for the sides they look more beveled.
You would need to tweak the values for positions, etc. It might take 5 mins or it might take an hour to get things just right.
Either way I don't really have a interest in doing it right now.
User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: Is it possible to not render subpixels for Gdip_FillRoundedRectangle?

21 Sep 2021, 10:14

Another alternative.

You could come up with a way of knowing which pixels are going to be an issue and then just setting the color yourself using a method similar to this

viewtopic.php?f=76&t=92850&start=20#p413738

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: gongnl, Google [Bot], inseption86, Mannaia666, mikeyww and 152 guests