Newb seeking help w batch image processing applescript/automator app.

Hello world. I have been trolling around the tubes for weeks now trying to put together a script (bundled inside an automator application) that will help me sort, process and delete old TIFF files. My current workflow requires that I drop some files with “xxx, xxy, xxz” in the name on a photoshop droplet that creates a .JPG and then drop the rest on a droplet that saves a compressed .TIF. I started in Automator and was able to get the files sorted into new folders and begin processing but thats when things fell apart. Photoshop’s droplets and actions don’t return anything back to automator so I couldn’t get it to wait until the jpg side was done before it started the tif part of the process. I have backtracked so many times and tried different methods of processing (telling photoshop directly, telling automator to use droplet ‘x’ etc.) that my head is spinning and I’m running out of time to figure this out myself. Here’e my workflow, I hope someone has the time here to point me in the right direction:

drop folder containing “_xxx.TIF, _xxy.TIF, _xxz.TIF, _YY.TIF” onto app.
grab xxx, xxy, xxz - save as JPG with options {class:JPEG save options, embed color profile:false, format options:optimized, quality:12}
delete xxx, xxy, xxz.TIF
grab whats left - save as TIF with options {class:TIFF save options, embed color profile:true, image compression:LZW, byte order:IBM PC}

sorting into folders can happen before or after, though I think Automator will have an easier time with after. My biggest hurdle that I keep running into is getting the script to get the path of the “Input” variable in Automator and use it. I have tried

set filePath to POSIX path of the input

and then recalled filePath as the location to save but I think I am just too new at this to have the correct syntax etc. in place. The reason for this is the final Automator app needing to run on ANY folder on ANY computer so this becomes a “drag and drop” solution. I process hundreds of files a day and I hope to be able to dedicate machines across my network to just run this badboy for me and let me stick to shooting. My (broken) code:

on run {input, parameters}
	set myFile to POSIX path of folder of the input as string
	tell application "Finder"
		set fl to input as alias list
		repeat with f in fl
			tell application "Adobe Photoshop CS6"
				set myOptions to {class:JPEG save options, embed color profile:false, format options:optimized, quality:12}
				open f
				save current document in file myFile as JPEG with options myOptions appending no extension without copying
				activate
			end tell
		end repeat
	end tell
end run

Thanks in advance for any insight/time spent.

If you are simply trying to convert huge batches of TIFF files to JPG files, you may consider the command line tool sips, via AppleScript’s do shell script command. The file conversion goes pretty fast; probably faster than scripting Photoshop. The man page for sips is available here.

Craig - Thanks for the tip! I did see that searching through the forum before I posted my thread, and I plan on giving that a shot ASAP. I fear I am still going to have a problem getting the actual folder contents handed in properly from Automator, but I suppose we’ll have to see. I’ll keep the thread updated with my progress. Anyone else with recommendations as to my file handling feel free to chime in; I need all the help I can get.

I am curious about why you feel the need to use Automator. Even so, there is an Automator action for Run AppleScript, so I understand that it may be simpler for your workflow.

This script is the bare-bones version of a script I assembled in 2009 to convert a few thousand scanned TIFF files of old family photos. All it does is reduce each TIFF file to around 2MB, which made it much easier to import into iPhoto for key-wording and date manipulation. It is a simple case of choosing a source folder, and choosing a destination folder, and then going to bed. In the morning, all the reduced TIFF files are in a subfolder of the destination folder entitled _Done.

Perhaps you can use parts of it.

--Basic TIFF conversion using sips

