Chris Norman
Chris Norman

Reputation: 235

Getting image dimensions using Javascript via AppleScript

Trying to do something that I thought would be easy, and that is to get an online image's dimensions using javascript and then throwing those values back to AppleScript.

Check out this source code, I thought it would work, but I am a complete noob when it comes to Javascript.

set theVar to "https://i.ebayimg.com/images/g/M58AAMXQaBtRAPkA/s-l500.jpg"

set theScript to "var img = theVar;
var height = img.height;
var width = img.width;"

tell application "Safari"
do JavaScript theScript
end tell
set theResult to result

I would have hoped that the dimensions would have been returned as the result.

Upvotes: 1

Views: 599

Answers (4)

red_menace
red_menace

Reputation: 3412

The files will need to be downloaded in order to get the images to work with, but you don't necessarily need to save them. You can use AppleScript or JXA to get the contents of the URL into an NSImage, where you can get its size property - for example:

AppleScript:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"

set theURL to current application's NSURL's URLWithString:"https://i.ebayimg.com/images/g/M58AAMXQaBtRAPkA/s-l500.jpg"
set theImage to current application's NSImage's alloc's initByReferencingURL:theURL
theImage's |size| as record

EDIT:

Taking another look after comments, if an URL is used that isn't an image, both script editors crash when using initWithContentsOfURL (osascript also errors out). Using initByReferencingURL appears to work OK (you can also use the valid property to check the image).

JXA:

ObjC.import('Cocoa')
theURL = $.NSURL.URLWithString('https://i.ebayimg.com/images/g/M58AAMXQaBtRAPkA/s-l500.jpg')
theImage = $.NSImage.alloc.initWithContentsOfURL(theURL)
theImage.size

Upvotes: 2

RobC
RobC

Reputation: 24982

Obtaining the width and height properties of the first image:

Given that the URL in your question has one image consider the following gist:

set theURL to "https://i.ebayimg.com/images/g/M58AAMXQaBtRAPkA/s-l500.jpg"

set js to "[].slice.call(document.querySelectorAll('img')).map(function(img) {return {src: img.src, width: img.width, height: img.height}});"

tell application "Safari"
  make new document with properties {URL:theURL}
  delay 4
  set imgProps to (do JavaScript js in current tab of window 1)

  if (length of imgProps > 0) then
    set {width:width} to item 1 of imgProps
    set {height:height} to item 1 of imgProps
    set {src:src} to item 1 of imgProps

    log width
    log height
    log src
  end if
end tell

Explanation:

  1. The following line of JavaScript which is assigned to the AppleScript variable named js:

    [].slice.call(document.querySelectorAll('img')).map(function(img) {return {src: img.src, width: img.width, height: img.height}});
    
    • Utilizes the document's querySelectorAll() method to obtain a NodeList of every img element in the DOM.
    • The [].slice.call(...) part transforms the NodeList (which are array-like) into an Array - this enables us to utilize methods provided by the Array such as map().

      Note: For modern versions of Safari that support you can substitute this with the Array.from(...) method. However, [].slice.call(...) works for versions of Safari that support ES5 only, and modern ES6 too.

    • The callback function provided to map, i.e. this part;

      function(img) {return {src: img.src, width: img.width, height: img.height}}
      

      returns an Object with properties/values for src, width, and height for each img element.

  2. The make new document with properties {URL:theURL} part creates a new document in Safari with given URL. It essentially opens/loads the URL.

  3. The delay 4 part utilizes the delay command to pause script execution, (4 seconds in this example), to allow the webpage time to load before proceeding to execute the JavaScript.

    Important You may need to increase/decrease this duration depending on how fast the page loads. There are also other solutions for waiting for the webpage to load that you may want to consider trying, such as this post, and this post. In essence Safari's AppleScript API doesn't provide a built-in feature for this so any solution, including the use of the delay command, is a workaround/hack ¯\_(ツ)_/¯

  4. The set imgProps to do JavaScript js in current tab of window 1 part executes the JavaScript and assigns the result (i.e. an AppleScript list of record's'), to the imgProps variable.

  5. The final parts:

    set {width:width} to item 1 of imgProps
    set {height:height} to item 1 of imgProps
    set {src:src} to item 1 of imgProps
    
    log width
    log height
    log src
    

    assigns the values for each property (width, height, and src) from the first record in the list to their own variables namely; width, height, and src.

    Finally, we log the value for each variable.

    Note These final parts reside in the body of the if (length of imgProps > 0) then staement so that they only run when the given webpage does contain one or more images


