Jump to content

mozjpeg bulk compressor


mikeytown2
 Share

Recommended Posts

Something I threw together. Uses these exe's
http://mozjpeg.codelove.de/binaries.html
http://www.sentex.net/~mwandel/jhead/
Will auto rotate the image and keep the original exif data. I use this to compress photos before putting them in email or dropbox. Will use the number of cores your box has for processing the images so it can plow though them fairly quickly.
 

 

#include <Array.au3>
#include <FileConstants.au3>
#include <MsgBoxConstants.au3>
#include <File.au3>
#include <GUIConstantsEx.au3>
#include <Crypt.au3>

FileInstall('cjpeg.exe', @ScriptDir & '\cjpeg.exe')
FileInstall('libjpeg-62.dll', @ScriptDir & '\libjpeg-62.dll')
FileInstall('jhead.exe', @ScriptDir & '\jhead.exe')
FileInstall('jpegtran.exe', @ScriptDir & '\jpegtran.exe')

;add to array, list of files in a dir
Func FileListFromDir($dir, $filetype, ByRef $filelist)
    ;search for the first file with the correct file extenstion
    Local $file, $search = FileFindFirstFile($dir & "\" & $filetype)
    ; Check if the search was successful
    If $search = -1 Then
        $searchDIR = FileFindFirstFile($dir & "\*")
        While 1
            $file = FileFindNextFile($searchDIR)
            If @error Then
                ExitLoop
            EndIf
            If StringInStr(FileGetAttrib($dir & "\" & $file), "D") Then
                FileListFromDir($dir & "\" & $file, $filetype, $filelist)
            EndIf
        WEnd
        FileClose($searchDIR) ; Close the search handle
    EndIf

    ;add found files to array
    While 1
        $file = FileFindNextFile($search)
        If @error Then
            ExitLoop
        EndIf
        ;Add file to array
        _ArrayAdd($filelist, $dir & "\" & $file)
        $filelist[0] += 1
    WEnd
    FileClose($search) ; Close the search handle
EndFunc   ;==>FileListFromDir

;add from given array to Filelist
Func GetListOfFiles()
    Local $dirbit = 0
    Local $filetype = '*.jpg'
    Local $filelist[1]
    $filelist[0] = 0

    ;Grab EXE Drag-n-Droped files/dir's
    If $CmdLine[0] > 0 Then
        For $x = 1 To $CmdLine[0] Step +1 ;run though all files droped and look for dir's
            If StringInStr(FileGetAttrib($CmdLine[$x]), "D") Then
                $dirbit += 1
                FileListFromDir($CmdLine[$x], $filetype, $filelist) ;parce dir looking for file of that extenstion
            Else ;add file to list
                _ArrayAdd($filelist, $CmdLine[$x])
                $filelist[0] += 1
            EndIf
        Next
    EndIf
    If $filelist[0] <= 0 Then
        ; Create a constant variable in Local scope of the message to display in FileOpenDialog.
        Local Const $sMessage = "Hold down Ctrl or Shift to choose multiple files."

        ; Display an open dialog to select a list of file(s).
        Local $sFileOpenDialog = FileOpenDialog($sMessage, @WindowsDir & "\", "JPG Files (*.jpg)", $FD_FILEMUSTEXIST + $FD_MULTISELECT)
        If @error Then
            ; Display the error message.
            MsgBox($MB_SYSTEMMODAL, "", "No file(s) were selected.")

            ; Change the working directory (@WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder.
            FileChangeDir(@ScriptDir)
        Else
            ; Change the working directory (@WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder.
            FileChangeDir(@ScriptDir)

            If StringInStr($sFileOpenDialog, '|') Then
                $templist = StringSplit($sFileOpenDialog, '|')
                $dir = $templist[1]
                _ArrayDelete($templist, 1)
                $templist[0] -= 1
                While $templist[0] > 0
                    $newfile = $dir & '\' & $templist[1]
                    _ArrayDelete($templist, 1)
                    $templist[0] -= 1
                    _ArrayAdd($filelist, $newfile)
                    $filelist[0] += 1
                WEnd
            Else
                _ArrayAdd($filelist, $sFileOpenDialog)
                $filelist[0] += 1
            EndIf
        EndIf
    EndIf


    Return $filelist
EndFunc   ;==>ArrayToFileList

Func shrinkjpeg($filename, $pids)
    ; Get dir and filename info.
    Local $sDrive = "", $sDir = "", $sFilename = "", $sExtension = ""
    Local $aPathSplit = _PathSplit($filename, $sDrive, $sDir, $sFilename, $sExtension)
    Local $sNewDir = $sDrive & $sDir & 'small\'

    If DirGetSize($sNewDir) == -1 Then
        DirCreate($sNewDir)
    EndIf

    ; Run X number of threads.
    $cores = EnvGet("NUMBER_OF_PROCESSORS")
    While $pids[0] > $cores
        For $x = 1 To $cores Step +1
            If _elementExists($pids, $x) And ProcessExists($pids[$x]) == 0 Then
                _ArrayDelete($pids, $x)
                $pids[0] -= 1
            EndIf
        Next
        Sleep(20)
    WEnd

    ; Let GUI know what file is being worked on.
    OutputStatus($sFilename)

    $newfilename = $sNewDir & $sFilename & '-small.jpg'
    Local $cmds = ''
    $cmds &= @ComSpec & ' /c '
    ; run mozjpeg.
    $cmds &= '' & @ScriptDir & '\cjpeg.exe -quality 60,51 -optimize "' & $filename & '" > "' & $newfilename & '"'
    ; Copy exif data.
    $cmds &= ' & ' & @ScriptDir & '\jhead.exe -te "' & $filename & '" "' & $newfilename & '"'
    ; Rotate jpeg.
    $cmds &= ' & ' & @ScriptDir & '\jhead.exe -autorot "' & $newfilename & '"'
    ; Run it.
    Local $iPID = Run($cmds, "", @SW_HIDE)
    ; Set priority low.
    ProcessSetPriority($iPID, 0)

    _ArrayAdd($pids, $iPID)
    $pids[0] += 1
    Return $pids
EndFunc



Func OutputStatus($sMessage)
    Local $hWnd = WinGetHandle("")
    TrayTip('Status:', $sMessage, 30)
    TraySetToolTip($sMessage)
    WinActivate($hWnd)
EndFunc

Func _elementExists($array, $element)
    If $element > UBound($array)-1 Then Return False ; element is out of the array bounds
    Return True ; element is in array bounds
EndFunc

$files = GetListOfFiles()
Local $pids[1]
$pids[0] = 0
If $files[0] > 0 Then
    While $files[0] > 0
        $pids = shrinkjpeg($files[1], $pids)
        _ArrayDelete($files, 1)
        $files[0] -= 1
    WEnd

    $cores = EnvGet("NUMBER_OF_PROCESSORS")
    If $pids[0] > $cores Then
        For $x = 1 To $cores Step +1
            If _elementExists($pids, $x) Then
                ProcessWaitClose($pids[$x])
            EndIf
        Next
    EndIf

    MsgBox($MB_SYSTEMMODAL, "", "Done")
EndIf

 

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