Commit d7cecb57 by Dk Saha

Removed Image Manager caching

parent 6a79b682
### unreleased (master branch)
- ### 1.1.0
- Breaking : The image module no longer swallows error thrown by `options.getImage` and `options.getSize`. It is the implementors responsibility to not throw any errors, or the error will be passed. You can return a falsy value in getImage to not render an image at all.
- Add Async support
### 3.0.2
- ### 1.0.0
- Fix issue with PPTX : Before, you had to add to your options : {fileType: "pptx"} in the module options passed as argument in the constructor of the module. Now, the fileType is retrieved from the main docxtemplater.
- This version is compatible with docxtemplater 3.0.
### 3.0.1
- Add support for PPTX.
- Add centering of images with {%%image} syntax
### 3.0.0
- This version is compatible with docxtemplater 3.0.
Open source docxtemplater image module
Open Source docxtemplater image module
==========================================
This repository holds an updated version of docxtemplater image module.
This repository holds an maintained version of docxtemplater image module.
This package is open source. There is also a [paid version](https://docxtemplater.com/modules/image/) maintained by docxtemplater author.
Note this version is compatible with docxtemplater 3.x.
Installation
=============
-------------
You first need to install docxtemplater by following its [installation guide](https://docxtemplater.readthedocs.io/en/latest/installation.html).
For Node.js install this package:
```
npm install open-docxtemplater-image-module
npm install docxtemplater-image-module-free
```
For the browser find builds in `build/` directory.
......@@ -25,7 +25,7 @@ npm run uglify
```
Usage
=====
-----
Assuming your **docx** or **pptx** template contains only the text `{%image}`:
```javascript
//Node.js example
......@@ -72,8 +72,81 @@ Some notes regarding templates:
* **docx** files: the placeholder `{%image}` must be in a dedicated paragraph.
* **pptx** files: the placeholder `{%image}` must be in a dedicated text cell.
In the browser, this shows how to get the image asynchronously :
```html
<html>
<script src="node_modules/docxtemplater/build/docxtemplater.js"></script>
<script src="node_modules/jszip/dist/jszip.js"></script>
<script src="node_modules/jszip/vendor/FileSaver.js"></script>
<script src="node_modules/jszip-utils/dist/jszip-utils.js"></script>
<script src="build/imagemodule.js"></script>
<script>
JSZipUtils.getBinaryContent('examples/image-example.docx', function (error, content) {
if (error) {
console.error(error);
return;
}
var opts = {}
opts.centered = false;
opts.getImage = function (tagValue, tagName) {
return new Promise(function (resolve, reject) {
JSZipUtils.getBinaryContent(tagValue, function (error, content) {
if (error) {
return reject(error);
}
return resolve(content);
});
});
}
opts.getSize = function (img, tagValue, tagName) {
// FOR FIXED SIZE IMAGE :
return [150, 150];
// FOR IMAGE COMING FROM A URL (IF TAGVALUE IS AN ADRESS) :
// To use this feature, you have to be using docxtemplater async
// (if you are calling setData(), you are not using async).
return new Promise(function (resolve, reject) {
var image = new Image();
image.src = url;
image.onload = function () {
resolve([image.width, image.height]);
};
image.onerror = function (e) {
console.log('img, tagValue, tagName : ', img, tagValue, tagName);
alert("An error occured while loading " + tagValue);
reject(e);
}
});
}
var imageModule = new ImageModule(opts);
var zip = new JSZip(content);
var doc = new docxtemplater()
.loadZip(zip)
.attachModule(imageModule)
.compile();
doc.resolveData({
image: 'examples/image.png'
}).then(function () {
console.log('ready');
doc.render();
var out = doc.getZip().generate({
type: "blob",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
saveAs(out, "generated.docx");
})
});
</script>
</html>
```
Centering images
================
----------------
You can center all images by setting the global switch to true `opts.centered = true`.
If you would like to choose which images should be centered one by one:
......@@ -82,3 +155,133 @@ If you would like to choose which images should be centered one by one:
* Use `{%%image}` for images that you would like to see centered.
In **pptx** generated documents, images are centered vertically and horizontally relative to the parent cell.
## Async support
It is possible to get images asynchronously by returning a Promise in the getImage function and use the docxtemplater async api : http://docxtemplater.readthedocs.io/en/latest/async.html
You can also return a promise in the getSize function if you want to resolve the size asynchronously (like in the browser example above).
Here is an example in node that allows you to retrieve values from an URL and use a fixed width, and keep the aspect ratio.
```js
const fs = require("fs");
const DocxTemplater = require("docxtemplater");
const https = require("https");
const Stream = require("stream").Transform;
const ImageModule = require("./es6");
const JSZip = require("jszip");
const content = fs.readFileSync("demo_template.docx");
const data = {
image: "https://docxtemplater.com/xt-pro.png"
};
const opts = {};
opts.getImage = function (tagValue, tagName) {
console.log(tagValue, tagName);
// tagValue is "https://docxtemplater.com/xt-pro-white.png" and tagName is "image"
return new Promise(function (resolve, reject) {
getHttpData(tagValue, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
};
opts.getSize = function (img, tagValue, tagName) {
console.log(tagValue, tagName);
// img is the value that was returned by getImage
// This is to force the width to 600px, but keep the same aspect ration
const sizeOf = require("image-size");
const sizeObj = sizeOf(img);
console.log(sizeObj);
const forceWidth = 600;
const ratio = forceWidth / sizeObj.width;
return [
forceWidth,
// calculate height taking into account aspect ratio
Math.round(sizeObj.height * ratio),
];
};
const imageModule = new ImageModule(opts);
const zip = new JSZip(content);
const doc = new DocxTemplater()
.loadZip(zip)
.attachModule(imageModule)
.compile();
doc
.resolveData(data)
.then(function () {
console.log("data resolved");
doc.render();
const buffer = doc
.getZip()
.generate({
type: "nodebuffer",
compression: "DEFLATE"
});
fs.writeFileSync("test.docx", buffer);
console.log("rendered");
})
.catch(function (error) {
console.log("An error occured", error);
});
function getHttpData(url, callback) {
https
.request(url, function (response) {
if (response.statusCode !== 200) {
return callback(
new Error(
`Request to ${url} failed, status code: ${response.statusCode}`
)
);
}
const data = new Stream();
response.on("data", function (chunk) {
data.push(chunk);
});
response.on("end", function () {
callback(null, data.read());
});
response.on("error", function (e) {
callback(e);
});
})
.end();
}
```
## Size and path based on placeholder
You can have customizable image loader using the template's placeholder name.
```
opts.getImage = function (tagValue, tagName) {
if(tagName === 'logo')
return fs.readFileSync(__dirname + '/logos/' + tagValue);
return fs.readFileSync(__dirname + '/images/' + tagValue);
};
```
The same thing can be used to customize image size.
```
opts.getSize = function (img, tagValue, tagName) {
if(tagName === 'logo')
return [100, 100];
return [300, 300];
};
```
\ No newline at end of file
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ImageModule = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({"/js/index.js":[function(require,module,exports){
"use strict";
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
......@@ -93,6 +95,9 @@ var ImageModule = function () {
value: function parse(placeHolderContent) {
var module = moduleName;
var type = "placeholder";
if (this.options.setParser) {
return this.options.setParser(placeHolderContent);
}
if (placeHolderContent.substring(0, 2) === "%%") {
return { type: type, value: placeHolderContent.substr(2), module: module, centered: true };
}
......@@ -126,16 +131,23 @@ var ImageModule = function () {
});
if (!tagValue) {
return { value: this.fileTypeConfig.tagTextXml };
}
} else if ((typeof tagValue === "undefined" ? "undefined" : _typeof(tagValue)) === "object") {
return this.getRenderedPart(part, tagValue.rId, tagValue.sizePixel);
}
// this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
var imgManager = new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
var imgBuffer = this.options.getImage(tagValue, part.value);
var rId = imgManager.addImageRels(this.getNextImageName(), imgBuffer);
var sizePixel = this.options.getSize(imgBuffer, tagValue, part.value);
return this.getRenderedPart(part, rId, sizePixel);
}
}, {
key: "resolve",
value: function resolve(part, options) {
var _this = this;
this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
var imgManager = this.imgManagers[options.filePath];
// this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
var imgManager = new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
if (!part.type === "placeholder" || part.module !== moduleName) {
return null;
}
......
......@@ -103,16 +103,14 @@ class ImageModule {
else if (typeof tagValue === "object") {
return this.getRenderedPart(part, tagValue.rId, tagValue.sizePixel);
}
this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
const imgManager = this.imgManagers[options.filePath];
const imgManager = new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
const imgBuffer = this.options.getImage(tagValue, part.value);
const rId = imgManager.addImageRels(this.getNextImageName(), imgBuffer);
const sizePixel = this.options.getSize(imgBuffer, tagValue, part.value);
return this.getRenderedPart(part, rId, sizePixel);
}
resolve(part, options) {
this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
const imgManager = this.imgManagers[options.filePath];
const imgManager = new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
if (!part.type === "placeholder" || part.module !== moduleName) {
return null;
}
......
......@@ -133,8 +133,8 @@ var ImageModule = function () {
} else if ((typeof tagValue === "undefined" ? "undefined" : _typeof(tagValue)) === "object") {
return this.getRenderedPart(part, tagValue.rId, tagValue.sizePixel);
}
this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
var imgManager = this.imgManagers[options.filePath];
var imgManager = new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
var imgBuffer = this.options.getImage(tagValue, part.value);
var rId = imgManager.addImageRels(this.getNextImageName(), imgBuffer);
var sizePixel = this.options.getSize(imgBuffer, tagValue, part.value);
......@@ -145,8 +145,7 @@ var ImageModule = function () {
value: function resolve(part, options) {
var _this = this;
this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
var imgManager = this.imgManagers[options.filePath];
var imgManager = new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
if (!part.type === "placeholder" || part.module !== moduleName) {
return null;
}
......
{
"name": "docxtemplater-image-module-free",
"version": "1.0.0",
"version": "1.1.0",
"description": "Open Source Image Module for docxtemplater",
"main": "js/index.js",
"scripts": {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment