Replace Text with Images in Google Slides for 200 slides? - google-apps-script

I would like to replace some text box text in Google slides with corresponding images. I have tried to following method: How to replace Text with Image on Google Slide using Google Script
It only works on small amounts of data, but I have over 500 object to loop through. I cannot use the Slides API only apps script.
Are there any efficient ways to go about it?
Here is my code so far:
function addFruits() {
//adding search texts
var apple = "Apple";
var orange = "Orange";
var cherry = "Cherry";
var bamboo = "Bamboo";
//addding file ids
var appleID = 'XXXXXXX';
var orangeID = 'XXXXXXXXXXX';
var cherryID = 'XXXXXXXXX';
var bambooID = 'XXXXXXXXXX';
//getting images
var appleIMG = DriveApp.getFileById(appleID).getBlob();
var orangeIMG = DriveApp.getFileById(orangeID).getBlob();
var cherryIMG = DriveApp.getFileById(cherryID).getBlob();
var bambooIMG = DriveApp.getFileById(bambooID).getBlob();
//Logger.log(appleIMG)
//Logger.log(orangeIMG)
//Logger.log(cherryIMG)
//Logger.log(bambooIMG)
// retreive all slides.
var presentation = SlidesApp.openById(slideID);
var slides = presentation.getSlides();
//Logger.log(slides)
//get all shapes and reduce them to a 1d array
var shapesArrays = [];
slides.forEach(slide => {
let shape = slide.getShapes();
shapesArrays.push(shape)
})
var shapes = [].concat.apply([], shapesArrays);
//Logger.log(shapes)
shapes.forEach(s => {
if (s.getText().asString().includes(apple)) {
s.replaceWithImage(appleIMG);
}
else if (s.getText().asString().includes(orange)) {
s.replaceWithImage(orangeIMG);
}
else if (s.getText().asString().includes(cherry)) {
s.replaceWithImage(cherryIMG);
}
else if (s.getText().asString().includes(bamboo)) {
s.replaceWithImage(bambooIMG);
}
});
}

