You can make a difference in the Apple Support Community!

When you sign up with your Apple Account, you can provide valuable feedback to other community members by upvoting helpful replies and User Tips.

scripting image replacement within numbers

I need to script an update within my Numbers file.


No NoCode 'shortcut' nonsense. I need an actual coding solution. Applescript worked great for the first part of my requirements, but can't seem to interact with the image I have inserted into one of my tabs (i need to replace my svg file to pick up changes made to it.)


Applescript lacks current (up to date) documentation or examples for manipulating numbers images (and, appears to be deprecated, because Apple seems to assume no one who can actually program wants to interact with applications any more).


Shortcuts suck, and are super limited (again, because Apple is trying to dumb things down, instead of actually allow folks who can program to do so).


I'm able to delete an image, but i can't replace it, nor can i insert a new image (which would also be a less elegant, but sufficient solution).

MacBook Pro (M1, 2020)

Posted on Sep 20, 2024 12:24 PM

Reply
Question marked as Top-ranking reply

Posted on Sep 20, 2024 2:31 PM

A subtle problem that, for sure, Apple could fix, but I think I understand why.


Ultimately, when you embed an image, the image is stored within the .numbers file and is, essentially, disassociated with the source file (especially bearing in mind that the image could be a file from disk or a photo from your Photos library. That's essentially why it doesn't update with changes to the source file.


The easiest workaround I could come up with is this:


ell application "Numbers"
	tell sheet 1 of document 1
		-- get the image
		set myImage to image 1
		-- grab its properties
		tell myImage
			set {fn, h, l, o, pos, refs, refv, rot, w} to its {file name, height, locked, opacity, position, reflection showing, reflection value, rotation, width}
		end tell
		delete myImage
		
		-- this assumes the image is on your desktop. Amend to your image path
		set newImage to make new image with properties {file:(POSIX path of (path to desktop) as text) & fn}
		tell newImage
			set {height, locked, opacity, position, reflection showing, reflection value, rotation, width} to {h, l, o, pos, refs, refv, rot, w}
			
		end tell
	end tell
end tell


It works by identifying the image (in this case I'm just assuming 'image 1'), and grabs all its properties.

It then deletes the image and immediately recreates it with the same filename (assuming it was a file on disk). The script then (re)sets all the image properties to match the original image.


Not quite the same as updating in-place, but pretty close.


Since the image is embedded, there is no record of where the original source image came from, so you'll have to set that part yourself.


This is essentially the same thing as happens if you click the 'Replace' button in the Image sidebar when the image is selected, but you wanted a scripted version.

18 replies
Question marked as Top-ranking reply

Sep 20, 2024 2:31 PM in response to .m.

A subtle problem that, for sure, Apple could fix, but I think I understand why.


Ultimately, when you embed an image, the image is stored within the .numbers file and is, essentially, disassociated with the source file (especially bearing in mind that the image could be a file from disk or a photo from your Photos library. That's essentially why it doesn't update with changes to the source file.


The easiest workaround I could come up with is this:


ell application "Numbers"
	tell sheet 1 of document 1
		-- get the image
		set myImage to image 1
		-- grab its properties
		tell myImage
			set {fn, h, l, o, pos, refs, refv, rot, w} to its {file name, height, locked, opacity, position, reflection showing, reflection value, rotation, width}
		end tell
		delete myImage
		
		-- this assumes the image is on your desktop. Amend to your image path
		set newImage to make new image with properties {file:(POSIX path of (path to desktop) as text) & fn}
		tell newImage
			set {height, locked, opacity, position, reflection showing, reflection value, rotation, width} to {h, l, o, pos, refs, refv, rot, w}
			
		end tell
	end tell
end tell


It works by identifying the image (in this case I'm just assuming 'image 1'), and grabs all its properties.

It then deletes the image and immediately recreates it with the same filename (assuming it was a file on disk). The script then (re)sets all the image properties to match the original image.


Not quite the same as updating in-place, but pretty close.


Since the image is embedded, there is no record of where the original source image came from, so you'll have to set that part yourself.


This is essentially the same thing as happens if you click the 'Replace' button in the Image sidebar when the image is selected, but you wanted a scripted version.

Sep 23, 2024 11:01 AM in response to .m.

What a beautiful rathole that is...


There seems to be some internal confusion within Numbers when it relates to file references - actually this is a long-standing problem with multiple ways to define a 'file' in AppleScript, and not all applications are clear about which form they accept (and when).


I was able to replicate the problem with the documents folder. That occurs because Numbers.app overrides the path to command:


set sysPath to path to documents folder
-- > alias "Macintosh HD:Users:<username>:Documents:"


tell application "Numbers"
	set nPath to path to documents folder
	-- > alias "Macintosh HD:Users:<username>:Library:Containers:com.apple.iWork.Numbers:Data:Documents:"
end tell


which I guess kind of makes sense since you're asking Numbers for its Documents folder, but I didn't expect that (and don't see why it should affect the Desktop, which should be universal).


in either case, it's then further complicated by the fact path to returns an alias object whereas Numbers wants a file (hence the levels of coercion - file.. POSIX file... text.. yada yada yada).


Upshot, if you want to reference an image from your Documents folder, grab that path outside of a tell application "Numbers" block:


set docPath to POSIX path of (path to documents folder)

tell application "Numbers"
	-- ... existing script stripped for clarity 
		
		-- used the saved path to Documents
		set newImage to make new image with properties {file:POSIX file ((docPath) & fn as text)} --at end of images
		tell newImage
			set {height, locked, opacity, position, reflection showing, reflection value, rotation, width} to {h, l, o, pos, refs, refv, rot, w}
		end tell
	end tell
end tell



Sep 23, 2024 11:30 AM in response to .m.

> First, my scripts and SVG file are stored in the same directory as my Numbers spreadsheet. Rather than hardcode the path I want to build it programmatically based upon some manipulations of '(path to me)' for the helper script.


path to me returns the path to the running application, not the current document.


To get the current document's path, ask it for its file:


tell application "Numbers"
	tell document 1
		set f to its file		
	end tell
end tell


Now you have the path to the .numbers file. There are a couple of ways of finding the directory from there - the easiest is to ask the Finder.


Here's a revised script that looks for a file in the same folder as the .numbers file:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

tell application "Numbers"
	set docPath to file of document 1
	tell sheet 1 of document 1
		-- get the image
		set myImage to image 1
		-- grab its properties
		tell myImage
			set {fn, h, l, o, pos, refs, refv, rot, w} to its {file name, height, locked, opacity, position, reflection showing, reflection value, rotation, width}
		end tell
		delete myImage
		
	end tell
end tell

-- have to drop out of Numbers here due to property name conflicts
tell application "Finder"
	set d to container of (file docPath) -- find the folder containing the .numbers file
	-- build a path to the image by combining the folder path and the image name
	set newImagePath to (file fn of d) as text
end tell

-- and back to Numbers
tell application "Numbers"
	tell sheet 1 of document 1
		
		set newImage to make new image with properties {file:newImagePath}
		tell newImage
			set {height, locked, opacity, position, reflection showing, reflection value, rotation, width} to {h, l, o, pos, refs, refv, rot, w}
			
		end tell
	end tell
end tell


With a little work you could add a safeguard to verify the file exists before deleting the current one

Sep 24, 2024 2:18 PM in response to .m.

> The one remaining thing I'm curious about now is whether it's possible to specify an explicit image name directly (thereby extending how increadibly usefult this is), or if


As above, you can reference an image by index (... image 1 ...) or by file name.


If you know the filename, you can reference it by that:


tell application "Numbers"
	tell sheet 1 of document 1
		set myImage to first image whose file name is "Sample Image.svg"
	end tell
end tell


However, you can reference images by any of their properties:


tell application "Numbers"
	tell sheet 1 of document 1
		set myImageByHeight to first image whose height is 600 -- based on height
		set myImageByWidth to first image whose width is 450 -- based on width
		set myImagebyPosition to first image whose position is {72, 19} -- at a specific location
		set myImageByRotation to first image whose rotation is 101 -- at a specific orientation
		set myImageByDescription to first image whose description is "blah" -- with a specific description
	end tell
end tell


(note: in writing this post I realized I forgot to copy the original image's description into the replacement image, which you may want to do if you're using image descriptions)

Sep 30, 2024 12:55 PM in response to .m.

> I did a lot of digging before posting my query here, and Camelot was able to sort through some fairly esoteric layers determining how Numbers seems to actually be interacting with Applescript.


I've been doing this AppleScript thing for a while. For better or worse, core AppleScript hasn't changed much over the years, so lessons learned years ago still apply :)


> I don't know if Apple actually documents Numbers document object structure or the API abstraction model, but it would be super helpful for things like this if they do.


The starting point for any script is the target application's dictionary. In Script Editor: File -> Open Dictionary -> choose your target app.


This will show you the commands and object hierarchy, properties and structure that you can use in your script.

Experience tells you how to apply that to real-world scenarios.


For most scripts, though, I prefer Script Debugger. It's like Script Editor on steroids, with debugging features (hence its name) such as code stepping, breakpoints, variable inspection (see what your variables are as your script executes, and change them on the fly!), as well as the Explorer which lets you examine the application's state real-time. Well worth it for serious AppleScripting.

(Note: I'm not affiliated with Script Debugger or Late Night Software, just a fan :) )


Sep 25, 2024 10:50 AM in response to .m.

> I haven't been able to determine how to interpret the cryptic 'coordinate' references (1178:1188 and 414:498, respectively), so i haven't been able to pinpoint the specific source of the errors (assuming that's what thoose numeric references are supposed to help with).


That is exactly what the numbers relate to.


They represent the actual characters in the (plain text) script that are throwing the error.


In this case (assuming you're using the earlier version of the script ), it's telling you that the error occurs between characters 414 and 498, which relates to:


... make new image with properties {file:(POSIX path of (path to documents) as text) & fn}


You're on your own for mapping the number to characters in the script (I used BBEdit), but it's really only an issue when running via osascript since both Script Editor and Script Debugger would highlight the offending command if you run the script within them.

Sep 20, 2024 6:38 PM in response to Camelot

Thank you for the reply.


I have no idea why, but I run into exactly the same problem with this.


Up to the delete, this functions identically to my earlier scripting attempts.


But, as soon as I attempt to set the path to the new file (which is in the same directory as both my numbers document and my applescript, not desktop), I get this error no matter how i attempt to construct a scriptPath:


./replace_svg.scpt:1178:1188: execution error: Can’t make «class NmSh» 1 of document id "A99293C6-42C7-4F9D-8A0C-7E167B902E40" of application "Numbers" into the expected type. (-1700)


For the sake of testing, i moved a copy of my image to my desktop, and the error I get then is instead:


./replace_svg.scpt:1183:1267: execution error: Numbers got an error: Unsupported item. (-2763)


Yet, if I manually select the file, either initially, or using 'Replace Image...', it imports the image without a peep.


I literally used exactly the code in the example (with the initial 't' replaced):

tell application "Numbers"
	tell sheet 1 of document 1
		-- get the image
		set myImage to image 1
		-- grab its properties
		tell myImage
			set {fn, h, l, o, pos, refs, refv, rot, w} to its {file name, height, locked, opacity, position, reflection showing, reflection value, rotation, width}
		end tell
		delete myImage

		-- this assumes the image is on your desktop. Amend to your image path
		set newImage to make new image with properties {file:(POSIX path of (path to desktop) as text) & fn}
		tell newImage
			set {height, locked, opacity, position, reflection showing, reflection value, rotation, width} to {h, l, o, pos, refs, refv, rot, w}

		end tell
	end tell
end tell


and I get the following error:

%# osascript ./replace_svg.scpt
./replace_svg.scpt:414:498: execution error: Numbers got an error: Unsupported item. (-2763)

Sep 20, 2024 7:46 PM in response to .m.

I was able to get the script to work on Numbers 14.2 running under macOS 14.6.1 (Sonoma). I ran it from Script Editor.


I'm always curious about new uses of Numbers. Your efforts to automate suggest you must be working with a lot of images in Numbers. Otherwise manual replacement would be more efficient.


Can you share a little more about your project? In your experience how good is Numbers at handling images?


SG

Sep 23, 2024 6:26 AM in response to SGIII

I'm also using Numbers 14.2, in Sonoma 14.6.1.


This particular project is for an Electoral College Calculator.


On a sheet, I built a table that has all of the states, including the district-level breakouts for Maine and Nebraska, a (hidden) column with their electoral values, and columns of checkboxes. I have summary headers that, based upon the status of the checkboxes, calculate the sum of the values of the electoral votes, and an additional column that checks each row for exactly one checkbox each. If there isn't exactly one checkbox for a given row, an arrow is displayed indicating it needs attention.


Additionally, I have an election countdown table, and a Tally check table that has a summary header indicating if the tally is complete (all 538 votes accounted for), if there are too few, or too many, and provides either a Tally Complete, Too Many, or Too Few votes, with instructions to check for arrows to identify rows requiring attention. The check table also displays a larger, color-coded tally for each candidate, and it displays different messages, based upon the final results.


And, I have a 'Notes' table, explaining the Split States of Maine and Nebraska and how they handle their electoral votes, notes on Data Sources, Color coding, and other relevant information about how the calculator works.


That all works perfectly.


My next addition was adding an SVG image of the US, which includes embedded stylesheet information allowing me to color code each state. That's the image I'm trying to replace programmatically using Applescript.


Now I'm doing some scripting to update the color coding. I've written a Ruby script which calls a helper Applescript which populates an array indicating to which candidate a state has been assigned based upon the checkbox values, then processes the array to update the CSS data within the SVG file. This also works as intended.


The last element I now want to automate is to replace the SVG image after the CSS data has been updated, by calling another helper Applescript. I had a script very similar to the one suggested, but, just like now, I get as far as deleting the old image, which works, but I still appear to be running into two distinct problems.


First, my scripts and SVG file are stored in the same directory as my Numbers spreadsheet. Rather than hardcode the path I want to build it programmatically based upon some manipulations of '(path to me)' for the helper script. I've tried at least half-a-dozen different methods for that, but those all seem to return the error:


./replace_svg.scpt:1178:1188: execution error: Can’t make «class NmSh» 1 of document id "A99293C6-42C7-4F9D-8A0C-7E167B902E40" of application "Numbers" into the expected type. (-1700)


After deciding to ignore that for the moment (one problem at a time), adding a copy of my SVG to the desktop to test the rest of the script suggested by Camelot, their script appears to find the SVG file, but then instead returns the error:


./replace_svg.scpt:414:498: execution error: Numbers got an error: Unsupported item. (-2763)


So, I'm left wondering if Applescript for some reason is balking at adding an SVG file, even though I can add the file to the sheet manually without any problem.


(Ultimately, I'd love to add a button to trigger my other scripts, but that may be beyond Numbers capabilities directly. That might be something I can automate using something like a 'Shortcut', but that's a different matter, and moot unless I can get this part to work.)

Sep 23, 2024 8:43 AM in response to .m.

Further digging into Error Codes:

-1700 Bad parameter data was detected or there was a failure while performing a coercion.

This suggests there's some sort of casting error when trying to set the correct path to my .svg file. I'd somewhat expected it's something like that from the rest of the message. I'll dig into path references to try to sort that out. (I wish the documentation wasn't written at the level of a man page where you can parse it only if you already know what it means, but 'if wishes were horses, then beggars would ride'...)


The other error turns out to be:

-2763 No result was returned for some argument of this expression.


which could, i suppose, mean that Applescript can't find the file, even when it's on the Desktop, or could be something else. I haven't been able to determine how to interpret the cryptic 'coordinate' references (1178:1188 and 414:498, respectively), so i haven't been able to pinpoint the specific source of the errors (assuming that's what thoose numeric references are supposed to help with).

Sep 24, 2024 11:52 AM in response to Camelot

THANK YOU!


"And, just like that..."


set newImage now pulls the updated SVG image in, without a murmur of complaint.


The path was indeed the 'terrible, awful, no good, very bad' problem, that you have so very helpfully solved. :D


Since I'm only dealing with a single image per sheet within my Numbers document, I was able to rapidly amend this to reference my explicit file name, and explicit sheet names within my document, with a guard test to delete only if a file already exists, so i can now replace the relevant image in specific sheets, which is exactly what i was hoping to do. (Of course, if no file exists from which to pull properties, then it will fail at the 'tell new image' step, since i haven't yet set defaults, but that I think I can sort out, which would allow me to adapt my scripting to create templates for things at some later point.)


The one remaining thing I'm curious about now is whether it's possible to specify an explicit image name directly (thereby extending how increadibly usefult this is), or if

set myImage to Image 1

is the only feasible way to do this?


If using an image index is the only way to do this, is there a way to identify the appropriate image index by first querying a sheet for all images, then comparing the images in the returned list to an explicit image name (even if that requires iterating through the returned list/array to identify the matching image)?

Sep 30, 2024 11:38 AM in response to SGIII

Indeed I do. :)


I did a lot of digging before posting my query here, and Camelot was able to sort through some fairly esoteric layers determining how Numbers seems to actually be interacting with Applescript.


I don't know if Apple actually documents Numbers document object structure or the API abstraction model, but it would be super helpful for things like this if they do.


The assistance here is greatly appreciated.

Oct 5, 2024 6:39 AM in response to SGIII

Yup. Thanks.


Your link suggestion was one of the sites I found when digging around. It helped me get as far as i did before posting my question here. 🙂


It does indeed have some useful stuff.


(And , yes, I’ve been upvoting, too, but it seems sometimes the community discussions site ignores that. 🤪)

scripting image replacement within numbers

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.