-- version 0.2a

-- © 2011 Jürgen Schell

-- No guarantee whatsoever.

-- Regard as training example

-- http://www.j-schell.de

-- Distribution allowed if the copyright remains intact


-- This script belongs to pages:

-- http://www.j-schell.de/node/477 (English)

-- http://www.j-schell.de/node/478 (Deutsch)


-- Purpose of this AppleScript:

-- Use Ghostscript to convert PDF. PostScript print jobs and EPS files to

-- bitmap files.

-- Script works as folder action script and should be copied to

-- /Library/Scripts/Folder Action Scripts/

-- Ghostscript executable is expected to be /usr/local/bin/gs


-- if other Ghostscript output devices are needed, check handler find_job


-- Changes February 2012

-- Changed code for renaming resulting file or folder in case of duplicate names.

-- Reason: Finder does not return proper error if renaming fails.


-- Added devides for PSD RGB and CMYK, and for separation


-- additional change:

-- Finder under late Snow Leopard does not create error messages any longer,

-- if renaming a file does not work. (Lion is fine.)

-- Changed the code for Snow Leopard to handle this.


property gsSettinglst : "/gs -dSAFER -q -dNOPAUSE -dBATCH -sDEVICE=?¿?device?¿? -sOutputFile=?¿?outfile?¿?  -r?¿?resolution?¿? ?¿?jpeg_quality?¿? -c?¿?add_opts?¿? -f ?¿?infile"

property standardGSPaths : "/usr/local/bin" -- standard paths for gs


property magic_bytes : {"%PDF-", "%!PS-Adobe", "≈–”∆"}


property out_folder : "Pictures"


property delete_processed_files : true





on adding folder items to theFolder after receiving theFiles

main_action(theFolder, theFiles)

end adding folder items to




on run

-- mainly for debugging

set f to choose file

tell application "System Events"

set theFolder to (path of (container of f))

end tell

set theFolder to alias theFolder

main_action(theFolder, {f})

end run


on main_action(theFolder, theFiles)

-- create out folder if it does not exist

tell application "System Events"

if not (exists folder out_folder of theFolder) then

set picture_folder to (make new folder at end of theFolder)

--try

set pos_path to (POSIX path of picture_folder)

-- Make folder localized. Since "Pictures" is known to the Finder, it will result in localized display

set cmd to ("cd " & quoted form of pos_path) & "; " & "touch '.localized'"

do shell script cmd

--end try

set name of picture_folder to out_folder

end if

set picture_folder to (folder out_folder of theFolder)

set f_name to name of theFolder

end tell

set job_values to find_job(f_name)

--log job_values

-- process list of files

repeat with X from 1 to count theFiles

-- handle a single file

set curr to item X of theFiles

-- check for magic bytes

if my check_magic(curr) then -- that is: file can be handled

-- create temporary folder

-- It will be kept if more than one file is created.

-- Else it will be deleted later.

-- note that the number of files created can not be known in advance.

-- PDF files and print jobs may have several pages, resulting in several

-- bitmap files.

-- Since I do not know before, output is always created in a new folder.

-- The situation will be corrected afterwards, depending on the resulting situation.

tell application "System Events"

set temp_folder to (make new folder at end of picture_folder)

set temp_folder_path to path of temp_folder

set out_path to (POSIX path of temp_folder) & "/"

set picture_folder_path to path of picture_folder

end tell

-- prepare paths for Ghostscript command line

set file_name_original to my clean_name(curr)

set file_name to my escape_percent(file_name_original) -- masking % signs

set file_name to file_name & " %03d" -- have Ghostscript number the pages

set input_posix_path to POSIX path of curr

set output_posix_path to out_path & file_name & (suffix of job_values)

set input_posix_path to quoted form of input_posix_path

set output_posix_path to quoted form of output_posix_path

-- set up the Ghostscript command line

set currCommand to gsSettinglst

set currCommand to textReplace(currCommand, "?¿?infile", input_posix_path) -- setting input file

set currCommand to textReplace(currCommand, "?¿?outfile?¿?", output_posix_path) -- setting name and path for output file(s)

set currCommand to textReplace(currCommand, "?¿?resolution?¿?", (resolution of job_values) as string) -- set dpi

set currCommand to textReplace(currCommand, "?¿?device?¿?", format of job_values) -- set output device (i.e. the output format)