Obtaining the width and height properties of all images:

The same Javascript code as per above can be utilized to obtain the properties of all img elements in a webpage. The notable difference in the following example are:

  1. A different URL to a webpage is provided that does contain more than one img element.
  2. The delay duration is increased (note: change this as necessary).
  3. repeat is utilized to loop through each record in the list and log the properties.
set theURL to "https://en.wikipedia.org/wiki/Car"

set js to "[].slice.call(document.querySelectorAll('img')).map(function(img) {return {src: img.src, width: img.width, height: img.height}});"

tell application "Safari"
  make new document with properties {URL:theURL}
  delay 8
  set imgProps to do JavaScript js in current tab of window 1

  if (length of imgProps > 0) then
    repeat with img in items of imgProps
      log width of img
      log height of img
      log src of img
      log "-------"
    end repeat
  end if
end tell

Upvotes: 2

user73082
user73082

Reputation: 5

You could try a hacky method:

set theURL to "https://i.ebayimg.com/images/g/M58AAMXQaBtRAPkA/s-l500.jpg"

tell application "Safari"

    set URL of document 1 to theURL

    delay 1 --> lazy way to let image load; also see below

    tell window 1

        tell tab 1

            do JavaScript ("window.location.reload();") -- refresh window; otherwise you might get "Untitled"

        end tell

    end tell

    return name of document 1 --> "s-l500.jpg 500×301 pixels" -- from here you can parse to get dimensions
end tell

Upvotes: 0

wch1zpink
wch1zpink

Reputation: 3142

This is not a JavaScript solution. However, this following AppleScript code, will download all of the images from the image URLs you define in line 1 of the code. Next, it will write to a file, the image name and its dimensions. The end of the code provides a command to delete the downloaded images and will reveal the text file, in Finder, containing the image names and their dimensions.

The folder and file paths are not hardcoded, so all you need to do is enter the image URLs to the variable in the first line of this AppleScript.

This AppleScript code works for me using the latest version of macOS Mojave.

set imageURL to {"https://i.ebayimg.com/images/g/M58AAMXQaBtRAPkA/s-l500.jpg", "https://i.imgur.com/gQQHPBn.png"} -- Can Enter Multiples

-- Downloads The Images (Defined Above) To The Folder (Defined Below)
set downloadedImagesFolder to ((path to downloads folder as text) & "Images For Dimensions") as text
set quotedFormOfDownloadedImagesFolder to quoted form of POSIX path of downloadedImagesFolder
-- Writes Name Of Image And It's Dimensions To The File (Defined Below)
set imageDimensionsFile to ((path to downloads folder as text) & "File_Dimensions.txt") as text
set quotedFormOfImageDimensionsFile to quoted form of POSIX path of imageDimensionsFile

tell application "Finder"
    if not (exists of folder downloadedImagesFolder) then
        make new folder at (path to downloads folder) ¬
            with properties {name:"Images For Dimensions"}
    end if
end tell

repeat with i in imageURL
    set imageURLText to i
    set text item delimiters to "https" -- shell script "lwp-download " errors with "https"
    set tempURL to text items of imageURLText
    set text item delimiters to "http" -- replaces "https" with "http"
    set finalImgeURL to tempURL as text
    set text item delimiters to ""
    try
        do shell script "lwp-download " & quoted form of finalImgeURL & " " & quotedFormOfDownloadedImagesFolder
    end try
end repeat

tell application "Finder"
    set imageFiles to files of folder downloadedImagesFolder as alias list
    set quotedFormOfImageFiles to {}
    repeat with i in imageFiles
        set end of quotedFormOfImageFiles to quoted form of POSIX path of i
    end repeat
end tell

repeat with thisItem in quotedFormOfImageFiles
    delay 2 -- May Need To Increase Value If Returning Null Value Results
    -- replace " >> " with " > " Below... If You Prefer To Overwrite The File Instead Of Append
    do shell script "mdls -name kMDItemFSName -name kMDItemPixelHeight -name kMDItemPixelWidth " & thisItem & " >> " & quotedFormOfImageDimensionsFile
end repeat

tell application "Finder" to reveal imageDimensionsFile

(* Comment Out Or Remove The Following Line If You Don't Want To
Delete The Downloaded Images *)
tell application "Finder" to delete folder downloadedImagesFolder

Upvotes: 1

Related Questions