Updating script from AppleWorks to Pages...

I used to use AppleWorks for running the below script, but have since switched to Pages. I would like to know how to adapt this script to work with Pages as AppleWorks is sludge on OSX. When I change the application name to Pages.app from AppleWorks 6, I get a syntax error: “Can’t get number of characters. Access not allowed.” This is the pertinent part of the script:

tell application "AppleWorks 6"
	activate
	tell text body of front document
		set characterCount to number of characters
		set n to characterCount div 10
		set x to 1
		repeat with i from x to n + 1
			set font of character x to "MICHAEL-01"
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else

Then the script just goes on substituting fonts until character count shuts it down. Anyone out there who could give me a simple answer (and it has to be simple, because I sure am) of how to adapt this, you’d make me mighty happy…

Hi, flynnius.

tell application "Pages"
	activate
	tell body text of front document
		set characterCount to length
		if (n > 0) then set font name of (characters 1 thru (characterCount div 10 + 1)) to "MICHAEL-01"
	end tell
end tell

The Code Exchange forum is for posting working code that you want to share. I’ll see if I can get one of the administrators to transfer this to AppleScript | Mac OS X.

Hi Nigel,

Thank you so much for your help. I may have miscommunicated in my last post, or rather not communicated enough.

In an effort to remedy that I have pasted the entire script below so that you can comprehend the purpose better; the purpose being to effectively “randomize” the appearance fifteen variations of a font of my own handwriting (which I also built). The script used to work like gangbusters in AppleWorks, but alas that app is not with us any longer. The script should assign a different variation to each letter, in turn, of any text.

Once we get to the line: “repeat with i from x to n + 1” without an error, I think I’ll be home free.

Sadly I was not able to incorporate your idea into the script successfully - I think because I did not show you the whole script; because in my simplemindedness I did not think it would be necessary…

Forgive me, and thank you in advance for any help you can give-
-Michael Flynn AKA flynnius

tell application "AppleWorks 6"
	activate
	tell text body of front document
		set characterCount to number of characters
		set n to characterCount div 10
		set x to 1
		repeat with i from x to n + 1
			set font of character x to "MICHAEL-01"
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-02"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-03"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-04"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-06"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-07"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-08"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-09"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-10"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-11"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-12"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-13"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-14"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			else
				set font of character x to "MICHAEL-15"
			end if
			set x to (x + 1)
			if x > characterCount then
				exit repeat
			end if
		end repeat
	end tell
end tell

Hello

(1) you missed to look at the Pages AppleScript’s dictionary which state that was was ‘number of characters’ in AppleWorks is ‘count of characters’ in Numbers.

(2) you are facing an error in the dictionary which states :

font (text) : The name of the font of the first character.

when it would be

font name (text) : The name of the font of the first character.


tell application "Pages" to tell document 1
	set characterCount to count of characters
	--> 944
	properties of character 12
	(*
	--> {text indent:0.0, 
collapsed:false, 
underline color:missing value, 
strikethrough color:missing value, 
paragraph style:paragraph style "Format libre" of document id 1679709, 
color:{9766, 9766, 9766}, 
number label tiered:false, 
class:Unicode text, 
prevent widows and orphans:true, 
subscript:false, character style:missing value, 
list style:list style "Aucun" of document id 1679709, 
superscript:false, 
label type:none, 
space before:0.0, 
remove hyphenation:false, 
line spacing:1.0, 
baseline shift:0.0, 
shadow:false, 
label indent:0.0, 
contents:"s", 
label baseline shift:0.0, 
scale with text:true, 
italic:false, 
first line indent:0.0, 
shadow offset:missing value, 
shadow color:missing value, 
following paragraph style:missing value, 
font size:12.0, 
capitalization type:normal capitalization, 
space after:0.0, 
label size:1.0, 
left indent:0.0, 
length:1, 
character background color:missing value, 
indent level:1, 
label image data:missing value, 
right indent:0.0, 
shadow angle:missing value, 
number label style:number paren zero, 
paragraph background color:missing value, 
text label string:missing value, 
keep with next paragraph:false, 
underline type:none, 
bold:false, 
alignment:left, 
shadow opacity:missing value, 
character offset:12, 
shadow blur:missing value, 
start new page:false, 
line spacing type:relative, 
ligatures:default ligatures, 
outline:false, 
hidden:false, 
keep lines together:false, 
font name:"ArialMT", 
strikethrough type:none, 
containing page:page 1 of document id 1679709, 
tracking:0.0}
*)
	set font name of character 12 to "Helvetica"
