Monday, November 19, 2018

#1 2018-09-11 08:18:57 pm

chuckbo
Member
Registered: 2018-09-11
Posts: 4

Question about scripting Pages and Keynote

I'm trying to loop through a Keynote presentation and move the presenter notes into a Pages document. I'm close, but I have two problems so far. The one I've been working on mostly is trying to add pages to the bottom of the Pages document. Right now, every time I add a page or a section, it adds a page after the selected page, and page 1 stays selected. Therefore, my notes are copying in reverse order.

The other problem that I haven't really explored yet -- not sure how to explore it -- is how to copy the rich text from the presenter notes and not just the plain text.

Here's the code that I have so far. I've had some tips from a user on another board for the Pages, but I think he's stuck at the same place I am. There doesn't seem to be a way to select the last page in the code. I found out that if I put a breakpoint in the code before the Make statement and select the last page manually, then the code would work. If I had a way to set the insertion point at the bottom of the document right before the Make command, then I think it would work.

Applescript:


property defaultTemplateName : "Blank"
property Slide_notes : ""


tell application "Keynote"
   set theNumberOfSlides to count of slides in document 1
end tell

tell application "Pages"
   activate
   set Number_of_pages to count of documents
   if Number_of_pages = 0 then
       set myDocument to make new document with properties {document template:template defaultTemplateName}
   else
       set myDocument to document Number_of_pages
   end if
end tell

tell application "Keynote"
   set myPresentation to document 1
end tell

repeat with Slide_count from 1 to theNumberOfSlides
   tell application "Keynote"
       tell myPresentation
           set mySlide to slide Slide_count
           set Slide_notes to (presenter notes of mySlide)
       end tell
   end tell
   
   tell application "Pages"
       tell myDocument
           if Slide_count is 1 then
               set body text to Slide_notes
           else
               set newPage to make new page at the end of sections
               set body text of newPage to Slide_notes
           end if
       end tell
   end tell
   
end repeat


Filed under: applescript, keynote, pages

Offline

 

#2 2018-09-12 04:00:14 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4720

Re: Question about scripting Pages and Keynote

Hi. Welcome to MacScripter.

It seems to be a bug in Pages rather than anything you're doing wrong. The only way I can see so far to add pages and put text into the correct ones is to make all the pages first and then populate them. That is, replace your last repeat with these two:

Applescript:

-- Make the required number of additional pages.
repeat theNumberOfSlides - 1 times
   tell application "Pages" to tell myDocument to make new page
end repeat

-- Then add the required texts.
repeat with Slide_count from 1 to theNumberOfSlides
   tell application "Keynote"
       tell myPresentation
           set mySlide to slide Slide_count
           set Slide_notes to (presenter notes of mySlide)
       end tell
   end tell
   
   tell application "Pages" to set body text of page Slide_count of myDocument to Slide_notes
end repeat


NG

Offline

 

#3 2018-09-12 04:29:08 am

chuckbo
Member
Registered: 2018-09-11
Posts: 4

Re: Question about scripting Pages and Keynote

Hello, Nigel.
That's also the only workaround I had found.

How about the question with Keynote? Do you have any insights or guidance regarding rich text?
Chuck

Offline

 

#4 2018-09-12 05:43:35 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4720

Re: Question about scripting Pages and Keynote

Hi Chuck.

In broad terms, it's fairly simple. Get the properties of the each slide's presenter notes and set the properties of the corresponding page's body text to the same values:

Applescript:

-- Make the required number of additional pages.
repeat theNumberOfSlides - 1 times
   tell application "Pages" to tell myDocument to make new page
end repeat

-- Then add the required texts.
repeat with Slide_count from 1 to theNumberOfSlides
   tell application "Keynote"
       tell myPresentation
           set mySlide to slide Slide_count
           set Slide_notes to ({it, font, color, size} of presenter notes of mySlide)
       end tell
   end tell

   tell application "Pages"
       tell page Slide_count of myDocument
           set {body text, font of body text, color of body text, size of body text} to Slide_notes
       end tell
   end tell
end repeat

If you want to match style changes within each text, you have to go through character-by-character searching for them. The iWork text suite doesn't seem to support attribute runs.  sad


NG

Offline

 

#5 2018-09-12 05:51:53 am

chuckbo
Member
Registered: 2018-09-11
Posts: 4

Re: Question about scripting Pages and Keynote

Thanks for the advice, Nigel.

I haven't had to work much with characters and strings -- only a couple of scripts a few years ago that I don't remember. I'll play with examining and copying characters one at a time. Do you have any samples to go by?

Offline

 

#6 2018-09-13 07:34:16 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4720

Re: Question about scripting Pages and Keynote

chuckbo wrote:

