Keynote 6.1 export images

Hi there,

I know that there’s been issues with the latest version of Keynote where the applescript support was missing. I have version 6.1 that has the export command in the dictionary:


export‚v : Export a slideshow to another file
export document : The slideshow to export
to file : the destination file
[as HTML/Œmovie/ŒPDF/Œimage/ŒPowerPoint/ŒClassic] : The format to use.
[with properties export options] : Optional export settings.

I have tried using the below code to create PNG images:


set theFile to (path to desktop as string) & "my.png"

tell application "Keynote"
	export document 1 to file theFile as image with properties {compression factor:0.9, image format:PNG, export style:IndividualSlides, skipped slides:false, all stages:true}
end tell

Although the script runs without error nothing is produces! I have also tried changing the export type to a movie and you can even see Keynotes progress showing the status of the export but still no results are produces.

Can anybody offer any suggestions?

Many Thanks,
Nik

Something is puzzling here.

When I export by hand, I don’t get a file but a folder containing the pictures files.

I guess that it’s what is the origin of the wrong behavior.

To check my hypothesis, I ran this code :


set theFile to (path to desktop as string) & "my.ppt"

tell application "Keynote"
	activate
	export document 1 to file theFile as PowerPoint with properties {compression factor:1.0, export style:IndividualSlides, skipped slides:false, all stages:true}
end tell

As this one was supposed to create a file, it did its duty.

I was able to open the created file with LibreOffice (Open Office wrongly opened is as a text file).
The result is far from perfect. Text objects are displayed as two superposed ones with a small offset to the right and to the bottom.

Strong smell of bug here.

At this time I guess that GUI Scripting is the only scheme usable but it doesn’t offer the ability to rule every parameters settable in the official syntax.

Yvan KOENIG (VALLAURIS, France) vendredi 7 février 2014 16:07:39

Hi Yvan,

thanks for taking the time to test this.

I reported this as bug on the apple developers sight (ref 16010539) but was told this was already a duplicate issue of ref 15115242. This is still open but I can’t seem to view an info about it.

I took the time yesterday to write a gui version of the script which did work. I will update this post later with my code incase it’s of use to anybody else.

Thanks again,
Nik

It’s a bit boring to be unable to have access to the behavior of a bug report which duplicates the one which we sent.
Having the ability to exchange with the other(s) one(s) which found an oddity may help to trace it but it seems that Apple doesn’t understand that.
Maybe the old rule " Secret is secret " but it’s ridiculous to don’t allow guys taking time to report a bug (so both are aware of it) to exchange infos.

In some cases, one may have a workaround proposal which the other didn’t think to. Making them aware of it would be fairplay.

Yvan KOENIG (VALLAURIS, France) samedi 8 février 2014 17:43:42

I completely agree Yvan. I’ve been an Apple user for over 20 years and have always loved the products, but since Lion it’s beginning to feel like you have to do it the apple way or no other. The restrictions that they’re constantly applying is very frustrating and controlling.

I have have emailed them to ask how can I can track the progress of the bug if they have closed my report but as yet I’ve had no response.

I’ve also been trying to extract the Notes from a keynote file and again this function has been removed from version 6. I can’t find anyway to get them out, the best I can come up with is to export as a PDF, which like the PowerPoint file works strangely. Then use the command line binary pdftotext to get them out. The trouble is this would still extract any text that maybe on the slide and there seems to be no control over exporting specific slides. I thought that maybe I could delete unwanted slides and then export to a pdf but the delete function doesn’t seem to work either. I even tried the built in Automator action ‘Extract Notes’ but guess what, that also no longer works!!

Thanks,
Nik

It seems that you may get what you want with GUI Scripting.

Ask the script to open the document
display slide 1
keystroke “k” using {option down, cmd down, shift down}
AXApplication
” AXWindow:AXStandardWindow
”” AXScrollArea
””” AXPopover
”””” AXScrollArea
””””” AXTextArea
the value (AXValue) of the text box is the comment’s text
If there are several comments, you will have to trigger the triangular button pointing to the left to jump in the preceeding comment.

I know, it’s ugly but it may be useful.

Yvan KOENIG (VALLAURIS, France) dimanche 9 février 2014 11:59:28

Hi Yvan,

I appreciate your efforts on this but I need to extract the presentation Notes to text file.

I looked at gui scripting to check the ‘View’ menu to see if ‘Show Presentation Notes’ or ‘Hide Presentation Notes’ was visible and managed to activate them, but in terms of selecting the text in the notes section of the window I’m a not having much success. If you could shed any light on it that would be great.

Thanks again,
Nik

