Scripting Saturday

Right now as I type this, the windows scripting host and Adobe Photoshop are interacting in the background of my computer making quick work of the 150 or so pictures which will be a part of this years slideshow.

I have used this script for several years now for a variety of purposes. It has always been a huge hack (ok, it still is), and I just kept pasting hard coded data / statements in the script to do what I wanted each year. This was the first year where I decided to edit the script to create a general purpose script that would work for me each time.

Of all things, the first thing I did was that while I was adding proper error codes (yes, in vbscript, you can exit with a correct error code… wscript.quit) to various initial error conditions. In the last 5 years or so, I have learned to get rather picky about my scripting (vbscript / batch) habits. Even at work when I write small scripts for use in automation, I try to follow any coding standards I can which would apply to native development. On a side note, I am now the office wiz at batch development and love using the for command as a general regex substitute in batch.

I have been either using or working on windows for at least 18 years and only in the last year at work have I found the “net helpmsg” command in windows. Currently at work, I need this command almost every day since there are hundreds of different error codes my component produces now with almost no clear way to know what they mean without feeding the error code number into this command. From what I can tell, for the most part, what this command does is translate known and existing errors which are in winerror.h into actual strings. There are other sources which get compiled into this tool however from across windows as well. (On a personal note, when this doesn’t work, I also recommend hrplus.)

I realized though that net helpmsg did not have a reverse function. For instance, I wanted my script to return errors like ‘folder does not exist’ or ‘invalid parameter’ but wanted to look up the standard errors for these. (At this point many of you would ask why I didn’t just search… the answer is because for whatever reason, the first thing I thought of was how to make my own lookup file.) So, beaming idea in my head, that is what I did. I whipped up this VERY short script to create a file with a list of the most common windows errors. (I have added comments to help with the logic. ;))

REM Clear and reset text file
echo Help File>Messages.txt
echo. >>Messages.txt

