Applescript to change desktop background positioning (e.g., Fill to screen

applescriptdesktopmojave

I have the script

tell application "System Events"
    tell every desktop
        set picture to "/Users/jackson/Pictures/Backgrounds/backpic.jpg"
    end tell
end tell

That changes my desktop background to a specific image. The default is "Fill Screen," which I dislike. However, I cannot seem to script the dimensions.

Edit: the default seems to be whatever it was set to last, but I'd still like to know if you can control it from AppleScript

I read here that it might not be possible to directly script the answer (though it may have changed since then), but I was thinking there's probably some GUI scripting that could be done. Anyone have any ideas?

Best Answer

I pondered and researched this for some time, and with some help from this answer here, I have devised an AppleScriptObjc script that, on High Sierra at least (but should also work on Mojave), permits some customisation over the way the desktop background image is scaled to the (main) screen:

use framework "AppKit"
--------------------------------------------------------------------------------
# PROPERTY DECLARATIONS:
property this : a reference to current application

property NSWorkspace : a reference to NSWorkspace of this
property NSScreen : a reference to NSScreen of this
property NSColor : a reference to NSColor of this
property NSDictionary : a reference to NSDictionary of this

property fit : 1 -- NSImageScaleAxesIndependently (will never clip)
property centre : 2 -- NSImageScaleNone (will never clip)
property best : 3 -- NSImageScaleProportionallyUpOrDown (no clipping)
property fill : 3.1 -- NSImageScaleProportionallyUpOrDown (clipping)

property black : {0, 0, 0}
property white : {100, 100, 100}
property grey50 : {50, 50, 50}
property red : {100, 0, 0}
property green : {0, 100, 0}
property blue : {0, 0, 100}
--------------------------------------------------------------------------------
# IMPLEMENTATION:
on run
    scaleDesktopImage to fill over blue
end run
--------------------------------------------------------------------------------
# HANDLERS:
to scaleDesktopImage to scalingOption over {r, g, b} : {50, 50, 50}
    local scalingOption -- fit, centre, fill
    local r, g, b -- 0 to 100

    set clipping to false
    if scalingOption is not in [fit, centre, best, fill] then return false
    if scalingOption = fill then set clipping to true

    set sharedWorkspace to NSWorkspace's sharedWorkspace()
    set mainScreen to NSScreen's mainScreen()

    set options to {NSWorkspaceDesktopImageScalingKey:scalingOption ¬
        , NSWorkspaceDesktopImageAllowClippingKey:clipping ¬
        , NSWorkspaceDesktopImageFillColorKey:RGB(r, g, b)}

    set imageURL to sharedWorkspace's desktopImageURLForScreen:mainScreen

    set [success, E] to sharedWorkspace's setDesktopImageURL:imageURL ¬
        forScreen:mainScreen options:options |error|:(reference)

    if E = missing value then return success
    E's localizedDescription() as text
end scaleDesktopImage


on RGB(r as real, g as real, b as real)
    NSColor's colorWithCalibratedRed:r / 100 ¬
        green:g / 100 ¬
        blue:b / 100 ¬
        alpha:1.0
end RGB
---------------------------------------------------------------------------❮END❯

If you're not familiar with AppleScriptObjC, then observe the script is split into three sections: PROPERTY DECLARATIONS, IMPLEMENTATION, and HANDLERS, the first and last of which I suggest you don't try to adjust too much or at all, unless as a learning exercise.

That said, I'm sure you won't go far wrong if you decide to add your own custom colour properties to the grouping in the PROPERTY DECLARATIONS sections, each of which is simply a 3-item list specifying the red, green and blue colour components with values between 0 (zero contribution) and 100 (full contribution).

The second section of the script, headed IMPLEMENTATION, is the functional bit containing the explicitly declared (for clarity only) run handler. It's singular command is a call to the handler scaleDesktopImage, which is the line you'll be most wanting to play with to suit your needs.

It takes two forms, which I'll illustrate by example:

scaleDesktopImage to fill over blue

or:

scaleDesktopImage to fill

In other words, specifying the colour over which the desktop image is laid (i.e. the background colour), is optional. If omitted, the background colour defaults to 50% grey. Of course, you needn't use a pre-declared property to specify the background colour; you can supply directly a list of RGB values:

scaleDesktopImage to best over {100, 25, 50}

The remaining parameter is mandatory, and there are four possible named values:

  • fit: Stretches the image to fit the desktop's width and height;
  • centre: Centres the image without enlarging, however it will reduce the size of an image that would otherwise spill outside the boundary of the desktop;
  • best: Enlarges or reduces the size of the image to occupy the maximum possible area of the desktop without going outside the desktop boundary and preserving the aspect ratio of the image, i.e. a proportional size adjustment;
  • fill: Sizes the image to cover the full area of the desktop, preserving the aspect ratio, but extending beyond the boundary of the desktop along one of its axes if necessary in order to cover the background.