with timeout of weeks seconds --This will most likely take some time
	set Root_Folder to (choose folder with prompt "Select Root folder of scanned images") --Select the root folder that contains all the folders of images
	set Destination_Folder to (choose folder with prompt "Choose destination location for re-sized images") --Select or create the destination folder
	set Final_Resting_Place to (Destination_Folder as text) & ("_Done") & ":" --This is the location to save the newly converted file
	my CheckOrMakeFolder(Final_Resting_Place) --Make sure destination folder exists, or create it
	tell application "Finder" to set images_to_process to (every file in Root_Folder whose name extension = "tif") --Just get the TIFF files
	repeat with big_Tiff in images_to_process
		set orig_file to (POSIX path of (big_Tiff as text))
		set converted_Name to my GetFileName(orig_file) --This preserves the original fileName as scanned
		set new_file to (POSIX path of (Final_Resting_Place & converted_Name))
		set new_size to my GetResamplingFactor(orig_file) --Determines if 35mm or 6x6 and adjusts resampling size appropriately
		try
			--Here is where the file is converted to a smaller TIFF, renamed, and the original file path is installed in the metadata of the new file's description field
			do shell script ("sips --resampleHeight " & new_size & space & (quoted form of orig_file) & " --out " & (quoted form of new_file)) --This is the actual file conversion line
		on error
			--Write the original path to an error log file
		end try
	end repeat
end timeout
------------------------------------------------------
on CheckOrMakeFolder(dp)
	tell application "Finder" to if not (exists folder dp) then do shell script "mkdir -p " & quoted form of POSIX path of dp
end CheckOrMakeFolder
------------------------------------------------------
to GetResamplingFactor(px_path) --accepts quoted posix path, returns proper resampling factor based on image size/color space
	set image_info to paragraphs -3 thru -1 of (do shell script "sips -g pixelHeight -g pixelWidth -g space " & quoted form of px_path)
	set curr_Height to word -1 of image_info's item 1 as number
	set curr_Width to word -1 of image_info's item 2 as number
	set color_space to word -1 of image_info's item 3 --Returns RGB or Gray
	set img_ratio to curr_Width / curr_Height --curr_Height / curr_Width --ratio of height to width
	if color_space = "Gray" then --For BW images, we do a straight conversion based on the ratio to obtain a 2MB size final image file
		return ((2097152 / img_ratio) ^ 0.5) as integer
	else --For RGB images, the reduction has to be larger, due to the extra color data in the file
		return (((2097152 / img_ratio) ^ 0.5) / 1.2) as integer --Dividing by 3 SHOULD properly convert a color image, yet they are too small.  Dividing by 2 creates 1.5MB images, Testing indicates that 1.2 gets pretty close to 2MB
	end if
end GetResamplingFactor
------------------------------------------------------
on GetFileName(o_path) --non-quoted form of orig path
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "/"
	set f_Name to o_path's text item -1
	set AppleScript's text item delimiters to astid
	return f_Name
end GetFileName
------------------------------------------------------

Craig- Interesting! I will definitely look it over and see if anything applies. I need to make sure that SIPS allows me to not only strip color profiles but also compress LZW (which I’m seeing something here about that…) More reading!

To answer your question about Automator, I suppose I don’t have to use it. Again, I am new to AppleScripting and am quickly learning that it’s more worth my time to learn AS than trying to beat Automator into submission (though I DO feel like doing that, if not just recreationally.)

I guess the big thing is that I need to be able to literally HAND this to other people and/or drop a single folder with a few thousand images a day; Oh AND expect it to work as a standalone on any Mac (same photoshop & OSX v. of course). I have built little Automator things here and there that I share with coworkers to improve productivity and if I can get this one to work, I will save myself and others several hours a week, which is a big deal. Of course I got ASKED to make this one and I’m afraid it ran me out of my depth.

This forum has been EXTREMELY enlightening so far so I will likely be polishing this into a pretty little thing to share with the world when/if I can get it working. It feels like its just RIGHT there… ah, the elusive “Aha”.

So I’ve decided to take a different tack and leave Automator out until I can get the AS part working properly. I pulled most of this script from a guy who was processing with another software but it seems like I should be able to do some slight replacements and everything should work. I’m getting the error:

"General Photoshop Error occurred. This functionality may not be available in this version of Photoshop. -

Which is weird because the command is a simple “save this with these options.” It errors out as it is trying to save the first JPEG file. Anyone have any ideas?
Here’s the code:

-- This droplet processes both files or folders of files dropped onto the applet
on open these_items
	
	repeat with i from 1 to the count of these_items
		set this_item to (item i of these_items)
		set the item_info to info for this_item
		if folder of the item_info is true then
			process_folder(this_item)
		else if (alias of the item_info is false) then
			process_item(this_item)
		end if
	end repeat
