Swap Google Doc images with new images from Google Drive - google-apps-script

I have a Google Doc with images (let's say 4 but in reality there are many). I want to replace those with four new images available in Google Drive. I know I can get all images available in the Doc as:
var images = docFile.getBody().getImages();
All are InlineImage when displayed on the console, although a few are in the paragraph and others are inside table cells. The logic I have in my mind is:
Getting the list of images (as done above)
Getting the location of those images (Don't know how)
Delete the image and use appendImage method.
The exact code I tried is:
function imageExtract() {
const tempFile = DocumentApp.openById(idOfFile) //idOfFile is id of Doc file
var images = tempFile.getBody().getImages();
const blob=DriveApp.getFileById(idOfImage) //idOfImage is id of Doc file
for (var i = 0; i < images.length; i++){
Logger.log(images[i].getAttributes())
Logger.log(images[i])
// Here I want to delete the images[i]
// And put blob there
}
}

I believe your current situation and your goal are as follows.
Your Google Document has 4 images. The images are put into the paragraph, list, and table.
You have a list including 4 URLs of the direct links of image data.
You want to replace 1st image in Google Document with the 1st URL of the list.
You want to achieve this using Google Apps Script.
I thought that in this case, when Google Docs API is used, the script might be simple. So, how about the following sample script?
Sample script:
This script uses Google Docs API. So, please enable Docs API at Advanced Google services.
function myFunction() {
// Please set your 4 URLs.
const urls = [
"https://url1",
"https://url2",
"https://url3",
"https://url4",
];
// Retrieve the original title of images and set the unique image titles using Docs API.
const doc = DocumentApp.getActiveDocument();
const images = doc.getBody().getImages();
const titles = images.reduce((m, e, i) => {
const org = e.getAltTitle();
e.setAltTitle(`sample${i}`);
m.set(`sample${i}`, { title: org, uri: urls[i] });
return m;
}, new Map());
doc.saveAndClose();
// Create request body of Docs API.
const { inlineObjects } = Docs.Documents.get(doc.getId(), { fields: "inlineObjects" });
const requests = Object.entries(inlineObjects).reduce((ar, [imageObjectId, { inlineObjectProperties: { embeddedObject } }]) => {
if (embeddedObject.hasOwnProperty("imageProperties")) {
const { uri } = titles.get(embeddedObject.title);
ar.push({ replaceImage: { imageObjectId, uri } });
}
return ar;
}, []);
// Request Docs API using the created request body.
Docs.Documents.batchUpdate({ requests }, doc.getId());
// Set the original titles to the images.
const ar = [...titles];
DocumentApp.getActiveDocument().getBody().getImages().forEach((e, i) => e.setAltTitle(ar[i][1].title));
}
When this script is run, 4 images in Google Document are replaced with the images of 4 URLs.
References:
Method: documents.batchUpdate
ReplaceImageRequest
Added:
I think that your provided sample Document and your provided current script have 2 issues.
When I saw your sample Document, I saw 4 images. But, when I retrieve the images using Google Docs API, 5 images are existing. It seems that one image is not shown. Unfortunately, the reason for TypeError: Cannot destructure property 'uri' of 'titles.get(...)' as it is undefined. is due to this.
From this situation, in my added sample script, the unshown images are ignored. By this, this error is avoided.
I had thought that you have a list including 4 URLs of the direct links of image data. But, unfortunately, when I saw your provided script, the URLs are not the direct link like https://drive.google.com/file/d/{fileId}. In this case, an error occurs when Docs API is requested. I think that this will be your 2nd issue.
When these points are reflected in my proposed sample script, it becomes as follows.
Sample script:
In this sample, Google Docs API and Google Drive API are used. So, please enable Docs API and Drive API at Advanced Google services.
And, please set the file IDs of the image file on your Google Drive. The file ID is ### of https://drive.google.com/file/d/###. Please be careful about this.
function myFunction() {
// Please set the file IDs of the images in your Google Drive.
const fileIds = [
"### file ID 1 ###",
"### file ID 2 ###",
"### file ID 3 ###",
"### file ID 4 ###",
];
// Create direct links of the images.
const urls = fileIds.map(id => Drive.Files.get(id).thumbnailLink.replace(/\=s.+/, "=s512"));
// Retrieve the original title of images and set the unique image titles using Docs API.
const doc = DocumentApp.getActiveDocument();
const images = doc.getBody().getImages();
const titles = images.reduce((m, e, i) => {
const org = e.getAltTitle();
e.setAltTitle(`sample${i}`);
m.set(`sample${i}`, { title: org, uri: urls[i] });
return m;
}, new Map());
doc.saveAndClose();
// Create request body of Docs API.
const { inlineObjects } = Docs.Documents.get(doc.getId(), { fields: "inlineObjects" });
const requests = Object.entries(inlineObjects).reduce((ar, [imageObjectId, { inlineObjectProperties: { embeddedObject } }]) => {
if (embeddedObject.hasOwnProperty("imageProperties") && embeddedObject.title) {
const { uri } = titles.get(embeddedObject.title);
ar.push({ replaceImage: { imageObjectId, uri } });
}
return ar;
}, []);
// Request Docs API using the created request body.
Docs.Documents.batchUpdate({ requests }, doc.getId());
// Set the original titles to the images.
const ar = [...titles];
DocumentApp.getActiveDocument().getBody().getImages().forEach((e, i) => e.setAltTitle(ar[i][1].title));
}

Related

Image and Data Merge Sheets to Slides Apps Script - Update

I 'm very new to both Apps Script and coding in general.
I'm trying to take a google slides presentation, and merge with a csv to create multiple images.
I cannot get the merge function to work. I'm pretty sure I am not loading the csv data correctly - I can get it to show the data range in the execution log but it does not merge into the new presentation. I know I have my tags correct, because I've used them in a 3rd party extension and it works.
I know I'm probably just missing something stupid, but I cannot figure it out. Any help would be appreciated!
Below is the code I currently have:
Update 1
I was able to figure out how to call the data correctly, and am now able to replace the text correctly. However, when I use replaceAllShapesWithImage I get the following error:
GoogleJsonResponseException: API call to slides.presentations.batchUpdate failed with error: Invalid requests[2].replaceAllShapesWithImage: There was a problem retrieving the image. The provided image should be publicly accessible, within size limit, and in supported formats.
The images are being called from google drive, and are accessible by anyone with the link. Any ideas? Updated code below:
const spreadsheetId = '1JSXC0XrfUAtcRLXCgVnB-SAQjwk_-YG7W_kGefowONE';
const thetemplateId = '1Pug2cPiGsPL9iKPEnBAhvBVqfSTMyJERCRaSGkyFOr0';
const dataRange = 'Monthly Top Producers!A2:F';
function generateTopPro(){
var Presentation=SlidesApp.openById(thetemplateId);
let values = SpreadsheetApp.openById(spreadsheetId).getRange(dataRange).getValues();
for (let i = 0; i < values.length; ++i) {
const row = values[i];
const agent_name = row[0]; // name in column 1
const agent_phone = row[3]; // phone in column 4
const agent_photo = row[4]; // agent photo url column 5
const logo_state = row[5]; // state logo url column 6
// Duplicate the template presentation using the Drive API.
const copyTitle = agent_name + ' September';
let copyFile = {
title: copyTitle,
parents: [{id: 'root'}]
};
copyFile = Drive.Files.copy(copyFile, templateId);
const presentationCopyId = copyFile.id;
// Create the text merge (replaceAllText) requests for this presentation.
const requests = [{
replaceAllText: {
containsText: {
text: '{{agent_name}}',
matchCase: true
},
replaceText: agent_name
}
}, {
replaceAllText: {
containsText: {
text: '{{agent_phone}}',
matchCase: true
},
replaceText: agent_phone
}
}, {
replaceAllShapesWithImage: {
imageUrl: agent_photo,
imageReplaceMethod: 'CENTER_INSIDE',
containsText: {
text: '{{agent_photo}}',
matchCase: true
}
}
}, {
replaceAllShapesWithImage: {
imageUrl: logo_state,
imageReplaceMethod: 'CENTER_INSIDE',
containsText: {
text: '{{logo_state}}',
matchCase: true
}
}
}];
// Execute the requests for this presentation.
const result = Slides.Presentations.batchUpdate({
requests: requests
}, presentationCopyId);
// Count the total number of replacements made.
let numReplacements = 0;
result.replies.forEach(function(reply) {
numReplacements += reply.replaceAllText.occurrencesChanged;
});
console.log('Created presentation for %s with ID: %s', agent_name, presentationCopyId);
console.log('Replaced %s text instances', numReplacements);
}
}
There was a problem retrieving the image. The provided image should be publicly accessible, within size limit, and in supported formats is a known issue when trying to use an image from Google Drive
See for example Google slides API replaceAllShapesWithImage returns error for Google Drive file (2020)
There are workarounds like Google script replaceAllShapesWithImage with image from drive doesn"t work any more that work for some users/ images but not always.
There are several related issues filed on Google's Issue Tracker and a feature request asking for a full support of the functionality.
If no workaround work for you, the only two things you can do in the current state are:
"Star" the feature request to increase visibility which will hopefully accelerate implementation
Use the thumbnailLink that oyu can retrieve with Files: get as imageUrl - this gives you an image in low quality, but better than nothing

Download HEIC file in Google Photos as JPG

I am using this code to upload the heic file and finding a way to convert heic as jpg or png via apps script (not right click save as)
I have my code
function uploadMediaItems() {
const albumId = "AKwCquOrmWbEihvwEqIM7Jy_H8wrkM_dof1eIGwXq8YZV-uuj9jWvkMT5oWkG6P0a-w_w9VyTOxM"; // Please set the album ID.
var arrId =
[
"1ssNYJFSEdfRI55IUi_tte3iC_JcPLG-0"
];
const items = arrId.map(id => {
const file = DriveApp.getFileById(id);
return {blob: file.getBlob(), filename: file.getName()};
});
const res = GPhotoApp.uploadMediaItems({albumId: albumId, items: items});
console.log(JSON.stringify(res))
}
Source: Google Apps Scripts: import (upload) media from Google Drive to Google Photos?
I believe your goal is as follows.
You want to upload the HEIC file to Google Photos and export it as a Jpeg or PNG file using the sample script at this thread.
From your script, the HEIC file is put on your Google Drive.
I thought that in your goal, you might have wanted to convert the HEIC file to Jpeg or PNG file. In this case, how about the following sample scripts?
Sample script 1:
In this sample script, the sample script at this thread is used. So, in this case, a Google Apps Script library of GPhotoApp is used. Ref The sample script is as follows.
In this script, it supposes that your Google Apps Script project has already been linked with Cloud Platform Project, and Photos API has already been enabled, and also, the required scopes have already been added. Please be careful this.
function myFunction() {
const arrId = ["###"]; // Please set the file ID of your HEIC file.
const albumId = "###"; // Please set your albumn ID.
const items = arrId.map(id => {
const file = DriveApp.getFileById(id);
return { blob: file.getBlob(), filename: file.getName() };
});
const res1 = GPhotoApp.uploadMediaItems({ albumId: albumId, items: items });
const mediaItemId = res1.newMediaItemResults[0].mediaItem.id;
const res2 = GPhotoApp.getMediaItems({ mediaItemIds: [mediaItemId] });
const mediaItem = res2.mediaItemResults[0].mediaItem;
const blob = UrlFetchApp.fetch(mediaItem.baseUrl).getBlob();
DriveApp.createFile(blob.setName(mediaItem.filename.replace(".heic", ".png")));
}
When this script is run, the PNG file is created to the root folder.
Sample script 2:
The HEIC file is put on your Google Drive. And, you want to convert the HEIC file to Jpeg or PNG. In this case, I thought that this can be achieved using the following simple script. In this case, Photos API is not required to be used.
When you use this script, please enable Drive API at Advanced Google services.
function myFunction2() {
const fileId = "###"; // Please set the file ID of your HEIC file.
const obj = Drive.Files.get(fileId);
const blob = UrlFetchApp.fetch(obj.thumbnailLink.replace(/=s.+/, "=s2000")).getBlob();
DriveApp.createFile(blob.setName(obj.title.replace(".heic", ".png")));
}
When this script is run, the PNG file is created to the root folder.
References:
Photos Library API
GPhotoApp
Files: get

How to convert PDF to image using Google Apps Script? [duplicate]

is there a way to create an image (e.g. a png) from a google document?
I really mean an image, not just a pdf. GetAS only creates pdf, but returns an error if contentType is set to image/png or other equivalent formats.
My (actually trivial) code is
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE);
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
var target = source.makeCopy(source,targetFolder);
var newFile = DriveApp.createFile(target.getAs('image/png'));
}
When I run this code, I get the following error (my translation):
The conversion from application/vnd.google-apps.document to image/png is not supported.
Ty
How about this answer?
Reason of error:
makeCopy() returns File object. getAs() cannot be used for this. By this, the error occurs.
Workaround:
Unfortunately, in the current stage, Google Document cannot be directly exported as PNG images. So it is required to think of workarounds. Google Document can be converted to PDF. This answer uses this. As a workaround, I would like to propose to use an external API which is ConvertAPI. I thought that using the external API, the script becomes simple. This a method (PDF to PNG API) of API can be converted from PDF data to PNG data.
When you try this, for example, you can also test this using "Free Package". When you try using "Free Package", please Sign Up at "Free Package" and retrieve your Secret key.
Sample script:
Before you run this script, please retrieve your Secret key and set it.
var secretkey = "###"; // Please set your secret key.
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var url = "https://v2.convertapi.com/convert/pdf/to/png?Secret=" + secretkey;
var options = {
method: "post",
payload: {File: DriveApp.getFileById(SOURCE_TEMPLATE).getBlob()},
}
var res = UrlFetchApp.fetch(url, options);
res = JSON.parse(res.getContentText());
res.Files.forEach(function(e) {
var blob = Utilities.newBlob(Utilities.base64Decode(e.FileData), "image/png", e.FileName);
DriveApp.getFolderById(TARGET_FOLDER).createFile(blob);
});
References:
makeCopy()
getAs()
ConvertAPI
PDF to PNG API of ConvertAPI
Updated on January 11, 2023:
In the current stage, Google Apps Script can use V8 runtime. By this, there are some Javascript libraries that can be used with Google Apps Script. Ref1, Ref2 In this question, in the current stage, by using pdf-lib, all pages in a PDF file can be converted to PNG images using Google Apps Script. The sample script is as follows.
Sample script:
This method uses Drive API. Please enable Drive API at Advanced Google services.
Please set SOURCE_TEMPLATE and TARGET_FOLDER, and run main().
/**
* This is a method for converting all pages in a PDF file to PNG images.
* PNG images are returned as BlobSource[].
* IMPORTANT: This method uses Drive API. Please enable Drive API at Advanced Google services.
*
* #param {Blob} blob Blob of PDF file.
* #return {BlobSource[]} PNG blobs.
*/
async function convertPDFToPNG_(blob) {
// Convert PDF to PNG images.
const cdnjs = "https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js";
eval(UrlFetchApp.fetch(cdnjs).getContentText()); // Load pdf-lib
const setTimeout = function (f, t) { // Overwrite setTimeout with Google Apps Script.
Utilities.sleep(t);
return f();
}
const data = new Uint8Array(blob.getBytes());
const pdfData = await PDFLib.PDFDocument.load(data);
const pageLength = pdfData.getPageCount();
console.log(`Total pages: ${pageLength}`);
const obj = { imageBlobs: [], fileIds: [] };
for (let i = 0; i < pageLength; i++) {
console.log(`Processing page: ${i + 1}`);
const pdfDoc = await PDFLib.PDFDocument.create();
const [page] = await pdfDoc.copyPages(pdfData, [i]);
pdfDoc.addPage(page);
const bytes = await pdfDoc.save();
const blob = Utilities.newBlob([...new Int8Array(bytes)], MimeType.PDF, `sample${i + 1}.pdf`);
const id = DriveApp.createFile(blob).getId();
Utilities.sleep(3000); // This is used for preparing the thumbnail of the created file.
const link = Drive.Files.get(id, { fields: "thumbnailLink" }).thumbnailLink;
if (!link) {
throw new Error("In this case, please increase the value of 3000 in Utilities.sleep(3000), and test it again.");
}
const imageBlob = UrlFetchApp.fetch(link.replace(/\=s\d*/, "=s1000")).getBlob().setName(`page${i + 1}.png`);
obj.imageBlobs.push(imageBlob);
obj.fileIds.push(id);
}
obj.fileIds.forEach(id => DriveApp.getFileById(id).setTrashed(true));
return obj.imageBlobs;
}
// Please run this function.
async function myFunction() {
const SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
const TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
// Use a method for converting all pages in a PDF file to PNG images.
const blob = DriveApp.getFileById(SOURCE_TEMPLATE).getBlob();
const imageBlobs = await convertPDFToPNG_(blob);
// As a sample, create PNG images as PNG files.
const folder = DriveApp.getFolderById(TARGET_FOLDER);
imageBlobs.forEach(b => folder.createFile(b));
}
When this script is run, all pages of the inputted PDF file are converted to PNG images, and those images are created in the destination folder.
Note:
I think that the above script works. But, in this case, when you directly copy and paste the Javascript retrieved from https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js to your Google Apps Script project, the process cost for loading it can be reduced.
References:
pdf-lib
copyPages of pdf-lib
addPage of pdf-lib
I know this is an older question, but I thought I'd answer, since I believe I've found a solution that doesn't involve paying for a third-party subscription.
This can be accomplished by accessing the thumbnail of the Doc and creating a new PNG file from that thumbnail. Try this:
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE).getThumbnail().getAs('image/png');
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
TARGET_FOLDER.createFile(source);
}
However, I've found that getting the thumbnail of the Doc is not as high quality as getting the thumbnail of a PDF created from the Doc. You can try the code below to compare which version of the new PNG you prefer.
To do this, you will also need to enable Advanced Services on your project, specifically the Drive API service. To do this, follow these instructions to add a new Service to your Google Apps Script project:
Open the Apps Script project.
At the left, click Editor < >.
At the left, next to Services, click Add a service +.
Select Drive API and click Add.
Once you do that, you'll be able to use the Drive command in your script, which is different than DriveApp. Note also the update to source.makeCopy() to only include the TARGET_FOLDER:
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE);
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
var target = source.makeCopy(targetFolder);
var pdfBlob = target.getAs(MimeType.PDF);
var newPDF = TARGET_FOLDER.createFile(pdfBlob).setName('Some Name.pdf');
var newId = newPDF.getId();
Drive.Files.update({
title: newPDF.getName(), mimeType: MimeType.PDF
}, newId, pdfBlob);
var newFile = DriveApp.getFileById(newId).getThumbnail().getAs('image/png');
TARGET_FOLDER.createFile(newFile);
target.setTrashed(true);
newPDF.setTrashed(true);
}
This code will create a copy of your Google Doc file, convert it to a PDF, then grab the thumbnail of the PDF as a PNG, and then delete the copy of the Doc file and the PDF that were created.
The Drive.Files.update() function is the critical part of this code, as it finalizes the creation of the PDF file in your Drive. Trying to run the code without that portion will just return the new PDF file as null since the new PDF hasn't completely finished being created at that point.
Hope this helps!