end tell

Yvan KOENIG (VALLAURIS, France) mercredi 14 décembre 2011 09:24:49

Hi,

try


property fontList : {}

-- populate fontList (MICHAEL-01 to MICHAEL-15)
repeat with i from 1 to 15
	set end of fontList to "MICHAEL-" & text -2 thru -1 of ("0" & i)
end repeat

tell application "Pages"
	activate
	tell body text of front document
		set characterCount to length
		repeat with i from 1 to (characterCount div 10 + 1)
			set font name of character i to some item of fontList
		end repeat
	end tell
end tell

I tested with fonts available on my machine.

stephanK’s code which apply fonts randomly treats only a subset of the document

Here I treat the entire document like the OP’s code and apply fonts in the designed order.


set les_polices to {"Bodoni SvtyTwo OS ITC TT", "Book Antiqua", "Bradley Hand ITC TT", "Calibri", "Handwriting - Dakota", "Candara", "Candela", "Jazz LET", "Century Gothic", "Chalkboard", "Zapfino", "Marker Felt", "Cochin", "Zapf Chancery", "Comic Sans MS"}
set nbf to count les_polices

tell application "Pages"
	activate
	tell front document
		set characterCount to count of characters
		set x to 1
		repeat (characterCount div nbf) times
			repeat with f from 1 to nbf
				set font name of character x to item f of les_polices
				set x to (x + 1)
				if x > characterCount then exit repeat
			end repeat
			if x > characterCount then exit repeat
		end repeat
	end tell
end tell

Yvan KOENIG (VALLAURIS, France) mercredi 14 décembre 2011 10:54:36

Oops, There was an extraneous space character at the end of a font name “Comic Sans MS”.
I removed it.

Well spotted, Yvan. Looking at Michael’s complete script more closely, the ‘div 10’ is entirely superflous, perhaps left over from a time when he only used ten fonts.

The simplest way to write the script would be:


set fontNames to {"MICHAEL-01", "MICHAEL-02", "MICHAEL-03", "MICHAEL-04", "MICHAEL-05", "MICHAEL-06", "MICHAEL-07", "MICHAEL-08", "MICHAEL-09", "MICHAEL-10", "MICHAEL-11", "MICHAEL-12", "MICHAEL-13", "MICHAEL-14", "MICHAEL-15"}
set fontCount to count fontNames

tell application "Pages"
	activate
	tell body text of front document
		set characterCount to length
		repeat with x from 1 to characterCount
			set font name of character x to item ((x - 1) mod fontCount + 1) of fontNames
		end repeat
	end tell
end tell

But this is quite slow. It turns out to be quite a lot faster to concentrate on one font at a time, which presumably saves Pages some behind-the-scenes switching:


set fontNames to {"MICHAEL-01", "MICHAEL-02", "MICHAEL-03", "MICHAEL-04", "MICHAEL-05", "MICHAEL-06", "MICHAEL-07", "MICHAEL-08", "MICHAEL-09", "MICHAEL-10", "MICHAEL-11", "MICHAEL-12", "MICHAEL-13", "MICHAEL-14", "MICHAEL-15"}
set fontCount to count fontNames

tell application "Pages"
	activate
	tell body text of front document
		set characterCount to length
		repeat with i from 1 to fontCount
			set fontName to item i of fontNames
			repeat with x from i to characterCount by fontCount
				set font name of character x to fontName
			end repeat
		end repeat
	end tell
end tell

By the way, with regard to ‘count’, it’s a command, not a property, so ‘count of’’ is incorrect.

tell application "Pages"
	tell body text of front document
		set characterCount to (count characters)
		-- Or:
		set characterCount to (count each character)
	end tell
end tell

Faster still, apply the first font to the whole document instead of iterating through the individual characters: :slight_smile:


set fontNames to {"MICHAEL-01", "MICHAEL-02", "MICHAEL-03", "MICHAEL-04", "MICHAEL-05", "MICHAEL-06", "MICHAEL-07", "MICHAEL-08", "MICHAEL-09", "MICHAEL-10", "MICHAEL-11", "MICHAEL-12", "MICHAEL-13", "MICHAEL-14", "MICHAEL-15"}
set fontCount to count fontNames