I understood wrongly what are Notes.
It seems that in fact they are what is activated, in the French version thru the menu item « Afficher les notes de l’intervenant » which is just below the menu item whose shortcut is cmd + option + E

Is it really that ?

If it is, it seems that it would be easy to extract the contents thru GUI Scripting.

Yvan KOENIG (VALLAURIS, France) lundi 10 février 2014 15:01:49

Yvan,

That is correct, ‘Hide/Show Presenter Slide’ is the menu item that can be found under cmd + option + E ‘Edit Master Slides’ menu item. I have managed to show the Notes window using gui scripting but couldn’t see what element I needed to target in window 1 to extract the text.

tell application "System Events"
	tell application "Keynote"
		activate
	end tell
	
	tell process "Keynote"
		click window 1
		set menuList to name of every menu item of menu "View" of menu bar item "View" of menu bar 1
		if menuList contains "Show Presenter Notes" then
			click menu item "Show Presenter Notes" of menu "View" of menu bar item "View" of menu bar 1
		end if
		
		set f to entire contents of window 1
	end tell
end tell

Thanks,
Nik

Maybe this piece of code may help.

(*
Use the cliclick command supposed to be installed as : /usr/bin/cliclick
It's available at :
http://www.bluem.net/en/mac/cliclick/
*)

tell application "Keynote"
	set Show_Presenter_Notes_loc to localized string "Show Presenter Notes" from table "Keynote"
	activate
end tell
set view_index to 9
tell application "System Events" to tell process "Keynote"
	click window 1
	tell menu 1 of menu bar item view_index of menu bar 1
		--set menuList to name of every menu item
		if exists menu item Show_Presenter_Notes_loc then
			click menu item Show_Presenter_Notes_loc
		end if
	end tell
	click window 1
	tell window 1
		position of scroll areas
		repeat
			delay 0.1
			if (count scroll areas) > 3 then exit repeat
		end repeat
		set thePositions to position of scroll areas
		(*
The scroll area dedicated to notes is the lower one
It's the 2nd one if the notes were visible
It's the 3rd one if the script reveal the note
So we can't rely upon the index and must identify it by its vertical position.
*)
		set {xNote, yNote} to {0, 0}
		repeat with i from 1 to 4
			set {xi, yi} to item i of thePositions
			if yi > yNote then set {xNote, yNote} to {xi, yi}
		end repeat
		
		tell me to do shell script "/usr/bin/cliclick tc:" & (xNote + 10) & "," & (yNote + 10)
		keystroke "a" using command down
		keystroke "c" using command down
	end tell
end tell

(1) As always, I did my best to build a code usable worldwide.
(2) Don’t ask me why I use the triple click.
I tested with a simple click and nothing was selected
I tested with a double click and nothing was selected
I tested with a triple click and got the note selected and copied.

I guess that you will be able to continue the script to fit your needs.

Would be fair to post the entire script here.

Yvan KOENIG (VALLAURIS, France) lundi 10 février 2014 18:24:59

Hi Yvan,

Exceptional work. Thanks very much.

Once I have tested and completed I’ll post what I have.

Thanks,
Nik

Nothing exceptional, just a pig headed guy at work :wink:

Yvan KOENIG (VALLAURIS, France) mardi 11 février 2014 09:31:00

Hi Yvan,

I’m Sooooooo close now. The last thing I’m struggling with is showing the desired slide.

set cliclickbin to POSIX path of ((path to me as string) & "Contents:Resources:cliclick")

my checkcliclickbin(cliclickbin)

set theFile to choose file
set filenameNoExt to do shell script "FILENAME=$(basename " & quoted form of POSIX path of theFile & ");NOEXT=${FILENAME%.*}; echo $NOEXT"

tell application "System Events"
	tell application "Keynote"
		activate
		open theFile
		set docName to name of document 1
		set slideCount to count of slides of document 1
		set theSlideNo to text returned of (display dialog "Please enter a slide number between 1 - " & slideCount & " to export" default answer "") as integer
		set outputFile to (choose file name with prompt "Save Text As:" default name filenameNoExt default location (path to desktop as alias)) as string
		if outputFile does not end with ".txt" then set outputFile to outputFile & ".txt"
		set Show_Presenter_Notes_loc to localized string "Show Presenter Notes" from table "Keynote"
		activate
		tell document 1
			show slide theSlideNo
		end tell
	end tell
	set view_index to 9
	tell application "System Events" to tell process "Keynote"
		click window 1
		tell menu 1 of menu bar item view_index of menu bar 1
			if exists menu item Show_Presenter_Notes_loc then
				click menu item Show_Presenter_Notes_loc
			end if
		end tell
		click window 1
		tell window 1
			position of scroll areas
			repeat
				delay 0.1
				if (count scroll areas) > 3 then exit repeat
			end repeat
			set thePositions to position of scroll areas
			
			set {xNote, yNote} to {0, 0}
			repeat with i from 1 to 4
				set {xi, yi} to item i of thePositions
				if yi > yNote then set {xNote, yNote} to {xi, yi}
			end repeat
			
			tell me to do shell script "/usr/local/bin/cliclick tc:" & (xNote + 10) & "," & (yNote + 10)
			keystroke "a" using command down
			delay 1
			keystroke "c" using command down
			delay 1
		end tell
	end tell
