convert url with .svg extension to image in cell - google apps script - javascript

I have column B which contains a url in each cell. I have column C that my intention is to be the url of the cell in column B converted into an image.
The urls with extension .png/.jpg converts them to images without problem.
The urls with the .svg extension cannot be converted into images.
And this is really a problem, because the urls are automatically synchronized from another platform to Google Sheets and they are practically all .svg extension.
The strangest thing is that with the formula "=IMAGE(urlCell)" the urls with .svg extension are converted into images without problem.
Also, I am getting the error "Exception: The parameters (Blob,String) don't match the method signature for SpreadsheetApp.Sheet.insertImage."
So what am I doing wrong?
This is my code:
function imagenIcono4() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('📅 Todos los eventos');
const lastRow = sheet.getLastRow();
var rango = sheet.getRange(2, 2, lastRow -1, 2);
var values = rango.getValues();
values.forEach((fila)=> {
// Pon la imagen en todas las celdas donde la url no sea con extensión ".svg"
if ( !fila[0].toString().includes(".svg")) {
fila[1] = SpreadsheetApp.newCellImage().setSourceUrl(fila[0]).toBuilder().build();
} else {
var url = fila[0];
Logger.log(url);
const blob = UrlFetchApp.fetch(url).getBlob();
sheet.insertImage(blob, fila[1]);
}
})
rango.setValues(values);
}

It seems that unfortunately in the current stage, the SVG image data cannot be used for sheet.insertImage and SpreadsheetApp.newCellImage().setSourceUrl. By the way, the arguments of insertImage are blobSource, column, row and blobSource, column, row, offsetX, offsetY. If you want to use this, please be careful about this.
In your situation, I thought that this method (Author: me) might be able to be used.
When this is reflected in your script, how about the following modification?
In this case, Drive API is used. So, please enable Drive API at Advanced Google services.
From:
values.forEach((fila)=> {
// Pon la imagen en todas las celdas donde la url no sea con extensión ".svg"
if ( !fila[0].toString().includes(".svg")) {
fila[1] = SpreadsheetApp.newCellImage().setSourceUrl(fila[0]).toBuilder().build();
} else {
var url = fila[0];
Logger.log(url);
const blob = UrlFetchApp.fetch(url).getBlob();
sheet.insertImage(blob, fila[1]);
}
})
To:
values.forEach((fila) => {
if (!fila[0].toString().includes(".svg")) {
fila[1] = SpreadsheetApp.newCellImage().setSourceUrl(fila[0]).toBuilder().build();
} else {
Logger.log(fila[0]);
var blob = UrlFetchApp.fetch(fila[0]).getBlob();
var id = DriveApp.createFile(blob.setName("temp")).getId();
Utilities.sleep(2000);
var { thumbnailLink } = Drive.Files.get(id);
fila[1] = SpreadsheetApp.newCellImage().setSourceUrl(thumbnailLink.replace("=s220", "=s1000")).toBuilder().build();
DriveApp.getFileById(id).setTrashed(true);
}
});

Related

Google App Script: The number of rows in the data doesn't match the number of rows in the range