tell application "Pages"
	activate
	tell body text of front document
		set characterCount to length
		set font name to item 1 of fontNames -- Set the whole document to the first font.
		repeat with i from 2 to fontCount -- Then do the remaining fonts for the individual characters.
			set fontName to item i of fontNames
			repeat with x from i to characterCount by fontCount
				set font name of character x to fontName
			end repeat
		end repeat
	end tell
end tell

I am overwhelmed by the help you Nigel and you Yvan have given to me. Your scripts are SO much more elegant and sophisticated than mine. I’m afraid that my shallow knowledge is all too apparent. I taught myself applescript only enough to do this project and started that in my late fifties with no previous coding experience - so I trust you will overlook my lack of sophistication. You guys are obviously “rock stars” at this.

I have been trying out your variations and have come to a conclusion regarding the speed of the script: I don’t think it has to do with the sampling of characters (either in sequence or by font) or the “count”/“length” issue. But rather the key factor seems to be the number of fonts themselves. In other words, I found that using any more than eight fonts produced a marked slow-down of the script run. It didn’t matter if the number of fonts was 9 or 19, it would go from running at a speed of 100 characters per second to less than 20. Also, once the total number of characters processed passed approximately 1000 the script would run even slower - regardless of the number of fonts accessed by the script. By the time it had processed 1000 characters the script was running at about 40-50% of it’s starting speed.

If you’d like to keep working on this slowing problem (which is probably due to memory usage in Pages, I suspect) I would be thrilled, but the script runs well enough now to exceed any expectations I had. If there was a way to use only eight fonts per run - but a different eight each run - now, that would be cool! But I think that using the same eight variations of my font will be just fine for any normal purposes. I thank you (merci) again!!

Just for your info, I’m running a 27" iMac with 2.8 GHz Intel Core i7 processor.

Model: 27 iMac 2.8 GHz Intel Core i7
AppleScript: 2.1.2
Browser: Safari 534.52.7
Operating System: Mac OS X (10.6)

My understanding is a bit different.
I don’t think that the problem is linked to the number of fonts.
I ran my script from the AppleScrip Editor which the log report feature active.
The behavior is cyclic.
fast . slowing down . slow . fast again . slowing down . slow . fast again . slowing down . slow . fast again
I didn’t identify the meaningful parameter but it resemble to something linked to a temporary buffer.
It seems that in a given range, the time required to reach a character is linked to the square value of its ‘local’ index.

The day I will have free time available, I will try to identify the exact parameter.

Yvan KOENIG (VALLAURIS, France) jeudi 15 décembre 2011 10:52:51

OK. Horrible to behold in action, but it’s very much faster to apply the fonts through Pages’s GUI:

