0

For years, I have been using Google Cloud Print to print labels in our laboratories on campus (to standardize) using a Google Apps Script custom HtmlService form.

Now that GCP is becoming depreciated, I am in on a search for a solution. I have found a few options but am struggling to get the file to convert to a pdf as would be needed with these other vendors.

Currently, when you submit a text/html blob to the GCP servers in GAS, the backend converts the blob to application/pdf (as evidenced by looking at the job details in the GCP panel on Chrome under 'content type').

That said, because these other cloud print services require pdf printing, I have tried for some time now to have GAS change the file to pdf format before sending to GCP and I always get a strange result. Below, I'll show some of the strategies that I have used and include pictures of one of our simple labels generated with the different functions.

The following is the base code for the ticket and payload that has worked for years with GCP

   //BUILD PRINT JOB FOR NARROW TAPES
     var ticket = {
        version: "1.0",
        print: {
          color: {
            type: "STANDARD_COLOR",
            vendor_id: "Color"
          },
          duplex: {
            type: "NO_DUPLEX"
          },
          copies: {copies: parseFloat(quantity)},
          media_size: {
             width_microns: 27940,
             height_microns:40960
          },
          page_orientation: {
            type: "LANDSCAPE"  
          },
           margins: {
             top_microns:0,
             bottom_microns:0,
             left_microns:0,
             right_microns:0
          },
         page_range: {
            interval: 
              [{start:1,
              end:1}]
            
          },
          
        }
      };
     
          
      var payload = {
        "printerid" : QL710,
        "title"     : "Blank Template Label",
        "content"   : HtmlService.createHtmlOutput(html).getBlob(),
        "contentType": 'text/html',
        "ticket"    : JSON.stringify(ticket)
      };

This generates the expected following printout: Expected Output

When trying to convert to pdf using the following code: The following is the code used to transform to pdf:

  var blob = HtmlService.createTemplate(html).evaluate().getContent();
  var newBlob = Utilities.newBlob(html, "text/html", "text.html");
  var pdf = newBlob.getAs("application/pdf").setName('tempfile');
  var file = DriveApp.getFolderById("FOLDER ID").createFile(pdf);
  
  
  var payload = {
    "printerid" : QL710,
    "title"     : "Blank Template Label",
    "content"   : pdf,//HtmlService.createHtmlOutput(html).getBlob(),
    "contentType": 'text/html',
    "ticket"    : JSON.stringify(ticket)
  };

an unexpected result occurs:

enter image description here

This comes out the same way for direct coding in the 'content' field with and without .getBlob():

"content" : HtmlService.createHtmlOutput(html).getAs('application/pdf'),

note the createFile line in the code above used to test the pdf. This file is created as expected, of course with the wrong dimensions for label printing (not sure how to convert to pdf with the appropriate margins and page size?): see below

Uploaded to Drive shows accurate pdf created

I have now tried to adopt Yuri's ideas; however, the conversion from html to document loses formatting.

 var blob = HtmlService.createHtmlOutput(html).getBlob();
  var docID = Drive.Files.insert({title: 'temp-label'}, blob, {convert: true}).id
  var file = DocumentApp.openById(docID);
  file.getBody().setMarginBottom(0).setMarginLeft(0).setMarginRight(0).setMarginTop(0).setPageHeight(79.2).setPageWidth(172.8);

This produces a document looks like this (picture also showing expected output in my hand).

enter image description here

Does anyone have insights into:

  1. How to format the converted pdf to contain appropriate height, width and margins.
  2. How to convert to pdf in a way that would print correctly.

Here is a minimal code to get a better sense of context https://script.google.com/d/1yP3Jyr_r_FIlt6_aGj_zIf7HnVGEOPBKI0MpjEGHRFAWztGzcWKCJrD0/edit?usp=sharing

4
  • Can you share the HTML used to create the template? Please post the minimal code required to reproduce your issue. Commented Oct 29, 2020 at 8:32
  • Here is a link to the minimal code required to reproduce the issue. I have commented out the parts that cause it not to work. script.google.com/d/… Commented Nov 2, 2020 at 18:00
  • If I understand you correctly, the problem is not creating a PDF file out of the HTML, but setting an appropriate size and margins for it, right? Commented Nov 3, 2020 at 13:46
  • Yes lamblichus. Commented Nov 7, 2020 at 1:49

3 Answers 3

2

I've made the template (80 x 40 mm -- sorry, I don't know your size):

enter image description here

https://docs.google.com/document/d/1vA93FxGXcWLIEZBuQwec0n23cWGddyLoey-h0WR9weY/edit?usp=sharing

And there is the script:

