Word to PDF with osascript

Why is this giving a super messed up PDF with no images? What am I doing wrong?

use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "AppKit"

-- dimensions of print area:
property thePaperSize : {height:479, width:516}
property theLeft : 0
property theRight : 0
property theTop : 0
property theBottom : 0

on run argv
    set course to "course1"
    set theyear to "2023"
    set semester to "Spring"
    set exam to item 1 of argv
    set session to item 2 of argv
    set chapters to item 3 of argv

    if semester="Spring" then
        set sem_num to "1"
    else if semester="Summer" then
        set sem_num to "2"
    else if semester="Fall" then
        set sem_num to "3"
    else
        return "wrong semester"
    end if

    set inpath to "/Users/Dropbox/"& course &" - " & "Current/" & theyear & "-"& sem_num &"-"& semester &"/2." & " " & "Chapter" & " " & "Reviews/" & ¬
        "Exam" & " " & exam & " " & "Session" & " " & session & "/"& course &" Exam " & exam & " Session " & session & " (Ch "& chapters &").docx"

    -- choose Word document file, make URL and build destination path
    set posixPath to inpath
    set theURL to current application's |NSURL|'s fileURLWithPath:posixPath
    set destPath to theURL's |path|()'s stringByDeletingPathExtension()'s stringByAppendingPathExtension:"pdf"

	-- get doc's contents as styled text
	set {styledText, theError} to current application's NSAttributedString's alloc()'s initWithURL:theURL options:(missing value) documentAttributes:(missing value) |error|:(reference)
	if styledText = missing value then error (theError's localizedDescription() as text)
	
	-- set up printing specs
	set printInf to current application's NSPrintInfo's sharedPrintInfo()'s |copy|()
	printInf's setJobDisposition:(current application's NSPrintSaveJob)
	printInf's dictionary()'s setObject:destPath forKey:(current application's NSPrintSavePath)
	
	-- make text view and add text
	set theView to current application's NSTextView's alloc()'s initWithFrame:{{0, 0}, {(width of thePaperSize) - theLeft - theRight, (height of thePaperSize) - theTop - theBottom}}
	theView's textStorage()'s setAttributedString:styledText
	
	-- set up and run print operation without showing dialog
	set theOp to current application's NSPrintOperation's printOperationWithView:theView printInfo:printInf
	theOp's setShowsPrintPanel:false
	theOp's setShowsProgressPanel:false
	theOp's runOperation()
	
end run

I might be wrong but you’re unlikely to get any kind of usable results by trying to extract Word doc contents as NSAttributedString.

I assume you don’t have Word installed that’s why you’re not using its own AppleScript facilities.

You may have better luck trying to find a command line utility that can print Word docs in combination with a virtual PDF printer.

Here’s one such suggestion:

I have a GUI Apple script that does this for me too. Problem is that it breaks with every single OS update (when buttons and overall layout change). I wanted to have a script that I could use from the command line without any GUI involved. Is your suggestion like that?

@scienception
You could install:
https://pandoc.org
brew install pandoc
then you could use command-line

Other approach is but not what you exatly want but it will solve you GUI scripting issue
If you open the print dialog you could see there is Save as PDF
You could make this a keyboard shortcut for application Word.
Now you could use key code to get a save dialog for you to save the file.
The problem could be to set the save path if you like to do everything with AppleScript.

Something like this, the first key code get print dialog and second is custom for Save as PDF and the last keystroke will click return on keyboard. It looks like the save path is the same path as the document was open in.

set thePath to POSIX path of (path to desktop) & "testDoc.docx"
tell application "Microsoft Word" to open thePath
tell application "System Events" to tell application process "Microsoft Word"
	set frontmost to true
	
	key code 35 using {command down}
	key code 35 using {control down} --> custom app shortcut
	delay 2
	keystroke return
end tell
delay 0.5
tell application "Microsoft Word" to quit

@scienception
In addition to excellent suggestions from @Fredrik71: If you do have Word then you don’t need GUI scripting - you can use Word’s own AppleScript commands (if I understand your question correctly).

Thank you! But how can I set up a specific page size/margins for printing?

I need to automatize converting Word files to PDF files with a specific layout and password protection.

for password protection you’ll need to create PDF first, then use PDFKit to assign security settings including password.

as to specific layout: normally, all layout options should be covered by Word’s AppleScript dictionary (although some of them you may need to apply to the document itself first rather then set them up as print settings).

How could I set up something like this? Could you provide me a link to an example using Word’s AppleScript dictionary?

you’ll probably need to set your Word document size to your custom page size.

i don’t have specific examples but you’ll need to use document’s page setup property.

@scienception
Many things you like to do… would category as GUI Scripting.
But if here is an version from Yvan that us Word Scriptable features.

set thePath to POSIX path of (path to desktop) & "testDoc.docx"
tell application "Microsoft Word"
	open POSIX file thePath
	delay 1
	tell front document
		set savePath to POSIX path of (path to desktop) & "testDoc.pdf"
		save as file format format PDF file name savePath
	end tell
	quit
end tell

Thanks again! But in this script where is the layout defined?

@scienception
I made a GUI Script for you to try, open Word and run the Script

The variable presetsNames is a list of every name of the Preset:
So you could make your custom ones. I could also say before tell menu 1
there is a click. The reason is the names of every menu item doesn’t reveal themselves
without the click. So to be able to do GUI Script is to get every step in some order.
It took me some time to understand it at begining.

I use: class of UI elements to reveal the class of Ui elemens and navigate and also guessing the path. Its not always straitforward.

tell application "System Events" to tell application process "Microsoft Word"
	set frontmost to true
	
	key code 35 using {command down} --> Print dialog
	
	tell window 1 to tell pop up button 2
		click
		tell menu 1
			set presetsNames to name of menu items
			click menu item "Last Used Settings"
		end tell
	end tell
end tell

You can find these in the Word dictionary. It is expansive so you might search for ‘page setup’.

This may give you something to start with but you should be able to work with more than just margins:

tell application "Microsoft Word"
	set top margin of page setup of document 1 to 24
	-- to return the page setup object…
	-- properties of page setup of document 1
	
	left margin of page setup of document 1
	--> 90.0
	top margin of page setup of document 1
	--> 24.0
	right margin of page setup of document 1
	--> 90.0
	bottom margin of page setup of document 1
	--> 72	
	
	set left margin of page setup of document 1 to 36
	left margin of page setup of document 1
	--> 36.0
	
	-- you can use inches like so
	set left margin of page setup of document 1 to (inches to points inches 0.75)
	left margin of page setup of document 1
	--> 54.0
	
	-- and metric like so but note the spelling
	set right margin of page setup of document 1 to (centimeters to points centimeters 2)
	right margin of page setup of document 1
	--> 56.70000076294

end tell

You can also use millimeters, lines —and best of all— picas (i.e. 12 points).

@zevrix… by the way, that’s not a custom size… that’s Letter in millimetres.

@Mockman Made it simple :slight_smile:

tell application "Microsoft Word"
	tell front document
		its properties of page setup
	end tell
end tell

yeah i thought it looks like a standard size…

but all i know is that it’s defined as “custom” paper:

who knows maybe OP works in an environment where Letter page should be defined as custom size.

Seems weird for Word but I guess that’s the case.

Here is other

tell application "System Events" to tell application process "Microsoft Word"
	set frontmost to true
	
	tell menu bar 1 to tell menu bar item "File"
		tell menu 1
			click menu item "Page Setup..."
		end tell
	end tell
	
	tell window 1 to tell pop up button 2
		click
		tell menu 1 to set paperSizeNames to its name of menu items
		(*
		{"8x10 203 by 254 mm", "10x12 254 by 305 mm", "A3 297 by 420 mm", "A4 210 by 297 mm", "A5 148 by 210 mm", "Envelope #10 105 by 241 mm", "Envelope Choukei 3 120 by 235 mm", "Envelope DL 110 by 220 mm", "Executive 184 by 267 mm", "Super B/A3 330 by 483 mm", "Tabloid 279 by 432 mm", "Tabloid Oversize 305 by 457 mm", "US Legal 216 by 356 mm", "US Letter 216 by 279 mm", missing value, "Manage Custom Sizes…"}
		*)
		tell menu 1 to click menu item "A3 297 by 420 mm"
	end tell
end tell