Image crop with AppScripts in Sheets or Drive - google-apps-script

I am evaluating Google Sheets with AppScripts for a report generator. The requirements include inserting images from Google Drive. One of the input image has a fix format, which I need to crop. ( So the dimensions of the original image and the dimensions of the crop is known.)
I am looking for a solution to achieve this outcome, but I am struggling. I looked into the following methods:
No image crop function in the Drive API
No image crop ( only resize) for the Sheets OverGridImage object
No image crop for the =IMAGE() function
Manually you can create a drawing, add an image and crop it:
But you can't do this from AppScripts
You can't access the image within the drawing as an OverGridImage object. ( Which would allow you to replace it's image.)
You can use the Slides API replace(imageUrl, crop)
Is it possible to embed/link the slide into the sheet via AppScript?
Is there any other workaround? ( Even if it means creating a new file in drive?)
EDIT: Obviously there is the solution to call an external API, or to use GCP services such as CloudFunctions ( which are not free). However I am hoping for an AppScript solution. ( Or using a compatible JS library.)

I believe your goal as follows.
You want to achieve the crop of image using Google Apps Script.
Issue and workaround:
Unfortunately, in the current stage, there are no methods for directly cropping image using Google Apps Script. This has already been mentioned by your comment. So in this answer, I would like to propose a workaround for cropping image using Google Apps Script.
In this workaround, I use Microsoft Powerpoint and Google Slides. The flow of this workaround is as follows.
Create Microsoft Powerpoint (PPTX data) by setting the page size.
In this case, the width and height of the image left by the crop are set. This is used as a window of image.
When the converted PPTX data is unzipped, the data can be analyzed as the XML data. Fortunately, at Microsoft Docs, the detail specification is published as Open XML. So in this case, Microsoft Docs like XLSX, DOCX and PPTX can be analyzed using XmlService of Google Apps Script. In this workaround, the PPTX data is directly created by including the page size. I think that this method will be also useful for other situations.
When the method of "presentations.create" of Slides API can be correctly used, this is not required. Ref
Convert PPTX data to Google Slides.
Insert the image, that you want to do the crop, to the created Google Slides.
At that time, the crop of "top" and "left" is subtracted from the origin of coordinates. Because the origin of coordinates of Google Slides is the upper-left corner.
The thumbnail image is retrieved using the method of "presentations.pages.getThumbnail" in Slides API.
By above flow, the cropped image can be retrieved as a blob.
In this sample script, an image is cropped using the parameters using Google Apps Script. In this case, the script reflecting above flow is a bit complicated. So here, I would like to introduce the sample script using a Google Apps Script library. Ref Of course, you can see the whole script there.
Sample script:
Before you use this script, please install ImgApp of the Google Apps Script library. Ref And in this case, please enable Drive API and Slides API at Advanced Google services.
function myFunction() {
const id = "###"; // If you want to crop the image on Google Drive, please set the file ID of the image here.
const object = {blob: DriveApp.getFileById(id).getBlob(), crop: {t: 50, b: 100, l: 200, r: 100}};
const blob = ImgApp.editImage(object);
DriveApp.createFile(blob);
}
This sample script crops an image on Google Drive and the cropped image is created to the root folder.
crop: {t: 50, b: 100, l: 200, r: 100} means that the crop size of t, b, l and r are the top, bottom, left and right, respectively. The unit is pixel.
About the maximum image size, you can see it at Limitations for Inserting Images to Google Docs. In this sample script, 25,000,000 pixels^2 is the maximum size of the image.
References:
Understanding the Open XML file formats
XML Service
editImage() in ImgApp

Related

Google Apps Script - Slides - replaceWithImage too slow

I'm using Apps Script to generate slides containing tiles.
Each tile contain some information, example: name, ID and an image.
To generate each slide & each tile, I'm using a template composed of shapes, each shape to be modified contains a label such as {{label}}
When I find {{image}} shape, I replace the shape by an image.
Images are stored on Drive. I put everything in place to retrieve the blob associated to image but the single operation replaceWithImage takes around 2 seconds (I used console.time/timeEnd just before replaceWithImage and after).
Any idea how to accelerate this ? Initially I was suspecting the search on Drive, but it's around 200ms to look for the file and get the blob.

