Calculating image dimensions in server side apps script

Apps Script (intermediate level) posted on 18th September 2018


I have a Node project that looks at Google Cloud storage and figures out the dimensions of images stored there. This is handy for an API to be able to serve up the right one for the right device. I needed the same capability in Apps Script, but the Nodejs code uses some stuff not available in Apps Script. I could have spun up an htmlservice  and done that using the DOM, but since dimensions are buried in the encoding for images I figured it must be possible to play around with an image blob instead. I came across this project https://github.com/tanaikech/ImgApp from Kanshi TANAIKE, which is more extensive than I need, but it did contain the code to extract out the dimensions from various images. 

It's now in the Images namespace of my cUseful library - 1EbLSESpiGkI3PYmJqWh3-rmLkYKAtCNPi1L2YCtMgo2Ut8xMThfJ41Ex

Example 

cUseful.Images.getInfo(blob) will work on any blob containing a supported image, so if that's all you need then you can stop here, but for a more substantial demo of a workflow, I'm going to do all this in a few lines of code.
  • Use a service account to authenticate to Google Cloud Storage, using my goa library.
  • Get list of objects in a cloud storage folder, and get their contents as a blob using my gcsstore library.
  • Get info about the images using the new name space (Images) in my cuseful library
  • Populate a sheet with info about each of the found images.
The test uses 2 images - all exactly the same but in jpg, bmp, gif and png formats. For the full example you'll need these libraries
  • cUseful - 1EbLSESpiGkI3PYmJqWh3-rmLkYKAtCNPi1L2YCtMgo2Ut8xMThfJ41Ex
  • cGoa - 1v_l4xN3ICa0lAW315NQEzAHPSoNiFdWHsMEwj2qA5t9cgZ5VWci2Qxv2
  • cGcsStore - 1w0dgijlIMA_o5p63ajzcaa_LJeUMYnrrSgfOzLKHesKZJqDCzw36qorl

Setting up service account to access cloud storage

  • Create a service account  for the project containing the cloud storage bucket you'll use, give it storage admin role, download the .json credentials to Drive and grab the file ID
  • Run this code to register the service account in your script, substituting your drive ID. You can delete it once you've run it once.
function oneOffgcsDownload() { 
  
  // used by all using this script
  var propertyStore = PropertiesService.getScriptProperties();
  // DriveApp.createFile(blob)
  // service account for cloud download
  cGoa.GoaApp.setPackage (propertyStore , 
    cGoa.GoaApp.createServiceAccount (DriveApp , {
      packageName: 'gcs_download',
      fileId:'15Nxxxxxxxxxx_6FFD4rKA',
      scopes : cGoa.GoaApp.scopesGoogleExpand (['devstorage.read_only']),
      service:'google_service'
    }));
}

Create the demo.

This example does the whole thing starting from this in cloud storage
and finishing with this in a sheet


 The embedded comments should explain the steps
function testImages () {
  // set up oauth - I'm using a service account with storage admin role
  // that ive previously set up and called gcs_download
  const goa = cGoa.make ('gcs_download',PropertiesService.getScriptProperties());
  
  // get a handle for cloud storage
  // my data is in a bucket called test-bucket
  // in a folder called testimages
  const store = new cGcsStore.GcsStore()
    .setAccessToken(goa.getToken())
    .setBucket('test-bucket')
    .setExpiryLog (false);
    
  // get the sheet I'm writing the result to
  const sheet = SpreadsheetApp
    .openById('1xxxxxxxxxxx0A')
    .getSheetByName('testimages');
    
  // get the list of files in the folder
  const files = store
    .setFolderKey ('testimages')
    .getObjects();

  // now we have the fully qualified names, we can set the folderkey back to root 
  // filter out any non-images in the folder
  // and get the blobs and info for each one
  store.setFolderKey("");
  const info = files
    .filter (function (d) {
      return d.contentType.match (/^image\//);
    })
    .map (function (d) {
      return store.get(d.name);
    })
    .map (function (d) {
      return cUseful.Images.getInfo(d);
    });
    
  // now write all that to a sheet after clearing the thing
  // we don't need the blob back so delete that column
  new cUseful.Fiddler(sheet.clearContents())
    .setData (info)
    .filterColumns (function (name) {
      return name !== "blob";
    })
    .dumpValues();
 
}


You want to learn Google Apps Script?

Learning Apps Script, (and transitioning from VBA) are covered comprehensively in my my book, Going Gas - from VBA to Apps script, All formats are available from O'ReillyAmazon and all good bookshops. You can also read a preview on O'Reilly

If you prefer Video style learning I also have two courses available. also published by O'Reilly.
Google Apps Script for Developers and Google Apps Script for Beginners.

Comments