Try this:
function addFruits() {
const ids = [{ id: "id1", name: "name1",{ id: "id2", name: "name2" }];
var presentation = SlidesApp.openById(slideID);
var slides = presentation.getSlides();
slides.forEach(slide => {
let shapes = slide.getShapes();
shapes.forEach(shape => {
let text = shape.getText().asString();
ids.forEach(e => {
if (text.includes(id.name)) {
shape.replaceWithImage(DriveApp.getFileById(e.id).getBlob());
}
});
});
});
}
You can limit the number of slides you attempt by limiting the size of ids

Related

Google Docs Search entire document and bold words

I have a google doc and there are several instance of the words Description, Rationale, and Inheritance that I want to set as bold. From searching here I built this from other suggestions:
function searchAndReplace() {
let doc = DocumentApp.getActiveDocument();
let body = doc.getBody();
// Set some elements to bold
let target1 = "Description"
let searchResult1 = body.findText(target1);
if (searchResult1 !== null) {
let thisElement1 = searchResult1.getElement();
let thisElement1Text = thisElement1.asText();
thisElement1Text.setBold(searchResult1.getStartOffset(), searchResult1.getEndOffsetInclusive(), true);
}
let target2 = "Rationale"
let searchResult2 = body.findText(target2);
if (searchResult2 !== null) {
let thisElement2 = searchResult2.getElement();
let thisElement2Text = thisElement2.asText();
thisElement2Text.setBold(searchResult2.getStartOffset(), searchResult2.getEndOffsetInclusive(), true);
}
let target3 = "Inheritance"
let searchResult3 = body.findText(target3);
if (searchResult3 !== null) {
let thisElement3 = searchResult3.getElement();
let thisElement3Text = thisElement3.asText();
thisElement3Text.setBold(searchResult3.getStartOffset(), searchResult3.getEndOffsetInclusive(), true);
}
}
When I run this it only bolds the first instance of Rationale. I tried changing the if to a while but that just ran and did not complete.
Any ideas?
This should do. Credits to this post. The laste line inside the while is the key.
function searchAndReplace() {
let doc = DocumentApp.getActiveDocument();
let body = doc.getBody();
// Set some elements to bold
let target1 = "blandit"
let searchResult1 = body.findText(target1);
while (searchResult1 !== null) {
let thisElement1 = searchResult1.getElement();
let thisElement1Text = thisElement1.asText();
thisElement1Text.setBold(searchResult1.getStartOffset(), searchResult1.getEndOffsetInclusive(), true);
searchResult1 = body.findText(target1, searchResult1)
}
}
function highlight_words() {
var doc = DocumentApp.getActiveDocument();
var words = ['Description','Rationale','Inheritance']; // <-- put your words here
var style = { [DocumentApp.Attribute.BOLD]: true };
var pgfs = doc.getParagraphs();
for (var word of words) for (var pgf of pgfs) {
var location = pgf.findText(word);
if (!location) continue;
var start = location.getStartOffset();
var end = location.getEndOffsetInclusive();
location.getElement().setAttributes(start, end, style);
}
}
Note: unlike the accepted answer my code changes all the words of the given array at once.
If you want to highligth the words with yellow color here is my previous solution: https://stackoverflow.com/a/69420695/14265469

How to mask out shadows from LANDSAT/LE07/C01/T1_TOA?

I want to use the LANDSAT/LE07/C01/T1_TOA collection in google earth engine and I am struggling to understand how the bits work in order to mask out areas with clouds and shadows. I managed to write the following, but I am not very confident and do not know how to mask out shadows.
var dataset = ee.ImageCollection('LANDSAT/LE07/C01/T1_TOA')
.filterBounds(geometry)
.map(function(image){return image.clip(geometry)})
.filter(ee.Filter.calendarRange(6,8,'month'))
.filterDate('1999-05-01','2017-09-30');
var qas = function(image) {
var qa = image.select('BQA');
var mask = qa.eq(672);
return image.updateMask(mask).copyProperties(image);
}
var merged = dataset.map(qas);
var addNDVI = function(image) {
var ndvi = image.normalizedDifference(['B4', 'B3']).rename('NDVI');
return image.addBands(ndvi);
};
var ndvi = merged.map(addNDVI);
How to properly do quality masking with bits?
Try It
var cloudMaskL7 = function(image) {
var qa = image.select('BQA');
var cloud = qa.bitwiseAnd(1 << 4)
.and(qa.bitwiseAnd(1 << 6))
.or(qa.bitwiseAnd(1 << 8));
var mask2 = image.mask().reduce(ee.Reducer.min());
return image
.select(['B3', 'B4'], ['Red', 'NIR'])
.updateMask(cloud.not()).updateMask(mask2)
.set('system:time_start', image.get('system:time_start'));
};
var dataset = ee.ImageCollection("LANDSAT/LE07/C01/T1_TOA")
.filterBounds(geometry)
.filterDate('2012-05-01','2017-09-30')
.map(cloudMaskL7)
var NDVIofLANDSAT = function(image) {
var ndvi = image.normalizedDifference(['NIR', 'Red']).rename('NDVI');
return image.addBands(ndvi);
};
var ndviCollection = dataset
.map(NDVIofLANDSAT)
.select("NDVI");
print("Total no of LANDSAT Images ", ndviCollection);
Map.addLayer (ndviCollection.first().select('NDVI').clip(geometry), {min:0, max:1, 'palette': ['red','yellow', 'green']}, 'NDVI')

Angular 2 - Parsing Excel worksheet to Json

I have an Excel file with the following content:
Inside my component.ts, I extract the Excel's content as follow:
var testUrl= "excel.xlsx";
var oReq = new XMLHttpRequest();
oReq.open("GET", testUrl, true);
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
var arraybuffer = oReq.response;
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for(var i = 0; i != data.length; ++i){
arr[i] = String.fromCharCode(data[i]);
}
var bstr = arr.join("");
var workbook = XLSX.read(bstr, {type:"binary"});
var first_sheet_name = workbook.SheetNames[0];
var worksheet = workbook.Sheets[first_sheet_name];
var json = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], {header:1, raw:true});
var jsonOut = JSON.stringify(json);
console.log("test"+jsonOut);
}
oReq.onerror = function(e) {
console.log(e);
}
oReq.send();
XLSX.utils.sheet_to_json will format JSON as follow:
However, I would like the JSON to be as follow:
Most probably I would need to manually create the JSON, but can anyone help me point to the direction on how I can accomplish this?
In your case we need to modify the JSON data by looping over XLSX.utils.sheet_to_json JSON object:
// This object will contain the data in the format we want
var finalObj = { "object": []};
// Variables to track where to insert the data
var locIndex, firstCondIndex, secondCondIndex,
lockey, firstCondKey, secondCondkey;
// We need to initialize all indexes to -1 so that on first time we can get 0, as arrays start with 0 in javascript
locIndex = -1;
// here obj is XLSX.utils.sheet_to_json
obj.object.map((value, index) => {
// we don't want to consider name of columns which is first element of array
if(!index) return;
// Go inside only if not null
if(value[0]) {
// For Location
finalObj.object.push(createObj(value[0]));
locIndex++;
// We also need to store key names to push it's children
lockey = value[0];
firstCondIndex = -1;
}
if(value[1]) {
// For First Condition
finalObj.object[locIndex][lockey].push(createObj(value[1]));
firstCondIndex++;
firstCondKey = value[1];
secondCondIndex = -1;
}
if(value[2]) {
// For Second Condition
finalObj.object[locIndex][lockey][firstCondIndex][firstCondKey].push(createObj(value[2]));
secondCondIndex++;
secondCondkey = value[2];
}
if(value[3]) {
// For Products
// We just push the string
finalObj.object[locIndex][lockey][firstCondIndex][firstCondKey][secondCondIndex][secondCondkey].push(value[3]);
}
});
function createObj(val) {
// We need to initialize blank array so we can push the children of that element later on
var obj = {};
obj[val] = [];
return obj;
}
console.log(finalObj);