Google Sheets Hide Images When Hiding Rows

I have been trying to figure out a way to hide an image in google sheets when I am hiding rows that include the image.
The image is a button that has a script attached to it, which means that I cannot just use the =IMAGE() formula, and cannot use an image inside of a cell either.
The problem is that when I hide rows the image stays. Is there any way to get around this?
Answer:
Unfortunately, there is no way of doing this.
More Information:
Images in a Google Sheet that are not inserted using the =IMAGE() formula, nor by inserting the image directly in a cell, are represented by an OverGridImage object in Google Apps Script.
As you can see in the documentation for this class, there exists no method which allows you to hide the image, other than deleting it altogether.
The reason that hiding cells/rows/columns does not hide the image either, is because the image is not tied to any indvidual cell, row or column - it is inserted over the grid system of a specific sheet.
A Mix of Both Good and Bad News:
Now, in theory, what you could do instead, is store the information about the image in the script properties, and then delete/insert the image again when you wish to hide it.
Unfortunately, it appears that the .getUrl() method of the aforementioned OverGridImage class is bugged and does not return the URL of the image - this is something that I have checked myself.
In this case, I would suggest going to the issue link for this bug and hit the ☆ next to the issue number in the top left to let Google know that more people need this to be seen to.
I would also suggest filing a Feature Request with Google here, detailing that you would like to see the showing and hiding of overlay images implemented in Google Apps Script. The above link is directly for Apps Script feature requests.
And for future readers: If you are encountering this, and the .getUrl() method has been fixed, then you can use the following functions as a workaround to show and hide images. This uses PropertiesService to save the image data into the script's properties, and then uses them to re-insert the image after deletion.
function hideImage() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var image = ss.getImages(); // assuming this is the only image
var url = image[0].getUrl();
var col = image[0].getAnchorCell().getColumn();
var row = image[0].getAnchorCell().getRow();
var xOffset = image[0].getAnchorCellXOffset();
var yOffset = image[0].getAnchorCellYOffset();
var details = [url, col, row, xOffset, yOffset];
console.log(details);
PropertiesService.getScriptProperties().setProperty("image", details.toString());
image[0].remove();
}
function showImage() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var details = PropertiesService.getScriptProperties().getProperty("image").split(",");
// change for your sheet name
ss.getSheetByName("Sheet1")
.insertImage(details[0], details[1], details[2], details[3], details[4])
}
References:
Class OverGridImage | Apps Script | Google Developers
OverTheGrid Image getUrl() seems to not working - Google Issue Tracker
Google Apps Script Feature Request Form - Google Issue Tracker
Class PropertiesService | Apps Script | Google Developers
insertImage(url, column, row, offsetX, offsetY) - Class Spreadsheet | Apps Script

How can I set an image title and description when inserting an image into a Google slide using Google Apps Script?

Background
I have looked through the Google API for images and there are two methods I'm interested in using getDescription() and getTitle(). Both of these method appear in the autofill in my appscript, and both seem to work.
Problem
I cannot find a method to set the description and title of an image when inserting a an image into a Google slide.
This is the method for inserting an image, but there is not argument for a title or description.
currentPage.insertImage(imageUrl, left, top, width, height)
Question
How can I set an image title and description when inserting an image into a Google slide using Google Apps Script?
Although I'm not sure whether this workaround is useful for your situation, how about this answer? I always use for adding the title and description using Slides API, because I couldn't find the methods in SlidesApp. The sample script is as follows. In this case, I used batchUpdate of Slides API.
Sample script :
var id = currentPage.insertImage(imageUrl, left, top, width, height).getObjectId();
SlidesApp.getActivePresentation().saveAndClose(); // Important
var resource = {"requests": [
{"updatePageElementAltText": {
"objectId": id,
"description": "sampleDescription",
"title": "sampleTitle"
}
}]};
Slides.Presentations.batchUpdate(resource, presentationId);
var fields = {fields: "pageElements(description,objectId,title)"};
var ele = Slides.Presentations.Pages.get(presentationId, currentPage.getObjectId(), fields).pageElements;
ele.forEach(function(e){
if (e.objectId == id) {
Logger.log(e)
}
});
Note :
When you use this script
Please enable Slides API at advanced Google services and API console.
Please prepare presentationId and currentPage.
Please use saveAndClose() after the image is inserted.
Reference :
presentations.batchUpdate
Updated at November 20, 2018:
The Slides service was updated at Google's update at November 14, 2018, and several methods were added for achieving this issue.
new methods let you add alt titles and alt descriptions to page elements. The following methods have been added to the Group, Image, Line, PageElement, Shape, SheetsChart, Table, Video, and WordArt classes
setDescription(description)
setTitle(title)