I am writing a Google App Script, and I've gotten stuck. I am a beginner.
I have a .csv from our SQL server with 943 rows that is uploaded to my google drive. This script takes the contents of the .csv and moves it to a Google Sheet for use on my website.
It is working as long as the number of rows in the csv doesn't change. As items are added or removed from our web store, the script will not work and throws the error:
"Exception: The number of rows in the data does not match the number of rows in the range. The data has 943 but the range has 944."
function CSVCopyPaste(sourcelink,sourcerange,destilink,destisheet,destirange {
//Source link
var file = DriveApp.getFilesByName('CommercialAvailability.csv').next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
// Destination
var ss = SpreadsheetApp.openByUrl(destilink);
var sheet = ss.getSheetByName(destisheet);
// transfer to destination range
sheet.getRange(destirange).clearContent();
sheet.getRange(destirange).setValues(csvData);
}
The second function is called CommercialAvailability and it is the function I'm actually running to accomplish the result. It is:
function CommercialAvailability() {
SettlemyreCSVCopyPaste(
"https://drive.google.com/file/d/1-V040x0t6SWT14xx6N22MlVFhHnj9XE4",
"A3:C",
"https://docs.google.com/spreadsheets/d/1s8kzVxmJ6v3akpoZ8N2VoGMZ90U2kozlSXdRHUU2BAg/edit#gid=0",
"Commercial Availability",
"B6:D945"
)
}
Any help with this would be greatly appreciated!!
Thank you,
Alex
Alex, the issue is that your range is fixed (B6:D945) but the size of the data in the CSV is variable.
Try:
function CSVCopyPaste(sourcelink,sourcerange,destilink,destisheet,destirangestart) {
//Source link
var file = DriveApp.getFilesByName('CommercialAvailability.csv').next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
//we need to check if the CSV is not empty
if (csvData.length > 0){
// Destination
var ss = SpreadsheetApp.openByUrl(destilink);
var sheet = ss.getSheetByName(destisheet);
var rangestart = sheet.getRange(destirangestart);
var writeRange = sheet.getRange(rangestart.getRow(),rangestart.getColumn(),csvData.length,csvData[0].length);
var clearRange = sheet.getRange(rangestart.getRow(),rangestart.getColumn(),sheet.getMaxRows()-rangestart.getRow(),csvData[0].length);
// transfer to destination range
clearRange.clearContent();
writeRange.setValues(csvData);
}
}
function CommercialAvailability() {
CSVCopyPaste(
"https://drive.google.com/file/d/1-V040x0t6SWT14xx6N22MlVFhHnj9XE4",
"A3:C",
"https://docs.google.com/spreadsheets/d/1s8kzVxmJ6v3akpoZ8N2VoGMZ90U2kozlSXdRHUU2BAg/edit#gid=0",
"Commercial Availability",
"B6"
)
}
Note that I haven't tested it. Also, you have unused arguments in CSVCopyPaste that you may want to get rid of.

App Script new Google Sheet creation issue

I am trying to write an App Script that takes string data from multiple different spreadsheets (completely separate documents) and puts them all in a new spreadsheet. When I run the logger, it shows me all the data I want. I want each piece of data to show up in Column A, but when I run my script, it only puts 1 data point in the spreadsheet instead of all of them. Can someone give me some guidance? Here is my code:
function pullTogether() {
var files = DriveApp.getFolderById('Folder ID').searchFiles('title != "nothing"');
const rangeName = 'Sheet1!B2:C';
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getId();
const values = Sheets.Spreadsheets.Values.get(name, rangeName).values;
for (const row in values) {
var a1 = (values[row][0]);
Logger.log(a1);
var ss = SpreadsheetApp.openById("ID of new spreadsheet"); //I have the real ID in my code
var cell = ss.getRange("A2");
cell.setValue(a1);
}
}
}
I believe your goal is as follows.
You want to retrieve the values from the column "B" of each Spreadsheet under the specific folder.
You want to put the retrieved values to the column "A" of the destination sheet.
Modification points:
About but when I run my script, it only puts 1 data point in the spreadsheet instead of all of them., when I saw your script, the retrieved value is always put to the cell "A2" of the destination sheet. I think that this might be the reason for your issue.
In your script, I thought that when the following flow is used, the process cost will become low. By this flow, your issue can be also removed.
In your situation, even when Sheets API is not used, the script might work using getValues().
When these points are reflected in your script, it becomes as follows.
Modified script:
Please set the folder ID and the destination Spreadsheet ID.
function pullTogether() {
// Retrieve values from each Spreadsheet.
var values = [];
var files = DriveApp.getFolderById('Folder ID').searchFiles(`title != 'nothing' and mimeType='${MimeType.GOOGLE_SHEETS}'`);
var sheetName = 'Sheet1'
while (files.hasNext()) {
var xFile = files.next();
var sheet = SpreadsheetApp.open(xFile).getSheetByName(sheetName);
if (sheet) {
var v = sheet.getRange("B2:B" + sheet.getLastRow()).getValues();
values = [...values, ...v];
}
}
// Put values to the destination sheet.
var ss = SpreadsheetApp.openById("ID of new spreadsheet"); //I have the real ID in my code
var dstSheet = ss.getSheets()[0];
dstSheet.getRange(2, 1, values.length, values[0].length).setValues(values);
}
Note:
Although I'm not sure about your actual situation, when the above script didn't work by the large data, please modify as follows.
From
dstSheet.getRange(2, 1, values.length, values[0].length).setValues(values);
To
Sheets.Spreadsheets.Values.update({ values }, ss.getId(), `'${dstSheet.getSheetName()}'!A2`, { valueInputOption: "USER_ENTERED" });
References:
getValues()
setValues(values)

Google Sheets, stack report from multiple workbooks