end tell

do shell script "pbpaste | textutil -convert txt -stdin -stdout -encoding 30 | pbcopy"
do shell script "echo " & quoted form of (the clipboard) & " > " & quoted form of POSIX path of outputFile

on checkcliclickbin(cliclickbin)
	set destFile to "/usr/local/bin/cliclick"
	set fileStatus to do shell script "if [ -f " & quoted form of destFile & " ]; then echo true;else echo false; fi;"
	if fileStatus is "false" then do shell script "cp " & quoted form of cliclickbin & space & quoted form of "/usr/local/bin/" with administrator privileges
end checkcliclickbin

I have embedded the cliclicm binary in the resources folder of my app so that I can make it portable. I’ve also given the user the option to specify what slide they want to export but the standard applescript code for this seems to do nothing.

set x to 3

tell application "Keynote"
	tell document 1
		show slide x
	end tell
end tell

Have you any ideas how I can gui script clicking or showing the specified slide?

Thanks,
Nik

Quick and dirty sample code :

tell application "Keynote"
	activate
	try
		stop document 1
	end try
	tell document 1
		start from slide 1
		set nbs to count slides
		repeat with i from 2 to nbs
			my extractPresenterNotes(i)
			--activate application "Keynote" # bring Keynote at front
			(*
# I tried to bring Keynote at front this way with no result.
tell application "System Events" to tell process "Keynote"
set frontmost to true
end tell
			*)
			show next # display next slide
		end repeat
		delay 2
	end tell
	stop document 1
end tell

on extractPresenterNotes(indx)
	# fake code
	say "wait 2 seconds to display slide " & indx
	delay 2
end extractPresenterNotes

Yvan KOENIG (VALLAURIS, France) mardi 11 février 2014 14:21:07

Hi Yvan,

I’ve just discovered the wanders of PFiddlesofts UI Browser which has opened my eyes.

I have managed to come up with this:

tell application "Keynote"
	activate
	set slideCount to count of slides of document 1
	set theSlideNo to text returned of (display dialog "Please enter a slide number between 1 - " & slideCount & " to export" default answer "")
end tell

tell application "System Events"
	tell process "Keynote"
		click window 1
		try
			click menu item "First Slide" of menu 1 of menu item "Go To" of menu 1 of menu bar item "Slide" of menu bar 1
		end try
		repeat with i from 1 to slideCount
			if i < theSlideNo then
				click menu item "Next Slide" of menu 1 of menu item "Go To" of menu 1 of menu bar item "Slide" of menu bar 1
			else
				exit repeat
			end if
		end repeat
	end tell
end tell

which allows me to target a specific slide.

Thanks you so much for you help, this has been the first time that I’ve tried gui scripting and now with UI Browser it doesn’t seem quite so alien.

Thanks,
Nik

I dislike UI Browser because it build scripts dedicated to a single localized version and I hate such scripts.
Here is an edited version usable worldwide.

Don’t be afraid if it appears to be long, it’s just that I left instructions useful for tests and of course it’s commented.

tell application "Installation OS X 10.9 - 10.9:Applications:Keynote.app:"
	activate
	set slideCount to count of slides of document 1
end tell

# Since 10.6 we are urged to no longer call an OSAX (here Standard Additions) from a tell application block !
# SystemUIServer is the exception confirming the rule ;-)
tell application "SystemUIServer" to set theSlideNo to text returned of (display dialog "Please enter a slide number between 1 - " & slideCount & " to export" default answer "") as integer

# If theSlideNo is too big, set it to slideCount
if theSlideNo ≥ slideCount then set theSlideNo to slideCount

# Activate is required again due to the preceeding tell to SystemUIServer
tell application "Installation OS X 10.9 - 10.9:Applications:Keynote.app:" to activate

