Support for Docxtemplater pro



  • From our discussion in https://forum.jsreport.net/topic/1028/chart-as-images-into-docxtemplater/13 it sounds like someone has had success using docxtemplater pro with jsreport.

    1. Can someone from jsreport.net confirm that this is supported?
    2. How would you install the pro version? My guess is that after running npm install jsreport-docxtemplater I would go into the node modules, delete the now installed docxtemplater module and replace it with my paid version. Is that correct?

    Thanks,
    James



  • We didn't run any test with PRO version, however, it should work.
    You likely need to purchase the module. Like the html module.
    They probably send you some kind of zip with the package you extract into node_modules.
    Then you call .attachModule(htmlModule) somewhere here.
    Please share some info if you make it work, we would be able to make the attachModule configurable I think.



  • Thanks for the info. I'll give it a shot and let you know what happens.



  • @jan_blaha after I make this change how do I do the equivalent of npm install jsreport-docxtemplater? Can I just replace the jsreport-docxtemplater folder under node-modules?


  • administrators

    Can I just replace the jsreport-docxtemplater folder under node-modules?

    yes, after the install of jsreport-docxtemplater and the unzip of the pro module i would replace the jsreport-docxtemplater folder under node-modules as you said.



  • I was able to get this working. a few weeks ago. I had to modify the jsreport-docxtemplater module and the jsreport-scripts module.

    The jsreport-scripts change was just to allow more render calls in a pre-render script. Without this change I was limited to a max of 3 images I could put inside my final document. The change I made is documented in this forum post: https://forum.jsreport.net/topic/1170/error-reached-maximum-number-of-script-rendering-requests

    The jsreport-docxtemplater module change was to attach the image module to the docxtemplater instance and to auto detect the size of the PNG images I wanted to substitute into the document.

    The changes are all to the jsreport-docxtemplater/lib/recipe.js file. Around where the docxtemplater instance is being created and the document is being generated, the code now looks like this

      function base64DataURLToArrayBuffer(dataURL) {
        let binaryString;
        if (typeof window !== "undefined") {
          binaryString = window.atob(dataURL);
        } else {
          binaryString = Buffer.from(dataURL, "base64").toString("binary");
        }
        const len = binaryString.length;
        const bytes = new Uint8Array(len);
        for (let i = 0; i < len; i++) {
          const ascii = binaryString.charCodeAt(i);
          bytes[i] = ascii;
        }
        return bytes.buffer;
      }
    
      // This function gets the width and height of a PNG. A PNG’s width and height are always bytes 16-24 of its byte representation.
      // Here is a stack overflow post where some of this is explained and shows how to convert the base64 to the width and height.
      //https://stackoverflow.com/questions/15327959/get-height-and-width-dimensions-from-base64-png
      // In node it works differently because there is no atob function.
      function getPngDimensions(base64) {
        // This is essentially the atob() function on the first 50 characters of the base64 representation of an image.
        // We only care to process the first 50 chars or so because we only need bytes 16-24 after it's converted.
        const header = Buffer.from(base64.slice(0,50), 'base64').toString('binary').slice(16,24);
        const uint8 = Uint8Array.from(header, c => c.charCodeAt(0))
        const dataView = new DataView(uint8.buffer)
    
        return {
            width: dataView.getInt32(0),
            height: dataView.getInt32(4)
        }
      }
    
      const opts = {};
      opts.getImage = function(tag) {
        return base64DataURLToArrayBuffer(tag);
      };
      opts.getSize = function(img) {
        var sizeObj = getPngDimensions(img);
        console.log(sizeObj);
        return [sizeObj.width, sizeObj.height];
      };
    
      var imageModule = new ImageModule(opts);
      var zip = new JSZip(templateAsset.content);
      var docx = new Docxtemplater()
        .attachModule(imageModule)
        .loadZip(zip)
        .setData(req.data)
        .render();
    

    also had to add

    const ImageModule=require('docxtemplater-image-module')
    

    to the top of the file.

    For any of this to work I needed to first buy the docxtemplater image module. Once you've purchased this module you need to install it in your jsreport directory using npm. They will send you the command to run.

    After you've made the javascript changes above to jsreport-scripts and jsreport-docxtemplater you need to delete the existing jsreport-scripts and jsreport-docxtemplater npm modules from your jsreport app directory and replace them with your customized versions (copy/paste or you can just make the change the the existing module itself).

    To put this all together what I do is create a docxtemplater template with the appropriate markup for image substitution and in that recipe i create a beforeRender script that takes data posted to the template and posts it to another template which returns a PNG from a chrome-image recipe. I feed the return value from the image template into the data of the docxtemplater template. Below is an example of what I'm doing in the beforeRender.

    const jsreport = require('jsreport-proxy')
    
    async function beforeRender(req, res, done) {
        const promise1 = jsreport.render({template: {name: 'MyTemplate'}, data: {"myData": req.data.myData, "otherData": req.data.otherData }});
        var myResult = await promise1;
        myContentAsBase64 = Buffer.from(myResult.content).toString('base64');
        req.data.myImageData = myContentAsBase64;
        done();
    }
    

    Reminder that if you want to generate more than 3 templates in this before render script that you NEED to make the corresponding change in jsreport-scripts module.

    And that's it! Hope this helps someone in the future.


Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.