on main()
	-- List values to be referenced as script object properties for speed of access to their items.
	script o
		property fontNames : {"MICHAEL-01", "MICHAEL-02", "MICHAEL-03", "MICHAEL-04", "MICHAEL-05", "MICHAEL-06", "MICHAEL-07", "MICHAEL-08", "MICHAEL-09", "MICHAEL-10", "MICHAEL-11", "MICHAEL-12", "MICHAEL-13", "MICHAEL-14", "MICHAEL-15"}
		property selectionList : missing value -- Will be a list of character references.
	end script
	set fontCount to (count o's fontNames)
	
	-- Set up Pages's front document window to receive GUI Scripting.
	tell application "System Events"
		tell application process "Pages"
			set frontmost to true
			set frontWindow to first window whose subrole is "AXStandardWindow"
			set noFormatBar to (not (pop up button 1 of frontWindow exists))
		end tell
		-- If the Format bar isn't showing, show it.
		if (noFormatBar) then keystroke "r" using {shift down, command down}
	end tell
	
	tell application "Pages"
		activate
		tell front document
			set characterCount to length
			-- Apply the first font to the whole of the body text.
			set font name of body text to beginning of o's fontNames
			
			-- . then apply the remaining fonts to the selected characters.
			repeat with i from 2 to fontCount
				set o's selectionList to {}
				repeat with j from i to characterCount by fontCount
					set end of o's selectionList to (a reference to character j of body text)
				end repeat
				
				select o's selectionList
				my applyFont(frontWindow, item i of o's fontNames)
			end repeat
			
			-- When done, clear the selection and park the cursor at the top of the document.
			select insertion point before character 1
		end tell
	end tell
	
	-- If the Format Bar wasn't showing before, hide it again.
	if (noFormatBar) then tell application "System Events" to keystroke "r" using {shift down, command down}
end main

on applyFont(frontWindow, fontName)
	tell application "System Events"
		tell application process "Pages"
			-- Click the front document window's Format Bar pop-up
			-- and select the font from the menu.
			tell (pop up button 1 of frontWindow)
				click
				tell menu 1
					repeat until (it exists)
						delay 0.2
					end repeat
					try
						click menu item fontName
					on error
						-- Use "Lucida Grande" if the required font isn't in the menu.
						click menu item "Lucida Grande"
					end try
					repeat while (it exists)
						delay 0.2
					end repeat
				end tell
			end tell
		end tell
	end tell
end applyFont

main()

WONDERFUL !

My test document was treated in 11 seconds when scripts using plain Vanilla code required between 107 and 175 seconds.
Who will say that GUI Scripting is a bad tool ?

I would just apply one change requiring less typing when writing the script with, at least on my sample file, exactly the same execution time.
I post only the edited tell block.


tell application "Pages"
		activate
		tell front document
			set characterCount to length
			-- Apply the first font to the whole of the body text.
			--set font name of body text to beginning of o's fontNames -- I disabled this instruction
			
			-- . then apply the remaining fonts to the selected characters.
			repeat with i from 1 to fontCount -- Now it scans starting from 1
				set o's selectionList to {}
				repeat with j from i to characterCount by fontCount
					set end of o's selectionList to (a reference to character j of body text)
				end repeat
				
				select o's selectionList
				my applyFont(frontWindow, item i of o's fontNames)
			end repeat
			
			-- When done, clear the selection and park the cursor at the top of the document.
			select insertion point before character 1
		end tell
	end tell

Yvan KOENIG (VALLAURIS, France) jeudi 15 décembre 2011 14:37:34

Hi, Yvan.

I did try it both ways before posting and found my version to be a couple of seconds faster, both with the test document you e-mailed me yesterday and with a much longer one of my own. I think my computer isn’t quite as fast as yours, so any time saved is more noticeable.

Hi

iMac 21"5, 2.8 GHz Intel Core i7, 12 Gbytes, 1 Tbytes, mac OS X 10.7.2

I searched a lot of time before discovering that there was an extraneous space in a font name in my original script.
It didn’t hurt when running plain Vanilla code but was odd in GUIScripting : there is no menu item "Comic Sans MS "

Yvan KOENIG (VALLAURIS, France) jeudi 15 décembre 2011 16:27:13

Hello again Yvan, Nigel & Stefan-
I never knew when I posted my problem that I would incite such a flurry of assistance. Thank you all very much. After trying all of your suggestions as best I could (I had trouble with the ones targeting Pages GUI - I kept getting errors that read: “error “System Events got an error: Access for assistive devices is disabled.” number -1719”) and finally settled on Yvan’s revised attempt. I also decided to use only eight font variants because no matter what version I used, they all worked MUCH faster over the long haul with eight or less fonts. The results are quite splendid; it’s hard to tell the results from actual hand written documents. I use this script only once a year really, when I send out my Christmas cards. My real handwriting has gotten so bad and my typing is so fast that it’s the only way to send out 150 cards with personal notes. Again: THANKS! I would share the results with you if you like, but I don’t know how to attach a PDF or JPEG to this forum. If you would like to send me your email, I could show you that way I suppose. Mine is “web me at flynn photo dot com” , of course without the spaces and with an “at” symbol and a “.”
Merry Christmas and a Happy New Year!!
-M

Hi, Michael. Thanks for the feedback. Glad you got your cards “written”. :wink:

System Preferences → Universal Access → Enable access for assistive devices.

This box has to be checked for GUI Scripting to work. I think it’s a security thing.

Okay Nigel-
You win!! The GUI scripting is blazing fast. At least twice as fast as the alternative. Where did you learn this? Do you do coding for a living? You should. And I’ll bet you’re younger than I. Once, back in '68 I was teaching (I think it was) 84 step punch card programing (on a Wang) in the first programing class our high school district had. I was 15. I never went any farther than that and went to Hollywood instead. Never tried any coding again till I put together that little script that you so awesomely rethought.
Thanks-
-Michael Flynn
P.S. you can see me on the IMDB at: http://www.imdb.com/name/nm0283468/ The picture is about 13 years old.