qwert Posted June 13, 2016 Share Posted June 13, 2016 (edited) I have a set of 5 images (PNGs) that I need to combine, vertically, into one PNG. The result needs to be a "stacked" format, with the images left-aligned. Although there are always 5, the dimensions of each image can differ. (see example) I recall a post with some method to combine two images, but it was quite a while ago and I've been unable to find any reference. I'll certainly appreciate any advice on how to go about this. Thanks in advance. Edited June 13, 2016 by qwert Link to comment Share on other sites More sharing options...
UEZ Posted June 13, 2016 Share Posted June 13, 2016 That should be an easy task. Pseudo code: For each Image iWidth = Max(ImageDimension) iHeight += ImageHeight(i) Next NewBitmap (iWidth, iHeight) iHeight = 0 For each Image copyImage(NewBitmap, 0, iHeight) iHeight += ImageHeight(i) Next SaveImage(NewBitmap) Give it a try. Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
qwert Posted June 13, 2016 Author Share Posted June 13, 2016 Thanks for your response. The "flowchart" of steps that you describe is clear. But what is the right "foundation" of the AU3 operations? ... hBitMaps? For example, are WinAPI_CopyImage and WinAPI_SaveHBITMAPToFile the kind of statements to be using? Or is GDI+ more appropriate (_GDIPlus_ImageSaveToFile)? Maybe a better way to ask is: can you suggest an example script that basically works with an image in the way you're suggesting? (i.e., "load image ... work on image ... save image") Link to comment Share on other sites More sharing options...
UEZ Posted June 13, 2016 Share Posted June 13, 2016 expandcollapse popup#include <Array.au3> #include <File.au3> #include <GDIPlus.au3> Global Const $sFolder = FileSelectFolder("Select a folder with images", "") If @error Then Exit MsgBox($MB_ICONERROR, "Error", "No folder was selected!", 10) Global $aFilter = _FileListToArrayRec($sFolder, "*.jpg;*.png;*.bmp", $FLTAR_FILES, $FLTAR_NORECUR, $FLTAR_NOSORT, $FLTAR_FULLPATH) If @error Then Exit MsgBox($MB_ICONERROR, "Error", "No images were found in selected folder!", 10) _GDIPlus_Startup() Global $hBitmap_Stacked = _GDIPlus_BitmapCreateStackedBitmaps($aFilter) _GDIPlus_ImageSaveToFile($hBitmap_Stacked, @ScriptDir & "\StackedBitmaps.png") _GDIPlus_ImageDispose($hBitmap_Stacked) _GDIPlus_Shutdown() Func _GDIPlus_BitmapCreateStackedBitmaps($aFiles, $iLimit = 5) If $aFiles[0] = 1 Then Return SetError(1, 0, 0) ;only one image $iLimit = $iLimit > $aFiles[0] ? $aFiles[0] : $iLimit Local $i, $aDim, $iW_max = 0, $iH_max = 0, $aImages[$iLimit + 1], $iY = 0 $aImages[0] = $iLimit For $i = 1 To $iLimit $aImages[$i] = _GDIPlus_ImageLoadFromFile($aFiles[$i]) $aDim = _GDIPlus_ImageGetDimension($aImages[$i]) $iW_max = $aDim[0] > $iW_max ? $aDim[0] : $iW_max $iH_max += $aDim[1] Next Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW_max, $iH_max), $hGfx = _GDIPlus_ImageGetGraphicsContext($hBitmap) For $i = 1 To $iLimit $aDim = _GDIPlus_ImageGetDimension($aImages[$i]) _GDIPlus_GraphicsDrawImageRect($hGfx, $aImages[$i], 0, $iY, $aDim[0], $aDim[1]) _GDIPlus_ImageDispose($aImages[$i]) $iY += $aDim[1] Next _GDIPlus_GraphicsDispose($hGfx) Return $hBitmap EndFunc Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
qwert Posted June 13, 2016 Author Share Posted June 13, 2016 Wow. 33 statements! And fast. (It produced a 3Mb result instantly.) This belongs in the Examples topic. I can foresee a variety of uses ... and versions that could do horizontal ... and mosaics, with automatic image sizing. Plus, it's an excellent example of proper GDI+ implementation with ImageDispose, GraphicsDispose, etc. We see these things in scripts, of course, but rarely in such a concise context. Thank you for this. Link to comment Share on other sites More sharing options...
Legion4400 Posted March 16, 2020 Share Posted March 16, 2020 Hi. How can i use this for batch process? I have about 1000 photos and i want to combine just 2 into 1. How can i make so the process continues to combine the rest of the photos? I have very basic knowledge about autoit. I am doing genealogy research and i have a lot of scanned documents, some are 2 pages long; i want to combine those into 1 image. The only thing i think i can do right now is to delete first 2 already combined images from the folder and run the scrip again; also move the combined image into another folder under a different name :) I am looking into saving the combined files under the same name as the 1st image used from every set. Thank you! Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted March 16, 2020 Moderators Share Posted March 16, 2020 Moved to the appropriate forum. Moderation Team Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
Nine Posted March 16, 2020 Share Posted March 16, 2020 You can use something like this (I comment out the FileDelete as a precaution) : #include <Constants.au3> #include <File.au3> Opt ("MustDeclareVars", 1) Local $aFileList = _FileListToArray ("Your full path goes here", "*.jpg", $FLTA_FILES, True) _ArrayDisplay ($aFileList) For $i = 1 To $aFileList[0] Step 2 CombineFiles ($aFileList[$i],$aFileList[$i+1]) If @error Then Exit MsgBox ($MB_SYSTEMMODAL,"","Combine has reported an error : " & @error) ;FileDelete ($aFileList[$i]) ;FileDelete ($aFileList[$i+1]) Next Func CombineFiles ($sFile1, $sFile2) ;Your code goes here EndFunc “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Legion4400 Posted March 17, 2020 Share Posted March 17, 2020 Thank you. Because of my lack of knowledge i dont know how to implement this in the script above. i made it work for 2 files but if i try to automate i get an error at $adim. However i find a workaround: i made 2 programs. please excuse my mess this is basically the same as above, with small changes expandcollapse popup#cs ---------------------------------------------------------------------------- AutoIt Version: 3.3.14.5 Author: myName Script Function: Template AutoIt script. #ce ---------------------------------------------------------------------------- ; Script Start - Add your code below here #include <AutoItConstants.au3> #include <Array.au3> #include <Date.au3> #include <File.au3> #include <GDIPlus.au3> _createdir() Func _createdir() ; Create a constant variable in Local scope of the directory. Local Const $sFilePath = @ScriptDir & "\Merged" ; If the directory exists the don't continue. If FileExists($sFilePath) Then ; MsgBox($MB_SYSTEMMODAL, "", "An error occurred. The directory already exists.") Return False EndIf ; Open the temporary directory. ;ShellExecuteWait(@ScriptDir) ; Create the directory. DirCreate($sFilePath) ; Display a message of the directory creation. ;MsgBox($MB_SYSTEMMODAL, "", "The directory has been created.") EndFunc ;==>_createdir Local $dir, $dir1, $dir2 $dir = _PathFull(@ScriptDir) $dir1 = StringRight($dir, 14) $dir2 = StringLeft($dir1, 4) Global Const $sFolder = @ScriptDir If @error Then Exit MsgBox($MB_ICONERROR, "Error", "No folder was selected!", 10) Global $aFilter = _FileListToArrayRec($sFolder, "*.jpg;*.png;*.bmp", $FLTAR_FILES, $FLTAR_NORECUR, $FLTAR_NOSORT, $FLTAR_FULLPATH) If @error Then Exit MsgBox($MB_ICONERROR, "Error", "No images were found in selected folder!", 10) _GDIPlus_Startup() Global $hBitmap_Stacked = _GDIPlus_BitmapCreateStackedBitmaps($aFilter) ;$dirpart1 = StringRight(@ScriptDir, 14) _GDIPlus_ImageSaveToFile($hBitmap_Stacked, @ScriptDir & "\merged\" & $dir2 & " " & @MDAY & "-" & @MON & "-" & @YEAR & " " & @HOUR & @MIN & @SEC & ".jpg") _GDIPlus_ImageDispose($hBitmap_Stacked) _GDIPlus_Shutdown() Func _GDIPlus_BitmapCreateStackedBitmaps($aFiles, $iLimit = 2) If $aFiles[0] = 1 Then Return SetError(1, 0, 0) ;only one image $iLimit = $iLimit > $aFiles[0] ? $aFiles[0] : $iLimit Local $i, $aDim, $iW_max = 0, $iH_max = 0, $aImages[$iLimit + 1], $iY = 0 $aImages[0] = $iLimit For $i = 1 To $iLimit $aImages[$i] = _GDIPlus_ImageLoadFromFile($aFiles[$i]) $aDim = _GDIPlus_ImageGetDimension($aImages[$i]) $iW_max = $aDim[0] > $iW_max ? $aDim[0] : $iW_max $iH_max += $aDim[1] Next Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW_max, $iH_max), $hGfx = _GDIPlus_ImageGetGraphicsContext($hBitmap) For $i = 1 To $iLimit $aDim = _GDIPlus_ImageGetDimension($aImages[$i]) _GDIPlus_GraphicsDrawImageRect($hGfx, $aImages[$i], 0, $iY, $aDim[0], $aDim[1]) _GDIPlus_ImageDispose($aImages[$i]) $iY += $aDim[1] Next _GDIPlus_GraphicsDispose($hGfx) Return $hBitmap EndFunc ;==>_GDIPlus_BitmapCreateStackedBitmaps i compiled this into merger.exe this is the second that calls for merger.exe expandcollapse popup#cs ---------------------------------------------------------------------------- AutoIt Version: 3.3.14.5 Author: Kristian Script Function: Template AutoIt script. #ce ---------------------------------------------------------------------------- ; Script Start - Add your code below here #include <AutoItConstants.au3> #include <Array.au3> #include <File.au3> Local $FileList = _FileListToArray(@ScriptDir, "*.jpg") If @error = 1 Then MsgBox(0, "", "No Folders Found.") Exit EndIf If @error = 4 Then MsgBox(0, "", "No Files Found.") Exit EndIf Local $exeLocation = @ScriptDir & "\merger.exe" Local $k = $FileList[0] While $k > 0 Run($exeLocation) Sleep(100) ProcessWaitClose("merger.exe") $k = $k - 2 Local $Fileremain = _FileListToArray(@ScriptDir, "*.jpg") FileDelete($Fileremain[1]) FileDelete($Fileremain[2]) WEnd Link to comment Share on other sites More sharing options...
Nine Posted March 17, 2020 Share Posted March 17, 2020 (edited) Here, you have made a good effort, I believe you need a little help : expandcollapse popup#include <AutoItConstants.au3> #include <Array.au3> #include <Date.au3> #include <File.au3> #include <GDIPlus.au3> Global Const $sFilePath = @ScriptDir & "\Merged\" ; make sure you have \ at then end Global Const $sFolder = @ScriptDir Global $hBitmap_Stacked, $aTmp[3] = [2] Global $sDrive, $sDir, $sFileName, $sExtension If FileExists($sFilePath) Then Exit MsgBox($MB_SYSTEMMODAL, "", "An error occurred. The directory already exists.") DirCreate($sFilePath) Global $aFilter = _FileListToArrayRec($sFolder, "*.jpg;*.png;*.bmp", $FLTAR_FILES, $FLTAR_NORECUR, $FLTAR_NOSORT, $FLTAR_FULLPATH) If @error Then Exit MsgBox($MB_ICONERROR, "Error", "No images were found in selected folder!", 10) ;_ArrayDisplay($aFilter) _GDIPlus_Startup() For $i = 1 to $aFilter[0] Step 2 ; I would personnaly make some checks about file names, ensuring that they are the right ones... $aTmp[1] = $aFilter[$i] $aTmp[2] = $aFilter[$i+1] $hBitmap_Stacked = _GDIPlus_BitmapCreateStackedBitmaps($aTmp) If @error Then ExitLoop MsgBox ($MB_SYSTEMMODAL,"","Error combining files") _PathSplit ($aTmp[1], $sDrive, $sDir, $sFileName, $sExtension) _GDIPlus_ImageSaveToFile($hBitmap_Stacked, $sFilePath & $sFileName & $sExtension) ; You said you wanted to save it under first file name _GDIPlus_ImageDispose($hBitmap_Stacked) ;FileDelete ($aTmp[1]) ;FileDelete ($aTmp[2]) Next _GDIPlus_Shutdown() Func _GDIPlus_BitmapCreateStackedBitmaps($aFiles, $iLimit = 2) If $aFiles[0] = 1 Then Return SetError(1, 0, 0) ;only one image $iLimit = $iLimit > $aFiles[0] ? $aFiles[0] : $iLimit Local $i, $aDim, $iW_max = 0, $iH_max = 0, $aImages[$iLimit + 1], $iY = 0 $aImages[0] = $iLimit For $i = 1 To $iLimit $aImages[$i] = _GDIPlus_ImageLoadFromFile($aFiles[$i]) $aDim = _GDIPlus_ImageGetDimension($aImages[$i]) $iW_max = $aDim[0] > $iW_max ? $aDim[0] : $iW_max $iH_max += $aDim[1] Next Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW_max, $iH_max), $hGfx = _GDIPlus_ImageGetGraphicsContext($hBitmap) For $i = 1 To $iLimit $aDim = _GDIPlus_ImageGetDimension($aImages[$i]) _GDIPlus_GraphicsDrawImageRect($hGfx, $aImages[$i], 0, $iY, $aDim[0], $aDim[1]) _GDIPlus_ImageDispose($aImages[$i]) $iY += $aDim[1] Next _GDIPlus_GraphicsDispose($hGfx) Return $hBitmap EndFunc ;==>_GDIPlus_BitmapCreateStackedBitmaps You will need to adjust filter and ensure it is working properly before removing comments on FileDelete. I would also recommend checking file names as I have commented in the script... Edited March 17, 2020 by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Legion4400 Posted March 18, 2020 Share Posted March 18, 2020 Thank you very much! This works perfectly. I made this changes to combine horizontally. The result looks how it should so i guess is ok... $iH_max = $aDim[1] > $iH_max ? $aDim[1] : $iH_max $iW_max += $aDim[0] _GDIPlus_GraphicsDrawImageRect($hGfx, $aImages[$i], $iY, 0, $aDim[0], $aDim[1]) _GDIPlus_ImageDispose($aImages[$i]) $iY += $aDim[0] 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