end open

-- this sub-routine processes folders
on process_folder(this_folder)
	set these_items to list folder this_folder without invisibles
	repeat with i from 1 to the count of these_items
		set this_item to alias ((this_folder as text) & (item i of these_items))
		set the item_info to info for this_item
		if folder of the item_info is true then
			process_folder(this_item)
		else if (alias of the item_info is false) then
			process_item(this_item)
		end if
	end repeat
end process_folder

-- this sub-routine processes files
on process_item(this_item)
	set the item_info to info for this_item
	set nam to the name of the item_info
	set dir to the POSIX path of (this_item as alias)
	if nam contains "_y" or nam contains "_t" or nam contains "_a" then
		tell application "Finder"
			open this_item
		end tell
		tell application "Adobe Photoshop CS6"
			activate
			save current document as JPEG in this_item with options {class:JPEG save options, embed color profile:false, format options:optimized, quality:12} with extension without copying
			close current document
		end tell
	else
		tell application "Adobe Photoshop CS6"
			activate
			save current document as TIFF in this_item --with options {class:TIFF save options, embed color profile:true, image compression:LZW, byte order:IBM PC}
			close current document
		end tell
	end if
end process_item

Don’t tell the Finder to open the document, tell Photoshop.

Hi unklhefe,

Just my little contribute:

Looking the script I would like to notify you that you save JPEG files without color profile embedded.
This is in general an ERROR. Color profile is the “colorimetric identity” of the file, so it should NEVER been removed.
In some situation, for example if you need to generate JPEG for Web, the image profile must be converted to sRGB that is the standard for Internet use.
RGB color profile is just few bytes compared to CMYK color profile that can be 1-3 MB.
Also consider that extension of files can be double: JPEG files can arrive as “jpg” or “jpeg” and TIFF files can arrive as “tif” or “tiff” so after you get file extension you can check in this way:

if imageExtension is in {“TIF”, “TIFF”} then …


Stefano - AME

@Shane - Thanks for the tip. I had moved it out there to make sure the problem I had opening the file wasn’t a photoshop thing, and had forgotten to move it back. Good catch!

@ame - Appreciate the input. There is in fact a very good reason I have for stripping the color profile because of specific things I/we do with the imagery. We have outputs to our clients that require very specific RGB and CMYK color outputs that happen further down the line from this script. I guess I never really mentioned that before, but this script is for handling the RAW photography straight from Canon DPP and “stripping” it down to nothing before it gets handed to many others for extensive editing/processing/output.

Great tip on the extension though! I was wondering how/if I would run into a problem with that so it’s good to know there’s syntax that can handle it!

This place is so great; so much to learn and so many people to help. Anyone else have some thoughts? I am a dry sponge ready to soak up some knowledge!

Moving along, I moved the Open command inside the Tell Photoshop block, but now I am getting a “Can’t make some data into the expected type” error. I found another thread here on MacScripter https://secure.macscripter.net/viewtopic.php?pid=150946
where the guy was using some of the same code I am for the file/folder drop. The solution he ended up with doesn’t seem to be working for me though. When I change

set this_item to (item i of these_items)

to

set this_item to (item i of these_items) as string

I get the error: “file ___ wasn’t found” error with the path in “macintosh HD:folder:folder:file.tif” form. Again, I’m a bit new to this stuff but is that an alias that needs to be a string? I always get the alias/string/posix/path stuff mixed up and feel like this is crux of my issue getting photoshop to shut up and grab the dang file.

Ideas?

EDIT: the Tell Photoshop block begins:

tell application "Adobe Photoshop CS6"
			activate
			open file this_item showing dialogs never
			set docRef to the current document
			tell docRef
				set newFileName to my getBaseName(name)
				save in file newFileName as JPEG with options {class:JPEG save options, embed color profile:false, format options:optimized, quality:12} with extension without copying
			end tell
			close the current document saving no
		end tell

Hi,

this_item is an alias specifier.
Photoshop CS 6 works well with this syntax


	tell application "Adobe Photoshop CS6"
		open file (this_item as text)