Google script replaceAllShapesWithImage with image from drive doesn"t work any more

Since yesterday one of my google script doesn't work anymore.
The script
take an image on the drive
copie a slide
replace a shape with an image
But I got this error:
"The provided image is in an unsupported format."
-> I give all access to the image: it doesn't change anything
-> The script work if I take an url outside the drive
Any idea
function test_image(){
var imageUrls = DriveApp.getFilesByName("DSC_3632.png");
var file = "undefined";
while ( imageUrls.hasNext()) {
var file = imageUrls.next();
}
var imageUrl = file.getDownloadUrl() + "&access_token=" + ScriptApp.getOAuthToken();
var model_file = DriveApp.getFileById("your-id");
var presentation = model_file.makeCopy("totot");
var presentation =Slides.Presentations.get(presentation.getId())
var requests = [{
"replaceAllShapesWithImage":
{
"imageUrl": imageUrl,
"imageReplaceMethod": "CENTER_INSIDE",
"containsText": {
"text": "toto",
"matchCase": false,
}
}
}];
var presentationId = presentation.presentationId
var createSlideResponse = Slides.Presentations.batchUpdate({
requests: requests
}, presentationId);
}
How about this answer? Please think of this as just one of several possible answers.
Issue and workaround:
I think that the reason of your issue is due to the following modification of official document.
First, we’re making changes to authorization for the Google Drive API. If you authorize download requests to the Drive API using the access token in a query parameter, you will need to migrate your requests to authenticate using an HTTP header instead. Starting January 1, 2020, download calls to files.get, revisions.get and files.export endpoints which authenticate using the access token in the query parameter will no longer be supported, which means you’ll need to update your authentication method.
By above situation, the URL of var imageUrl = file.getDownloadUrl() + "&access_token=" + ScriptApp.getOAuthToken(); cannot be used. For example, when it accesses to the URL, the login screen is displayed even when the access token is used.
In order to avoid this issue, how about the following modification?
Modification points:
The file is shared publicly and put to Google Slides. Then, the sharing file is closed.
In this case, even when the share of file is closed, the put image on Slides is not removed.
The webContentLink is used as the URL.
It's like https://drive.google.com/uc?export=download&id=###.
Modified script:
When your script is modified, it becomes as follows.
function test_image(){
var imageUrls = DriveApp.getFilesByName("DSC_3632.png");
var file; // Modified
while (imageUrls.hasNext()) {
file = imageUrls.next();
}
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW); // Added
var imageUrl = "https://drive.google.com/uc?export=download&id=" + file.getId(); // Modified
var model_file = DriveApp.getFileById("your-id");
var presentation = model_file.makeCopy("totot");
var presentation =Slides.Presentations.get(presentation.getId())
var requests = [{
"replaceAllShapesWithImage": {
"imageUrl": imageUrl,
"imageReplaceMethod": "CENTER_INSIDE",
"containsText": {
"text": "toto",
"matchCase": false,
}
}
}];
var presentationId = presentation.presentationId
var createSlideResponse = Slides.Presentations.batchUpdate({requests: requests}, presentationId);
file.setSharing(DriveApp.Access.PRIVATE, DriveApp.Permission.NONE); // Added
}
References:
Upcoming changes to the Google Drive API and Google Picker API
setSharing()
If I misunderstood your question and this was not the direction you want, I apologize.

