3
votes

I would like to export a native Google spreadsheet/document/drawing/presentation file to another format, in that same folder, using Google Apps Script. I have enabled Advanced Drive Service, and looked at the instructions to Open and Convert Google Docs in your app.

Was hoping I could use Export to get a File which I could then save/rename using Insert.

Trying to achieve something like:

var file = {fileId: "1yDe...lD2U", 
            folderId: "0B_...hZ1k", 
            mimetype:"application/vnd.google-apps.document", 
            targetMimetype:"application/pdf", 
            targetName:"my converted document"}
var newFile = Drive.Files.export(file.fileId, file.targetMimetype)

// results in error message:
// "Export requires alt=media to download the exported content."

// I am sure the above is incomplete, but unsure how to actually
// save the exported file, in the correct location, with correct filename

Update: when adding alt=media to the call (var newFile = Drive.Files.export(file.fileId, file.targetMimetype, {alt: "media"})), then the script exits with error code 200 and shows the PDF content in the error message. Similar to issue 6573.

Update: this may not have been clear enough, I want to convert from/to all of the formats listed in the Advanced Drive page, not just to PDF. And the DriveApp getAs documentation states that DriveApp can convert mostly to PDF and images. Hence the focus on using Advanced Drive instead of DriveApp.

4
Any reason you cannot use app script native functions like so: var blob = DriveApp.getFileById(file.fileId).getAs('application/pdf') and DriveApp.getFolderById(file.folderId).createFile(blob) to create your newPdfFile?Jack Brown
Good point. Should work for PDF exports. I need to convert to all formats listed in the "Open and Convert Google Docs in your app" though. developers.google.com/apps-script/reference/drive/… states: the MIME type to convert to. For most blobs, 'application/pdf' is the only valid option. For images in BMP, GIF, JPEG, or PNG format, any of 'image/bmp', 'image/gif', 'image/jpeg', or 'image/png' are also valid.wivku

4 Answers

3
votes

As a workaround I now use the OAuth2 library and the direct Drive API.

// ---------------------------------------------------------------------------------------------------
function testConvert() {
  var file = {
    id: "1cpAZp...I7ejZW1idk", // Google Sheet
    folderId: "0B_...Z1k", // test folder
  }

  convert(file, "pdf", "application/pdf");
  convert(file, "csv", "text/csv");
  convert(file, "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}

// ---------------------------------------------------------------------------------------------------
function convert(file, extension, targetMimeType) {
  var exportDetails = {
    targetMimeType: targetMimeType || "application/pdf",
    extension: extension || "pdf",
    postfix: "CONVERTED_FROM_GOOGLE_DOC",
  }

  // http://stackoverflow.com/questions/42887569/using-google-apps-script-how-to-convert-export-a-drive-file
  // https://code.google.com/p/google-apps-script-issues/issues/detail?id=6573

  // var blob = Drive.Files.export(file.id, exportDetails.targetMimeType, {alt: "media"})
  /*
    results in error 200 + content of converted file
    documentation https://developers.google.com/drive/v2/reference/files/export
    1) does not mention the {alt:"media"} (and without it the error is: "export requires alt=media to download the exported content")
    2) states the output is a Files resource (not a blob)
  */

  // using alternative: OAuth2 + public API
  // https://github.com/googlesamples/apps-script-oauth2
  var driveService = getDriveService();
  if (!driveService.hasAccess()) {
    showSidebar();
    return;
  }

  var accessToken = driveService.getAccessToken();
  var url = "https://www.googleapis.com/drive/v2/files/"+file.id+"/export?mimeType="+ exportDetails.targetMimeType
  var blob = UrlFetchApp.fetch(url, {
    headers: {
      Authorization: 'Bearer ' + driveService.getAccessToken()
    }
  });

  var resource = {
    title: DriveApp.getFileById(file.id).getName() +" "+ exportDetails.postfix +"."+ exportDetails.extension,
    description: "This is a converted document",
    mimeType: exportDetails.targetMimeType,
    parents: [{
      "kind": "drive#parentReference",
      "id": file.folderId,
      //"selfLink": string,
      //"parentLink": string,
      "isRoot": false
    }],
  }

  try {
    var convertedFile = Drive.Files.insert(resource, blob);
    Logger.log('ID: %s, File size (bytes): %s', convertedFile.id, convertedFile.fileSize);

  } catch(e) {
    Logger.log(e)
  }
}
1
votes

Try to tweak this code from Armit Agarwal. The important bits to exporting your drive file to PDF is this part of code:

var blob = DriveApp.getFileById(ss.getId()).getAs("application/pdf");

  blob.setName(ss.getName() + ".pdf"); 

Then you can send it to your email by attaching the pdf file:

// If allowed to send emails, send the email with the PDF attachment
  if (MailApp.getRemainingDailyQuota() > 0) 
    GmailApp.sendEmail(email, subject, body, {
      htmlBody: body,
      attachments:[blob]     
    });  

Check the guide for additional reference.

1
votes

Here is the proper solution from https://issuetracker.google.com/issues/36765129#comment8, by a Google person.

Files.export() was recently added to the Drive v2 API, but an alternative is to use the older File.exportLinks field instead. Here's an example:

function convertToDocx(documentId) { 
  var file = Drive.Files.get(documentId); 
  var url = file.exportLinks['application/vnd.openxmlformats-officedocument.wordprocessingml.document']; 
  var oauthToken = ScriptApp.getOAuthToken(); 
  var response = UrlFetchApp.fetch(url, { 
    headers: { 
      'Authorization': 'Bearer ' + oauthToken 
    } 
  }); 
  return response.getBlob(); 
}
0
votes

You're very close. Just use the pdf content as one of the parts of a multipart insert/post.