Got some time on your hands? then maybe you can help me!!
Here is a script that I’ve been working on and would like some feed back (no insults please this is my first attempt at doing a script for someone else to use).
It should use an image file to posterize and an illustrator file containing symbols (the order of which is based from darkest parts of image top symbol down to lightest bottom symbol. I used a transparent square box behind the art of each symbol. Most of how this is supposed to work you can see from the code.
Where I need help is finding where I can either speed things up & error handling. It is slow so avoid trying anything but smaller images. Who knows you may be rewarded with a nice poster graphic for your efforts. Thanks.
tell application "Illustrator CS"
activate
set user interaction level to interact with all
--
if (count of documents) is less than 1 then
set noDoc to "You have no Illustrator file open" & return & "do you want to find it?"
set FindDoc to display dialog noDoc buttons {"Cancel", "Find it"} default button 2 with icon note
if button returned of FindDoc is "Find it" then
set theFile to choose file with prompt "Please locate the file you want to be used" without invisibles
tell application "Finder"
set theFile to theFile as alias
end tell
tell application "Illustrator CS"
open theFile
end tell
end if
end if
set docRefA to the current document
tell docRefA
if (count of symbols) is less than 2 then
display dialog "Your document needs at least" & return & ¬
"2 symbols to create a pattern." buttons {"Cancel"} default button 1
end if
if (count of symbols) is greater than 64 then
display dialog "This script only works with" & return & ¬
"upto 64 symbols to create a pattern." buttons {"Cancel"} default button 1
end if
set pageWidth to get width
set pageHeight to get height
set ROx to pageWidth / 2
set ROy to pageHeight / 2
set ruler origin to {ROx, ROy}
make new layer at beginning of docRefA with properties ¬
{name:"Symbols Test", visible:true}
make new symbol item at beginning of layer "Symbols Test" with properties ¬
{symbol:symbol 1, position:{0, 0}}
set Symbol_x to width of page item 1
set Symbol_y to height of page item 1
set Symbol_1x to Symbol_x as integer
set Symbol_1y to Symbol_y as integer
if Symbol_1x ≠Symbol_1y then
display dialog "Your symbols are not defined" & return & ¬
"using a square box." & return & ¬
"The trick is to use a transparent" & return & ¬
"square box behind each one." buttons {"Cancel"} default button 1
end if
--
repeat with a from 2 to (count of symbols)
make new symbol item at beginning of layer "Symbols Test" with properties ¬
{symbol:symbol a, position:{0, 0}}
set Symbol_2x to width of page item 1 as integer
set Symbol_2y to height of page item 1 as integer
if Symbol_1x ≠Symbol_2x or Symbol_1y ≠Symbol_2y then
display dialog "Your symbols are not" & return & ¬
"of an equal size." buttons {"Cancel"} default button 1
end if
delete page item 1
end repeat
delete layer named "Symbols Test"
display dialog "Your symbols passed the basic size tests" giving up after 2
--
set OldLayers to count of layers
set properties of every layer to {visible:false}
--
set MySymbols to get count of symbols
repeat with b from 1 to MySymbols
set SymbolName to get name of symbol b as string
set LayerName to SymbolName & " Layer" as string
make new layer at end of docRefA with properties {name:LayerName, visible:true}
end repeat
end tell
end tell
--
tell application "Adobe Photoshop CS"
activate
set display dialogs to never
set UserPrefs to properties of settings
set ruler units of settings to pixel units
--
if (count of documents) is less than 1 then
set noDoc to "You have no Photoshop image open" & return & "do you want to find it?"
set FindDoc to display dialog noDoc buttons {"Cancel", "Find it"} default button 2 with icon note
if button returned of FindDoc is "Find it" then
set theFile to choose file with prompt "Please locate the image you want to be used" without invisibles
tell application "Finder"
set theFile to theFile as alias
end tell
tell application "Adobe Photoshop CS"
open theFile
end tell
end if
end if
set docRefB to the current document
tell docRefB
repeat
set TheTiles to display dialog "How many tiles do you want" & return & ¬
"to use when making this mosaic?" default answer "400" with icon note
try
set HowMany to (text returned of TheTiles) as integer
exit repeat
on error
display dialog "Integers only please!" with icon caution
end try
end repeat
if HowMany ≤ 500 then
display dialog "Have a break." & return & "Go put the kettel on" & return & ¬
"make a nice cup of tea!!!" buttons {"Cancel", "Continue"} default button 2 with icon note
end if
if (HowMany > 500) and (HowMany ≤ 2500) then
display dialog "Go for lunch this may take some" & return & ¬
"time, say no to McDonalds." & return & ¬
"This script was given to you by a veggie!!!" buttons {"Cancel", "Continue"} default button 1 with icon note
end if
if HowMany > 2500 then
display dialog "You would be better off investing" & return & ¬
"in a plug-in to do this kind of thing" buttons {"Cancel", "Continue"} default button 1 with icon note
end if
if (mode is not grayscale) then
change mode to grayscale
end if
if (bits per channel is sixteen) then
set bits per channel to eight
end if
if (count of art layers) > 1 or (count of layer sets) > 0 or ((count of art layers) is 1 and not background layer of layer 1) then flatten
set docHeight to height
set docWidth to width
set pixelWidth to ((docWidth * HowMany / docHeight) ^ 0.5) as integer
set pixelHeight to (docHeight * pixelWidth / docWidth) as integer
resize image height pixelHeight width pixelWidth resolution 72
adjust layers using posterize with options ¬
{class:posterize, level:MySymbols}
end tell
end tell
--
set theLevels to {0}
--
set thesplit to 255 / (MySymbols - 1)
repeat with c from 1 to (MySymbols - 1)
set the end of theLevels to (thesplit * c) div 1
end repeat
--
repeat with d from 1 to pixelHeight
set theValues to {}
tell application "Adobe Photoshop CS"
activate
tell docRefB
repeat with e from 1 to pixelWidth
select region {{e - 1, d - 1}, {e, d - 1}, {e, d}, {e - 1, d}}
set f to histogram of channel "Gray"
set theGray to {}
repeat with g from 1 to (count of theLevels)
set h to (item g of theLevels) as number
if item (h + 1) of f is 1 then
set theGray to g
end if
end repeat
copy (theGray as number) to end of theValues
deselect
end repeat
end tell
end tell
--
tell application "Illustrator CS"
activate
tell docRefA
set ROx to -((pixelWidth * Symbol_x) / 2) + (pageWidth / 2)
set ROy to ((pixelHeight * Symbol_y) / 2) + (pageHeight / 2)
set ruler origin to {ROx, ROy}
repeat with i from 1 to pixelWidth
set j to (item i of theValues) as number
make new symbol item at beginning of layer (j + OldLayers) with properties ¬
{symbol:symbol j, position:{0 + (Symbol_x * (i - 1)), 0 - (d * Symbol_y)}}
end repeat
end tell
end tell
end repeat
--
tell application "Adobe Photoshop CS"
set ruler units of settings to ruler units of UserPrefs
close docRefB saving no
end tell
--
tell application "Illustrator CS"
activate
beep 3
display dialog "All done. You may want to save this!!!" & return & ¬
"Sorry not able to resize the page" buttons {"Cancel"} default button 1
end tell
Hey Mark - I didn’t try running your script yet - but I do a lot of Adobe Applescripting (mainly Indesign and Pshop) and thought I could offer a little feedback.
For example - I notced that you are tell(ing) Illustrator in a few places - where you are already inside of an Illustrator tell, and telling the finder to do things that you don’t have to tell the Finder to do.
ie:
[applescript tell application “Finder”
set theFile to theFile as alias
end tell
tell application “Illustrator CS”
open theFile
end tell
you can simply do this in place of those 6 lines - becasue you are already in the Illustrator tell block.
set theFile to choose file with prompt "Please locate the file you want to be used" without invisibles
open theFile
another quick thing although this sometimes makes scripts harder to follow.
ie: instead of:
set pageWidth to get width
set pageHeight to get height
set ROx to pageWidth / 2
set ROy to pageHeight / 2
try:
set ROx to (width / 2)–or maybe set ROx to (get width / 2)
set ROy to (height / 2)
I have CS2 - so this might not work with CS - but I think if you went through the script and did a few of these things - you might get a little speed back, individually they are nothing, but collectively might add up to something.
Just my 2 cents, it really looks like a great script though.
Chris
Chris, thanks. I think I see what you mean about the finder bit that would be for making a list item to alias but I have no lists just file. I do tend to over word a few things too. I will run through and try some tidying. What I have yet to understand is if pulling this apart to be performed by sub routines has any difference on how this script may preform or if in this case it would be of no advantage. Do sub routines operate any faster or are they just for a better way to just assign certain tasks on request. On a side note I have just downloaded iMaginePhoto to see what I can do with this if any thing but thats for another day.
Mark - as far as adding subroutines, It really depends I guess, but for the most part I don’t think speed is what you gain with them, mainly portability, and repetition. You can create cleaner scripts with them, which makes them shorter and sometimes easier to read. Sometimes I think they make things more confusing though actually.
The best way to speed up a script is to limit the calls to a program to the bare miinimum to get the job done. I don’t think that handlers will speed up your script, the main reasons to use them is to organize you scripts for reusable code. The main thing that I can see that is slowing your script down is the selection and histogram calls to photoshop, and I don’t think that you can speed that up without a faster processor. From looking at it a little this is my attempt at gaining a bit of speed:
set TheTime to current date
tell application "Adobe Illustrator"
activate
set user interaction level to interact with all
--
if (count of documents) is less than 1 then
set FindDoc to display dialog ("You have no Illustrator file open" & return & "do you want to find it?") buttons {"Cancel", "Find it"} default button 2
if button returned of FindDoc is "Find it" then
set theFile to (choose file with prompt "Please locate the file you want to be used" without invisibles) as alias
open theFile
end if
end if
set docRefA to the current document
tell docRefA
set MySymbols to get count of symbols
if MySymbols is less than 2 then
display dialog "Your document needs at least" & return & ¬
"2 symbols to create a pattern." buttons {"Cancel"} default button 1
end if
if MySymbols is greater than 64 then
display dialog "This script only works with" & return & ¬
"upto 64 symbols to create a pattern." buttons {"Cancel"} default button 1
end if
copy {width, height} to {pageWidth, pageHeight}
set ROx to pageWidth / 2
set ROy to pageHeight / 2
set ruler origin to {ROx, ROy}
make new layer at beginning of docRefA with properties ¬
{name:"Symbols Test", visible:true}
make new symbol item at beginning of layer "Symbols Test" with properties ¬
{symbol:symbol 1, position:{0, 0}}
set Symbol_x to width of page item 1
set Symbol_y to height of page item 1
set Symbol_1x to Symbol_x as integer
set Symbol_1y to Symbol_y as integer
if Symbol_1x ≠Symbol_1y then
display dialog "Your symbols are not defined" & return & ¬
"using a square box." & return & ¬
"The trick is to use a transparent" & return & ¬
"square box behind each one." buttons {"Cancel"} default button 1
end if
--
repeat with a from 2 to MySymbols
make new symbol item at beginning of layer "Symbols Test" with properties ¬
{symbol:symbol a, position:{0, 0}}
set Symbol_2x to width of page item 1 as integer
set Symbol_2y to height of page item 1 as integer
if Symbol_1x ≠Symbol_2x or Symbol_1y ≠Symbol_2y then
display dialog "Your symbols are not" & return & ¬
"of an equal size." buttons {"Cancel"} default button 1
end if
delete page item 1
end repeat
delete layer named "Symbols Test"
--display dialog "Your symbols passed the basic size tests" giving up after 2
--
set OldLayers to count of layers
set properties of every layer to {visible:false}
--
repeat with b from 1 to MySymbols
set SymbolName to get name of symbol b as string
set LayerName to SymbolName & " Layer" as string
make new layer at end of docRefA with properties {name:LayerName, visible:true}
end repeat
end tell
end tell
--
tell application "Adobe Photoshop CS2"
activate
set display dialogs to never
set UserPrefs to properties of settings
set ruler units of settings to pixel units
--
if (count of documents) is less than 1 then
set FindDoc to display dialog ("You have no Photoshop image open" & return & "do you want to find it?") buttons {"Cancel", "Find it"} default button 2
if button returned of FindDoc is "Find it" then
set theFile to (choose file with prompt "Please locate the image you want to be used" without invisibles) as alias
open theFile
end if
end if
set docRefB to the current document
tell docRefB
repeat
set TheTiles to display dialog "How many tiles do you want" & return & ¬
"to use when making this mosaic?" default answer "400" with icon note
try
set HowMany to (text returned of TheTiles) as integer
exit repeat
on error
display dialog "Integers only please!" with icon caution
end try
end repeat
if HowMany ≤ 500 then
display dialog "Have a break." & return & "Go put the kettel on" & return & ¬
"make a nice cup of tea!!!" buttons {"Cancel", "Continue"} default button 2 with icon note
end if
if (HowMany > 500) and (HowMany ≤ 2500) then
display dialog "Go for lunch this may take some" & return & ¬
"time, say no to McDonalds." & return & ¬
"This script was given to you by a veggie!!!" buttons {"Cancel", "Continue"} default button 1 with icon note
end if
if HowMany > 2500 then
display dialog "You would be better off investing" & return & ¬
"in a plug-in to do this kind of thing" buttons {"Cancel", "Continue"} default button 1 with icon note
end if
if (mode is not grayscale) then
change mode to grayscale
end if
if (bits per channel is sixteen) then
set bits per channel to eight
end if
if (count of art layers) > 1 or (count of layer sets) > 0 or ((count of art layers) is 1 and not background layer of layer 1) then flatten
set docHeight to height
set docWidth to width
set pixelWidth to ((docWidth * HowMany / docHeight) ^ 0.5) as integer
set pixelHeight to (docHeight * pixelWidth / docWidth) as integer
resize image height pixelHeight width pixelWidth resolution 72
adjust layers using posterize with options ¬
{class:posterize, level:MySymbols}
end tell
end tell
--
set theLevels to {0}
--
set thesplit to 255 / (MySymbols - 1)
repeat with c from 1 to (MySymbols - 1)
set the end of theLevels to (thesplit * c) div 1
end repeat
--
tell application "Adobe Photoshop CS2"
activate
tell docRefB
set TheGrid to {}
repeat with d from 1 to pixelHeight
set theValues to {}
repeat with e from 1 to pixelWidth
select region {{e - 1, d - 1}, {e, d - 1}, {e, d}, {e - 1, d}}
set f to histogram of channel "Gray"
set theGray to {}
repeat with g from 1 to (count of theLevels)
set h to (item g of theLevels) as number
if item (h + 1) of f is 1 then
set theGray to g
end if
end repeat
copy (theGray as number) to end of theValues
deselect
end repeat
copy theValues to end of TheGrid
end repeat
end tell
end tell
tell application "Adobe Illustrator"
activate
tell docRefA
set ROx to -((pixelWidth * Symbol_x) / 2) + (pageWidth / 2)
set ROy to ((pixelHeight * Symbol_y) / 2) + (pageHeight / 2)
set ruler origin to {ROx, ROy}
repeat with d from 1 to count of TheGrid
repeat with i from 1 to count of item d of TheGrid
set j to (item i of item d of TheGrid) as number
make new symbol item at beginning of layer (j + OldLayers) with properties ¬
{symbol:symbol j, position:{0 + (Symbol_x * (i - 1)), 0 - (d * Symbol_y)}}
end repeat
end repeat
end tell
end tell
set TotalTime to (current date) - TheTime
display dialog TotalTime
The main thing that I did was to build a nested list for the all the values taken from the photoshop file and then bring the list into Illustrator and draw it all at once instead of switching between applications. Other observations are that it appears to run a lot faster from Script editor (about 1/3 the time on a value of 50) than as an application bundle or a script launced from the Illustrator menue. It might be worth it to look into builing it into an AppleScript Studio application, but if it were me I would just run it from Script Editor.