Jump to content

File still used by AutoIt Script after using _GDIPlus_ImageDispose()


Recommended Posts

Hello guys, I am relatively new to AutoIt. I want to practise and always think of programs I can use for myself in my everyday life. So currently, I am working on a script that lets you sort a collection of photos. It is supposed to seperate the pictures within a folder you have selected via the FileSelectFolder() Function into a subfolder of pictures you want to keep and a subfolder of pictures you do not want to keep. Maybe you decide otherwise later. That is why they should not be deleted instantly. 

I needed to use GDI Plus to keep the aspect ratio of every picture while making it fit into a defined area of the GUI. Also I needed to use the _FileListToArray() script below, because the program should only put files into the array which are image files (.jpg, .jpeg, .png, .gif and .bmp, which are the most common formats). The script is the least work intensive method of doing that.

 


Everything is working to my liking, except for the fact that I am unable to move Files instead of just copying them. I have tried disposing the image, the graphics and even closing the file, all at once, even shutting down GDI Plus before attempting to move. Nope, simply does not work. I have looked into so many other threads now, but my problem seems to be a bit more specific. I am sure it has something to do with GDI Plus using the picture, which is because it is not possible to move or delete the file. But, I am not able to find out how I can fix that.

So, here is my script:

;~ #RequireAdmin ;thought this would be needed for moving files, maybe, but nah, it's not
#NoTrayIcon

#include <ColorConstantS.au3>
#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include <_FileListToArrayEx.au3>
#include <Array.au3>

$inputFolder = FileSelectFolder("Open Input Folder", "\input");

;Create the GUI
$hGui = GUICreate("Quick Photo Sorter", 1200, 910)
GUISetBkColor($COLOR_GRAY)
$butOk = GUICtrlCreateButton("Favourite", 5, 875, 327, 30)
$butPrev = GUICtrlCreateButton("<<", 337, 875, 163, 30)
$butRel = GUICtrlCreateButton("Reload", 505, 875, 192, 30) ;reload button needed, because image is not being refreshed by itself
$butNext  = GUICtrlCreateButton(">>", 702, 875, 163, 30)
$butNah = GUICtrlCreateButton("Sort out", 868, 875, 327, 30)

$imgField_size_x = 1180
$imgField_size_y = 850

Local $labelNo, $pic, $height, $width, $ratio

GUISetState(@SW_SHOW, $hGui)

$arr = _FileListToArrayEx($inputFolder, '*.jpg;*.jpeg;*.png;*.gif;*.bmp', 1) ;TODO: figure out how to exclude subfolders
While UBound($arr) = 0 ;check if selected folder contains photo files, if not, let the user retry (or abort)
    $getmsg = MsgBox(1, "No Photos", "The folder you have selected contains no image files.")
    Switch $getmsg
        Case 1
            $inputFolder = FileSelectFolder("Open Input Folder", "\input");
            $arr = _FileListToArrayEx($inputFolder, '*.jpg;*.jpeg;*.png;*.gif;*.bmp',1)
        Case 2
            Exit
    EndSwitch
WEnd
;~ _ArrayDisplay($arr, "$aFileList") ;debugging purpose
$iterator = 1

_GDIPlus_Startup()
$graphics = _GDIPlus_GraphicsCreateFromHWND($hgui)
displayImage()

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $butOk
            keep()
            nextImage()
        Case $butNah
            sort_out()
            nextImage()
        Case $butNext
            nextImage()
        Case $butPrev
            prevImage()
        Case $butRel
            _GDIPlus_ImageDispose($pic)
            displayImage()
    EndSwitch
WEnd

Func nextImage() ;shows the next image without removing the current one from the array
    GUICtrlDelete($labelNo)
    GUISetBkColor($COLOR_GRAY)
    _GDIPlus_ImageDispose($pic)
    increaseIterator()
    displayImage()
EndFunc

Func prevImage();shows the previous image without removing the current one from the array
    GUICtrlDelete($labelNo)
    GUISetBkColor($COLOR_GRAY)
    _GDIPlus_ImageDispose($pic)
    decreaseIterator()
    displayImage()
EndFunc