if (format of job_values) = "jpeg" then -- set quality value if format is jpeg

set currCommand to textReplace(currCommand, "?¿?jpeg_quality?¿?", "-dJPEGQ=" & (quality of job_values) as string)

else

set currCommand to textReplace(currCommand, "?¿?jpeg_quality?¿?", "")

end if

-- activate crop according to bounding box comment, if in file is EPSF

if check_epsf(curr) then

set currCommand to textReplace(currCommand, "?¿?add_opts?¿?", " -dEPSCrop")

else

set currCommand to textReplace(currCommand, "?¿?add_opts?¿?", "")

end if

set currCommand to standardGSPaths & currCommand

-- command line is ready here

--log currCommand

try

do shell script currCommand

log currCommand

if delete_processed_files then

tell application "Finder"

delete curr

end tell

end if

on error theError number theNum

if theNum ≠ -128 then -- i.e. not user cancelled

display dialog theError

end if

end try

-- the job may have produced one or more picture files, depending on the input file

-- Now we start to reshuffle names and folders depending on result.

-- if more than one file was created, keep folder and rename it, according to imput file name

-- else: move file to picture folder and rename it, delete the temp folder

tell application "Finder"

--try

set file_list to (files of temp_folder)

set fc to (count file_list)

if fc > 1 then -- more than one file has been created

-- That is: File names in the folder are OK, but the temporary folder should be kept and must get a nice but unique name

set new_path to picture_folder_path & file_name_original

if not (my change_name(folder temp_folder_path, file_name_original)) then

set ds to my date_string()

set new_folder_name to file_name_original & " " & ds

set new_path to picture_folder_path & new_folder_name

if not (my change_name(folder temp_folder_path, new_folder_name)) then

-- if failed still, add a number, give up after 100

-- in real life, this case should never happen

repeat with J from 1 to 100

set new_folder_name to file_name_original & " " & ds & " " & J

set new_path to picture_folder_path & new_folder_name

if (my change_name(folder temp_folder_path, new_folder_name)) then

exit repeat

end if

end repeat -- counting up numbers for unique folder name

end if

end if -- renaming. If anything faild, the default name  will remain

-- (that is simething like "untitled folder"

else -- case, only one file has been created.

-- The one file should be moved up one level into the picture folder.

-- It should get a nice but unique name.

-- The temporary folder should be deleted

set result_file to file 1 of temp_folder

set name of result_file to my unique() -- this is a UUID which should be unique for sure

set result_file to file 1 of temp_folder

tell application "System Events"

set result_file_path to (path of result_file)

end tell

set result_file to (move file result_file_path to folder picture_folder_path)

delete folder temp_folder_path

-- renaming strategy is basically the same as for the folder case before

set new_name to (file_name_original & (suffix of job_values))

set new_path to picture_folder_path & new_name

if not (my change_name(result_file, new_name)) then

-- if name exists, add string for current date and time

set ds to my date_string()

--set ds to "-" -- test

set new_name to (file_name_original & " " & ds & (suffix of job_values))

set new_path to picture_folder_path & new_name

if not (my change_name(result_file, new_name)) then

-- if this name exists as well, add a number. Give up after 100

-- in real life, this case should never happen

repeat with J from 1 to 100

set new_name to (file_name_original & " " & ds & "-" & J & (suffix of job_values))

set new_path to picture_folder_path & new_name

if (my change_name(result_file, new_name)) then

exit repeat

end if

end repeat -- counting up numbers for file name

end if

end if -- renaming file. If everything failed, the name would still be the UUID

end if -- multipe file vs. one file cases

--end try

end tell

end if -- magic bytes were OK

end repeat

end main_action




--======================================


on clean_name(file_ref)

-- remove suffix from name

tell application "System Events"

set f_name to name of file_ref

set f_suffix to (name extension of file_ref)

end tell

if f_suffix is not "" then

set suffix_length to (length of f_suffix) + 2

set f_name to characters 1 thru (suffix_length * -1) of f_name as text

end if

return f_name

end clean_name


--======================================



on textReplace(mainText, fromText, toText)

set oldDelims to AppleScript's text item delimiters

set AppleScript's text item delimiters to {fromText}

set textList to every text item of mainText

set AppleScript's text item delimiters to {toText}

set mainText to textList as text

set AppleScript's text item delimiters to oldDelims

return mainText

end textReplace


--======================================


on check_magic(file_ref)

-- several types of files like EPS, PDF start

-- with a certain byte sequence to allow for an identification

-- of the file type

-- requires property or global magic_bytes

set check_strg to "xxxxxxxxxx"

try

set fh to open for access file_ref

set check_strg to (read fh from 1 to 12)

end try

try

close fh

end try

repeat with X from 1 to count magic_bytes

if (offset of (item X of magic_bytes) in check_strg) = 1 then

return true

end if

end repeat

return false

end check_magic


--======================================


on check_epsf(file_ref)

-- check for EPSF at beginning of file

set r to false

set check_strg to "xxxxx"

try

set fh to open for access file_ref

set check_strg to (read fh from 1 to 100)

end try

try

close fh

end try

if check_strg contains "EPSF" then

set r to true

end if

return r

end check_epsf


--======================================


on date_string()

set now to current date

return (((year of now) as string) & "-" & pad_2((month of now) as integer) ¬

& "-" & pad_2(day of now) & "T" & pad_2(hours of now) & "-" & pad_2(minutes of now) & "-" & pad_2(seconds of now))

end date_string


--======================================


on pad_2(num)

set num to num + 100

return ((characters 2 thru 3 of (num as text)) as text)

end pad_2


--======================================


on escape_percent(the_string)

-- Percent signs must be escaped in output

-- file name since they start the page numbering

-- specification for PDFs with several pages.

set old_delims to AppleScript's text item delimiters

set AppleScript's text item delimiters to "%"

set tl to every text item of the_string

set AppleScript's text item delimiters to "%%"

set r to tl as string

set AppleScript's text item delimiters to old_delims

return r

end escape_percent


--======================================


on find_job(arg)

-- defaults for missing values

set format to "pngalpha" -- Ghostscript output device

set resolution to 72 -- dpi of resulting image

set suffix to ".png" -- suffix used for output file name

set jpeg_quality to 75 -- JPEG quality

-- If new output devices need to be added, change the following three lists consistently

-- Note that the handling of CMYK tiffs is done in extra code below

set formats_in to {"separation", "png", "tiff", "tif", "jpeg", "jpg", "psd"} -- these are the format markers understood in the folder name

set formats_out to {"tiffsep", "pngalpha", "tiff24nc", "tiff24nc", "jpeg", "jpeg", "psdrgb"} -- these are the corresponding Ghostscript output devices

set suffixes to {".tiff", ".png", ".tiff", ".tiff", ".jpeg", ".jpeg", ".psd"} -- these are the suffixes used for the resulting output files

set parts to every word of arg

set num_vals to {}

repeat with X from 1 to count parts

set curr to item X of parts

-- extracting sequences of digits

try

set the_val to curr as integer

copy the_val to end of num_vals

end try

end repeat

-- checking for requested forma

repeat with X from 1 to count formats_in

set curr to item X of formats_in

if parts contains curr then

set format to item X of formats_out

set suffix to item X of suffixes

end if

end repeat

-- Handle case of CMYK tiff / psd

if (parts contains "cmyk") and (format = "tiff24nc") then

set format to "tiff32nc"

end if

if (parts contains "cmyk") and (format = "psdrgb") then

set format to "psdcmyk"

end if

-- extract resolution value and JPEG quality from digit sequences

if (count num_vals) > 0 then

set resolution to item 1 of num_vals -- first sequence of digits

end if

if (count num_vals) > 1 then

set jpeg_quality to item -1 of num_vals -- last sequence of digits

end if

return {resolution:resolution, format:format, suffix:suffix, quality:jpeg_quality}

end find_job



--======================================


on unique()

set r to (do shell script "uuidgen")

return r

end unique



--======================================


on change_name(file_ref, new_name)

-- This handler has been introduced

-- after Apple broke error messages in Finder

-- in Snow Leopard

-- Can hopefully be changed when

-- Snow Leopard withered away.

tell application "Finder"

set d to (name of file_ref) as text

set f to (container of file_ref) as text

-- check if file / folder exists already

try

file f & new_name

return false

end try

try

folder f & new_name

return false

end try

-- try the renaming

try

set name of file (f & d) to new_name

end try

try

set name of folder (f & d) to new_name

end try

-- check if old name is gone

try

file (f & d)

return false

end try

try

folder (f & d)

return false

end try

return true

end tell

end change_name