Skip to content

Instantly share code, notes, and snippets.

@Max-Makhrov
Last active December 21, 2023 18:17
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Max-Makhrov/a70ca1a5a5fbf32b7ef97c5cd1888510 to your computer and use it in GitHub Desktop.
Save Max-Makhrov/a70ca1a5a5fbf32b7ef97c5cd1888510 to your computer and use it in GitHub Desktop.
Upload image from your Computer to Google Drive using HTML-form. Show image via URL (IMAGE function) in your Spreadsheet

Upload image from your Computer to Google Drive using HTML-form. Show image via URL (IMAGE function) in your Spreadsheet

About the script

The sctipt was originally designed by Kanshi TANAIKE.

Please see the original script and instructions first.

Script : Google Apps Script

// this function executes from html-form
function doPost(e) {
  var data = Utilities.base64Decode(e.parameters.data);
  var blob = Utilities.newBlob(data, e.parameters.mimetype, e.parameters.filename);
  // save image to selected folder
  var folder = DriveApp.getFolderById('1tPY3eyK3qh5nDrgb_-G1Kl-ltYJp-j5k');                      // your folder id
  var file = folder.createFile(blob);
  
  // put the image with the help of a formula in a cell in Google Sheets
  // https://webapps.stackexchange.com/questions/86081/insert-image-from-google-drive-into-google-sheets
  var ss = SpreadsheetApp.openById('1BKkd5LwBYyGoi2um-S3pTCBKrUEko34m9vJu94K8uOQ');              // your spreadsheet id
  var r = ss.getSheetByName('Image_test').getRange('B2');                                        // your sheet name and cell-address
  var id = file.getId();
  r.setFormula('=IMAGE("https://docs.google.com/uc?export=view&id=' + id + '")');
  

  // here I want browser window to close 
  PropertiesService.getScriptProperties().setProperty('my_unique_key', 'Done')  
  var output = HtmlService.createHtmlOutput("<b>Done!</b>");
  output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
  return output;
}
function doGet(e) {
}

// this function openes dialog window
function openImageForm()
{  
  var html = HtmlService.createHtmlOutputFromFile('UploadForm');
  SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .showModalDialog(html, 'Select image'); 
  
}

// this function executes from HTML-form and returnes signal to close the window
// after successful loading of the file to Drive
function clientSideFunctionToProcessReturnedData()
{
  var key = 'my_unique_key';
  var props = PropertiesService.getScriptProperties()
  
  while (true)
  {
    var result = props.getProperty(key);
    if (result === 'Done')
    {
      props.deleteProperty(key);
      return true;
    } 
    // check each second
    Utilities.sleep(1000);
  }
}

Script : HTML

<!DOCTYPE html>
<html>
<head>
    <title>Sample script for uploading image and pasting it to a cell</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
	<style>
	  <!--Solution with progress-bar from here: https://www.html5rocks.com/en/tutorials/file/dndfiles-->
	  #progress_bar {
		margin: 10px 0;
		padding: 3px;
		border: 1px solid #000;
		font-size: 14px;
		clear: both;
		opacity: 0;
		-moz-transition: opacity 1s linear;
		-o-transition: opacity 1s linear;
		-webkit-transition: opacity 1s linear;
	  }
	  #progress_bar.loading {
		opacity: 1.0;
	  }
	  #progress_bar .percent {
		background-color: #99ccff;
		height: auto;
		width: 0;
	  }
	</style>
</head>
<body>  
                 <!---------------- P U T   Y O U R   W E B - A P P   U R L   H E R E  --------------->    
    <form action="https://script.google.com/macros/s/AKfycbw8B2TbYnFBZbkvzopSHXPJvEJ7fnREIQabicOz/exec" id="form" method="post">
        Upload a file
        <div id="data"></div>
        <input name="file" id="uploadfile" type="file" accept="image/*">        
        <input id="btnSubmit" type="submit">
    </form>
    <div id="progress_bar"><div class="percent">0%</div></div>

	<script>

		var reader;
		var progress = document.querySelector('.percent');

		// on error
		function errorHandler(evt) {
			switch(evt.target.error.code) {
			case evt.target.error.NOT_FOUND_ERR:
				alert('File Not Found!');
				break;
			case evt.target.error.NOT_READABLE_ERR:
				alert('File is not readable');
				break;
			case evt.target.error.ABORT_ERR:
				break; // noop
				default:
				alert('An error occurred reading this file.');
			};
		}
		
		// close html-window: https://developers.google.com/apps-script/guides/html/communication
		function closeMe() { google.script.host.close(); }

		// onprogress
		function updateProgress(evt) {
			// evt is an ProgressEvent.
			if (evt.lengthComputable) {
				var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
				// Increase the progress bar length.
				if (percentLoaded < 100) {
					progress.style.width = percentLoaded + '%';
					progress.textContent = percentLoaded + '%';
				}
			}
		}
		
		// to forse click-event. The form with file-select will open automatically
		function clickForse_() {
			var element = document.getElementById("uploadfile");
			element.click();   
		}  		
		
		// on file selected by user
		function handleFileSelect(evt) {
			// Reset progress indicator on new file selection.
			progress.style.width = '0%';
			progress.textContent = '0%';	
			reader = new FileReader();
			// remember selected file (first selected)
			var file = this.files[0];    
			reader.fileName = file.name; // save name
			reader.onerror = errorHandler;
			reader.onprogress = updateProgress;
			reader.onabort = function(e) {
				alert('File read cancelled');
			};
			reader.onloadstart = function(e) {
				document.getElementById('progress_bar').className = 'loading';
			};
			reader.onload = function(e) {
				// create data object
				// form will send data via #data element
				// https://gist.github.com/tanaikech/2f16f467c94612dc83920a3158614d95
				html = '<input type="hidden" name="data" value="' + e.target.result.replace(/^.*,/, '') + '" >';
				html += '<input type="hidden" name="mimetype" value="' + e.target.result.match(/^.*(?=;)/)[0] + '" >';
				html += '<input type="hidden" name="filename" value="' + e.target.fileName + '" >';                
				$("#data").empty().append(html);  
				// Ensure that the progress bar displays 100% at the end.
				progress.style.width = '100%';
				progress.textContent = '100%';
				// The form will close automatically when load to Google Drive is finished
				google.script.run.withSuccessHandler(closeMe).clientSideFunctionToProcessReturnedData();
			}
			// Read in the image file as a Data URL	
			reader.readAsDataURL(file);
		}

		// when user clicks button #uploadfile, add event handleFileSelect
		document.getElementById('uploadfile').addEventListener('change', handleFileSelect, false);
		// when document is loaded, add event 
		document.addEventListener('DOMContentLoaded', clickForse_, false); // gives error
    </script>
</body>
</html>

The above script is developed to create some improvements in user interaction with the form:

  1. The window with image select will open automatically

  2. A user will see the progress bar of image loading

  3. The HTML-window will close automatically when loading to drive is finished

There are also restrictions I've made:

  • the script form has a restriction to show only image file types: accept="image/*"

  • the script shows the image immediately in a cell. Please see more about inserting images from Drive to Sheets here. Note: you'll need to wait for big pictures to upload.

@JoshuaPoddoku
Copy link

Can we do this in react?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment