Jump to content

[Solved] Looking for method to append images - (Moved)


Recommended Posts

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.

Five PNGs.png

 

Edited by qwert
Link to comment
Share on other sites

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

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

#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

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

  • 3 years later...

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

  • Moderators

Moved to the appropriate forum.

Moderation Team

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png 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 columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

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

 

#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

 

#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

Here, you have made a good effort, I believe you need a little help :

#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 by Nine
Link to comment
Share on other sites

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...