1

My project has been written by Ruby on Rails, since google-api-client gem does not support inserting the image to spreadsheet through sheet apis, so I am using Google app script to handle this task. Most of times, the inserting has been success with this calling:

@app_script.run_script(script_id, request) 

I just provide my script for anyone who're curious: https://script.google.com/a/vectorgroup.vn/d/1ndcgpfJMj3YdKj0pEvHWz0pF4NtcQyR1Qg8wj7ZnpKfIwP2UsH0xaYq4/edit?splash=yes

The problem is sometimes, the calling is failed with below error:

Error detail: [{\"@type\"=>\"type.googleapis.com/google.apps.script.v1.ExecutionError\", \"scriptStackTraceElements\"=>[{\"function\"=>\"addImageOnSpreadsheet\"}], \"errorMessage\"=>\"Exception: Error retrieving image from URL or bad URL: https://drive.google.com/uc?id=1MS6KMfua7kZCSGMUhny4kDUvalxTkoKJ&export=download\", \"errorType\"=>\"ScriptError\"}]" 2020-04-06T06:03:33.821Z pid=26645 tid=tz8bh class=ImageTakerWorker jid=d847bf91beea8aeb4a30b042 elapsed=11.689 INFO: done Error: 3" "Error detail: [{\"@type\"=>\"type.googleapis.com/google.apps.script.v1.ExecutionError\", \"scriptStackTraceElements\"=>[{\"function\"=>\"addImageOnSpreadsheet\"}], \"errorMessage\"=>\"Exception: Error retrieving image from URL or bad URL: https://drive.google.com/uc?id=1G9EDgvygwVztMG66FArZ6BEFpzW71izA&export=download\", \"errorType\"=>\"ScriptError\"}]" 2020-04-06T08:00:28.330Z pid=26645 tid=tz7zl class=ImageTakerWorker jid=a6b4fcb47db15f71dbf1d3f5 elapsed=6.514 INFO: done "Insert image ERROR: #, #" "Error: 3" "Error detail: [{\"@type\"=>\"type.googleapis.com/google.apps.script.v1.ExecutionError\", \"scriptStackTraceElements\"=>[{\"function\"=>\"addImageOnSpreadsheet\"}], \"errorMessage\"=>\"Exception: Error retrieving image from URL or bad URL: https://drive.google.com/uc?id=1_3KzBDDgpINMCNkEZj2LivqdUaxFKZNT&export=download\", \"errorType\"=>\"ScriptError\"}]" 2020-04-06T08:00:28.941Z pid=26645 tid=tzahx class=ImageTakerWorker jid=8010f8c64cb9a0efa672b713 elapsed=7.121 INFO: done

The issue seems happen with url image, somehow google app script could not extract image data. But when issue happen, I just copy and paste above image url in error log to browser manually, it can download the image successfully. Note that I already set the public for image url.

Below is my google app script part:

class GoogleAppScript
  APPLICATION_NAME = "Insert image to spreadsheet".freeze

  def initialize(user_id, sheet_id, options = {})
    @user = User.find(user_id)
    @sheet_id = sheet_id
    @from_class = options[:from_class]
    @service = options[:service]
    @keyword = options[:keyword]
    @sheet_name = options[:service] == "google" ? "G" + options[:keyword].strip : "Y" + options[:keyword].strip
    @image_file_id = options[:image_file_id]
    @google_authorization = GoogleAuthorization.new(@user).authorize
    @app_script = Google::Apis::ScriptV1::ScriptService.new
    @app_script.client_options.application_name = APPLICATION_NAME
    @app_script.authorization = @google_authorization
  end

  def execute
    script_id = "1ndcgpfJMj3YdKj0pEvHWz0pF4NtcQyR1Qg8wj7ZnpKfIwP2UsH0xaYq4"
    url_image = "https://drive.google.com/uc?id=#{@image_file_id}&export=download"

    start_col = 1
    if @from_class == "ImageX"
      start_row = 51
      width = 692
      height = 1500
    else # "ImageY"
      start_row = @keyword.last == " " ? 30 : 9
      width = 694
      height = 418
    end
    request = Google::Apis::ScriptV1::ExecutionRequest.new(
      function: "addImageOnSpreadsheet",
      parameters: [@sheet_id, @sheet_name, url_image, start_col, start_row, width, height],
    )

    begin
      response = @app_script.run_script(script_id, request)
      if response.error
        # Retry until success
        # ImageTakerWorker.perform_async(@user.id, @sheet_id, @sheet_name, @image_file_id)
        p "Insert image ERROR: #{response}, #{response.error}"
        p "Error: #{response.error.code}"
        p "Error detail: #{response.error.details}"
      else
        p "Insert image successfully"
      end
    rescue Google::Apis::ClientError
      # Handle the error...
    end
  end
end

Anyone have experience on this?

Tiktac
  • 966
  • 1
  • 12
  • 32
  • 1
    Can you provide the sample URL for replicating your issue? Or, if no error occurs when you directly use the URL in the Google Apps Script at the script editor, can you provide the request body or your script? – Tanaike Apr 06 '20 at 07:52
  • @Tanaike I just attached them into the question. – Tiktac Apr 06 '20 at 08:11
  • Thank you for replying and adding the information. At first, from your replying, when you directly use the URL in your Google Apps Script, no error occurs. Is my understanding correct? And, in the case of the webContentLink, the file is required to be shared publicly. Can you confirm it? And, can you confirm whether the file is the image file which can be put? Also, when you put the file ID as the argument and the image blob is used by retrieving in your script, what result will you get? If these didn't lead to the solution or the reason of the issue, I apologize. – Tanaike Apr 06 '20 at 08:25
  • Thanks for your suggestion, I mean when the script execute error, I can still see that browser can download the image well if I copy and paste the image URL to web browser by hand. As I told, I already set the Public on the web permission for my images folder. That mean all image are public. Then I also try to modify my app script and params to retrieve the image url via webContentLink, I observed the same error log. It can be found here: https://script.google.com/d/1SKX1zMKaVcmnct9OqOYA7YL1gCOyXebElhwPB4HXCR-4uG2t5bkTZ98x/edit?usp=sharing. – Tiktac Apr 06 '20 at 08:38
  • I tried to run my application several times, sometimes, it can complete inserting without any error. Sometimes, above error happens. – Tiktac Apr 06 '20 at 08:43
  • Thank you for replying. I have to apologize for my poor English skill. I could confirm my proposal was not reflected. When you put the file ID as the argument and the image blob is used by retrieving in your script, what result will you get? The script is like `SpreadsheetApp.openById(spreadsheet_id).getSheetByName(sheet_name).insertImage(DriveApp.getFileById(image_file_id).getBlob(), column, row)`. In this case, as a test, please directly run at the script editor. When the error occurs, please provide it. – Tanaike Apr 06 '20 at 08:46
  • I think that when you use the image file on own Google Drive, you can put the blob retrieved by the Google Apps Script. In this case, the issue of sharing and authorizing can be avoided. How about this? By the way, there are some limitations for inserting an image to Google Docs. Also please be careful this. [Ref](https://gist.github.com/tanaikech/9414d22de2ff30216269ca7be4bce462) – Tanaike Apr 06 '20 at 08:54
  • Understand what you mean @Tanaike, let me try your solution then double check :) – Tiktac Apr 06 '20 at 08:56
  • Thanks for your great help, seem that following your solution can by pass above issue. But somehow google app script responses with `Server error` message instead of. It happens with some images, not at all. How do you think? – Tiktac Apr 06 '20 at 17:18
  • In that case of "Server error", I think that the reason of issue might be due to [the limitation of the image size](https://gist.github.com/tanaikech/9414d22de2ff30216269ca7be4bce462). So how about checking it again? But I'm not sure about your actual situation. So if my understanding of your issue is not correct, I apologize. – Tanaike Apr 06 '20 at 22:19
  • Seem you are right again, in my case, image can be inserted well with resolution is `628 × 1658`. But if the resolution is `652×1737` or higher, `Server error` happen. I checked your Ref page and saw that `the limitation of area is 1,048,576 pixels^2 for Spreadsheet`. So is there away to resize image Blob automatically before inserting it inside app script? Could you advise? – Tiktac Apr 07 '20 at 03:25
  • I found a solution which you provided [here](https://stackoverflow.com/questions/58958716/google-script-how-to-resize-image-in-blob#comment104174316_58958716) . Could it be applicable for me? I just try this approach but whenever I call `UrlFetchApp.fetch`, I get this error: `You do not have permission to call UrlFetchApp.fetch. Required permissions: https://www.googleapis.com/auth/script.external_request\", \"errorType\"=>\"ScriptError\"}]"` – Tiktac Apr 07 '20 at 06:15
  • Thank you for replying. About the resize of the image, I proposed a sample script as an answer. Could you please confirm it? If that was not the direction you want, I apologize. – Tanaike Apr 07 '20 at 06:26

1 Answers1

2

This is my understanding:

  • In your situation, when an image is inserted to Google Spreadsheet, an error of Server error occurs.
  • In this case, it is considered that the size of image is more than the limitation. Reference
  • You want to resize the image when the limitation size for inserting to Google Spreadsheet is over.

Issue and workaround:

In this case, even when setWidth and setHeight are used, the error cannot be removed. Because the error occurs when the image is inserted. So in this answer, I would like to propose to insert the image by resizing at a Google Apps Script library.

Modified script:

When your script is modified, it becomes as follows. Before you use this script, please install a GAS library of ImgApp.

function addImageOnSpreadsheet(spreadsheet_id, sheet_name, image_file_id, column, row, width, height) {
  let blobSource = DriveApp.getFileById(image_file_id).getBlob();
  const obj = ImgApp.getSize(blobSource);
  if (obj.height * obj.width > 1048576) {
    blobSource = ImgApp.doResize(image_file_id, width).blob;
  }
  let image = SpreadsheetApp.openById(spreadsheet_id).insertImage(blobSource, column, row);
  image.setWidth(width).setHeight(height);
}
  • As a test, I recommend to directly run the script at the script editor.

Note:

  • In this case, the following 3 scopes are used. Although I'm not sure about your whole script, please add those scopes. Please be careful this. In your case, please add the scopes and reauthorize again. By this, the valid access token can be used.
    • https://www.googleapis.com/auth/drive
    • https://www.googleapis.com/auth/script.external_request
    • https://www.googleapis.com/auth/spreadsheets

References:

Added:

Sample script:

This sample script is for receiving multiple file IDs.

function addImageOnSpreadsheet(ar) {
  ar.forEach(o => {
    let blobSource = DriveApp.getFileById(o.image_file_id).getBlob();
    const obj = ImgApp.getSize(blobSource);
    if (obj.height * obj.width > 1048576) {
      blobSource = ImgApp.doResize(o.image_file_id, o.width).blob;
    }
    var image = SpreadsheetApp.openById(o.spreadsheet_id).insertImage(blobSource, o.column, o.row);
    image.setWidth(o.width).setHeight(o.height);
  });
}
  • For example ar is like as follows.

      ar = [
        {spreadsheet_id: "###", image_file_id: "###", column: ##, row: ##, width: ###, height: ###},
        {spreadsheet_id: "###", image_file_id: "###", column: ##, row: ##, width: ###, height: ###},
        ,
        ,
      ];
    
halfer
  • 19,824
  • 17
  • 99
  • 186
Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • thank you, this is what I want. But when using your lib, I face another error: `Error detail: [{\"@type\"=>\"type.googleapis.com/google.apps.script.v1.ExecutionError\", \"scriptStackTraceElements\"=>[{\"function\"=>\"ImgApp.DoResize\", \"lineNumber\"=>125}, {\"function\"=>\"doResize\", \"lineNumber\"=>37}], \"errorMessage\"=>\"Error: '1046l265YJSBDhMiW19t-lz7QCLZeVUUT' is not compatible file. Error message is {}\", \"errorType\"=>\"ScriptError\"}]"`. Might it come from your doResize function? – Tiktac Apr 07 '20 at 06:42
  • @Tiktac Thank you for replying. I apologize for the inconvenience. About the file of `1046l265YJSBDhMiW19t-lz7QCLZeVUUT`, can I ask you about the file type of it? When that is the file except for BMP, GIF, PNG and JPG, an error might occur. Please be careful this. – Tanaike Apr 07 '20 at 06:43
  • They are jpg images, which I wanted to insert. You can see this file here https://drive.google.com/file/d/1046l265YJSBDhMiW19t-lz7QCLZeVUUT/view – Tiktac Apr 07 '20 at 06:47
  • @Tiktac Thank you for replying. When I tested the image of URL, no error occurs. So can you confirm the script and request body again? And when you directly run the script at the script editor, what result will you get? – Tanaike Apr 07 '20 at 06:49
  • I just changed params to run script `request = Google::Apis::ScriptV1::ExecutionRequest.new( function: "addImageOnSpreadsheet", parameters: [@sheet_id, @sheet_name, @image_file_id, start_col, start_row, width, height], )`. I just pass `@image_file_id` instead of `url_image` and use your script in the answer. The correct behavior is some images are inserted success but others get the error as I commented. Let me check again – Tiktac Apr 07 '20 at 06:58
  • @Tiktac Thank you for replying and testing it. In my environment, I couldn't still replicate your situation. I apologize for this. The script works for the image of your URL. – Tanaike Apr 07 '20 at 07:01
  • somehow, the script execute success when I run it directly from script editor. But in my case, I am calling script from my ruby application, script will be call continuously until all images are inserted. Then I got the error about `is not compatible file`, it is so strange. Do you have any idea? – Tiktac Apr 07 '20 at 08:26
  • @Tiktac Thank you for replying. I could understand that in your situation, the script works at the script editor. About your ruby script, I cannot understand about `script will be call continuously until all images are inserted.`. Can I ask you about it? – Tanaike Apr 07 '20 at 08:40
  • I mean I need to insert a bunch of images into several spreadsheet. Each time, to insert image, my ruby code will invoke google app script to execute. So I will call it many times. You can think as I will have a loop: `while(!allImagesInserted){ GoogleAppScript.new.execute }` – Tiktac Apr 07 '20 at 08:50
  • 1
    @Tiktac Thank you for replying. In your case, for example, how about sending the several file IDs by one API call using an array in the request body? And the file IDs are processed in the Google Apps Script. In your ruby script, `[@sheet_id, @sheet_name, url_image, start_col, start_row, width, height]` of `parameters` is one of elements in an array. How about this? – Tanaike Apr 07 '20 at 08:52
  • Let me try, but as I see the calling `blobSource = ImgApp.doResize(image_file_id, width).blob;` raising the error from the beginning (The first image has size exceed limitation) – Tiktac Apr 07 '20 at 08:57
  • @Tiktac I added one more sample script for receiving multiple file IDs. Could you please confirm it? At first, please test it at the script editor. – Tanaike Apr 07 '20 at 09:01
  • Thanks you, let me work on it and I will let you know the result. – Tiktac Apr 07 '20 at 09:07
  • You seem right, it is possible if I put all images in one execution, Is it possible to insert a bunch of hundred image for a script executions? I am trying 30 images but google reply with `execution expired` message. – Tiktac Apr 08 '20 at 03:49
  • So the error might happen if I invoke script several times? – Tiktac Apr 08 '20 at 03:50
  • @Tiktac Thank you for replying. About ` Is it possible to insert a bunch of hundred image for a script executions?`, I don't have the clear answer. This is due to my poor skill. I deeply apologize for this. And when the API is continuously requested, an error might occur. So please be careful this. The reason I cannot tell the clear answer for your replying is due to my poor skill. I deeply apologize for this. – Tanaike Apr 08 '20 at 04:23
  • No @Tanaike, You are awesome! Thank you for your great help. – Tiktac Apr 08 '20 at 04:35
  • @Tiktac Thank you for replying. I would like to study more for understanding the various situations. From your question, I could also study. Thank you, too. – Tanaike Apr 08 '20 at 04:36
  • Thank you @Tanaike for your strong professional. I have one more question. After resizing, the image quality is not meet our expectation. Could you please advise, how can I achieve the best quality for resizing? – Tiktac Apr 08 '20 at 06:21
  • @Tiktac Thank you for replying. Unfortunately, I'm not sure about `how can I achieve the best quality for resizing`. This is also due to my poor skill. I deeply apologize for this. – Tanaike Apr 08 '20 at 06:24
  • @Tiktac I'm so sorry. – Tanaike Apr 08 '20 at 06:45