I'll play with examining and copying characters one at a time. Do you have any samples to go by?


The following's not very pleasant, but fairly effective. Effects like bold, italic, and underline can only be reproduced where Keynote uses separate fonts for them.

Applescript:

property defaultTemplateName : "Blank"

tell application "Keynote"
   set myPresentation to document 1
   set theNumberOfSlides to (count myPresentation's slides)
end tell

tell application "Pages"
   activate
   if ((count documents) is 0) then
       set myDocument to (make new document with properties {document template:template defaultTemplateName})
   else
       set myDocument to back document -- Equivalent to the original 'document Number_of_pages'. Change to 'front document' or 'document 1' if that's what's meant.
   end if
   
   -- Make the required number of additional pages. (This script assumes that the document starts with only one page.)
   repeat theNumberOfSlides - 1 times
       tell myDocument to make new page
   end repeat
end tell


-- Then add the required texts.
repeat with slideCount from 1 to theNumberOfSlides
   tell application "Keynote"
       tell myPresentation
           set mySlide to slide slideCount
           -- Get the text of the presenter notes and three lists containing respectively the fonts, colours, and sizes of all the text's characters.
           tell mySlide's presenter notes to set {noteText, fontList, colourList, sizeList} to {it, font of characters, color of characters, size of characters}
       end tell
   end tell
   
   -- Initialise an attribute details list to the index and font attributes of the first character.
   set previousAttributes to {1, {beginning of fontList, beginning of colourList, beginning of sizeList}}
   -- Initialise a collector for pseudo-"attribute runs".
   set attributeRuns to {}
   -- Work through the attributes for each of the remaining characters in turn.
   repeat with c from 2 to (count fontList)
       -- Get this character's font, colour, and size.
       set theseAttributes to {item c of fontList, item c of colourList, item c of sizeList}
       -- If any of them have changed since the previous character …
       if (previousAttributes does not end with {theseAttributes}) then
           -- … replace the start index in the previousAttributes list with the full text to which those attributes apply …
           set item 1 of previousAttributes to text (get beginning of previousAttributes) thru (c - 1) of noteText
           -- … store the list in attributeRuns …
           set end of attributeRuns to previousAttributes
           -- … and start a new previousAttributes list with the current character index and the character's attributes.
           set previousAttributes to {c, theseAttributes}
       end if
   end repeat
   -- Finish the attribute run in progress at the end of the repeat.
   set item 1 of previousAttributes to text (get beginning of previousAttributes) thru c of noteText
   set end of attributeRuns to previousAttributes
   
   tell application "Pages"
       tell page slideCount of myDocument
           -- The only way I can find to append text directly to Pages 7.1 body text is to set the body text's last character to itself and the additional text.
           -- Initialise this page's body text to a space so that it actually contains a last character.
           set body text to space
           -- Work through the collected "attribute runs" in turn.
           repeat with theseAttributes in attributeRuns
               -- Get the text, font, colour, and size of this run.
               set {txt, fontColourAndSize} to theseAttributes
               -- I've not been able to set the attributes of a _range_ of characters in a Pages 7.1 body text.
               -- Rather than append the additional text and then set the attributes of each of its characters in turn, this code just appends a space, changes its attributes, and then replaces it with (sets it to) the additional text.
               tell body text
                   set character -1 to character -1 & space
                   tell character -1 to set {its font, its color, its size} to fontColourAndSize
                   set character -1 to txt
               end tell
           end repeat
           -- When done, delete the original initialisation space.
           set character 1 of body text to ""
       end tell
   end tell
end repeat

Last edited by Nigel Garvey (2018-09-13 07:36:49 am)


NG

Offline

 

#7 2018-09-13 09:37:29 am

chuckbo
Member
Registered: 2018-09-11
Posts: 4

Re: Question about scripting Pages and Keynote

Thanks for the example -- I think it would've been a long time before I reached this same code. And you're right, it's not very elegant.

I have to step back and reconsider how badly I want to move the formatting. I tend to make large-point speaker notes. I was running tests yesterday, and moving the formatted text conflicted with our method of pre-adding pages and then copying each slides' value separately because the notes on some slides are longer than one page. That returned me to the problem that I would have to add pages to the bottom of the document within the loop that populates the text -- which we found to not be possible.

Offline

 

#8 2018-09-13 11:24:00 am

Yvan Koenig
Member
Registered: 2006-09-14
Posts: 3287

Re: Question about scripting Pages and Keynote

You may create a document for each slide then merge them in a single one.
You will get the pages in the desired order.

An other way would be to use an index specific to the target page.
If the inserted 'note' use one page the index will be incremented by one. If it use say 3 pages, the index will be incremented by 3.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 13 septembre 2018 19:23:54

Online

 

#9 2018-09-13 03:03:44 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4720

Re: Question about scripting Pages and Keynote

chuckbo wrote:

I tend to make large-point speaker notes. I was running tests yesterday, and moving the formatted text conflicted with our method of pre-adding pages and then copying each slides' value separately because the notes on some slides are longer than one page.


The solution may be to add 'sections' rather than 'pages'. If a note text is longer than a page, Pages will create extra page(s) within the current, numbered section.

Texts as long as or longer than a page are going to have huge numbers of characters, so I've modified the script to reference the list variables and make them non-persistent. It may still hesitate over very long texts, but this is due to the time it takes to Keynote to return all the characters' properties. The script's analysis of them is actually pretty fast.

Applescript:

property defaultTemplateName : "Blank"

-- Code in a handler to make the variables local and therefore non-persistent.
on main()
   -- Script object to allow references to the list variables, for speed of access to the lists' items.
   script o
       property fontList : missing value
       property colourList : missing value
       property sizeList : missing value
       property attributeRuns : missing value
   end script
   
   tell application "Keynote"
       set myPresentation to document 1
       set theNumberOfSlides to (count myPresentation's slides)
   end tell
   
   tell application "Pages"
       activate
       if ((count documents) is 0) then
           set myDocument to (make new document with properties {document template:template defaultTemplateName})
       else
           set myDocument to back document -- Equivalent to the original 'document Number_of_pages'. Change to 'front document' or 'document 1' if that's what's meant.
       end if
       
       -- Make the required number of additional sections. (This script assumes that the document starts with only one section.)
       repeat theNumberOfSlides - 1 times
           tell myDocument to make new section
       end repeat
   end tell
   
   -- Repeat with every slide in the Keynote document.
   repeat with slideCount from 1 to theNumberOfSlides
       -- Get the presenter notes data from the Keynote slide.
       tell application "Keynote"
           tell myPresentation
               set mySlide to slide slideCount
               -- Get the text of the slide's presenter notes and three lists containing respectively the fonts, colours, and sizes of all the text's characters.
               tell mySlide's presenter notes
                   set noteText to it
                   set {o's fontList, o's colourList, o's sizeList} to {font, color, size} of characters
               end tell
           end tell
       end tell
       
       -- Analyse the data into pseudo-"attribute runs".
       set o's attributeRuns to {}
       -- Initialise an attribute details list to the index and font attributes of the first character.
       set previousAttributes to {1, {beginning of o's fontList, beginning of o's colourList, beginning of o's sizeList}}
       -- Work through the attributes for each of the remaining characters in turn.
       repeat with c from 2 to (count o's fontList)
           -- Get this character's font, colour, and size.
           set theseAttributes to {item c of o's fontList, item c of o's colourList, item c of o's sizeList}
           -- If any of them have changed since the previous character …
           if (previousAttributes does not end with {theseAttributes}) then
               -- … replace the start index in the previousAttributes list with the full text to which those attributes apply …
               set item 1 of previousAttributes to text (get beginning of previousAttributes) thru (c - 1) of noteText
               -- … store the list in attributeRuns …
               set end of o's attributeRuns to previousAttributes
               -- … and start a new previousAttributes list with the current character index and the character's attributes.
               set previousAttributes to {c, theseAttributes}
           end if
       end repeat
       -- Finish the attribute run in progress at the end of the repeat.
       set item 1 of previousAttributes to text (get beginning of previousAttributes) thru c of noteText
       set end of o's attributeRuns to previousAttributes
       
       -- Insert the data into the relevant section of the Pages document.
       tell application "Pages"
           tell myDocument
               tell section slideCount
                   -- The only way I can find to append text directly to Pages 7.1 body text is to set the body text's last character to itself and the additional text.
                   -- Initialise this section's body text to a space so that it actually contains a last character.
                   set body text to space
                   -- Work through the collected "attribute runs" in turn.
                   repeat with theseAttributes in o's attributeRuns
                       -- Get the text, font, colour, and size of this run.
                       set {txt, fontColourAndSize} to theseAttributes
                       -- I've not been able to set the attributes of a _range_ of characters in a Pages 7.1 body text.
                       -- Rather than append the additional text and then set the attributes of each of its characters in turn, this code just appends a space, changes its attributes, and then replaces it with (sets it to) the additional text.
                       tell body text
                           set character -1 to character -1 & space
                           tell character -1 to set {its font, its color, its size} to fontColourAndSize
                           set character -1 to txt
                       end tell
                   end repeat
                   -- When done, delete the original initialisation space.
                   set character 1 of body text to ""
               end tell
           end tell
       end tell
   end repeat
end main

main()


NG

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)