For file conversion you can use also the built-in faceless application Image Events which is based on sips

http://www.macosxautomation.com/applescript/imageevents/08.html

Hi unklhefe,

My personal experience with batch images (I processed in last 15 years some millions of images) is that I allways use string paths because I can “assemble” them. Very very useful. I never use alias.

I always use HFS paths and in some case, for example when you get path using do shell script like LS, you have to coerce to Posix file as string like:

set imagePosixPath to "/Users/adminosx/Desktop/Marella_HARRY_alta.jpg"
set imageHFSPath to (imagePosixPath as POSIX file) as string

Latest version of Photoshop can works also with Posix path but I never use this syntax.

The syntax I use in Photoshop is

open file pathImmagine showing dialogs never
save current document in file hResPath as JPEG with options jpgOptions with copying

Stefano - AME

Success! Thanks, Stephan that’s all I needed! Now onto sorting, deleting and naming folders. I fear the REAL fun is going to be forcing recursion on Canon DPP to handle nested folders of my RAW files. SHould I kick open a new thread when I inevitably run into problems with that? Anyhow, thanks mucho to everyone! Lemme clean up my code a bit and I will post it here for posterity, as I’m sure there are other noobs who could use it.

Here she blows. All in all pretty simple stuff but it works exactly as I had hoped. I built this for Photoshop CS6 to run on OSX 10.6.8 using Applescript v2.1.2. it works as a drag/drop app. for both files and folders.

-- This droplet processes both files or folders of files dropped onto the applet.
--The input is expected to be uncompressed TIF(or TIFF) files and the output is a mix of compressed TIF and JPG files based on filenaming conventions (in my case:{_y,_t,_a} become JPG (deleting the source TIF file) and everything else gets LZW compressed TIFs)
--------------------------------
on open these_items
	
	repeat with i from 1 to the count of these_items
		set this_item to (item i of these_items)
		set the item_info to info for this_item
		if folder of the item_info is true then
			process_folder(this_item)
		else if (alias of the item_info is false) then
			process_item(this_item)
		end if
	end repeat
end open

-- this sub-routine processes folders
on process_folder(this_folder)
	set these_items to list folder this_folder without invisibles
	repeat with i from 1 to the count of these_items
		set this_item to alias ((this_folder as text) & (item i of these_items))
		set the item_info to info for this_item
		if folder of the item_info is true then
			process_folder(this_item)
		else if (alias of the item_info is false) then
			process_item(this_item)
		end if
	end repeat
end process_folder

-- this sub-routine processes files
on process_item(this_item)
	set the item_info to info for this_item
	set nam to the name of the item_info
	set dir to the POSIX path of (this_item as alias)
	if nam contains "_y" or nam contains "_t" or nam contains "_a" then
		
		tell application "Adobe Photoshop CS6"
			activate
			open file (this_item as text) showing dialogs never
			save current document in dir as JPEG with options {class:JPEG save options, embed color profile:false, format options:optimized, quality:12} appending lowercase extension without copying
			close the current document
		end tell
		tell application "Finder"
			delete this_item
		end tell
	else
		tell application "Adobe Photoshop CS6"
			activate
			open file (this_item as text) showing dialogs never
			save current document in dir as TIFF with options {class:TIFF save options, embed color profile:false, image compression:LZW, byte order:IBM PC}
			close the current document
		end tell
	end if
end process_item

AppleScript: 2.1.2
Browser: Chrome
Operating System: Mac OS X (10.6)

Hi unklhefe,

This is short recursive routine to extract all folders path giving an input folder as you requested.
In “pure” AppleScript. Probably there is equivalent in AppleScriptObjC…

property globalFoldersList : missing value

set globalFoldersList to {}
set folderPath to "Macintosh HD:Users:adminosx:Desktop:Test folder:"
recursiveCheck(folderPath)

globalFoldersList -- show like log the array that contains all folders path