Goal: To stack data from 90+ google workbooks, all with the same sheet name, into the one master sheet for reporting
Info:
All worksheets have the same number of columns.
I have the following script but it does not run properly, I think the issue is with how I am caching / Pushing the data to the array before pasting to the output sheet.
I am trying to build an array then paste it in one go.
The tables I am stacking have 47 columns, unknown number of rows.
The part that opens the sheets is all working perfectly.
// Get the data from the worksheets
var indexsheet = SpreadsheetApp.getActive().getSheetByName("Index");
var outputsheet = SpreadsheetApp.getActive().getSheetByName("Output");
var response = SpreadsheetApp.getUi().prompt('Current Cycle', 'Enter Cycle Name Exactly in YY-MMM-Cycle# format', SpreadsheetApp.getUi().ButtonSet.OK_CANCEL)
var CurrentCycleName = response.getResponseText()
// Assign datasets to variables
var indexdata = indexsheet.getDataRange().getValues();
// For each workbook in the index sheet, open it and copy the data to a cache
indexdata.forEach(function(row, r) {
try {
//open Entity specific workbook
var workbookid = indexsheet.getRange(r + 1, 7, 1, 1).getValues();
var Entityworkbook = SpreadsheetApp.openById(workbookid)
// Open workhseet
Entitysheet.getSheetByName(CurrentCycleName)
// Add PR Data to cache - stacking for all countrys
var PRDataCache = Entitysheet.getDataRange().push()
} catch {}
})
// Set the all values of the sheet at once
outputsheet.getRange(r + 1, 14).setValue('Issue Splitting Data')
Entitysheet.getRange(2, 1, PRDataCache.length || 1, 47).setValues(PRDataCache)
};
This is the index tab where we are getting the workbookid from to open each file
This is the output file, we are stacking all data from each country
I believe your goal is as follows.
You want to retrieve the Spreadsheet IDs from the column "G" of "Index" sheet.
You want to give the specific sheet name using a dialog.
You want to retrieve all values from the specification sheet in all Spreadsheets. In this case, you want to remove the header row.
You want to put the retrieved values on "Output" sheet.
In this case, how about the following sample script?
Sample script:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var indexsheet = ss.getSheetByName("Index");
var outputsheet = ss.getSheetByName("Output");
var response = SpreadsheetApp.getUi().prompt('Current Cycle', 'Enter Cycle Name Exactly in YY-MMM-Cycle# format', SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
var CurrentCycleName = response.getResponseText();
var ids = indexsheet.getRange("G1:G" + indexsheet.getLastRow()).getValues();
var values = ids.reduce((ar, [id]) => {
try {
var [, ...values] = SpreadsheetApp.openById(id).getSheetByName(CurrentCycleName).getDataRange().getValues();
ar = [...ar, ...values];
} catch (e) {
console.log(`"${id}" was not found.`);
}
return ar;
}, []);
if (values.length == 0) return;
// If the number of columns is different in all Spreadsheets, please use the following script.
// var maxLen = Math.max(...values.map(r => r.length));
// values = values.map(r => r.length < maxLen ? [...r, ...Array(maxLen - r.length).fill("")] : r);
outputsheet.getRange(outputsheet.getLastRow() + 1, 1, values.length, values[1].length).setValues(values);
}
Note:
When the number of Spreadsheet IDs is large, the processing time might be over 6 minutes. I'm worried about this. At that time, how about separating the Spreadsheet IDs?
Reference:
reduce()

"The coordinates of the range are outside the dimensions of the sheet." error when sorting

I'm trying to create a script to sort and then get some stat from an active CSV extension sheet/tab but I get an error that I couldn't identify. I keep getting the following message: Range coordinates are outside the sheet dimensions. My file contains data only in column A. The data consists of ID numbers and names. It does not contain any formulas. What am I doing wrong with my script?
NB: According to the error the problem comes from the line
var pivotValue = pivotTable1.addPivotValue(2, SpreadsheetApp.PivotTableSummarizeFunction.COUNT)
.
Thanks for your help !
// TDC1
var pivotTable1 = syntheseSheet.getRange('A3').createPivotTable(sourceData);
var pivotValue = pivotTable1.addPivotValue(2, SpreadsheetApp.PivotTableSummarizeFunction.COUNT);//Ligne
pivotValue.setDisplayName('Nbre de LIGNES');
var pivotGroup = pivotTable1.addRowGroup(16);
// TDC2
// sourceData = refSheet.getRange('1:'+nbr);
syntheseSheet.setHiddenGridlines(true);
var pivotTable2 = syntheseSheet.getRange('D3').createPivotTable(sourceData);
pivotValue = pivotTable2.addPivotValue(6, SpreadsheetApp.PivotTableSummarizeFunction.COUNTUNIQUE);//REF
pivotValue.setDisplayName('Nbre de Ref');
pivotGroup = pivotTable2.addRowGroup(16); // agtPlanning

Google App Script throwing a #REF error when exporting a PDF

