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