tell application "System Events" to tell (first process whose frontmost is true)
	# I use the pathname and (first process whose frontmost is true)
	# because here, the app used currently is Keynote 5.3
	# Coding this way I'm sure that I use the 6.1 one.
	click window 1 # seems to be useless
	tell menu bar 1
		# name of every menu bar item # just for tests
		--> {"Apple", "Keynote", "Fichier", "Édition", "Insertion", "Diapositive", "Format", "Disposition", "Présentation", "Lecture", "Partage", "Fenêtre", "Aide"}
		set SlideIndex to 6
		# name of every menu item of menu 1 of menu bar item SlideIndex # just for tests
		--> {"Nouvelle diapositive", missing value, "Ignorer la diapositive", missing value, "Développer", "Tout développer", "Condenser", "Tout condenser", missing value, "Afficher les numéros de diapo sur toutes les diapos", missing value, "Copier les guides", "Coller les guides", missing value, "Aller à "}
		set GotoIndex to -1
		# name of every menu item of menu 1 of menu item GotoIndex of menu 1 of menu bar item SlideIndex # just for tests 
		--> {"Diapositive suivante", "Diapositive précédente", missing value, "Première diapositive", "Dernière diapositive"}	
		set nextSlideIndex to 1
		set firstSlideIndex to 4
		tell menu 1 of menu item GotoIndex of menu 1 of menu bar item SlideIndex
			# name of menu item firstSlideIndex  # just for tests
			--> "Première diapositive"
			enabled of menu item firstSlideIndex
			if result then click menu item firstSlideIndex # If needed, jump to 1st slide
			# name of menu item nextSlideIndex  # just for tests
			--> "Diapositive suivante"
			# Now advance to slice index theSlideNo
				repeat  (theSlideNo - 1) times
					click menu item nextSlideIndex
				end repeat
		end tell # menu 1  .
	end tell # menu bar 1
end tell # System Events & process

My original script wasn’t using GUIScripting because I assumed that you wanted to grab notes from every slides. :rolleyes:

Yvan KOENIG (VALLAURIS, France) mardi 11 février 2014 18:49:33

Thank you for all of your efforts on this Yvan. I’ve always tried to steer clear of gui scripting in the past as it’s always seemed very messy and a little unpredictable.

I understand your dislike for UI Browser but from my point of view it’s interface has given me an incite on how to reference elements that I’ve not tried before.

With your help I’ve managed to achieve something that I didn’t think would be possible after Apple has made such a mess apple scripting Keynote. Hopefully other users will read these posts and revisit there Keynote scripts that no longer work.

Thanks again,
Nik

Here is a Go to Slide xx script which don’t use GUI Scripting.

tell application "/Volumes/Installation OS X 10.9 - 10.9/Applications/Keynote.app"
	activate
	set slideCount to count of slides of document 1
end tell

# Since 10.6 we are urged to no longer call an OSAX (here Standard Additions) from a tell application block !
# SystemUIServer is the exception confirming the rule ;-)
tell application "SystemUIServer" to set theSlideNo to text returned of (display dialog "Please enter a slide number between 1 - " & slideCount & " to reach" default answer "") as integer

# If theSlideNo is too big, set it to slideCount
if theSlideNo ≥ slideCount then set theSlideNo to slideCount


tell application "/Volumes/Installation OS X 10.9 - 10.9/Applications/Keynote.app" to tell document 1
	activate
	try
		stop slide 1
	end try
	start from slide 1
	delay 0.1 # required to let the app to reach slide 1
	repeat with i from 1 to (theSlideNo - 1)
		show next # display next slide
	end repeat
	my extractPresenterNotes(theSlideNo)
end tell

on extractPresenterNotes(indx)
	# fake code
	say "we are in slide " & indx
end extractPresenterNotes

Maybe I am missing something, but this may be a better approach to extracting the presenter notes?


tell application "Keynote"
	activate
	--To get all the presenter notes 
	set theSlideCount to the count of (get the every slide of the front document)
	log theSlideCount
	set theNotes to get presenter notes of every slide of the front document as text
	log theNotes
	
	--To get all the presenter notes from the slides arranged in paragraphs 
	set i to 1
	set theNotesList to ""
	repeat while i < theSlideCount
		try
			set theCurrentSlideRef to "Slide Number:" & i
			set theCurrentSlideNote to get presenter notes of slide i of the front document as text
			set theCurrentNotesList to theCurrentSlideRef & "\r" & theCurrentSlideNote & "\r\r"
			
		on error
			set theCurrentNotesList to theCurrentSlideRef & "\r" & "an error here" & "\r\r"
		end try
		set theNotesList to theNotesList & theCurrentNotesList
		set i to i + 1
	end repeat
	return theNotesList
	
end tell