Func getFileName()
    $Str = StringSplit($arr[$iterator], "\")
    return $Str[UBound($Str)-1]
EndFunc

Func keep() ;copies the picture to keep into the subfolder "_keep" (wanted: move the picture, but does not work)
;~  FileMove($arr[$iterator], "\_Favourites\" & getFileName(), 9) ;Why doesn't this work?
    FileCopy($arr[$iterator], $inputFolder & "\_Favourites\", $FC_OVERWRITE + $FC_CREATEPATH)
    removeImageFromArray()
EndFunc

Func sort_out() ;simply skips the current picture, but removes it from the array (wanted: move the picture to a folder called "unwanted" or sth like this, but does not work)
    removeImageFromArray()
EndFunc

Func removeImageFromArray() ;removes the image from the array and adjusts the iterator
    If NOT (checkArrayEnd()) Then
        _ArrayDelete($arr, $iterator)
        $iterator = $iterator - 1
    Else
        MsgBox(1,"Work is done","You have finished sorting your collection, so there is nothing more to display.")
    EndIf
EndFunc

Func displayImage() ;display the image fittingly into the gui
    ;read height and width and calculate the ascpet ratio
;~  $pic = _GDIPlus_ImageLoadFromFile($inputFolder & $arr[$iterator]) ;use this with standard FileListToArrayFunction
    $pic = _GDIPlus_ImageLoadFromFile($arr[$iterator])

    $height = _GDIPlus_ImageGetHeight($pic)
    $width = _GDIPlus_ImageGetWidth($pic)
    $ratio = $width/$height

;~  $labelx = GUICtrlCreateLabel("X: " & $width, 0, 0)
;~  $labely = GUICtrlCreateLabel("Y: " & $height, 50, 0)
;~  $labelRatio = GUICtrlCreateLabel("R: " & $ratio, 100, 0)
    $labelNo = GUICtrlCreateLabel("File: " & $iterator & "/" & (Ubound($arr)-1) & " File name: " & $arr[$iterator], 0, 0)

    ;resize
    if $width > $height Then
        $width = $imgField_size_x
        $height = $width/$ratio
    ElseIf $height > $width  OR $height = $width Then
        $height = $imgField_size_y
        $width = $height*$ratio
    EndIf

    ;after resize check if the boundaries are exeeded and resize again
    if $width > $imgField_size_x Then
        $width = $imgField_size_x
        $height = $width/$ratio
    ElseIf $height > $imgField_size_y Then
        $height = $imgField_size_y
        $width = $height*$ratio
    EndIf

    $pic = _GDIPlus_ImageResize ($pic, $width, $height)
    ;now calculate the center position
    $posX = 10 + ($imgField_size_x/2) - ($width/2)
    $posY = 20 + ($imgField_size_y/2) - ($height/2)

    ;display the picture
    _GDIPlus_GraphicsDrawImage($graphics, $pic, $posX, $posY)
EndFunc

Func increaseIterator() ;for displaying the next picture
    if NOT (checkArrayEnd()) Then
        If $iterator < Ubound($arr) - 1 Then
            $iterator = $iterator + 1
        Else
            $iterator = 1
        EndIf
    EndIf
EndFunc

Func decreaseIterator() ;for displaying the previous picture
    if NOT (checkArrayEnd()) Then
        If $iterator > 1 Then
            $iterator = $iterator - 1
        Else
            $iterator = Ubound($arr) - 1
        EndIf
    EndIf
EndFunc

Func checkArrayEnd() ;preventing crashes, because the array gets empty after skipping all pictures
    If (UBound($arr)-1) = 0 Then
        Return true
    Else
        Return False
    EndIf
EndFunc

 

QuickPhotoSorter.au3

Edited by darkDrakee
Link to comment
Share on other sites

Hello,

without having done any tests I could imagine, that the files are kept opened, so that you cannot move them.

 

So you could give it a try to copy your images to a temporary location to open them with your gui. By that the originals will remain closed and it should be possible to move them.

 

The tempory copies of your images can be deleted later on.

 

Regards, Rudi.

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

@AutoBert Thanks!

@Rudi Yes, the file is kept opened. When I try to move the files manually within Windows Exporer it will say that the file is being used by AutoItv3.exe, but only, if the file has been opened by GDI Plus. So, normally _GDIPlus_ImageDispose($pic) should close the file, but it does not.

EDIT: Creating copies from the source files as temporary files is not a solution at all, because that causes more problems than just directly loading the source pictures. It makes displaying the pictures very buggy and also, the temporary files cannot be deleted.

Edited by darkDrakee
Link to comment
Share on other sites

I have found the error. Seems like this line
 

$pic= _GDIPlus_ImageResize ($pic, $width, $height)


makes it impossible for GDIPlus to close the file loaded into $pic, as it creates a new object handle, so the other one remains in memory, but is not disposable anymore, because the pointer has changed.

So I needed to make a new pointer:

$resized = _GDIPlus_ImageResize ($pic, $width, $height)
_GDIPlus_ImageDispose($pic)

_GDIPlus_GraphicsDrawImage($graphics, $resized, $posX, $posY)
    
_GDIPlus_ImageDispose($resized)

So the file is being closed now upon using _GDIPlus_ImageDispose()

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...