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. 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. Note this version is compatible with docxtemplater 3.x.
Installation Installation
============= -------------
You first need to install docxtemplater by following its [installation guide](https://docxtemplater.readthedocs.io/en/latest/installation.html). 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: 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. For the browser find builds in `build/` directory.
...@@ -25,7 +25,7 @@ npm run uglify ...@@ -25,7 +25,7 @@ npm run uglify
``` ```
Usage Usage
===== -----
Assuming your **docx** or **pptx** template contains only the text `{%image}`: Assuming your **docx** or **pptx** template contains only the text `{%image}`:
```javascript ```javascript
//Node.js example //Node.js example
...@@ -72,8 +72,81 @@ Some notes regarding templates: ...@@ -72,8 +72,81 @@ Some notes regarding templates:
* **docx** files: the placeholder `{%image}` must be in a dedicated paragraph. * **docx** files: the placeholder `{%image}` must be in a dedicated paragraph.
* **pptx** files: the placeholder `{%image}` must be in a dedicated text cell. * **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 Centering images
================ ----------------
You can center all images by setting the global switch to true `opts.centered = true`. 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: 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: ...@@ -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. * 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. 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){ (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"; "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; }; }(); 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"); } } 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 () { ...@@ -93,6 +95,9 @@ var ImageModule = function () {
value: function parse(placeHolderContent) { value: function parse(placeHolderContent) {
var module = moduleName; var module = moduleName;
var type = "placeholder"; var type = "placeholder";
if (this.options.setParser) {
return this.options.setParser(placeHolderContent);
}
if (placeHolderContent.substring(0, 2) === "%%") { if (placeHolderContent.substring(0, 2) === "%%") {
return { type: type, value: placeHolderContent.substr(2), module: module, centered: true }; return { type: type, value: placeHolderContent.substr(2), module: module, centered: true };
} }
...@@ -126,16 +131,23 @@ var ImageModule = function () { ...@@ -126,16 +131,23 @@ var ImageModule = function () {
}); });
if (!tagValue) { if (!tagValue) {
return { value: this.fileTypeConfig.tagTextXml }; return { value: this.fileTypeConfig.tagTextXml };
} else if ((typeof tagValue === "undefined" ? "undefined" : _typeof(tagValue)) === "object") {
return this.getRenderedPart(part, tagValue.rId, tagValue.sizePixel);
} }
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", key: "resolve",
value: function resolve(part, options) { value: function resolve(part, options) {
var _this = this; var _this = this;
this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType); // 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) { if (!part.type === "placeholder" || part.module !== moduleName) {
return null; return null;
} }
......
...@@ -103,16 +103,14 @@ class ImageModule { ...@@ -103,16 +103,14 @@ class ImageModule {
else if (typeof tagValue === "object") { else if (typeof tagValue === "object") {
return this.getRenderedPart(part, tagValue.rId, tagValue.sizePixel); 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 = new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
const imgManager = this.imgManagers[options.filePath];
const imgBuffer = this.options.getImage(tagValue, part.value); const imgBuffer = this.options.getImage(tagValue, part.value);
const rId = imgManager.addImageRels(this.getNextImageName(), imgBuffer); const rId = imgManager.addImageRels(this.getNextImageName(), imgBuffer);
const sizePixel = this.options.getSize(imgBuffer, tagValue, part.value); const sizePixel = this.options.getSize(imgBuffer, tagValue, part.value);
return this.getRenderedPart(part, rId, sizePixel); return this.getRenderedPart(part, rId, sizePixel);
} }
resolve(part, options) { resolve(part, options) {
this.imgManagers[options.filePath] = this.imgManagers[options.filePath] || new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType); const imgManager = new ImgManager(this.zip, options.filePath, this.xmlDocuments, this.fileType);
const imgManager = this.imgManagers[options.filePath];
if (!part.type === "placeholder" || part.module !== moduleName) { if (!part.type === "placeholder" || part.module !== moduleName) {
return null; return null;
} }
......
...@@ -133,8 +133,8 @@ var ImageModule = function () { ...@@ -133,8 +133,8 @@ var ImageModule = function () {
} else if ((typeof tagValue === "undefined" ? "undefined" : _typeof(tagValue)) === "object") { } else if ((typeof tagValue === "undefined" ? "undefined" : _typeof(tagValue)) === "object") {
return this.getRenderedPart(part, tagValue.rId, tagValue.sizePixel); 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 imgBuffer = this.options.getImage(tagValue, part.value);
var rId = imgManager.addImageRels(this.getNextImageName(), imgBuffer); var rId = imgManager.addImageRels(this.getNextImageName(), imgBuffer);
var sizePixel = this.options.getSize(imgBuffer, tagValue, part.value); var sizePixel = this.options.getSize(imgBuffer, tagValue, part.value);
...@@ -145,8 +145,7 @@ var ImageModule = function () { ...@@ -145,8 +145,7 @@ var ImageModule = function () {
value: function resolve(part, options) { value: function resolve(part, options) {
var _this = this; var _this = this;
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 imgManager = this.imgManagers[options.filePath];
if (!part.type === "placeholder" || part.module !== moduleName) { if (!part.type === "placeholder" || part.module !== moduleName) {
return null; return null;
} }
......
{ {
"name": "docxtemplater-image-module-free", "name": "docxtemplater-image-module-free",
"version": "1.0.0", "version": "1.1.0",
"description": "Open Source Image Module for docxtemplater", "description": "Open Source Image Module for docxtemplater",
"main": "js/index.js", "main": "js/index.js",
"scripts": { "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