Page 1 of 2
How to perfectly fit any image on a fixed size picture control
Posted: 20 Jul 2017, 18:39
by SKAN
Run the code and drop images ( including icons,DLL, EXE ) on the GUI
Code: Select all
#NoEnv
#SingleInstance, Force
Gui, Margin, 20, 20
OPTIONS := ( SS_BITMAP := 0xE ) | ( SS_CENTERIMAGE := 0x200 )
Gui, Add, Picture, w640 h480 %OPTIONS% Border hwndhwndPic vPicture
Gui, Show,, Image viewer - Just Drag N Drop
Return ; // End of auto-execute section //
GuiDropFiles:
File := StrSplit( A_GuiEvent, "`n" ).1
hBM := LoadPicture( File )
IfEqual, hBM, 0, Return
BITMAP := getHBMinfo( hBM ) ; Extract Width andh height of image
New := ScaleRect( BITMAP.Width, BITMAP.Height, 640, 480 ) ; Derive best-fit W x H for source image
DllCall( "DeleteObject", "Ptr",hBM ) ; Delete Image handle ...
hBM := LoadPicture( File, "GDI+ w" New.W . " h" . New.H ) ; ..and get a new one with correct W x H
GuiControl,, Picture, *w0 *h0 HBITMAP:%hBM%
Return
GuiClose:
GuiEscape:
ExitApp
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
getHBMinfo( hBM ) {
Local SzBITMAP := ( A_PtrSize = 8 ? 32 : 24 ), BITMAP := VarSetCapacity( BITMAP, SzBITMAP )
If DllCall( "GetObject", "Ptr",hBM, "Int",SzBITMAP, "Ptr",&BITMAP )
Return { Width: Numget( BITMAP, 4, "UInt" ), Height: Numget( BITMAP, 8, "UInt" )
, WidthBytes: Numget( BITMAP,12, "UInt" ), Planes: Numget( BITMAP,16, "UShort")
, BitsPixel: Numget( BITMAP,18, "UShort"), bmBits: Numget( BITMAP,20, "UInt" ) }
}
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ScaleRect( SW, SH, TW, TH, Upscale := 0 ) { ; By SKAN | Created: 19-July-2017 | Topic: goo.gl/
Local SAF := SW/SH, TAF := TW/TH ; Aspect ratios of Source and Target
Return ( !Upscale and SW <= TW and SH <= TH ) ? {W: SW, H: SH}
: ( SAF < TAF ) ? { W: Floor( ( TW / TAF ) * SAF ), H: TH}
: ( SAF > TAF ) ? { W: TW, H: Floor( ( TH / SAF ) * TAF )}
: { W: TW, H: TH }
}
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Re: How to perfectly fit any image on a fixed size picture control
Posted: 20 Jul 2017, 23:58
by scriptor2016
Line 12 returns an error:
Call to non existent function.
hBM := LoadPicture( File )
where can we get that function?
Re: How to perfectly fit any image on a fixed size picture control
Posted: 21 Jul 2017, 00:27
by jeeswg
Re: How to perfectly fit any image on a fixed size picture control
Posted: 25 Jul 2017, 10:30
by carno
Works perfectly!
AutoHotkey : v1.1.24.04 Unicode 32-bit (Installed)
SystemOS : WIN_XP 32-bit Service Pack 2 v5.1.2600 (WIN32_NT)
Re: How to perfectly fit any image on a fixed size picture control
Posted: 28 Jul 2017, 09:37
by Drugwash
AHK is awful at resizing very large images to very small sizes. (
example)
Does anybody know of a fast and efficient resizing algorithm usable with AHK that produces results similar to the right picture in the example? (resized with FastStone Image Viewer, using default Lanczos algorithm - most notable difference is the title in white)
Re: How to perfectly fit any image on a fixed size picture control
Posted: 28 Jul 2017, 11:16
by gwarble
its a limitation of GDI/GDI+ from what I understand, you have to roll your own
https://www.codeproject.com/Articles/11 ... erform-GDI
Re: How to perfectly fit any image on a fixed size picture control
Posted: 29 Jul 2017, 17:33
by SKAN
Thanks for the link.
There is a 32bit DLL based on that code
Plain C Resampling DLL :
https://www.codeproject.com/Articles/22 ... mpling-DLL
Wish AHK have this incorporated.. Not sure if
CPOL License is compatible with GPL v2
Re: How to perfectly fit any image on a fixed size picture control
Posted: 29 Jul 2017, 17:37
by SKAN
Drugwash wrote:Does anybody know of a fast and efficient resizing algorithm usable with AHK that produces results similar to the right picture in the example? (resized with FastStone Image Viewer, using default Lanczos algorithm - most notable difference is the title in white)
Here we go:
Code: Select all
#NoEnv
#Warn
#SingleInstance, Force
SetWorkingDir %A_ScriptDir%
If ! FileExist( "logo.png" )
URLDownloadToFile, https://autohotkey.com/boards/styles/simplicity/theme/images/logo.png, logo.png
DllCall( "LoadLibrary", "Str", "Resample.dll" )
BELL := 0x00000000
BOX := 0x00000001
CATMULLROM := 0x00000002
COSINE := 0x00000003
CUBICCONVOLUTION := 0x00000004
CUBICSPLINE := 0x00000005
HERMITE := 0x00000006
LANCZOS3 := 0x00000007
LANCZOS8 := 0x00000008
MITCHELL := 0x00000009
QUADRATIC := 0x0000000A
QUADRATICBSPLINE := 0x0000000B
TRIANGLE := 0x0000000C
hBM1 := LoadPicture( "Logo.png", "GDI+")
hBM2 := DllCall( "Resample\CreateResampledBitmap", "UInt",DllCall( "GetDC", "UInt", 0 )
, "UInt",hBM1, "UInt",300, "UInt",45, "UInt",LANCZOS3 )
Gui, Font, S10, Calibri
Gui, Add, Text, xm ym, Resampled by AHK
Gui, Add, Picture, xm y+5 w300 h45, Logo.png ; AHK will use GDI+ for PNG
Gui, Add, Text, xm Y+10 , Resampled by DLL
Gui, Add, Picture, xm y+5 w300 h45, HBITMAP:%hBM2%
Gui, Show,, Resampling
Re: How to perfectly fit any image on a fixed size picture control
Posted: 29 Jul 2017, 19:15
by Drugwash
Thank you both. Few years ago I actually read that article but the code was (and still is) unusable for me with AHK Basic.
I'll test the Resample library soon; now it's 3AM and gotta go to sleep.
However until now I fought with gdiplus and found out it can produce higher quality output when appropriate settings are made.
Also certain versions of gdiplus (currently I have 11 versions for testing) may produce different results with the same settings.
Contrary to opinions found on the web, gdiplus v6.0 does work in Win9x and effects are applied correctly (at least on my system). Just tested blur minutes ago.
I'll be back with details and screenshots.
Re: How to perfectly fit any image on a fixed size picture control
Posted: 29 Jul 2017, 23:00
by arcticir
Using GDI to draw controls has a nice effect.
Re: How to perfectly fit any image on a fixed size picture control
Posted: 30 Jul 2017, 01:53
by SKAN
arcticir wrote:Using GDI to draw controls has a nice effect.
Looks nice... Post some code, please!.
Re: How to perfectly fit any image on a fixed size picture control
Posted: 30 Jul 2017, 02:21
by arcticir
I did not save the test code, so I rewrote one. It needed H2.
Code: Select all
gui:=GuiCreate()
k:=GuiCreate("+E0x80000 0x10000000 +Parent" gui.hwnd)
pic:="Z:\logo.png"
GdipCreateBitmapFromFile(&PIC,getvar(pBitmap:=0))
GdipGetImageDimension(pBitmap,__w:=getvar(width:=0), __h:=getvar(height:=0))
width:=width:=NumGet(__w,"Float")
height:=height:=NumGet(__h,"Float")
VarSetCapacity(bi, 40, 0),NumPut(300,bi,4),NumPut(45,bi,8),NumPut(40, bi, 0),NumPut(1,bi,12,"ushort"),NumPut(0, bi, 16),NumPut(32, bi, 14, "ushort")
hbm:=hbm := CreateDIBSection( hdc:=GetDC(), &bi),ReleaseDC(0,hdc)
hdc := CreateCompatibleDC(),obm := SelectObject(hdc, hbm)
GdipCreateFromHDC(hdc,getvar(G:=0)),GdipSetInterpolationMode(G, 7)
GdipDrawImageRectRectI(G,pBitmap,0,0,300,45,0,0,width,height,2)
pt:=Struct("x,y")
pt.x:=10,pt.y:=0
UpdateLayeredWindow(k.hwnd,0,pt[],getvar(temp1:=300|45<<32),hdc, getvar(temp2:=0),0,getvar(temp3:=255<<16|1<<24),2)
gui.show("w400 h120")
Return
Re: How to perfectly fit any image on a fixed size picture control
Posted: 30 Jul 2017, 03:51
by HotKeyIt
I have optimized the code above for
AHK_H v2 a little bit
Code: Select all
(gui:=GuiCreate()).OnEvent("Close","ExitApp")
k:=GuiCreate("+E0x80000 0x10000000 +Parent" gui.hwnd)
GdiplusStartup(getvar(pToken:=0),(si:=Struct("UINT GdiplusVersion;PTR DebugEventCallback;BOOL SuppressBackgroundThread;BOOL SuppressExternalCodecs",{GdiplusVersion:1}))[])
GdipCreateBitmapFromFile(&"G:\logo.png",getvar(pBitmap:=0))
GdipGetImageDimension(pBitmap, getvar(width:=0), getvar(height:=0))
BITMAPINFOHEADER:="DWORD biSize;LONG biWidth;LONG biHeight;WORD biPlanes;WORD biBitCount;DWORD biCompression;DWORD biSizeImage;LONG biXPelsPerMeter;LONG biYPelsPerMeter;DWORD biClrUsed;DWORD biClrImportant;"
bi:=Struct(BITMAPINFOHEADER,{biSize:sizeof(BITMAPINFOHEADER),biWidth:300,biHeight:45,biPlanes:1,biBitCount:32})
hbm := CreateDIBSection( hdc:=GetDC(), bi[]),ReleaseDC(0,hdc)
hdc := CreateCompatibleDC(),obm := SelectObject(hdc, hbm)
GdipCreateFromHDC(hdc,getvar(G:=0)),GdipSetInterpolationMode(G, 7)
GdipDrawImageRectRectI(G,pBitmap,0,0,300,45,0,0,Cast("UInt",width,"Float"),Cast("Uint",height,"Float"),2)
UpdateLayeredWindow(k.hwnd,0,(pt:=Struct("x,y",{x:10}))[],getvar(temp1:=300|45<<32),hdc, getvar(temp2:=0),0,getvar(temp3:=255<<16|1<<24),2)
gui.show("w320 h50")
Return
Re: How to perfectly fit any image on a fixed size picture control
Posted: 30 Jul 2017, 14:37
by Drugwash
What language is that aboveā¦? I can't read it.
Honestly, that's not the AHK I once knew. But forget that.
The only way I could get XP to actually use the specific version of gdiplus I wanted was to modify the AHK exe manifest. 98SE has no shame in loading and using whatever library I feed it. Unfortunately 98 has a problem in manipulating and displaying the alpha channel. Not that it matters for any of you.
The highest "official" version of gdiplus on my XP is 5.2.6002.23846 and although it's branded "vistasp2" it does not have the effects-related API. Those come only with v6.0+ (or as some call it v1.1). Such version can be found in Power Point Viewer, for one or in some newer version of MS Office (Office 13 might have a newer gdiplus 6 that PPViewer).
Enough talking, here's the old-fashioned code; if you get a crash or last image isn't blurred then you need to coerce your AHK into using a specific gdiplus:
code+screenshots (~2.8MB)
Screenshots are in the package because the board resizes images and destroys their quality. Both screenshots were captured in 98SE, the one using gdiplus 5.2 can't create blur on last image but image quality for InterpolationMode 5 is visibly better than with v6 (compare the white text).
Re: How to perfectly fit any image on a fixed size picture control
Posted: 31 Jul 2017, 17:00
by SKAN
Thanks arcticir and HotKeyIt.
@HotKeyIt
Doesn't AHK use GDI+ Smoothing / Interpolation settings?!
Or does it use GDI+ only to open the image and then use CopyImage() to resize?
Please confirm.
Re: How to perfectly fit any image on a fixed size picture control
Posted: 31 Jul 2017, 17:19
by HotKeyIt
Re: How to perfectly fit any image on a fixed size picture control
Posted: 31 Jul 2017, 17:59
by SKAN
HotKeyIt wrote:As far as I can see it uses CopyImage to resize
Ah.. I see.. Disappointing .
Thanks for the confirmation.
Re: How to perfectly fit any image on a fixed size picture control
Posted: 01 Aug 2017, 02:11
by SKAN
Drugwash wrote:here's the old-fashioned code; if you get a crash or last image isn't blurred then you need to coerce your AHK into using a specific gdiplus:
code+screenshots (~2.8MB)
Excellent! Thanks for sharing
Drugwash.
Can you explain what the last parameter does?. Won't 0xFFFFFFFF mess up a PNG with semitransparent pixels?
Code: Select all
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap"
, Ptr, pB
, PtrP, hBmp%A_Index%
, "Int", 0xFFFFFFFF)
Re: How to perfectly fit any image on a fixed size picture control
Posted: 01 Aug 2017, 03:11
by jNizM
Code: Select all
GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap, HBITMAP* hbmReturn, ARGB background)
bitmap -> [in] Pointer to the Bitmap object.
hbmReturn -> [out] Pointer to an HBITMAP that receives a handle to the GDI bitmap.
background -> [in] ARGB color that specifies the background color. This parameter is ignored if the bitmap is totally opaque.
Re: How to perfectly fit any image on a fixed size picture control
Posted: 01 Aug 2017, 03:18
by Drugwash
@ SKAN: You're welcome.
Honestly, part of the code I found here and there on the web, didn't get documented much about all API.
In regard to the one you mentioned I don't think it breaks anything, i tried the same script with logo.png (same AHK logo used in yours and arcticir's examples) and it displayed it properly in XP (apart from bad aspect ratio); only 98 has problems (transparent background was displayed blue instead).