REM Cycle through top 1000 errors
FOR /L %%i in (1,1,1000) do (

    REM This command is here simply to check
    REM whether there is a valid error value
    REM or not, errors piped to NUL
    net helpmsg %%i 1>NUL 2>NUL


        REM Assuming we found an error
        REM echo that number to the file
        echo %%i>>Messages.txt

        REM Then echo the text matching
        REM that number to the file
        net helpmsg %%i>>Messages.txt


So, file at hand, I was able to find the error codes I needed. Somewhat a waste of time, but honestly its simple, quick, and fun solutions like this which keep me amused both at work and at home a lot. At work, they get way more complicated at times, but honestly, its about finding creative and fun solutions to easy and every day problems.

So after that was out of the way, I headed off to refine my Photoshop script. I should point out that, this script will not adjust the visual quality of your pictures. You could program it to do that for you, but what I have found over the years is that the composition of every image is different and color balance, highlights, noise reduction always takes a hand touch. So each year, I adjust all 100+ images in the slideshow by hand. I don’t make HUGE changes, but just try to clean up any crappy conditions I may have taken the picture in. The purpose of this script though is just to turn each picture into a 16x9 image for the slideshow (since the built-in movement scripts in the slideshow applications work better when all the images are the same size) and to cut them down to a more manageable size. I have found I can crash almost any slideshow app with panoramic pictures that are 70,000 pixels wide. With that said, here is the script I created. (You may re-use however you like, you may repost only with attribution, and this code is released ‘as is’ with no warranty or rights attached.)

Option Explicit

Dim NamedArgCount

NamedArgCount = WScript.Arguments.Named.Count

if ((NamedArgCount < 1) or (Wscript.Arguments.Named.Exists("Folder") <> True)) then

    wscript.echo "This script takes a named argument to set the folder location."
    wscript.echo "cscript SlideshowImages.vbs /Folder:""c:\Full_Path_To_Images"""

    'Invalid Parameter
    wscript.quit 87

end if

Dim FolderPathString
FolderPathString = Wscript.Arguments.Named.Item("Folder")

Dim fsoRef, folderRef, outputFolderRef, f

Set fsoRef = CreateObject( "Scripting.FileSystemObject" )

if (fsoRef.FolderExists(FolderPathString) <> True) then

    wscript.echo "Input Folder was not found!"
    wscript.echo FolderPathString

    'Path not found
    wscript.quit 3

end if

Set folderRef = fsoRef.GetFolder( FolderPathString )

if (fsoRef.FolderExists(folderRef.Path & "\OutputImages")) then

    wscript.echo "Output folder already exists!"
    wscript.echo folderRef.Path & "\OutputImages"
    wscript.echo "Please rename or remove the existing folder."

    'File Exists
    wscript.quit 80

end if

wscript.echo "Found " & folderRef.Files.Count & " files in: " & folderRef.Path
wscript.echo "Creating output path: " & folderRef.Path & "\OutputImages"

set outputFolderRef = fsoRef.CreateFolder (folderRef.Path & "\OutputImages")

wscript.echo "Detecting and Initializing Photoshop..."

Dim appRef, startRulerUnits, startTypeUnits, startDisplayDialogs
Set appRef = CreateObject("Photoshop.Application")

' Save the current preferences
startRulerUnits = appRef.Preferences.RulerUnits
startTypeUnits = appRef.Preferences.TypeUnits
startDisplayDialogs = appRef.DisplayDialogs
' Set Photoshop CS2 to use pixels and display no dialogs
appRef.Preferences.RulerUnits = 1 'for PsUnits --> 1 (psPixels)
appRef.Preferences.TypeUnits = 1 'for PsTypeUnits --> 1 (psPixels)
appRef.DisplayDialogs = 3 'for PsDialogModes --> 3 (psDisplayNoDialogs)

Dim jpgsave
set jpgsave = CreateObject("Photoshop.JPEGSaveOptions")
jpgsave.quality = 9

For Each f in folderRef.Files

    if (LCase(Right(f.ShortName,3)) <> "jpg") then
        wscript.echo "Skipping file:" & f.Name
        wscript.echo f.path
        dim document

        set document = appRef.Open(f.Path)

        dim h, w, newHeight, newWidth, resave
        h = document.Height
        w = document.Width

        wscript.echo "Resolution: " & w & "x" & h & "(" & CStr(Round(w / h, 6)) & ")"

        resave = false

        if (Round(w / h,6) <> Round(16/9,6)) then

            resave = true

            if (Round(w / h,6) > Round(16/9,6)) then
                newHeight = Round(w * (9 / 16),0)
                newWidth  = w

                wscript.echo "WIDE: " & CStr(newWidth) & "x" & CStr(newHeight)


                newHeight = h
                newWidth  = Round(h * (16 / 9),0)

                wscript.echo "TALL: " & CStr(newWidth) & "x" & CStr(newHeight)       

            end if

            document.ResizeCanvas newWidth, newHeight


            Wscript.echo "Image is already 16/9, skipping canvas adjustment..."

            newHeight = h
            newWidth  = w

        end if

        if (newWidth > 3840) then

            'Since many slideshow software does VERY badly / crashes on images
            'which are more than 7000px wide, just cut these down to 4K

            wscript.echo "LARGE: 3840x2160"           
            document.ResizeImage 3840, 2160

            resave = true

        end if

        if (resave) then

            wscript.echo "Saving as: " & outputFolderRef.Path & "\" & f.Name
            document.SaveAs outputFolderRef.Path & "\" & f.Name, jpgsave
        end if

        ' 2 == Do not prompt

    end if

' Reset the application preferences
appRef.Preferences.RulerUnits = startRulerUnits
appRef.Preferences.TypeUnits = startTypeUnits
appRef.DisplayDialogs = startDisplayDialogs


Now that the pictures are just about ready to go (they are now all in the right format and ready to get put in the timeline) I need to settle on the soundtrack. My possible song options ballooned in the last few months and I have been re-considering the songs be listening to a playlist over and over again. You can check out the list here. Not all 39 songs can make it. Maybe only the top 6 or 7. They are listed on that page in the order in which I first heard them this year.

Honestly I have so many other topics I could sit down and write about here lately such as the article I want to write about Portland now (similar to my “J.P.’s Guide to Vegas”), but I just have not had the time lately. (Nothing there is new I guess.)

My photos from my recent trips to Phoenix and Portland are both online now. Many more in the later than the former.

I also found that over 90% of the images in this year’s slideshow happened to already be ‘lurking’ in my Flickr photostream from the year as well. So for the hell of it, I corralled them into a preview bucket. Of course EVERY image from all of my slideshows is neatly stored on Flickr still as well in this collection. Not to mention the collections I have specifically dedicated to Travel and Hiking/Biking as well. And as always, my moblog (perma-linked at the top of this page) is hosted on Flickr as well.

Have a very happy holidays everyone. Looked for a finished slideshow “soon” ;).

» Similar Posts

  1. From Italy with Love
  2. The Internet just devolved a little
  3. New Media and Social Network / Identity Interop

Comments are closed