I am running a app script that works perfectly and exports a PDF from a organic sheet within a spreadsheet.
The problem is that the spreadsheet copies and throws a #REF error in all the cells.
Is there any way around this? I did see this SO question but I couldn't work my way around it. Code below:
I would assume one needs to use the range. Copy to function? but I couldn't figure it out.
// Simple function to send Weekly Status Sheets to contacts listed on the "Contacts" sheet in the MPD.
// Load a menu item called "Project Admin" with a submenu item called "Send Status"
// Running this, sends the currently open sheet, as a PDF attachment
function onOpen() {
var submenu = [{name:"Send Status", functionName:"exportSomeSheets"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu('Project Admin', submenu);
}
function exportSomeSheets() {
// Set the Active Spreadsheet so we don't forget
var originalSpreadsheet = SpreadsheetApp.getActive();
// Set the message to attach to the email.
var message = "Daily Sales Snapshot"; // Could make it a pop-up perhaps, but out of wine today
// Get Project Name from Cell A1
var projectname = originalSpreadsheet.getRange("A1:A1").getValues();
// Get Reporting Period from Cell B3
var period = originalSpreadsheet.getRange("B3:B3").getValues();
// Construct the Subject Line
var subject = projectname + " - Daily Status Sheet - " + period;
// Get contact details from "Contacts" sheet and construct To: Header
// Would be nice to include "Name" as well, to make contacts look prettier, one day.
var contacts = originalSpreadsheet.getSheetByName("Contacts");
var numRows = contacts.getLastRow();
var emailTo = contacts.getRange(2, 2, numRows, 1).getValues();
// Google scripts can't export just one Sheet from a Spreadsheet
// So we have this disgusting hack
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var projectname = SpreadsheetApp.getActiveSpreadsheet();
sheet = originalSpreadsheet.getActiveSheet();
sheet.copyTo(newSpreadsheet);
//create temp sheet that lets us copy the values
sheet = originalSpreadsheet.getActiveSheet();
var temp = originalSpreadsheet.duplicateActiveSheet();
//copy the values
range = temp.getDataRange();
range.copyTo(range, {contentsOnly: true});
//copy the values to a new spreadsheet
temp.copyTo(newSpreadsheet);
//delete our temp sheet.
ss.deleteSheet(temp);
// Find and delete the default "Sheet 1", after the copy to avoid triggering an apocalypse
newSpreadsheet.getSheetByName('Sheet1').activate();
newSpreadsheet.deleteActiveSheet();
// Make zee PDF, currently called "Weekly status.pdf"
// When I'm smart, filename will include a date and project name
var pdf = DriveApp.getFileById(newSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Daily Status.pdf',content:pdf, mimeType:'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
// Delete the wasted sheet we created, so our Drive stays tidy.
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
}
This worked for me if any unfortunate soul lands on this page.
// Simple function to send Weekly Status Sheets to contacts listed on the "Contacts" sheet in the MPD.
// Load a menu item called "Project Admin" with a submenu item called "Send Status"
// Running this, sends the currently open sheet, as a PDF attachment
function onOpen() {
var submenu = [{name:"Send Status", functionName:"exportSomeSheets"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu('Project Admin', submenu);
}
function exportSomeSheets() {
// Set the Active Spreadsheet so we don't forget
var originalSpreadsheet = SpreadsheetApp.getActive();
// Set the message to attach to the email.
var message = "Daily Sales Snapshot"; // Could make it a pop-up perhaps, but out of wine today
// Get Project Name from Cell A1
var projectname = originalSpreadsheet.getRange("H1:H1").getValues();
// Get Reporting Period from Cell B3
var period = originalSpreadsheet.getRange("B3:B3").getValues();
// Construct the Subject Line
var subject = projectname + " - Daily Status Sheet - " + period;
// Get contact details from "Contacts" sheet and construct To: Header
// Would be nice to include "Name" as well, to make contacts look prettier, one day.
var contacts = originalSpreadsheet.getSheetByName("Contacts");
var numRows = contacts.getLastRow();
var emailTo = contacts.getRange(2, 2, numRows, 1).getValues();
// Google scripts can't export just one Sheet from a Spreadsheet
// So we have this disgusting hack
var newSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheets = newSpreadsheet.getSheets;
for (var i = 5; i < sheets.length; i++) {
if (sheets[i].getSheetName() != sheetName) {
sheet[i].hideSheet();
}
}
// Make zee PDF, currently called "Weekly status.pdf"
// When I'm smart, filename will include a date and project name
var pdf = DriveApp.getFileById(newSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Daily Status.pdf',content:pdf, mimeType:'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
}

Categories

Resources