on recursiveCheck(folderPathToCheck)
	tell application "Finder"
		set foldersList to {}
		set foldersList to (name of every folder of item folderPathToCheck)
	end tell
	set numFolder to count foldersList
	repeat with j from 1 to numFolder
		set newFolderPath to (folderPathToCheck & item j of foldersList & ":") as string
		copy newFolderPath to end of globalFoldersList
		recursiveCheck(newFolderPath)
	end repeat
end recursiveCheck

Stefano - Ame

Stefano

You are simply brilliant. I was mostly joking when I mentioned I would have a hard time with this, but literally as I was working on it, you came up with something much more elegant. Now correct me if I am wrong, but the variable “newFolderPath” is what I want to use as the new input for my script right? I also need to change the input from a specific path to the path of the dropped folder.

what I am currently working on is one step too “high” in the folder hierarchy to be able to handle a dropped folder full of folders, but handles a single folder just fine.

on open dropFolder
	repeat with x from 1 to the count of theseFolders
		set thisFolder to (item x of theseFolders)
		display dialog theseFolders
		set the folderInfo to info for thisFolder
		if folder of the folderInfo is false then
			display dialog "No Folders to Process"
		end if
		if folder of the folderInfo is true then
			jobFolder(thisFolder)
		end if
	end repeat
end open

your idea of making a list is really sweet because I can output that later as a log of “here are the folders that were processed” Should I just adapt your code to change the input?

A crushing blow… It would appear that Canon’s DPP software can’t handle more than one round through my script before locking up. Everything works fine then my script errors out on the next passthrough because DPP has become unresponsive (though not all the way to Finder recognizing it as “Not Responding”) It just stops taking any commands other than clicking on the window. Short of force-quitting every iteration I don’t know if this is going to be possible now. Here’s my code as it sits if anyone has any ideas as to what is happening, though I fear it is (as always in my experience) Canon’s software just being cruddy.

my Code (along with all the helps from everyone on this thread)

property globalFoldersList : missing value

set globalFoldersList to {}
set folderPathToCheck to "Macintosh HD:Users:USER:Desktop:RAWS:ALL JOBS:"
recursiveCheck(folderPathToCheck)

globalFoldersList -- show like log the array that contains all folders path

on recursiveCheck(folderPathToCheck)
	tell application "Finder"
		set foldersList to {}
		set foldersList to (name of every folder of item folderPathToCheck)
	end tell
	set numFolder to count foldersList
	repeat with j from 1 to numFolder
		set newFolderPath to (folderPathToCheck & item j of foldersList & ":") as string
		copy newFolderPath to end of globalFoldersList
		recursiveCheck(newFolderPath)
	end repeat
	
	repeat with x from 1 to the count of globalFoldersList
		set thisFolder to (item x of globalFoldersList)
		jobFolder(thisFolder)
	end repeat
end recursiveCheck

on jobFolder(thisFolder)
	launch application "Digital Photo Professional"
	tell application "Finder"
		set aFile to item 1 of folder thisFolder --to force DPP to browse into the folder
		set thePath to POSIX path of thisFolder as text
		set tifFolder to thePath & "TIFS"
		if not (exists folder "TIFS" of folder thisFolder) then
			do shell script "/bin/mkdir -p " & quoted form of POSIX path of tifFolder --make new TIF folder to save files in
		end if
		open aFile using application file "Digital Photo Professional.app" of folder "Digital Photo Professional" of folder "Canon Utilities" of folder "Applications" of startup disk
		
	end tell
	tell application "Digital Photo Professional"
		activate
	end tell
	
	tell application "System Events"
		tell process "Digital Photo Professional"
			
			delay 1
			keystroke "a" using command down
			delay 1
			keystroke "b" using command down
			perform action "AXPress" of button "Browse..." of group "Save folder" of window "Batch settings" of application process "Digital Photo Professional" of application "System Events"
			keystroke tifFolder
			delay 1
			key code 36
			
			delay 0.5
			perform action "AXPress" of button "Execute" of window "Batch settings" of application process "Digital Photo Professional" of application "System Events"
			
		end tell
	end tell
	-----------
	-- wait until the first job is done before processing the second
	--------
	tell application "Digital Photo Professional Batch"
		activate
		tell application "System Events"
			set window_check to false
			repeat until (window_check)
				if (process "Digital Photo Professional Batch" exists) then
					delay 1
				else
					set window_check to true
				end if
			end repeat
		end tell
	end tell