function myFunction() {

  // input data
  var matName     = '<b>testing this to <u>see</u></b> if it <i>actually</i> works <i>e.coli</i>'
  var disposeWeek = 'end of semester'
  var prepper     = 'John Ruppert';
  var className   = 'Cell and <b>Molecular</b> Biology <u>Fall 2020</u> a few exercises a few exercises a few exercises a few exercises';
  var hazards     = 'Lots of hazards';

  // make a temporary Doc from the template
  var copyFile = DriveApp.getFileById('1vA93FxGXcWLIEZBuQwec0n23cWGddyLoey-h0WR9weY').makeCopy();
  var doc = DocumentApp.openById(copyFile.getId());
  var body = doc.getBody();

  // replace placeholders with data
  body.replaceText('{matName}',     matName);
  body.replaceText('{disposeWeek}', disposeWeek);
  body.replaceText('{prepper}',     prepper);
  body.replaceText('{className}',   className);
  body.replaceText('{hazards}',     hazards);

  // make Italics, Bold and Underline
  handle_tags(['<i>', '</i>'], body);
  handle_tags(['<b>', '</b>'], body);
  handle_tags(['<u>', '</u>'], body);

  // save the temporary Doc
  doc.saveAndClose();

  // make a PDF
  var docblob = doc.getBlob().setName('Label.pdf');
  DriveApp.createFile(docblob);

  // delete the temporary Doc
  copyFile.setTrashed(true);
}


// this function applies formatting to text inside the tags
function handle_tags(tags, body) {

  var start_tag = tags[0].toLowerCase();
  var end_tag   = tags[1].toLowerCase();
  var found     = body.findText(start_tag);

  while (found) {
    var elem    = found.getElement();
    var start   = found.getEndOffsetInclusive();
    var end     = body.findText(end_tag, found).getStartOffset()-1;

    switch (start_tag) {
      case '<b>': elem.setBold(start, end, true); break;
      case '<i>': elem.setItalic(start, end, true); break;
      case '<u>': elem.setUnderline(start, end, true); break;
    }

    found = body.findText(start_tag, found);
  }

  body.replaceText(start_tag, ''); // remove tags
  body.replaceText(end_tag, '');
}

The script just changes the {placeholders} with the data and saves the result as a PDF file (Label.pdf). The PDF looks like this:

enter image description here

There is one thing, I'm not sure if it's possible -- to change a size of the texts dynamically to fit them into the cells, like it's done in your 'autosize.html'. Roughly, you can take a length of the text in the cell and, in case it is bigger than some number, to make the font size a bit smaller. Probably you can use the jquery texfill function from the 'autosize.html' to get an optimal size and apply the size in the document.

Sign up to request clarification or add additional context in comments.

6 Comments

Again, thank you Yuri. This does look really promising. I do have only 5 templates but a bunch of loaded kits 'data kits'. I will give the autosize feature a shot and a doc template function. Thanks again!
This was so close to working. I got all the way to writing a function to check that the current row height was <= to the defined row height and shrink font size until satisfied. Unfortunately google apps can only pull the attribute 'minimum height'. Bummer. So not sure how to do an autosize of the text.
Yep. Interesting challenge. I'd try to use the jquery and get the size from the generated html. Sounds pretty crazy and I don't know if it's possible at all. It's need to try. And actually for the most cases, I believe, just a rough choice between 2-3 sizes will be enough.
I think this answer is the way to go. Not sure if I understand correctly, but if the problem is it should shrink font size if the text is too long, why not checking the text length and resizing with setFontSize if it's more than X characters?
@lamblichus. This is exactly what I proposed as a rough solution. Roughly, you can take a length of the text in the cell and, in case it is bigger than some number, to make the font size a bit smaller. I think it will work to a degree. But there is not exactly correlation between the length of text and it size. 'iiii' and 'mmmm' have a the same length = 4. It's need to take real texts, a real size of the label and to do a bit science: tests, measurements, you know. )
|
0

I'm not sure if I got you right. Do you need make PDF and save it on Google Drive? You can do in Google Docs.

As example:

  • Make a new document with your table and text. Something like this

enter image description here

  • Add this script into your doc:
function myFunction() {
  var copyFile = DriveApp.getFileById(ID).makeCopy();
  var newFile = DriveApp.createFile(copyFile.getAs('application/pdf')); 
  newFile.setName('label');
  copyFile.setTrashed(true);
}

Every time you run this script it makes the file 'label.pdf' on your Google Drive.

enter image description here

The size of this pdf will be the same as the page size of your Doc. You can make any size of page with add-on: Page Sizer https://webapps.stackexchange.com/questions/129617/how-to-change-the-size-of-paper-in-google-docs-to-custom-size

If you need to change the text in your label before generate pdf or/and you need change the name of generated file, you can do it via script as well.

3 Comments