mapserver with WMS call with openlayers

I scenario is below :
map is shown under from TiledWMS layer from mapserver. It has 2 layers.
TiledWMS layer for OSM world map.
TiledWMS layer for layers defined in kml file placed in mapserver through .map file. This map file contains many layers.
Now , when user click on map : it got 2 layers as above.
But since 2nd layer is made up of different layers as given in .map file , i am not able to uniquely identify these layers. I want that since 2 nd layer is made up of different layers in kml file i should be able to uniquely identify them on mouse click or hower.
Thanks
Satpal
I am able to get it : below is samaple code for others.
var coord = evt.coordinate;
var pixel = $scope.map.getPixelFromCoordinate(coord);
var viewProjection = $scope.map.getView().getProjection();
var viewResolution = $scope.map.getView().getResolution();
var numberOfLayersOnMap = $scope.map.getLayers();
var feature = $scope.map.forEachFeatureAtPixel(pixel, function(feature, layer){return feature;}, null, function(layer) {return true;});
if(feature === undefined)
{
$scope.map.forEachLayerAtPixel(pixel, function (layer)
{
if(!layer)
{
return ;
}
var urlWMSGetFeatureInfo = layer.getSource().getGetFeatureInfoUrl(coord, viewResolution, viewProjection, {
'INFO_FORMAT': 'application/vnd.ogc.gml'
});
if(urlWMSGetFeatureInfo.indexOf("osm-google.map")<0)
{
$http({
method: 'GET',
url: urlWMSGetFeatureInfo,
}).success(function(data){
var parser = new ol.format.WMSGetFeatureInfo();
var features = parser.readFeatures(data);
if(features.length>0)
{
var featureName = features[0].n.Name;
topOverlayElement.innerHTML = featureName;
$scope.highlightOverlay.setFeatures(new ol.Collection());
if($scope.flagLinkage == true)
{
var xmlObj = utility.StringToXML(data);
var xmlDocumnet = xmlObj.childNodes[0];
var layerNode = xmlDocumnet.children[0];
var gmlLayerNode = layerNode.children[0];
var layerName = gmlLayerNode.textContent;
var layerInfoObject = {};
layerInfoObject.layerName = layerName;
//layerInfoObject.placemarkName = featureName;
$scope.placemarksSelectedObject.push(layerInfoObject);
$scope.placemarksSelectedFeatureObject.push(features[0]);
}
else
{
$scope.placemarksSelectedFeatureObject.length = 0;
$scope.placemarksSelectedFeatureObject.push(features[0]);
}
$scope.highlightOverlay.setFeatures(new ol.Collection($scope.placemarksSelectedFeatureObject));
var featureDescription = features[0].n.description;
middleOverlayElement.innerHTML = (featureDescription === undefined) ? '' : featureDescription;
$scope.showOverlay(coord);
}
}).error(function (data) {
console.log("Not able to get capabilty data.");
});
}
else
{
$scope.closeOverlay(evt);
}
});

How to move a popup window from a client handler?

I have a code that simulates a popup window (thanks to Waqar Ahmad) that is triggered by a client handler.
I would like to get this popup appear near the button that triggered it but with the script I have I see no way to move the window.
The code is below and the app is viewable here, if ever someone has an idea about how I should re-organise or change the script so that the popup window shows up near the button that fired the process ?
var choice = ['-','Choice 1','Choice 2','Choice 3','Choice 4']; // var definition
function doGet(){
var app = UiApp.createApplication().setStyleAttribute("background", "beige");
app.add(createMaskPanel_());//this is used to make popup panel modal
var mainPanel = app.createVerticalPanel().setStyleAttributes({'padding' : '15'});
app.add(mainPanel);
// idx holds the index value of the button that is pressed
var idx = app.createTextBox().setId('idx').setName('idx').setVisible(false);
mainPanel.add(idx);
//Make a panel for popup and add your popup elements
var popup = app.createVerticalPanel().setId('popup').setVisible(false)
.setStyleAttributes(
{'position': 'fixed',
'border' : '1px solid brown',
'padding' : '15',
'background' : 'beige',
'top' : '150PX',
'left' : '300PX',
'width' : '200',
'height':'120',
'zIndex' : '2'});
popup.add(app.createLabel('Select your choice').setId('label'));
var list = app.createListBox().setId('ppValue').setName('ppValue').setWidth('200')
.addItem(choice[0], '0').addItem(choice[1], '1').addItem(choice[2], '2').addItem(choice[3], '3').addItem(choice[4], '4');
popup.add(list);
var valHandler = app.createServerHandler('showVal').addCallbackElement(mainPanel).addCallbackElement(popup);;
popup.add(app.createButton('✖ Close / confirm').addClickHandler(valHandler));
app.add(popup);
var mask = app.getElementById('mask')
var ppHandler = app.createClientHandler().forTargets([popup,mask]).setVisible(true)
var flex = app.createFlexTable()
for(nn=1;nn<11;++nn){
flex.setText(nn,0,'Item nr '+nn)
var text = app.createTextBox().setHeight('26').setWidth('150').setId('val'+nn).setName('val'+nn)
flex.setWidget(nn,1,text);
var handler = app.createClientHandler().forTargets(idx).setText(nn).forTargets(text).setText('suggestion = ?');
flex.setWidget(nn,2,app.createButton('✐').setHeight('26').setId('btn'+nn).addClickHandler(handler).addClickHandler(ppHandler))
}
mainPanel.add(flex);
return app;
}
function createMaskPanel_(){ //Called when UI loads, initially it will be invisble. it needs to be made visible
var app = UiApp.getActiveApplication();
var mask = app.createVerticalPanel().setId('mask').setSize('100%', '100%') //maskPanel to mask the ui
.setStyleAttributes({
'backgroundColor' : '#F0F0F0',
'position' : 'fixed',
'top' : '0',
'left' : '0',
'zIndex' : '1',
'opacity' : '0.4'}).setVisible(false);
mask.add(app.createLabel('POPUP')
.setStyleAttribute('color', '#F0F0F0')
.setStyleAttribute('opacity', '0.6'));
return mask;
}
function showVal(e){
var app = UiApp.getActiveApplication();
var source = e.parameter.idx
var value = app.getElementById('val'+source)
value.setText('choice value = '+choice[e.parameter.ppValue])
var popup = app.getElementById('popup')
var mask = app.getElementById('mask')
popup.setVisible(false)
mask.setVisible(false)
return app
}
EDIT : Since the server handler seems to be the only way I gave it a try, the app is viewable here and the (final ?) code is below for info.
var choice = ['-','Choice 1','Choice 2','Choice 3','Choice 4','Choice 5','Choice 6','Last choice !'];//var definition
function doGet(){
var app = UiApp.createApplication().setStyleAttribute("background", "beige");
app.add(createMaskPanel_());//this is used to make popup panel modal
var top = '100PX'
var left = '265PX'
var mainPanel = app.createVerticalPanel().setStyleAttributes({'padding' : '15'});
app.add(mainPanel);
// item definitions
var idx = app.createTextBox().setId('idx').setName('idx').setVisible(false);
mainPanel.add(idx);
//Make a panel for popup and add your popup elements
var popup = app.createVerticalPanel().setId('popup').setVisible(false)
.setStyleAttributes(
{'position': 'fixed',
'border' : '1px solid brown',
'padding' : '10',
'background' : 'beige',
'top' : top,
'left' : left,
'width' : '200',
'height':'110',
'zIndex' : '2'});
popup.add(app.createLabel('Select your choice').setId('label'));
var list = app.createListBox().setId('ppValue').setName('ppValue').setWidth('160')
for(c in choice){list.addItem(choice[c], c)}
popup.add(list);
var valHandler = app.createServerHandler('showVal').addCallbackElement(mainPanel).addCallbackElement(popup);;
popup.add(app.createButton('✖ Close / confirm').addClickHandler(valHandler));
app.add(popup);
var idxHandler = app.createServerHandler('setidx').addCallbackElement(mainPanel)
var flex = app.createFlexTable()
for(nn=1;nn<11;++nn){
flex.setText(nn,0,'Item nr '+nn)
flex.setWidget(nn,1,app.createTextBox().setPixelSize(180,26).setId('val'+nn).setName('val'+nn));
flex.setWidget(nn,2,app.createButton('✐').setHeight('26').setId('btn'+nn).addClickHandler(idxHandler))
}
mainPanel.add(flex);
return app;
}
function setidx(e){
var app = UiApp.getActiveApplication();
var idx = app.getElementById('idx')
var idxval = Number(e.parameter.source.replace(/[a-z]/g,''))
idx.setValue(idxval);
var top = -30+38*idxval+'PX'
var left = '265PX'
var popup = app.getElementById('popup')
var mask = app.getElementById('mask')
var label = app.getElementById('label').setText('Select your choice (item '+idxval+')')
var value = app.getElementById('val'+idxval)
value.setText('suggestion = ?')
popup.setVisible(true)
mask.setVisible(true)
popup.setStyleAttributes(
{'top' : top,
'left' : left});
return app
}
function createMaskPanel_(){ //Called when UI loads, initially it will be invisble. it needs to be made visible
var app = UiApp.getActiveApplication();
var mask = app.createVerticalPanel().setId('mask').setSize('100%', '100%') //maskPanel to mask the ui
.setStyleAttributes({
'backgroundColor' : '#F0F0F0',
'position' : 'fixed',
'top' : '0',
'left' : '0',
'zIndex' : '1',
'opacity' : '0.6'}).setVisible(false);
mask.add(app.createLabel('POPUP')
.setStyleAttribute('color', '#F0F0F0')
.setStyleAttribute('opacity', '0.6'));
return mask;
}
function showVal(e){
var app = UiApp.getActiveApplication();
var source = e.parameter.idx
var value = app.getElementById('val'+source)
value.setText('choice value = '+e.parameter.ppValue+' ('+choice[Number(e.parameter.ppValue)]+')')
var popup = app.getElementById('popup')
var mask = app.getElementById('mask')
popup.setVisible(false)
mask.setVisible(false)
return app
}
Serge I did something simular using a dialogbox to get this kind of functionality.
In the proper function that shows the dialogbox I decide the position of the dialogbox.
I used it to enlarge a image so I just put the (entire) code I used for the dialogbox.
function showimg(e){
var app = UiApp.getActiveApplication();
//
// Style
//
var _showimg =
{
"position":"fixed",
"width":"200px", // here you can change size
"top":"100px", // and horizontal position maybe you can use your
"left":"100px", // your setidx function .
"opacity":"0.95",
"border":"none",
}
var _container =
{
"width":"90%",
"border":"none",
}
var _img= {
"background-color":"none",
"width":"90%",
"border":"4px solid f2f2f2",
}
var _btn= {
"background-color":"none",
"background":"none",
"width":"80px",
"height":"24px",
"border":"None",
"font-family":"hobo std",
"font-size":"0.9em",
"color":"3f3f3f",
"opacity":"1",
}
//
// aplication
//
var f = DocsList.find("YOURSPREADSHEET");
var id = f[0].getId();
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheetByName("YOURSHEET");
var rows= sheet.getLastRow();
var cols = sheet.getLastColumn();
var dialogBox = app.createDialogBox(true, true).setId("dialogBox");
applyCSS(dialogBox, _showimg);
var cont = app.createAbsolutePanel().setId("cont").setVisible(true);
applyCSS(cont, _container);
var source = e.parameter.source;
for (var i = 1; i < rows ; i++) {
for (var j = 1; j <6 ; j++) {
if (source == "imgb"+[j]+[i]) {
if (j == 1) {
var img = app.createImage().setId('img').setUrl(sheet.getRange(i+1,[5]).getValue()).setVisible(true);
dialogBox.setText(sheet.getRange(i+1,[6]).getValue());
}
if (j == 2) {
var img = app.createImage().setId('img').setUrl(sheet.getRange(i+1,[7]).getValue()).setVisible(true);
dialogBox.setText(sheet.getRange(i+1,[8]).getValue());
}
}
app.getElementById( "imgb"+[j]+[i]).setEnabled(false);
//}
}
}
applyCSS(img,_img)
app.createImage().setId('img').setUrl("https://lh6.googleusercontent.com/-PTl6c-pfHoc/TzFvp1dteaI/AAAAAAAACTI/Mmx-7RU4i8g/s640/xxxxxxx.jpg").setVisible(true);
// applyCSS(img,_img)
var closeb = app.createButton("Close").setId("closeb").setTitle("close");
applyCSS(closeb,_btn);
var closeH = app.createServerClickHandler("closediag");
closeb.addClickHandler(closeH);
closeH.addCallbackElement(cont);
cont.add(img);
cont.add(closeb);
dialogBox.add(cont);
app.add(dialogBox);
return app;
}
The applyCss from James
function applyCSS(element, style){
for (var key in style){
element.setStyleAttribute(key, style[key]);
}
}
From what I've discovered so far using what I see in these replies, this methodology is positioning my widgets accordingly, but not the actual form itself. Unless, of course, I'm missing something, which is entirely possible. Thanks for the replies so far.