Resize Charts made by App Script on google site

I created a line chart using app script and inserted it on google site, it shows up fine on google site as the following screenshot, but I am just wondering if I could resize the chart to make it bigger so that all legends (e.g: store F) will fully show up. (It's like I could drag the chart and make it big in excel)
Here is the part of the code I used (copied from a tutorial) and changed a bit, I tried to use .setOption to change the width but nothing happened.
var chart = Charts.newLineChart()
.setDataTable(dataTable)
.setTitle("Testing Chart")
.setOption("width",1000)
.build();
var app = UiApp.createApplication().setTitle("Testing Chart");
app.add(chart)
return app;
In terms of inserting the app script into google site, I did set up the width of "app script gadget" to 100% so I guess this is not the issue. Any advice would be greatly appreciated!
Thanks!
Going through the docs, you should try changing setOption() to be like:
.setOption("theme", "maximized")
maximized from the docs (in line with theme):
Maximizes the area of the chart, and draws the legend and all of the labels inside the chart area. Sets the following options:

Cannot add image from Google Drive to a Google Form using Apps Script

I am trying to programmatically add an image from my Google Drive to a Google form. I can get it to work using a reference to a static image URL by using the google example such as:
var img = UrlFetchApp.fetch('https://www.google.com/images/srpr/logo4w.png');
form.addImageItem().setImage(img);
This works o.k. but I want to refer to an image in my Google Drive account.
If I try and use the image share link to a Google Drive image I get an error:
var img = UrlFetchApp.fetch("https://drive.google.com/open?id=0B_u2iAm1LaoZSHd1TTExcDFrbUU");
form.addImageItem().setImage(img);
ERROR: "Blob object must have an image content type for this
operation."
And if I try and open the file by it's ID I get a different error:
var img = DriveApp.getFileById("0B_u2iAm1LaoZSHd1TTExcDFrbUU");
form.addImageItem(img);
ERROR: "Could not add image, please wait a minute and try again."
I can't seem to find any documentation about how I can achieve this or what I am doing wrong. I tried changing the sharing settings on the image in my Google Drive to be publicly available. And I have tried to get a static image URL to the image in the Google Drive but the only URL that seems to be available is the share URL which goes to a holding/display page for the image and not the actual image itself.
Sorry, I think I posted the wrong code segment, so actually what I am doing is:
var img = DriveApp.getFileById("a_valid_drive_file_id_here");
var imageItem = form.addImageItem();
imageItem.setImage(img);
And getting the "Could not add image, please wait a minute and try again." error.
However, I think I have now answered my own question, the example above (getting the file by ID and calling setImage) DOES work for images stored in Google Drive, however you get the error if the image is too large. Unfortunately the API does not seem to specify any size limits and the error message is not very useful and again does not say anything about the image being too large.
So I don't know what the size limit is for images added in this way, but if anyone else has the same error, try reducing the size of the image file.
The method addImageItem does not take a parameter. It just adds an item that will hold an image to be specified. To specify that image, call setImage, passing a blob as an argument. A blob is obtained from a File object by calling its getBlob method.
var img = DriveApp.getFileById("0B_u2iAm1LaoZSHd1TTExcDFrbUU");
var blob = img.getBlob();
form.addImageItem().setImage(blob);
I recommend careful reading of Form and ImageItem class documentation.