TimRude Posted November 8, 2022 Share Posted November 8, 2022 (edited) I'm creating thumbnails of image files for populating an ImageList control to be used with a ListView. The image files may be of various types (i.e. jpg, png, gif, bmp, etc.) and of varying sizes. My ImageList thumbnail size is 160W x 100H. Presently, I'm creating the GUI, ListView, and thumbnails using this: expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiImageList.au3> #include <GuiListView.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <File.au3> #include <GDIPlus.au3> ; Create GUI with a ListView control Global $hGUI = GUICreate("ListView", 700, 420, -1, -1, $WS_OVERLAPPEDWINDOW) Global $hListView = _GUICtrlListView_Create($hGUI, "", 70, 0, 630, 420, BitOR($LVS_ICON, $LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_SORTASCENDING)) GUISetState(@SW_SHOW, $hGUI) ; Create and load ImageList control with thumbnails _GDIPlus_Startup() Global $sPath = StringReplace(@AutoItExe, "autoit3.exe", "Examples\GUI") Local $aFile = _FileListToArray($sPath, Default, $FLTA_FILES) If @error = 0 Then ; found some files Global $SizeX = 160 ; width of each thumbnail Global $SizeY = 100 ; height of each thumbnail Global $hImgLst = _GUIImageList_Create($SizeX, $SizeY) ; create an imagelist control Global $aImgFiles[1] ; create an array to hold the names of images we load For $i = 1 To $aFile[0] Local $hImage = _GDIPlus_ImageLoadFromFile($sPath & "\" & $aFile[$i]) ; try to load the image from the file If $hImage <> 0 Then Local $hImageScaled = _GDIPlus_ImageResize($hImage, $SizeX, $SizeY) ; resize the image to fit the thumbnail (doesn't maintain aspect ratio) Local $Bmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImageScaled) ; create a handle to the bitmap object Local $iIndex = _GUIImageList_Add($hImgLst, $Bmp) ; add the bitmap to the ImageList and note the index number _GDIPlus_ImageDispose($hImage) ; clean up _GDIPlus_ImageDispose($hImageScaled) ; clean up _WinAPI_DeleteObject($Bmp) ; clean up If $iIndex <> -1 Then ReDim $aImgFiles[$iIndex + 1] ; make room in the array for the file name of the image just loaded $aImgFiles[$iIndex] = $aFile[$i] ; store the file name of the image just loaded EndIf EndIf Next _GUICtrlListView_SetImageList($hListView, $hImgLst, 0) ; assign the ImageList to the ListView ; Add the thumbnails as items to the ListView, and use the file names as captions For $i = 0 To UBound($aImgFiles) - 1 _GUICtrlListView_AddItem($hListView, $aImgFiles[$i], $i) Next EndIf Do Local $Msg = GUIGetMsg() Until $Msg = $GUI_EVENT_CLOSE _GDIPlus_Shutdown() GUIDelete() Exit This does size the images to fit my thumbnail size, but it doesn't maintain the aspect ratio of the images. I end up with something that looks like this screenshot. What I want to create is a function to take the $hImage I've read from the file and rather than just running it through _GDIPlus_ImageResize, I want to size the image to the largest size that will fit in my thumbnail box (160x100) while maintaining the aspect ratio of the image. This will ordinarily result in a resized image that has one dimension the full size of the thumbnail's width or height, but with the other dimension smaller (such as 160 x 75, or 120 x 100). When that happens, I want to center the resized image in the thumbnail area on a black background. Like these two samples I've mocked up of a couple of the thumbnails. Now before anyone points it out, I've already tried the _GDIPlus_ImageGetThumbnail function but that often ends up truncating part of the image in the thumbnail, so it's a no-go. I can easily figure out what size to resize the image to while maintaining its aspect ratio, using a bit of code like this: Local $iWidth = 160 Local $iHeight = 100 Local $aImgDim = _GDIPlus_ImageGetDimension($hImage) Local $fRatioImage = $aImgDim[0] / $aImgDim[1] Local $fRatioThumb = $iWidth / $iHeight Switch True Case $fRatioThumb > $fRatioImage $iWidth = $iHeight * $fRatioImage Case $fRatioThumb < $fRatioImage $iHeight = $iWidth / $fRatioImage EndSwitch Local $hResizedImage = _GDIPlus_ImageResize($hImage, $iWidth, $iHeight) I just don't understand enough about the GDIPlus functions to take that resized image and center it it over a black background of 160x100 and then combine them into a new 160x100 image that I can then convert to a bitmap object and throw into my ImageList. Help? Edited November 8, 2022 by TimRude Move the pictures inline with the text for clarity Link to comment Share on other sites More sharing options...
KaFu Posted November 8, 2022 Share Posted November 8, 2022 expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiImageList.au3> #include <GuiListView.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <File.au3> #include <GDIPlus.au3> ; Create GUI with a ListView control Global $hGUI = GUICreate("ListView", 700, 420, -1, -1, $WS_OVERLAPPEDWINDOW) Global $hListView = _GUICtrlListView_Create($hGUI, "", 70, 0, 630, 420, BitOR($LVS_ICON, $LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_SORTASCENDING)) GUISetState(@SW_SHOW, $hGUI) ; Create and load ImageList control with thumbnails _GDIPlus_Startup() Global $sPath = StringReplace(@AutoItExe, "autoit3.exe", "Examples\GUI") Local $aFile = _FileListToArray($sPath, Default, $FLTA_FILES) If @error = 0 Then ; found some files Global $SizeX = 160 ; width of each thumbnail Global $SizeY = 100 ; height of each thumbnail Global $hImgLst = _GUIImageList_Create($SizeX, $SizeY) ; create an imagelist control Global $aImgFiles[1] ; create an array to hold the names of images we load Global $_dHash_hBitmap_SmallScale = _GDIPlus_BitmapCreateFromScan0($SizeX, $SizeY) Global $_dHash_hBitmap_SmallScale_Graphics = _GDIPlus_ImageGetGraphicsContext($_dHash_hBitmap_SmallScale) _GDIPlus_GraphicsSetInterpolationMode($_dHash_hBitmap_SmallScale_Graphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) Global $hBrush = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) For $i = 1 To $aFile[0] $sFile = $sPath & "\" & $aFile[$i] Switch StringRight($sFile, 4) Case ".png", ".jpg", ".gif" Case Else ContinueLoop EndSwitch Local $hImage = _GDIPlus_ImageLoadFromFile($sFile) ; try to load the image from the file ; ShellExecute($sPath & "\" & $aFile[$i]) If $hImage <> 0 Then $iImage_iWidth = _GDIPlus_ImageGetWidth($hImage) $iImage_iHeight = _GDIPlus_ImageGetHeight($hImage) If $iImage_iWidth > Round($iImage_iHeight * ($SizeX / $SizeY)) Then ConsoleWrite("+ ") $iImage_Resized_Width = $SizeX $iImage_Offset_X = 0 $iImage_Resized_Height = Round($iImage_iHeight / ($SizeX / $SizeY)) $iImage_Offset_Y = Round(($SizeY - $iImage_Resized_Height) / 2) Else ConsoleWrite("- ") $iImage_Resized_Width = Round($SizeX / ($SizeX / $SizeY)) $iImage_Offset_X = Round(($SizeX - $iImage_Resized_Width) / 2) $iImage_Resized_Height = $SizeY $iImage_Offset_Y = 0 EndIf ConsoleWrite($aFile[$i] & @TAB & @TAB & $iImage_Resized_Width & "x" & $iImage_Resized_Height & @TAB & $iImage_Offset_X & "x" & $iImage_Offset_Y & @CRLF) Local $hImageScaled = _GDIPlus_ImageResize($hImage, $iImage_Resized_Width, $iImage_Resized_Height) ; resize the image to fit the thumbnail (doesn't maintain aspect ratio) _GDIPlus_ImageDispose($hImage) ; clean up _GDIPlus_GraphicsFillRect($_dHash_hBitmap_SmallScale_Graphics, 0, 0, $SizeX, $SizeY, $hBrush) ; reset background to black _GDIPlus_GraphicsDrawImageRect($_dHash_hBitmap_SmallScale_Graphics, $hImageScaled, $iImage_Offset_X, $iImage_Offset_Y, $iImage_Resized_Width, $iImage_Resized_Height) ; draw loaded file to existing buffer _GDIPlus_ImageDispose($hImageScaled) Local $Bmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($_dHash_hBitmap_SmallScale) ; create a handle to the bitmap object Local $iIndex = _GUIImageList_Add($hImgLst, $Bmp) ; add the bitmap to the ImageList and note the index number _WinAPI_DeleteObject($Bmp) ; clean up If $iIndex <> -1 Then ReDim $aImgFiles[$iIndex + 1] ; make room in the array for the file name of the image just loaded $aImgFiles[$iIndex] = $aFile[$i] ; store the file name of the image just loaded EndIf EndIf Next _GDIPlus_GraphicsDispose($_dHash_hBitmap_SmallScale_Graphics) _GDIPlus_BitmapDispose($_dHash_hBitmap_SmallScale) _GDIPlus_BrushDispose($hBrush) _GUICtrlListView_SetImageList($hListView, $hImgLst, 0) ; assign the ImageList to the ListView ; Add the thumbnails as items to the ListView, and use the file names as captions For $i = 0 To UBound($aImgFiles) - 1 _GUICtrlListView_AddItem($hListView, $aImgFiles[$i], $i) Next EndIf Do Local $Msg = GUIGetMsg() Until $Msg = $GUI_EVENT_CLOSE _GDIPlus_Shutdown() GUIDelete() Exit OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
TimRude Posted November 8, 2022 Author Share Posted November 8, 2022 @KaFu That's real close. But I'm not getting the black background. It's white instead. Tried it on both v3.3.14.5 and v3.3.16.1. Thanks! Link to comment Share on other sites More sharing options...
KaFu Posted November 8, 2022 Share Posted November 8, 2022 Change this Global $hBrush = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) to this Global $hBrush = _GDIPlus_BrushCreateSolid(0xFF000000) OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
TimRude Posted November 8, 2022 Author Share Posted November 8, 2022 Thanks! Now I'll spend some time studying the code to figure out what it all does. Link to comment Share on other sites More sharing options...
pixelsearch Posted November 8, 2022 Share Posted November 8, 2022 @TimRudewhen you use this line : Global $hBrush = _GDIPlus_BrushCreateSolid(0xFF000000) Does the Torus thumbnail appears like that ? Link to comment Share on other sites More sharing options...
TimRude Posted November 8, 2022 Author Share Posted November 8, 2022 (edited) @pixelsearch Yes. I guess it's because the Torus.png file has a transparent background. If I want the Torus.png to look like my mock-up sample, I have to edit the .png with something like IrfanView and save it with a white background and no transparency. With transparency off and with the .png saved with a white background, it looks like this: I would prefer to have all .png's (or .gifs) that are loaded in the thumbnails to automatically be treated as if they had a white background wherever there's transparency in the image, with the black background showing up only wherever the resized image is smaller than the thumbnail. Do you know how to make that happen without having to edit the files ahead of time? This app's final purpose is to be an image viewer that displays a selected image full-screen on a large secondary monitor (TV). On the TV, the image will be displayed as large as possible while maintaining the aspect ratio, and any part of the TV display not covered by the image will be black. (Kind of like 'letterboxing' on old movies played on an HD TV.) So I want the thumbnails to be a preview of what it will look like on the TV. Edited November 8, 2022 by TimRude Link to comment Share on other sites More sharing options...
pixelsearch Posted November 8, 2022 Share Posted November 8, 2022 10 minutes ago, TimRude said: Do you know how to make that happen without having to edit the files ahead of time? I'm trying to solve it in a very strange way but not sure it will succeed, fingers crossed. Link to comment Share on other sites More sharing options...
pixelsearch Posted November 8, 2022 Share Posted November 8, 2022 (edited) It works... with a funny script. The background is light grey because it's the color I choosed on my computer. On yours it should be white. expandcollapse popup#include <File.au3> #include <GUIConstantsEx.au3> #include <GuiImageList.au3> #include <GuiListView.au3> #include <GDIPlus.au3> #include <WindowsConstants.au3> ; Create GUI with a ListView control Global $hGUI = GUICreate("ListView", 700, 420, -1, -1, $WS_OVERLAPPEDWINDOW) Global $hListView = _GUICtrlListView_Create($hGUI, "", 70, 0, 630, 420, _ BitOR($LVS_ICON, $LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_SORTASCENDING)) GUISetState(@SW_SHOW, $hGUI) ; Create and load ImageList control with thumbnails _GDIPlus_Startup() Global $sPath = StringReplace(@AutoItExe, "autoit3.exe", "Examples\GUI") Local $aFile = _FileListToArray($sPath, Default, $FLTA_FILES) If @error = 0 Then ; found some files Global $SizeX = 160 ; width of each thumbnail Global $SizeY = 100 ; height of each thumbnail Global $fRatioThumb = $SizeX / $SizeY Global $hImgLst = _GUIImageList_Create($SizeX, $SizeY) ; create an imagelist control Global $aImgFiles[1] ; create an array to hold the names of images we load ; create GUI2 visible... under the screen down left corner Local $hGUI2 = GUICreate("", $SizeX, $SizeY, 0, @DesktopHeight, $WS_POPUP) GUISetState(@SW_SHOW, $hGUI2) ; mandatory line or nothing will work For $i = 1 To $aFile[0] $sFile = $sPath & "\" & $aFile[$i] Switch StringRight($sFile, 4) Case ".png", ".jpg", ".gif" Case Else ContinueLoop EndSwitch Local $hImage = _GDIPlus_ImageLoadFromFile($sFile) ; try to load the image from the file If $hImage <> 0 Then $iImage_iWidth = _GDIPlus_ImageGetWidth($hImage) $iImage_iHeight = _GDIPlus_ImageGetHeight($hImage) $fRatioImage = $iImage_iWidth / $iImage_iHeight Switch True Case $fRatioThumb < $fRatioImage ConsoleWrite("+ ") $iImage_Resized_Width = $SizeX $iImage_Offset_X = 0 $iImage_Resized_Height = Round($iImage_Resized_Width / $fRatioImage) $iImage_Offset_Y = Floor(($SizeY - $iImage_Resized_Height) / 2) Case $fRatioThumb > $fRatioImage ConsoleWrite("- ") $iImage_Resized_Height = $SizeY $iImage_Offset_Y = 0 $iImage_Resized_Width = Round($iImage_Resized_Height * $fRatioImage) $iImage_Offset_X = Floor(($SizeX - $iImage_Resized_Width) / 2) Case Else ConsoleWrite("= ") $iImage_Resized_Width = $SizeX $iImage_Offset_X = 0 $iImage_Resized_Height = $SizeY $iImage_Offset_Y = 0 EndSwitch ConsoleWrite($aFile[$i] & @TAB & @TAB & $iImage_Resized_Width & "x" & $iImage_Resized_Height & @TAB & $iImage_Offset_X & "x" & $iImage_Offset_Y & @CRLF) Local $hImageScaled = _GDIPlus_ImageResize($hImage, $iImage_Resized_Width, $iImage_Resized_Height) ; resize the image (maintain aspect ratio) _GDIPlus_ImageDispose($hImage) Local $idPic = GUICtrlCreatePic("", $iImage_Offset_X, $iImage_Offset_Y, $iImage_Resized_Width, $iImage_Resized_Height) Local $hBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImageScaled) _WinAPI_DeleteObject(GUICtrlSendMsg($idPic, 0x0172, 0, $hBmp)) ; STM_SETIMAGE = 0x0172, $IMAGE_BITMAP = 0 _WinAPI_DeleteObject($hBmp) _GDIPlus_ImageDispose($hImageScaled) Local $idLabel, $idLabel2 If $iImage_Resized_Width <> $SizeX Then $idLabel = GuiCtrlCreateLabel("", 0, 0, $iImage_Offset_X, $SizeY) GUICtrlSetBkColor(-1, 0x000000) ; black label (left side of pic) $idLabel2 = GuiCtrlCreateLabel("", $iImage_Offset_X + $iImage_Resized_Width, 0, $iImage_Offset_X, $SizeY) GUICtrlSetBkColor(-1, 0x000000) ; black label (right side of pic) ElseIf $iImage_Resized_Height <> $SizeY Then $idLabel = GuiCtrlCreateLabel("", 0, 0, $SizeX, $iImage_Offset_Y) GUICtrlSetBkColor(-1, 0x000000) ; black label (above pic) $idLabel2 = GuiCtrlCreateLabel("", 0, $iImage_Offset_Y + $iImage_Resized_Height, $SizeX, $iImage_Offset_Y) GUICtrlSetBkColor(-1, 0x000000) ; black label (under pic) EndIf Local $hBmp2 = _WinCapture($hGUI2, $SizeX, $SizeY) ; capture the client area of hGUI2 (off the screen) Local $iIndex = _GUIImageList_Add($hImgLst, $hBmp2) ; add the bitmap to the ImageList and note the index number _WinAPI_DeleteObject($hBmp2) GUICtrlDelete($idPic) GUICtrlDelete($idLabel) GUICtrlDelete($idLabel2) If $iIndex <> -1 Then ReDim $aImgFiles[$iIndex + 1] ; make room in the array for the file name of the image just loaded $aImgFiles[$iIndex] = $aFile[$i] ; store the file name of the image just loaded EndIf EndIf Next _GUICtrlListView_SetImageList($hListView, $hImgLst, 0) ; assign the ImageList to the ListView ; Add the thumbnails as items to the ListView, and use the file names as captions For $i = 0 To UBound($aImgFiles) - 1 _GUICtrlListView_AddItem($hListView, $aImgFiles[$i], $i) Next GUIDelete($hGUI2) EndIf Do Until GUIGetMsg() = $GUI_EVENT_CLOSE _GDIPlus_Shutdown() GUIDelete($hGUI) ;======================================== Func _WinCapture($hWnd, $iWidth, $iHeight) Local $hSrcDC, $hDestDC, $hBmp $hSrcDC = _WinAPI_GetDC($hWnd) $hBmp = _WinAPI_CreateCompatibleBitmap($hSrcDC, $iWidth, $iHeight) $hDestDC = _WinAPI_CreateCompatibleDC($hSrcDC) _WinAPI_SelectObject($hDestDC, $hBmp) _WinAPI_PrintWindow($hWnd, $hDestDC, True) ; True = only the client area _WinAPI_BitBlt($hDestDC, 0, 0, $iWidth, $iHeight, $hSrcDC, 0, 0, $SRCCOPY) _WinAPI_DeleteDC($hDestDC) _WinAPI_ReleaseDC($hWnd, $hSrcDC) Return $hBmp EndFunc ;==>_WinCapture Updates : * Nov 9, 2022 : Create GUI2 off the screen in one pass. * Nov 10, 2022 : Add a 3rd parameter True to _WinAPI_PrintWindow() to capture only the client area (though GUI2 got only a $WS_POPUP style, then it makes no difference in this case) * Nov 11, 2022 : Use TimRude's calculation (from his last script) to keep thumbnail ratio always = original image ratio. The vertical black bars will then have a different width, depending on the original images. Edited November 12, 2022 by pixelsearch updates (listed above) TimRude 1 Link to comment Share on other sites More sharing options...
KaFu Posted November 8, 2022 Share Posted November 8, 2022 (edited) Here's my take, adjust the brushes white, green and red as desired (I know green and red should be black 🙂, but with green and red the example is better and you see what's going on). expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiImageList.au3> #include <GuiListView.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <File.au3> #include <GDIPlus.au3> ; Create GUI with a ListView control Global $hGUI = GUICreate("ListView", 700, 420, -1, -1, $WS_OVERLAPPEDWINDOW) Global $hListView = _GUICtrlListView_Create($hGUI, "", 70, 0, 630, 420, BitOR($LVS_ICON, $LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_SORTASCENDING)) GUISetState(@SW_SHOW, $hGUI) ; Create and load ImageList control with thumbnails _GDIPlus_Startup() Global $sPath = StringReplace(@AutoItExe, "autoit3.exe", "Examples\GUI") Local $aFile = _FileListToArray($sPath, Default, $FLTA_FILES) If @error = 0 Then ; found some files Global $SizeX = 160 ; width of each thumbnail Global $SizeY = 100 ; height of each thumbnail Global $hImgLst = _GUIImageList_Create($SizeX, $SizeY) ; create an imagelist control Global $aImgFiles[1] ; create an array to hold the names of images we load Global $_dHash_hBitmap_SmallScale = _GDIPlus_BitmapCreateFromScan0($SizeX, $SizeY) Global $_dHash_hBitmap_SmallScale_Graphics = _GDIPlus_ImageGetGraphicsContext($_dHash_hBitmap_SmallScale) Global $hBrush_White = _GDIPlus_BrushCreateSolid(0xFFFFFFFF) Global $hBrush_Green = _GDIPlus_BrushCreateSolid(0xFF00FF00) Global $hBrush_Red = _GDIPlus_BrushCreateSolid(0xFFFF0000) For $i = 1 To $aFile[0] $sFile = $sPath & "\" & $aFile[$i] Switch StringRight($sFile, 4) Case ".png", ".jpg", ".gif" Case Else ContinueLoop EndSwitch Local $hImage = _GDIPlus_ImageLoadFromFile($sFile) ; try to load the image from the file ; ShellExecute($sPath & "\" & $aFile[$i]) If $hImage <> 0 Then $iImage_iWidth = _GDIPlus_ImageGetWidth($hImage) $iImage_iHeight = _GDIPlus_ImageGetHeight($hImage) If $iImage_iWidth > Round($iImage_iHeight * ($SizeX / $SizeY)) Then ConsoleWrite("+ ") $iImage_Resized_Width = $SizeX $iImage_Offset_X = 0 $iImage_Resized_Height = Round($iImage_iHeight / ($SizeX / $SizeY)) $iImage_Offset_Y = Round(($SizeY - $iImage_Resized_Height) / 2) Else ConsoleWrite("- ") $iImage_Resized_Width = Round($SizeX / ($SizeX / $SizeY)) $iImage_Offset_X = Round(($SizeX - $iImage_Resized_Width) / 2) $iImage_Resized_Height = $SizeY $iImage_Offset_Y = 0 EndIf ConsoleWrite($aFile[$i] & @TAB & @TAB & $iImage_Resized_Width & "x" & $iImage_Resized_Height & @TAB & $iImage_Offset_X & "x" & $iImage_Offset_Y & @CRLF) $hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage) _GDIPlus_GraphicsSetInterpolationMode($hGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) Local $hImageScaled = _GDIPlus_ImageResize($hImage, $iImage_Resized_Width, $iImage_Resized_Height) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_ImageDispose($hImage) ; clean up _GDIPlus_GraphicsFillRect($_dHash_hBitmap_SmallScale_Graphics, 0, 0, $SizeX, $SizeY, $hBrush_White) If $iImage_Offset_X Then ConsoleWrite("a" & @CRLF) _GDIPlus_GraphicsFillRect($_dHash_hBitmap_SmallScale_Graphics, 0, 0, $iImage_Offset_X, $SizeY, $hBrush_Green) ConsoleWrite("0x0 - " & $iImage_Offset_X & "x" & $SizeY & @CRLF) _GDIPlus_GraphicsFillRect($_dHash_hBitmap_SmallScale_Graphics, $iImage_Resized_Height + $iImage_Offset_X, 0, $iImage_Offset_X, $SizeY, $hBrush_Red) ConsoleWrite($iImage_Resized_Height + $iImage_Offset_X & "x0 - " & $iImage_Offset_X & "x" & $SizeY & @CRLF) Else ConsoleWrite("b" & @CRLF) _GDIPlus_GraphicsFillRect($_dHash_hBitmap_SmallScale_Graphics, 0, 0, $SizeX, $iImage_Offset_Y, $hBrush_Green) ConsoleWrite("0x0 - " & $SizeX & "x" & $iImage_Offset_Y & @CRLF) _GDIPlus_GraphicsFillRect($_dHash_hBitmap_SmallScale_Graphics, 0, $iImage_Resized_Height + $iImage_Offset_Y, $SizeX, $iImage_Offset_Y, $hBrush_Red) ConsoleWrite("0x" & $iImage_Resized_Height + $iImage_Offset_Y & " - " & $SizeX & "x" & $iImage_Offset_Y & @CRLF) EndIf _GDIPlus_GraphicsDrawImageRect($_dHash_hBitmap_SmallScale_Graphics, $hImageScaled, $iImage_Offset_X, $iImage_Offset_Y, $iImage_Resized_Width, $iImage_Resized_Height) ; draw loaded file to existing buffer _GDIPlus_ImageDispose($hImageScaled) Local $Bmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($_dHash_hBitmap_SmallScale) ; create a handle to the bitmap object Local $iIndex = _GUIImageList_Add($hImgLst, $Bmp) ; add the bitmap to the ImageList and note the index number _WinAPI_DeleteObject($Bmp) ; clean up If $iIndex <> -1 Then ReDim $aImgFiles[$iIndex + 1] ; make room in the array for the file name of the image just loaded $aImgFiles[$iIndex] = $aFile[$i] ; store the file name of the image just loaded EndIf EndIf Next _GDIPlus_GraphicsDispose($_dHash_hBitmap_SmallScale_Graphics) _GDIPlus_BitmapDispose($_dHash_hBitmap_SmallScale) _GDIPlus_BrushDispose($hBrush_White) _GDIPlus_BrushDispose($hBrush_Green) _GDIPlus_BrushDispose($hBrush_Red) _GUICtrlListView_SetImageList($hListView, $hImgLst, 0) ; assign the ImageList to the ListView ; Add the thumbnails as items to the ListView, and use the file names as captions For $i = 0 To UBound($aImgFiles) - 1 _GUICtrlListView_AddItem($hListView, $aImgFiles[$i], $i) Next EndIf Do Local $Msg = GUIGetMsg() Until $Msg = $GUI_EVENT_CLOSE _GDIPlus_Shutdown() GUIDelete() Exit Edited November 8, 2022 by KaFu TimRude 1 OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
TimRude Posted November 9, 2022 Author Share Posted November 9, 2022 A couple of examples to try out! Gonna take me a little while to try these and work out what's being done. Thanks! Link to comment Share on other sites More sharing options...
TimRude Posted November 10, 2022 Author Share Posted November 10, 2022 (edited) After examining both approaches, I ended up going with a modified version of KaFu's method. @pixelsearch Your method was quite interesting, but in the end it seemed that since GDIPlus was needed for some of the process, it would be better to use it all the way through. But thanks for posting your sample! There are some useful tidbits in there for another project some day. @KaFu I worked my way through your GDIPlus calls and read the docs on them and definitely learned something in the process. So thanks for that! I extracted the code for building the thumbnail bitmap and put it into a function. The function lets you specify the filename to read, the size of the thumbnail, and the colors desired for the image background as well as the overflow area background. Here's what I ended up with: expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiImageList.au3> #include <GuiListView.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <File.au3> #include <GDIPlus.au3> ; Create GUI with a ListView control Global $hGUI = GUICreate("ListView", 700, 420, -1, -1, $WS_OVERLAPPEDWINDOW) Global $hListView = _GUICtrlListView_Create($hGUI, "", 70, 0, 630, 420, BitOR($LVS_ICON, $LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_SORTASCENDING)) GUISetState(@SW_SHOW, $hGUI) ; Create and load ImageList control with thumbnails _GDIPlus_Startup() Global $sPath = StringReplace(@AutoItExe, "autoit3.exe", "Examples\GUI") ;Global $sPath = StringReplace(@AutoItExe, "autoit3.exe", "Examples\Helpfile\Extras") Local $aFile = _FileListToArray($sPath, Default, $FLTA_FILES) If @error = 0 Then ; found some files Global $SizeX = 160 ; width of each thumbnail Global $SizeY = 100 ; height of each thumbnail Global $hImgLst = _GUIImageList_Create($SizeX, $SizeY) ; create an imagelist control Global $aImgFiles[1] ; create an array to hold the names of images we load For $i = 1 To $aFile[0] $sFile = $sPath & "\" & $aFile[$i] Local $hBmp = _MakeThumbnailBitmapFromFile($sFile, $SizeX, $SizeY) If $hBmp <> 0 Then Local $iIndex = _GUIImageList_Add($hImgLst, $hBmp) ; add the bitmap to the ImageList and note the index number _WinAPI_DeleteObject($hBmp) ; clean up If $iIndex <> -1 Then ReDim $aImgFiles[$iIndex + 1] ; make room in the array for the file name of the image just loaded $aImgFiles[$iIndex] = $aFile[$i] ; store the file name of the image just loaded EndIf EndIf Next _GUICtrlListView_SetImageList($hListView, $hImgLst, 0) ; assign the ImageList to the ListView ; Add the thumbnails as items to the ListView, and use the file names as captions For $i = 0 To UBound($aImgFiles) - 1 _GUICtrlListView_AddItem($hListView, $aImgFiles[$i], $i) Next EndIf Do Local $Msg = GUIGetMsg() Until $Msg = $GUI_EVENT_CLOSE _GDIPlus_Shutdown() GUIDelete() Exit Func _MakeThumbnailBitmapFromFile($sFile, $iThumbWidth = 160, $iThumbHeight = 100, $iARGB_Transparent = 0xFFFFFFFF, $iARGB_Background = 0xFF000000) ; Parameters: ; $sFile - name of image file (including path) to load ; $iThumbWidth - width of thumbnail (optional, default = 160) ; $iThumbHeight - height of thumbnail (optional, default = 100) ; $iARGB_Transparent - color for transparent areas of image files (PNG, GIF, ICO) (optional, default = 0xFFFFFFFF = white) ; $iARGB_Background - color of background areas not covered by image (optional, default = 0xFF000000 = black) ; If successful, returns handle to a bitmap that can be assigned to the thumbnail image ; If not successful, returns 0 ; Sample Use: ; ; #include <GDIPlus.au3> ; _GDIPlus_Startup() ; needed before any _GDIPlus functions are used ; ... ; $hBmp = _MakeThumbnailBitmapFromFile("path/filename") ; using default size and colors ; If $hBmp <> 0 Then ; $iIndex = _GUIImageList_Add($hImageList, $hBmp) ; assign bitmap to imagelist ; _WinAPI_DeleteObject($hBmp) ; <-- be sure to remember to do this cleanup! ; EndIf ; ... ; _GDIPlus_Shutdown() ; at end of script when finished with all _GDIPlus functions Local $hImage, $hGraphics, $hImageScaled, $hBmp Local $_dHash_hBitmap_SmallScale, $_dHash_hBitmap_SmallScale_Graphics Local $hBrush_Back, $hBrush_Trans Local $fRatioImage, $fRatioThumb Local $iImage_Width, $iImage_Height, $iImage_Resized_Height, $iImage_Resized_Width Local $iImage_Offset_X, $iImage_Offset_Y ; Try to load the image from the file $hImage = _GDIPlus_ImageLoadFromFile($sFile) If $hImage <> 0 Then ; Successfully read the image file, process it ; Resize the image to fit within the thumbnail while maintaining its aspect ratio $iImage_Width = _GDIPlus_ImageGetWidth($hImage) $iImage_Height = _GDIPlus_ImageGetHeight($hImage) $fRatioImage = $iImage_Width / $iImage_Height $fRatioThumb = $iThumbWidth / $iThumbHeight Switch True Case $fRatioThumb > $fRatioImage $iImage_Resized_Height = $iThumbHeight $iImage_Resized_Width = Round($iImage_Resized_Height * $fRatioImage) $iImage_Offset_X = Floor(($iThumbWidth - $iImage_Resized_Width) / 2) $iImage_Offset_Y = 0 Case $fRatioThumb < $fRatioImage $iImage_Resized_Width = $iThumbWidth $iImage_Resized_Height = Round($iImage_Resized_Width / $fRatioImage) $iImage_Offset_X = 0 $iImage_Offset_Y = Floor(($iThumbHeight - $iImage_Resized_Height) / 2) Case Else $iImage_Resized_Width = $iThumbWidth $iImage_Resized_Height = $iThumbHeight $iImage_Offset_X = 0 $iImage_Offset_Y = 0 EndSwitch Local $sDrive, $sDir, $sFileName, $sExtension _PathSplit($sFile, $sDrive, $sDir, $sFileName, $sExtension) ConsoleWrite($sFileName & $sExtension & @TAB & _ "Orig " & $iImage_Width & " x " & $iImage_Height & @TAB & _ "New " & $iImage_Resized_Width & " x " & $iImage_Resized_Height & @TAB & _ "Offsets = " & $iImage_Offset_X & " X , " & $iImage_Offset_Y & " Y" & @CRLF) $hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage) _GDIPlus_GraphicsSetInterpolationMode($hGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) $hImageScaled = _GDIPlus_ImageResize($hImage, $iImage_Resized_Width, $iImage_Resized_Height) _GDIPlus_GraphicsDispose($hGraphics) ; clean up _GDIPlus_ImageDispose($hImage) ; clean up ; Create a buffer to build the thumbnail image in $_dHash_hBitmap_SmallScale = _GDIPlus_BitmapCreateFromScan0($iThumbWidth, $iThumbHeight) $_dHash_hBitmap_SmallScale_Graphics = _GDIPlus_ImageGetGraphicsContext($_dHash_hBitmap_SmallScale) ; Add the background and transparent area colors to the appropriate areas of the buffer $hBrush_Back = _GDIPlus_BrushCreateSolid($iARGB_Background) $hBrush_Trans = _GDIPlus_BrushCreateSolid($iARGB_Transparent) _GDIPlus_GraphicsFillRect($_dHash_hBitmap_SmallScale_Graphics, 0, 0, $iThumbWidth, $iThumbHeight, $hBrush_Back) ; background outside of image _GDIPlus_GraphicsFillRect($_dHash_hBitmap_SmallScale_Graphics, $iImage_Offset_X, $iImage_Offset_Y, $iImage_Resized_Width, $iImage_Resized_Height, $hBrush_Trans) ; area where the resized image will be ; Add the resized image to the buffer and then create a handle to the bitmap object _GDIPlus_GraphicsDrawImageRect($_dHash_hBitmap_SmallScale_Graphics, $hImageScaled, $iImage_Offset_X, $iImage_Offset_Y, $iImage_Resized_Width, $iImage_Resized_Height) $hBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($_dHash_hBitmap_SmallScale) _GDIPlus_BrushDispose($hBrush_Back) ; clean up _GDIPlus_BrushDispose($hBrush_Trans) ; clean up _GDIPlus_ImageDispose($hImageScaled) ; clean up _GDIPlus_BitmapDispose($_dHash_hBitmap_SmallScale) ; clean up _GDIPlus_GraphicsDispose($_dHash_hBitmap_SmallScale_Graphics) ; clean up ; Return the bitmap handle (be sure to delete it with _WinAPI_DeleteObject after using it) Return $hBmp Else Return 0 ; failed EndIf EndFunc I modified a few things from KaFu's sample: For one, I eliminated checking for only certain file extensions. Instead I try to load every file in the folder. For files that aren't compatible image files, the _GDIPlus_ImageLoadFromFile function just returns a 0 and I skip that file and move on. Another change was in determining the size of the resized image. The posted sample wasn't quite getting the aspect ratio right, especially for images that are wider than they are tall. I also simplified the drawing of the backgrounds by first painting the entire buffer with the black background, then dropping the white background over it where the image goes, and then dropping on the image. That was easier than painting the black bars one at a time, and takes care of any rounding discrepancies better. There's another set of sample images in the C:\Program Files (x86)\AutoIt3\Examples\Helpfile\Extras folder that you can view by uncommenting the $sPath assignment line in the code and it shows how the routine also handles .bmp, .ico, and .emf files nicely, besides the the .gif, .png, and .jpg files. Edited November 10, 2022 by TimRude fixed a typo pixelsearch 1 Link to comment Share on other sites More sharing options...
pixelsearch Posted November 11, 2022 Share Posted November 11, 2022 (edited) 19 hours ago, TimRude said: There are some useful tidbits in there Thanks for the kind words. Glad you made it by choosing Kafu's style, which is certainly more appropriate as it's plain GDI+ I never took time to study GDI+ "graphics, pens & brushes" (until now) so I tried it in another way, which succeeded and I was the first to be surprised with this "off-the-screen popup GUI and its pic control" Thanks to @Bert (MVP) because his simple sentence in this thread started it all. In his own words : The only way I know to do it is have the window visible, but moved off the screen. Immediately after, in the same thread, James & wraithdu (2 other MVP's) reworked an old script found on the Forum and that was a big help too, plus Kafu's code above. We're lucky that this forum was (and gladly still is) full of resourceful MVP's ! Anyway, I'll keep on updating my script above, for example today : * major change : take care of images who don't need to be resized at all. @KaFu do you think this major change should also be applied to your script ? Please look at the attached pic, which is exactly 160x100 pixels, then see what happens when it's placed in the working folder, then the ratio will be lost as the resized pic will be 100x100 @TimRude great job on the msoobe.jpg, where the ratio 1.33 is kept after resizing, which ends in a resized pic of 133x100 (instead of 100x100 as in our scripts), this is your output : Thinking of it, maybe Kafu did want the vertical bars to always have the same width in his calculation ? But imho, if the horizontal bars are allowed to have a different height (depending on original pics) then shouldn't it be the same behavior for the vertical bars and their different widths ? I'm attaching below the original blue pic 160x100, in case you need to test it. Edit: new change in my script above (Nov 11, 2022) : Use TimRude's calculation (from his last script) to keep thumbnail ratio always = original image ratio. The vertical black bars will then have a different width, depending on the original images. Edited November 11, 2022 by pixelsearch added an Edit comment Link to comment Share on other sites More sharing options...
TimRude Posted November 11, 2022 Author Share Posted November 11, 2022 @pixelsearch The app I'm writing is actually a re-write of an app I wrote in VB6 a number of years ago that I now wanted to tweak a little. Unfortunately, due to a crashed HDD and a lax backup routine, I lost the source code to the VB app and therefore cannot tweak it. So I decided to recreated it in AutoIt this time. As I recall, in the VB app I used a similar approach to yours to create the thumbnails. VB has image-box and picture-box controls and using a combination of a couple of them as hidden controls on the form, I composited the thumbnail with the black bars where I wanted it. But the VB picture-box control also exposes it's internal picture object that can be used to assign it directly to the ImageList, so no screen-capture hoop jumping was needed. But the basic logic was very similar. Link to comment Share on other sites More sharing options...
KaFu Posted November 12, 2022 Share Posted November 12, 2022 No intention on my side, was just to quick for the correct math 🙄, yours look good 👍. OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now