end jobFolder


I might have to get even deeper here and make a script to pull all of the files out of their folders, process them, then replace them back where they came from (each job {folder} from each client needs to stay separate)

/frustration

Why you use Canon DPP instead of Adobe Photoshop and Camera Raw?

Stefano - Ame

Hi unklhefe,

using Photoshop CS6 and Camera Raw you can use something like that:

set rawFilePath to "Macintosh HD:Users:adminosx:Desktop:nikon_d3x_08.nef"

tell application "Adobe Photoshop CS6"
	open file rawFilePath as Camera RAW with options {class:Camera RAW open options, bits per channel:eight, color space:Adobe RGB, resolution:254, white balance:as shot} showing dialogs never
end tell

You can control 27 parameters about Raw properties (White Balance, Color profile, Bit Depth…)

As always, even if you convert data to the profile that somebody want at the end, don’t strip it.
Always preserve color profile in images. For RGB is just few bytes. And when in the future anybody open your images, they can have right colorimetric perception of the colors.
Have you try to open portrait image (with skin) calculated for ProPhoto profile and not saved with profile on standard Photoshop with working profile set as sRGB?

Remember to always save profile. If somebody ask you to have images without profile, much probably he don’t know much about color management…
The bible is “Real World Color Management” of Bruce Fraser.

When image has it’s color profile, the image can be correctly repurposed:

RGB → RGB
RGB → CMYK
CMYK → CMYK
CMYK → RGB for web use

Without the source profile you have to assume a standard profile that will be assigned to pixels changing Lab values.
And in 80% of the cases, this can have disastrous impact on your photo’s.

Stefano - Ame

Stefano-

I really do appreciate the concern for the color profiles, but I promise I do have specific reasons for stripping them. This script is a bridge between the beginning of our process (the photography) and MANY other forms of processing before things hit our clients. We have editors, illustrators, designers etc. that use these images and apply profiles before they ultimately see the light of day. The need of a profile before they get pushed into a direction is non-existent and in fact detrimental because we have other automation/humans that take care of applying color space for the several different outputs that we have. We are an imaging company and color space is extremely integral to what we do. I was leaving most of those facts out because I didn’t see them as affecting the function of this script, but hey! now we know. :slight_smile:

Getting back to the scripting- Camera Raw VS DPP. Ugh this is a pain to explain, but here goes:

Our photographers have the need to shoot tethered to the computers (we each shoot several hundred images a day) and as we shoot, we rotate images, and use Canon specific RAW adjustments (i.e. lens correction, noise reduction, chromatic aberration etc.) as well as the stellar “Trim” tool; ALL in DPP. The problem is ACR does not understand the tags that Canon places in their RAW files regarding these adjustments. Anything we do as we shoot the file would get lost if we used ACR to process the .CR2 RAW file, as Canon doesn’t want anyone having the ability to access that data.

This is a huge problem for us. And while we can trim (crop) in ACR, and use all of aforementioned adjustments in ACR, that would require more work on the job of the photographers (i.e. stuff that DPP does automatically with no time spent), which is the OPPOSITE of what this script is trying to do. We would have to shoot first, THEN open each image in ACR and apply changes and crops that vary from job to job. Even batching, and using presets, this is adding more time than we currently spend. As it stands currently, we:

(shoot and trim>>batch process to TIFFs) in DPP and then (convert some to JPG and LZW compress others) in Photoshop.

This script is ATTEMPTING to take that entire process and wrap it into a neat little drag/drop application to be run at the end of the day, instead of PER JOB, as we are doing currently, which massively kills our productivity. As I said yesterday, now it would appear that DPP doesn’t like “System Events” telling it what to do. I hope that wall of text helps to better explain the frustration of hitting the proverbial “wall” with this script.

TL;DR - ACR can’t do everything we need it to, and even trying to get close, it will add time to the process. I wish it wasn’t so. I need to find a way to force DPP to NOT lock up on me, but I’m at a complete loss.