Convert a gdoc into image

is there a way to create an image (e.g. a png) from a google document?
I really mean an image, not just a pdf. GetAS only creates pdf, but returns an error if contentType is set to image/png or other equivalent formats.
My (actually trivial) code is
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE);
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
var target = source.makeCopy(source,targetFolder);
var newFile = DriveApp.createFile(target.getAs('image/png'));
}
When I run this code, I get the following error (my translation):
The conversion from application/vnd.google-apps.document to image/png is not supported.
Ty
How about this answer?
Reason of error:
makeCopy() returns File object. getAs() cannot be used for this. By this, the error occurs.
Workaround:
Unfortunately, in the current stage, Google Document cannot be directly exported as PNG images. So it is required to think of workarounds. Google Document can be converted to PDF. This answer uses this. As a workaround, I would like to propose to use an external API which is ConvertAPI. I thought that using the external API, the script becomes simple. This a method (PDF to PNG API) of API can be converted from PDF data to PNG data.
When you try this, for example, you can also test this using "Free Package". When you try using "Free Package", please Sign Up at "Free Package" and retrieve your Secret key.
Sample script:
Before you run this script, please retrieve your Secret key and set it.
var secretkey = "###"; // Please set your secret key.
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var url = "https://v2.convertapi.com/convert/pdf/to/png?Secret=" + secretkey;
var options = {
method: "post",
payload: {File: DriveApp.getFileById(SOURCE_TEMPLATE).getBlob()},
}
var res = UrlFetchApp.fetch(url, options);
res = JSON.parse(res.getContentText());
res.Files.forEach(function(e) {
var blob = Utilities.newBlob(Utilities.base64Decode(e.FileData), "image/png", e.FileName);
DriveApp.getFolderById(TARGET_FOLDER).createFile(blob);
});
References:
makeCopy()
getAs()
ConvertAPI
PDF to PNG API of ConvertAPI
Updated on January 11, 2023:
In the current stage, Google Apps Script can use V8 runtime. By this, there are some Javascript libraries that can be used with Google Apps Script. Ref1, Ref2 In this question, in the current stage, by using pdf-lib, all pages in a PDF file can be converted to PNG images using Google Apps Script. The sample script is as follows.
Sample script:
This method uses Drive API. Please enable Drive API at Advanced Google services.
Please set SOURCE_TEMPLATE and TARGET_FOLDER, and run main().
/**
* This is a method for converting all pages in a PDF file to PNG images.
* PNG images are returned as BlobSource[].
* IMPORTANT: This method uses Drive API. Please enable Drive API at Advanced Google services.
*
* #param {Blob} blob Blob of PDF file.
* #return {BlobSource[]} PNG blobs.
*/
async function convertPDFToPNG_(blob) {
// Convert PDF to PNG images.
const cdnjs = "https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js";
eval(UrlFetchApp.fetch(cdnjs).getContentText()); // Load pdf-lib
const setTimeout = function (f, t) { // Overwrite setTimeout with Google Apps Script.
Utilities.sleep(t);
return f();
}
const data = new Uint8Array(blob.getBytes());
const pdfData = await PDFLib.PDFDocument.load(data);
const pageLength = pdfData.getPageCount();
console.log(`Total pages: ${pageLength}`);
const obj = { imageBlobs: [], fileIds: [] };
for (let i = 0; i < pageLength; i++) {
console.log(`Processing page: ${i + 1}`);
const pdfDoc = await PDFLib.PDFDocument.create();
const [page] = await pdfDoc.copyPages(pdfData, [i]);
pdfDoc.addPage(page);
const bytes = await pdfDoc.save();
const blob = Utilities.newBlob([...new Int8Array(bytes)], MimeType.PDF, `sample${i + 1}.pdf`);
const id = DriveApp.createFile(blob).getId();
Utilities.sleep(3000); // This is used for preparing the thumbnail of the created file.
const link = Drive.Files.get(id, { fields: "thumbnailLink" }).thumbnailLink;
if (!link) {
throw new Error("In this case, please increase the value of 3000 in Utilities.sleep(3000), and test it again.");
}
const imageBlob = UrlFetchApp.fetch(link.replace(/\=s\d*/, "=s1000")).getBlob().setName(`page${i + 1}.png`);
obj.imageBlobs.push(imageBlob);
obj.fileIds.push(id);
}
obj.fileIds.forEach(id => DriveApp.getFileById(id).setTrashed(true));
return obj.imageBlobs;
}
// Please run this function.
async function myFunction() {
const SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
const TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
// Use a method for converting all pages in a PDF file to PNG images.
const blob = DriveApp.getFileById(SOURCE_TEMPLATE).getBlob();
const imageBlobs = await convertPDFToPNG_(blob);
// As a sample, create PNG images as PNG files.
const folder = DriveApp.getFolderById(TARGET_FOLDER);
imageBlobs.forEach(b => folder.createFile(b));
}
When this script is run, all pages of the inputted PDF file are converted to PNG images, and those images are created in the destination folder.
Note:
I think that the above script works. But, in this case, when you directly copy and paste the Javascript retrieved from https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js to your Google Apps Script project, the process cost for loading it can be reduced.
References:
pdf-lib
copyPages of pdf-lib
addPage of pdf-lib
I know this is an older question, but I thought I'd answer, since I believe I've found a solution that doesn't involve paying for a third-party subscription.
This can be accomplished by accessing the thumbnail of the Doc and creating a new PNG file from that thumbnail. Try this:
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE).getThumbnail().getAs('image/png');
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
TARGET_FOLDER.createFile(source);
}
However, I've found that getting the thumbnail of the Doc is not as high quality as getting the thumbnail of a PDF created from the Doc. You can try the code below to compare which version of the new PNG you prefer.
To do this, you will also need to enable Advanced Services on your project, specifically the Drive API service. To do this, follow these instructions to add a new Service to your Google Apps Script project:
Open the Apps Script project.
At the left, click Editor < >.
At the left, next to Services, click Add a service +.
Select Drive API and click Add.
Once you do that, you'll be able to use the Drive command in your script, which is different than DriveApp. Note also the update to source.makeCopy() to only include the TARGET_FOLDER:
function convertFile() {
var SOURCE_TEMPLATE = "1HvqYidpUpihzo_HDAQ3zE5ScMVsHG9NNlwPkN80GHK0";
var TARGET_FOLDER = "1Eue-3tJpE8sBML0qo6Z25G0D_uuXZjHZ";
var source = DriveApp.getFileById(SOURCE_TEMPLATE);
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER);
var target = source.makeCopy(targetFolder);
var pdfBlob = target.getAs(MimeType.PDF);
var newPDF = TARGET_FOLDER.createFile(pdfBlob).setName('Some Name.pdf');
var newId = newPDF.getId();
Drive.Files.update({
title: newPDF.getName(), mimeType: MimeType.PDF
}, newId, pdfBlob);
var newFile = DriveApp.getFileById(newId).getThumbnail().getAs('image/png');
TARGET_FOLDER.createFile(newFile);
target.setTrashed(true);
newPDF.setTrashed(true);
}
This code will create a copy of your Google Doc file, convert it to a PDF, then grab the thumbnail of the PDF as a PNG, and then delete the copy of the Doc file and the PDF that were created.
The Drive.Files.update() function is the critical part of this code, as it finalizes the creation of the PDF file in your Drive. Trying to run the code without that portion will just return the new PDF file as null since the new PDF hasn't completely finished being created at that point.
Hope this helps!