Thank you Yuri, this seems like a great approach. I'll give it a shot and check back!
I get the idea of having a template table in which the cells are replaced with the appropriate text. This could work except for the autosizing and html formatting of the text appears to not update correctly in the document. I did try to convert the html to doc but the conversion didn't accurately render the html. The issue is that we have thousands of already programmed labels in our system in html format (italics, underlining, bolding in certain spots). Note: I updated the original post to reflect some of these ideas and also provided a minimal code file.
Well. No that I'm expert in jquery, but your HTML parts looks rather funny for me. Do you mean you have thousands HTML templates like in your Code.gs or you mean you have thousans 'data kits' -- some HTML strings (labelType, department, matName, disposeWeek, etc) with <b>bold</b>, <i>italics</i>, <u>underlines</u>? Since it looks more promising to replace this HTML template with some Google Doc template (that can take the same 'data kits') than try to convert this HTML into PDF.
0

Here is a variant of the script that changes a font size in one of the cells if the label doesn't fit into one page.

function main() {

  // input texts
  var text = {};
  text.matName     = '<b>testing this to <u>see</u></b> if it <i>actually</i> works <i>e.coli</i>';
  text.disposeWeek = 'end of semester';
  text.prepper     = 'John Ruppert';
  text.className   = 'Cell and <b>Molecular</b> Biology <u>Fall 2020</u> a few exercises a few exercises a few exercises a few exercises';
  text.hazards     = 'Lots of hazards';
  
  // initial max font size for the 'matName'
  var size = 10;
  var doc_blob = set_text(text, size);

  // if we got more than 1 page, reduce the font size and repeat
  while ((size > 4) && (getNumPages(doc_blob) > 1)) {
    size = size-0.5;
    doc_blob = set_text(text, size);
  }

  // save pdf
  DriveApp.createFile(doc_blob);

}

// this function takes texts and a size and put the texts into fields
function set_text(text, size) {
  
  // make a copy
  var copyFile = DriveApp.getFileById('1vA93FxGXcWLIEZBuQwec0n23cWGddyLoey-h0WR9weY').makeCopy();
  var doc  = DocumentApp.openById(copyFile.getId());
  var body = doc.getBody();
  
  // replace placeholders with data
  body.replaceText('{matName}',     text.matName);
  body.replaceText('{disposeWeek}', text.disposeWeek);
  body.replaceText('{prepper}',     text.prepper);
  body.replaceText('{className}',   text.className);
  body.replaceText('{hazards}',     text.hazards);
  
  // set font size for 'matName'
  body.findText(text.matName).getElement().asText().setFontSize(size);
  
  // make Italics, Bold and Underline
  handle_tags(['<i>', '</i>'], body);
  handle_tags(['<b>', '</b>'], body);
  handle_tags(['<u>', '</u>'], body);
  
  // save the doc
  doc.saveAndClose();
  
  // delete the copy
  copyFile.setTrashed(true);
  
  // return blob
  return docblob = doc.getBlob().setName('Label.pdf');
}

// this function formats the text beween html tags
function handle_tags(tags, body) {

  var start_tag = tags[0].toLowerCase();
  var end_tag   = tags[1].toLowerCase();
  var found     = body.findText(start_tag);

  while (found) {
    var elem    = found.getElement();
    var start   = found.getEndOffsetInclusive();
    var end     = body.findText(end_tag, found).getStartOffset()-1;

    switch (start_tag) {
      case '<b>': elem.setBold(start, end, true); break;
      case '<i>': elem.setItalic(start, end, true); break;
      case '<u>': elem.setUnderline(start, end, true); break;
    }

    found = body.findText(start_tag, found);
  }

  body.replaceText(start_tag, '');
  body.replaceText(end_tag, '');
}

// this funcion takes saved doc and returns the number of its pages
function getNumPages(doc) {
  var blob  = doc.getAs('application/pdf');
  var data  = blob.getDataAsString();
  var pages = parseInt(data.match(/ \/N (\d+) /)[1], 10);
  Logger.log("pages = " + pages);
  return pages; 
}

It looks rather awful and hopeless. It turned out that Google Docs has no page number counter. You need to convert your document into a PDF and to count pages of the PDF file. Gross!

Next problem, even if you managed somehow to count the pages, you have no clue which of the cells was overflowed. This script takes just one cell, changes its font size, counts pages, changes the font size again, etc. But it doesn't granted a success, because there can be another cell with long text inside. You can reduce font size of all the texts, but it doesn't look like a great idea as well.

1 Comment

Hi Yuri, yes. I tried that route yesterday and was having a bit of trouble tackling it because of delays in the system to detect two pages in the pdf. I tried doing it as a while loop working one by one through the fields instead of all at once but the loop continues before the file is updated and the pdf therefore shows one page. I really appreciate your deep thoughts on this!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.