Commit 2a0c660c by Edgar HIPP

Update algorithm

parent b868beeb
"use strict";
const _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// public method for encoding
module.exports.encode = function (input) {
let output = "";
let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
let i = 0;
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
}
else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
};
"use strict"; "use strict";
const DocUtils = require("docxtemplater").DocUtils;
const DOMParser = require("xmldom").DOMParser;
const XMLSerializer = require("xmldom").XMLSerializer;
const DocUtils = {};
DocUtils.xml2Str = function (xmlNode) {
const a = new XMLSerializer();
return a.serializeToString(xmlNode);
};
DocUtils.str2xml = function (str, errorHandler) {
const parser = new DOMParser({errorHandler});
return parser.parseFromString(str, "text/xml");
};
DocUtils.maxArray = function (a) { return Math.max.apply(null, a); };
DocUtils.decodeUtf8 = function (s) {
try {
if (s === undefined) { return undefined; }
// replace Ascii 160 space by the normal space, Ascii 32
return decodeURIComponent(escape(DocUtils.convertSpaces(s)));
}
catch (e) {
const err = new Error("End");
err.properties.data = s;
err.properties.explanation = "Could not decode string to UFT8";
throw err;
}
};
DocUtils.encodeUtf8 = function (s) {
return unescape(encodeURIComponent(s));
};
DocUtils.convertSpaces = function (s) {
return s.replace(new RegExp(String.fromCharCode(160), "g"), " ");
};
DocUtils.pregMatchAll = function (regex, content) {
/* regex is a string, content is the content. It returns an array of all matches with their offset, for example:
regex=la
content=lolalolilala
returns: [{0: 'la',offset: 2},{0: 'la',offset: 8},{0: 'la',offset: 10}]
*/
if (typeof regex !== "object") {
regex = (new RegExp(regex, "g"));
}
const matchArray = [];
const replacer = function () {
const pn = Array.prototype.slice.call(arguments);
pn.pop();
const offset = pn.pop();
// add match so that pn[0] = whole match, pn[1]= first parenthesis,...
pn.offset = offset;
return matchArray.push(pn);
};
content.replace(regex, replacer);
return matchArray;
};
module.exports = DocUtils; module.exports = DocUtils;
"use strict";
const XmlTemplater = require("docxtemplater").XmlTemplater;
const QrCode = require("qrcode-reader");
module.exports = class DocxQrCode {
constructor(imageData, xmlTemplater, imgName, num, getDataFromString) {
this.xmlTemplater = xmlTemplater;
this.imgName = imgName || "";
this.num = num;
this.getDataFromString = getDataFromString;
this.callbacked = false;
this.data = imageData;
if (this.data === undefined) { throw new Error("data of qrcode can't be undefined"); }
this.ready = false;
this.result = null;
}
decode(callback) {
this.callback = callback;
const self = this;
this.qr = new QrCode();
this.qr.callback = function () {
self.ready = true;
self.result = this.result;
const testdoc = new XmlTemplater(this.result,
{fileTypeConfig: self.xmlTemplater.fileTypeConfig,
tags: self.xmlTemplater.tags,
Tags: self.xmlTemplater.Tags,
parser: self.xmlTemplater.parser,
});
testdoc.render();
self.result = testdoc.content;
return self.searchImage();
};
return this.qr.decode({width: this.data.width, height: this.data.height}, this.data.decoded);
}
searchImage() {
const cb = (_err, data) => {
this.data = data || this.data.data;
return this.callback(this, this.imgName, this.num);
};
if (!(this.result != null)) { return cb(); }
return this.getDataFromString(this.result, cb);
}
};
"use strict"; "use strict";
const DocUtils = require("./docUtils"); const DocUtils = require("./docUtils");
const extensionRegex = /[^.]+\.([^.]+)/;
const imageExtensions = ["gif", "jpeg", "jpg", "emf", "png"];
const imageListRegex = /[^.]+\.([^.]+)/;
module.exports = class ImgManager { module.exports = class ImgManager {
constructor(zip, fileName) { constructor(zip, fileName, xmlDocuments) {
this.zip = zip; this.zip = zip;
this.fileName = fileName; this.xmlDocuments = xmlDocuments;
this.endFileName = this.fileName.replace(/^.*?([a-z0-9]+)\.xml$/, "$1"); const relsFileName = this.getRelsFile(fileName);
} this.relsDoc = xmlDocuments[relsFileName] || this.createEmptyRelsDoc(xmlDocuments, relsFileName);
getImageList() {
const imageList = [];
Object.keys(this.zip.files).forEach(function (path) {
const extension = path.replace(imageListRegex, "$1");
if (imageExtensions.indexOf(extension) >= 0) {
imageList.push({path: path, files: this.zip.files[path]});
}
});
return imageList;
} }
setImage(fileName, data, options) { getRelsFile(fileName) {
options = options || {}; let fileParts = fileName.split("/");
this.zip.remove(fileName); fileParts[fileParts.length - 1] = fileParts[fileParts.length - 1] + ".rels";
return this.zip.file(fileName, data, options); fileParts = [fileParts[0], "_rels"].concat(fileParts.slice(1));
return fileParts.join("/");
} }
hasImage(fileName) { createEmptyRelsDoc(xmlDocuments, relsFileName) {
return this.zip.files[fileName] != null; const file = this.zip.files["word/_rels/document.xml.rels"];
const content = DocUtils.decodeUtf8(file.asText());
const relsDoc = DocUtils.str2xml(content);
const relationships = relsDoc.getElementsByTagName("Relationships")[0];
const relationshipChilds = relationships.getElementsByTagName("Relationship");
for (let i = 0, l = relationshipChilds.length; i < l; i++) {
relationships.removeChild(relationshipChilds[i]);
}
xmlDocuments[relsFileName] = relsDoc;
return relsDoc;
} }
loadImageRels() { loadImageRels() {
const file = this.zip.files[`word/_rels/${this.endFileName}.xml.rels`] || this.zip.files["word/_rels/document.xml.rels"]; const iterable = this.relsDoc.getElementsByTagName("Relationship");
if (file == null) { return; } return Array.prototype.reduce.call(iterable, function (max, relationship) {
const content = DocUtils.decodeUtf8(file.asText()); const id = relationship.getAttribute("Id");
this.xmlDoc = DocUtils.str2xml(content);
// Get all Rids
const RidArray = [0];
const iterable = this.xmlDoc.getElementsByTagName("Relationship");
for (let i = 0, tag; i < iterable.length; i++) {
tag = iterable[i];
const id = tag.getAttribute("Id");
if (/^rId[0-9]+$/.test(id)) { if (/^rId[0-9]+$/.test(id)) {
RidArray.push(parseInt(id.substr(3), 10)); return Math.max(max, parseInt(id.substr(3), 10));
} }
} return max;
this.maxRid = DocUtils.maxArray(RidArray); }, 0);
this.imageRels = [];
return this;
} }
// Add an extension type in the [Content_Types.xml], is used if for example you want word to be able to read png files (for every extension you add you need a contentType) // Add an extension type in the [Content_Types.xml], is used if for example you want word to be able to read png files (for every extension you add you need a contentType)
addExtensionRels(contentType, extension) { addExtensionRels(contentType, extension) {
const content = this.zip.files["[Content_Types].xml"].asText(); const contentTypeDoc = this.xmlDocuments["[Content_Types].xml"];
const xmlDoc = DocUtils.str2xml(content); const defaultTags = contentTypeDoc.getElementsByTagName("Default");
let addTag = true; const extensionRegistered = Array.prototype.some.call(defaultTags, function (tag) {
const defaultTags = xmlDoc.getElementsByTagName("Default"); return tag.getAttribute("Extension") === extension;
for (let i = 0, tag; i < defaultTags.length; i++) { });
tag = defaultTags[i]; if (extensionRegistered) {
if (tag.getAttribute("Extension") === extension) { addTag = false; } return;
}
if (addTag) {
const types = xmlDoc.getElementsByTagName("Types")[0];
const newTag = xmlDoc.createElement("Default");
newTag.namespaceURI = null;
newTag.setAttribute("ContentType", contentType);
newTag.setAttribute("Extension", extension);
types.appendChild(newTag);
return this.setImage("[Content_Types].xml", DocUtils.encodeUtf8(DocUtils.xml2Str(xmlDoc)));
} }
const types = contentTypeDoc.getElementsByTagName("Types")[0];
const newTag = contentTypeDoc.createElement("Default");
newTag.namespaceURI = null;
newTag.setAttribute("ContentType", contentType);
newTag.setAttribute("Extension", extension);
types.appendChild(newTag);
} }
// Adding an image and returns it's Rid // Add an image and returns it's Rid
addImageRels(imageName, imageData, i) { addImageRels(imageName, imageData, i) {
if (i == null) { if (i == null) {
i = 0; i = 0;
} }
const realImageName = i === 0 ? imageName : imageName + `(${i})`; const realImageName = i === 0 ? imageName : imageName + `(${i})`;
if ((this.zip.files[`word/media/${realImageName}`] != null)) { if (this.zip.files[`word/media/${realImageName}`] != null) {
return this.addImageRels(imageName, imageData, i + 1); return this.addImageRels(imageName, imageData, i + 1);
} }
this.maxRid++; const image = {
const file = {
name: `word/media/${realImageName}`, name: `word/media/${realImageName}`,
data: imageData, data: imageData,
options: { options: {
base64: false,
binary: true, binary: true,
compression: null,
date: new Date(),
dir: false,
}, },
}; };
this.zip.file(file.name, file.data, file.options); this.zip.file(image.name, image.data, image.options);
const extension = realImageName.replace(/[^.]+\.([^.]+)/, "$1"); const extension = realImageName.replace(extensionRegex, "$1");
this.addExtensionRels(`image/${extension}`, extension); this.addExtensionRels(`image/${extension}`, extension);
const relationships = this.xmlDoc.getElementsByTagName("Relationships")[0]; const relationships = this.relsDoc.getElementsByTagName("Relationships")[0];
const newTag = this.xmlDoc.createElement("Relationship"); const newTag = this.relsDoc.createElement("Relationship");
newTag.namespaceURI = null; newTag.namespaceURI = null;
newTag.setAttribute("Id", `rId${this.maxRid}`); const maxRid = this.loadImageRels() + 1;
newTag.setAttribute("Id", `rId${maxRid}`);
newTag.setAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"); newTag.setAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
newTag.setAttribute("Target", `media/${realImageName}`); newTag.setAttribute("Target", `media/${realImageName}`);
relationships.appendChild(newTag); relationships.appendChild(newTag);
this.setImage(`word/_rels/${this.endFileName}.xml.rels`, DocUtils.encodeUtf8(DocUtils.xml2Str(this.xmlDoc))); return maxRid;
return this.maxRid;
}
getImageName(id) {
id = id || 0;
const nameCandidate = "Copie_" + id + ".png";
const fullPath = this.getFullPath(nameCandidate);
if (this.hasImage(fullPath)) {
return this.getImageName(id + 1);
}
return nameCandidate;
}
getFullPath(imgName) { return `word/media/${imgName}`; }
// This is to get an image by it's rId (returns null if no img was found)
getImageByRid(rId) {
const relationships = this.xmlDoc.getElementsByTagName("Relationship");
for (let i = 0, relationship; i < relationships.length; i++) {
relationship = relationships[i];
const cRId = relationship.getAttribute("Id");
if (rId === cRId) {
const path = relationship.getAttribute("Target");
if (path.substr(0, 6) === "media/") {
return this.zip.files[`word/${path}`];
}
throw new Error("Rid is not an image");
}
}
throw new Error("No Media with this Rid found");
} }
}; };
"use strict";
const DocUtils = require("./docUtils");
const DocxQrCode = require("./docxQrCode");
const PNG = require("png-js");
const base64encode = require("./base64").encode;
module.exports = class ImgReplacer {
constructor(xmlTemplater, imgManager) {
this.xmlTemplater = xmlTemplater;
this.imgManager = imgManager;
this.imageSetter = this.imageSetter.bind(this);
this.imgMatches = [];
this.xmlTemplater.numQrCode = 0;
}
findImages() {
this.imgMatches = DocUtils.pregMatchAll(/<w:drawing[^>]*>.*?<a:blip.r:embed.*?<\/w:drawing>/g, this.xmlTemplater.content);
return this;
}
replaceImages() {
this.qr = [];
this.xmlTemplater.numQrCode += this.imgMatches.length;
const iterable = this.imgMatches;
for (let imgNum = 0, match; imgNum < iterable.length; imgNum++) {
match = iterable[imgNum];
this.replaceImage(match, imgNum);
}
return this;
}
imageSetter(docxqrCode) {
if (docxqrCode.callbacked === true) { return; }
docxqrCode.callbacked = true;
docxqrCode.xmlTemplater.numQrCode--;
this.imgManager.setImage(`word/media/${docxqrCode.imgName}`, docxqrCode.data, {binary: true});
return this.popQrQueue(this.imgManager.fileName + "-" + docxqrCode.num, false);
}
getXmlImg(match) {
const baseDocument = `<?xml version="1.0" ?>
<w:document
mc:Ignorable="w14 wp14"
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:w10="urn:schemas-microsoft-com:office:word"
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">${match[0]}</w:document>
`;
const f = function (e) {
if (e === "fatalError") {
throw new Error("fatalError");
}
};
return DocUtils.str2xml(baseDocument, f);
}
replaceImage(match, imgNum) {
const num = parseInt(Math.random() * 10000, 10);
let xmlImg;
try {
xmlImg = this.getXmlImg(match);
}
catch (e) {
return;
}
const tagrId = xmlImg.getElementsByTagName("a:blip")[0];
if (tagrId == null) { throw new Error("tagRiD undefined !"); }
const rId = tagrId.getAttribute("r:embed");
const tag = xmlImg.getElementsByTagName("wp:docPr")[0];
if (tag == null) { throw new Error("tag undefined"); }
// if image is already a replacement then do nothing
if (tag.getAttribute("name").substr(0, 6) === "Copie_") { return; }
const imgName = this.imgManager.getImageName();
this.pushQrQueue(this.imgManager.fileName + "-" + num, true);
const newId = this.imgManager.addImageRels(imgName, "");
this.xmlTemplater.imageId++;
const oldFile = this.imgManager.getImageByRid(rId);
this.imgManager.setImage(this.imgManager.getFullPath(imgName), oldFile.data, {binary: true});
tag.setAttribute("name", `${imgName}`);
tagrId.setAttribute("r:embed", `rId${newId}`);
const imageTag = xmlImg.getElementsByTagName("w:drawing")[0];
if (imageTag == null) { throw new Error("imageTag undefined"); }
const replacement = DocUtils.xml2Str(imageTag);
this.xmlTemplater.content = this.xmlTemplater.content.replace(match[0], replacement);
return this.decodeImage(oldFile, imgName, num, imgNum);
}
decodeImage(oldFile, imgName, num, imgNum) {
const mockedQrCode = {xmlTemplater: this.xmlTemplater, imgName: imgName, data: oldFile.asBinary(), num: num};
if (!/\.png$/.test(oldFile.name)) {
return this.imageSetter(mockedQrCode);
}
return ((imgName) => {
const base64 = base64encode(oldFile.asBinary());
const binaryData = new Buffer(base64, "base64");
const png = new PNG(binaryData);
const finished = (a) => {
png.decoded = a;
try {
this.qr[imgNum] = new DocxQrCode(png, this.xmlTemplater, imgName, num, this.getDataFromString);
return this.qr[imgNum].decode(this.imageSetter);
}
catch (e) {
return this.imageSetter(mockedQrCode);
}
};
return png.decode(finished);
})(imgName);
}
};
"use strict"; "use strict";
const isNaN = function (number) { const DocUtils = require("docxtemplater").DocUtils;
function isNaN(number) {
return !(number === number); return !(number === number);
}; }
const SubContent = require("docxtemplater").SubContent;
const ImgManager = require("./imgManager"); const ImgManager = require("./imgManager");
const ImgReplacer = require("./imgReplacer"); const moduleName = "open-xml-templating/docxtemplater-image-module";
function getInner({part}) {
return part;
}
class ImageModule { class ImageModule {
constructor(options) { constructor(options) {
...@@ -17,230 +21,176 @@ class ImageModule { ...@@ -17,230 +21,176 @@ class ImageModule {
this.qrQueue = []; this.qrQueue = [];
this.imageNumber = 1; this.imageNumber = 1;
} }
handleEvent(event, eventData) { optionsTransformer(options, docxtemplater) {
if (event === "rendering-file") { const relsFiles = docxtemplater.zip.file(/\.xml\.rels/)
this.renderingFileName = eventData; .concat(docxtemplater.zip.file(/\[Content_Types\].xml/))
const gen = this.manager.getInstance("gen"); .map((file) => file.name);
this.imgManager = new ImgManager(gen.zip, this.renderingFileName); this.fileTypeConfig = docxtemplater.fileTypeConfig;
this.imgManager.loadImageRels(); this.zip = docxtemplater.zip;
options.xmlFileNames = options.xmlFileNames.concat(relsFiles);
return options;
}
set(options) {
if (options.zip) {
this.zip = options.zip;
} }
if (event === "rendered") { if (options.xmlDocuments) {
if (this.qrQueue.length === 0) { return this.finished(); } this.xmlDocuments = options.xmlDocuments;
} }
} }
get(data) { parse(placeHolderContent) {
if (data === "loopType") { const module = moduleName;
const templaterState = this.manager.getInstance("templaterState"); const type = "placeholder";
if (templaterState.textInsideTag[0] === "%") { if (placeHolderContent[0] === "%") {
return "image"; return {type, value: placeHolderContent.substr(1), module};
}
} }
return null; return null;
} }
getNextImageName() { postparse(parsed) {
const name = `image_generated_${this.imageNumber}.png`; const expandTo = this.options.centered ? "w:p" : "w:t";
this.imageNumber++; return DocUtils.traits.expandToOne(parsed, {moduleName, getInner, expandTo});
return name;
}
replaceBy(text, outsideElement) {
const xmlTemplater = this.manager.getInstance("xmlTemplater");
const templaterState = this.manager.getInstance("templaterState");
let subContent = new SubContent(xmlTemplater.content);
subContent = subContent.getInnerTag(templaterState);
subContent = subContent.getOuterXml(outsideElement);
return xmlTemplater.replaceXml(subContent, text);
} }
convertPixelsToEmus(pixel) { render(part, options) {
return Math.round(pixel * 9525); this.imgManager = new ImgManager(this.zip, options.filePath, this.xmlDocuments);
} if (!part.type === "placeholder" || part.module !== moduleName) {
replaceTag() { return null;
const scopeManager = this.manager.getInstance("scopeManager"); }
const templaterState = this.manager.getInstance("templaterState"); const tagValue = options.scopeManager.getValue(part.value);
const xmlTemplater = this.manager.getInstance("xmlTemplater");
const tagXml = xmlTemplater.fileTypeConfig.tagsXmlArray[0];
const tagXmlParagraph = tagXml.substr(0, 1) + ":p";
const tag = templaterState.textInsideTag.substr(1); const tagXml = this.fileTypeConfig.tagTextXml;
const tagValue = scopeManager.getValue(tag);
const startEnd = `<${tagXml}></${tagXml}>`;
const outsideElement = this.options.centered ? tagXmlParagraph : tagXml;
if (tagValue == null) { if (tagValue == null) {
return this.replaceBy(startEnd, tagXml); return {value: tagXml};
} }
let imgBuffer; let imgBuffer;
try { try {
imgBuffer = this.options.getImage(tagValue, tag); imgBuffer = this.options.getImage(tagValue, part.value);
} }
catch (e) { catch (e) {
return this.replaceBy(startEnd, tagXml); return {value: tagXml};
} }
const imageRels = this.imgManager.loadImageRels(); const rId = this.imgManager.addImageRels(this.getNextImageName(), imgBuffer);
if (!imageRels) { const sizePixel = this.options.getSize(imgBuffer, tagValue, part.value);
return;
}
const rId = imageRels.addImageRels(this.getNextImageName(), imgBuffer);
const sizePixel = this.options.getSize(imgBuffer, tagValue, tag);
const size = [this.convertPixelsToEmus(sizePixel[0]), this.convertPixelsToEmus(sizePixel[1])]; const size = [this.convertPixelsToEmus(sizePixel[0]), this.convertPixelsToEmus(sizePixel[1])];
const newText = this.options.centered ? this.getImageXmlCentered(rId, size) : this.getImageXml(rId, size); const newText = this.options.centered ? this.getImageXmlCentered(rId, size) : this.getImageXml(rId, size);
return this.replaceBy(newText, outsideElement); return {value: newText};
} }
replaceQr() { getNextImageName() {
const xmlTemplater = this.manager.getInstance("xmlTemplater"); const name = `image_generated_${this.imageNumber}.png`;
const imR = new ImgReplacer(xmlTemplater, this.imgManager); this.imageNumber++;
imR.getDataFromString = (result, cb) => { return name;
if ((this.options.getImageAsync != null)) {
return this.options.getImageAsync(result, cb);
}
return cb(null, this.options.getImage(result));
};
imR.pushQrQueue = (num) => {
return this.qrQueue.push(num);
};
imR.popQrQueue = (num) => {
const found = this.qrQueue.indexOf(num);
if (found !== -1) {
this.qrQueue.splice(found, 1);
}
else {
this.on("error", new Error(`qrqueue ${num} is not in qrqueue`));
}
if (this.qrQueue.length === 0) { return this.finished(); }
};
const num = parseInt(Math.random() * 10000, 10);
imR.pushQrQueue("rendered-" + num);
try {
imR.findImages().replaceImages();
}
catch (e) {
this.on("error", e);
}
const f = () => imR.popQrQueue("rendered-" + num);
return setTimeout(f, 1);
}
finished() {}
on(event, data) {
if (event === "error") {
throw data;
}
} }
handle(type, data) { convertPixelsToEmus(pixel) {
if (type === "replaceTag" && data === "image") { return Math.round(pixel * 9525);
this.replaceTag();
}
if (type === "xmlRendered" && this.options.qrCode) {
this.replaceQr();
}
return null;
} }
getImageXml(rId, size) { getImageXml(rId, size) {
if (isNaN(rId)) { if (isNaN(rId)) {
throw new Error("rId is NaN, aborting"); throw new Error("rId is NaN, aborting");
} }
return `<w:drawing> return `<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0"> <wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="${size[0]}" cy="${size[1]}"/> <wp:extent cx="${size[0]}" cy="${size[1]}"/>
<wp:effectExtent l="0" t="0" r="0" b="0"/> <wp:effectExtent l="0" t="0" r="0" b="0"/>
<wp:docPr id="2" name="Image 2" descr="image"/> <wp:docPr id="2" name="Image 2" descr="image"/>
<wp:cNvGraphicFramePr> <wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/> <a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
</wp:cNvGraphicFramePr> </wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"> <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"> <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr> <pic:nvPicPr>
<pic:cNvPr id="0" name="Picture 1" descr="image"/> <pic:cNvPr id="0" name="Picture 1" descr="image"/>
<pic:cNvPicPr> <pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1"/> <a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
</pic:cNvPicPr> </pic:cNvPicPr>
</pic:nvPicPr> </pic:nvPicPr>
<pic:blipFill> <pic:blipFill>
<a:blip r:embed="rId${rId}"> <a:blip r:embed="rId${rId}">
<a:extLst> <a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}"> <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/> <a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
</a:ext> </a:ext>
</a:extLst> </a:extLst>
</a:blip> </a:blip>
<a:srcRect/> <a:srcRect/>
<a:stretch> <a:stretch>
<a:fillRect/> <a:fillRect/>
</a:stretch> </a:stretch>
</pic:blipFill> </pic:blipFill>
<pic:spPr bwMode="auto"> <pic:spPr bwMode="auto">
<a:xfrm> <a:xfrm>
<a:off x="0" y="0"/> <a:off x="0" y="0"/>
<a:ext cx="${size[0]}" cy="${size[1]}"/> <a:ext cx="${size[0]}" cy="${size[1]}"/>
</a:xfrm> </a:xfrm>
<a:prstGeom prst="rect"> <a:prstGeom prst="rect">
<a:avLst/> <a:avLst/>
</a:prstGeom> </a:prstGeom>
<a:noFill/> <a:noFill/>
<a:ln> <a:ln>
<a:noFill/> <a:noFill/>
</a:ln> </a:ln>
</pic:spPr> </pic:spPr>
</pic:pic> </pic:pic>
</a:graphicData> </a:graphicData>
</a:graphic> </a:graphic>
</wp:inline> </wp:inline>
</w:drawing> </w:drawing>
`; `.replace(/\t|\n/g, "");
} }
getImageXmlCentered(rId, size) { getImageXmlCentered(rId, size) {
if (isNaN(rId)) { if (isNaN(rId)) {
throw new Error("rId is NaN, aborting"); throw new Error("rId is NaN, aborting");
} }
return ` <w:p> return `<w:p>
<w:pPr> <w:pPr>
<w:jc w:val="center"/> <w:jc w:val="center"/>
</w:pPr> </w:pPr>
<w:r> <w:r>
<w:rPr/> <w:rPr/>
<w:drawing> <w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0"> <wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="${size[0]}" cy="${size[1]}"/> <wp:extent cx="${size[0]}" cy="${size[1]}"/>
<wp:docPr id="0" name="Picture" descr=""/> <wp:docPr id="0" name="Picture" descr=""/>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"> <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"> <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr> <pic:nvPicPr>
<pic:cNvPr id="0" name="Picture" descr=""/> <pic:cNvPr id="0" name="Picture" descr=""/>
<pic:cNvPicPr> <pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1"/> <a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
</pic:cNvPicPr> </pic:cNvPicPr>
</pic:nvPicPr> </pic:nvPicPr>
<pic:blipFill> <pic:blipFill>
<a:blip r:embed="rId${rId}"/> <a:blip r:embed="rId${rId}"/>
<a:stretch> <a:stretch>
<a:fillRect/> <a:fillRect/>
</a:stretch> </a:stretch>
</pic:blipFill> </pic:blipFill>
<pic:spPr bwMode="auto"> <pic:spPr bwMode="auto">
<a:xfrm> <a:xfrm>
<a:off x="0" y="0"/> <a:off x="0" y="0"/>
<a:ext cx="${size[0]}" cy="${size[1]}"/> <a:ext cx="${size[0]}" cy="${size[1]}"/>
</a:xfrm> </a:xfrm>
<a:prstGeom prst="rect"> <a:prstGeom prst="rect">
<a:avLst/> <a:avLst/>
</a:prstGeom> </a:prstGeom>
<a:noFill/> <a:noFill/>
<a:ln w="9525"> <a:ln w="9525">
<a:noFill/> <a:noFill/>
<a:miter lim="800000"/> <a:miter lim="800000"/>
<a:headEnd/> <a:headEnd/>
<a:tailEnd/> <a:tailEnd/>
</a:ln> </a:ln>
</pic:spPr> </pic:spPr>
</pic:pic> </pic:pic>
</a:graphicData> </a:graphicData>
</a:graphic> </a:graphic>
</wp:inline> </wp:inline>
</w:drawing> </w:drawing>
</w:r> </w:r>
</w:p> </w:p>
`; `.replace(/\t|\n/g, "");
} }
} }
......
"use strict"; "use strict";
/* eslint-disable no-console */
const fs = require("fs"); const fs = require("fs");
const DocxGen = require("docxtemplater"); const Docxtemplater = require("docxtemplater");
const expect = require("chai").expect;
const path = require("path"); const path = require("path");
const JSZip = require("jszip");
const ImageModule = require("./index.js");
const testutils = require("docxtemplater/js/tests/utils");
const shouldBeSame = testutils.shouldBeSame;
const fileNames = [ const fileNames = [
"imageAfterLoop.docx",
"imageExample.docx", "imageExample.docx",
"imageHeaderFooterExample.docx", "imageHeaderFooterExample.docx",
"imageInlineExample.docx",
"imageLoopExample.docx", "imageLoopExample.docx",
"noImage.docx",
"qrExample.docx",
"qrExample2.docx",
"qrHeader.docx",
"qrHeaderNoImage.docx",
"expectedNoImage.docx", "expectedNoImage.docx",
"expectedHeaderFooter.docx",
"expectedOneImage.docx",
"expectedCentered.docx",
"expectedLoopCentered.docx",
"withoutRels.docx", "withoutRels.docx",
"expectedWithoutRels.docx",
]; ];
const shouldBeSame = function (zip1, zip2) {
if (typeof zip1 === "string") {
zip1 = new DocxGen(docX[zip1].loadedContent).getZip();
}
if (typeof zip2 === "string") {
zip2 = new DocxGen(docX[zip2].loadedContent).getZip();
}
return (() => {
const result = [];
Object.keys(zip1.files).map(function (filePath) {
expect(zip1.files[filePath].options.date).not.to.be.equal(zip2.files[filePath].options.date, "Date differs");
expect(zip1.files[filePath].name).to.be.equal(zip2.files[filePath].name, "Name differs");
expect(zip1.files[filePath].options.dir).to.be.equal(zip2.files[filePath].options.dir, "IsDir differs");
expect(zip1.files[filePath].asText().length).to.be.equal(zip2.files[filePath].asText().length, "Content differs");
result.push(expect(zip1.files[filePath].asText()).to.be.equal(zip2.files[filePath].asText(), "Content differs"));
});
return result;
})();
};
let opts = null;
beforeEach(function () { beforeEach(function () {
opts = {}; this.opts = {
opts.getImage = function (tagValue) { getImage: function (tagValue) {
return fs.readFileSync(tagValue, "binary"); return fs.readFileSync(tagValue, "binary");
}; },
opts.getSize = function () { getSize: function () {
return [150, 150]; return [150, 150];
},
centered: false,
}; };
opts.centered = false;
});
const ImageModule = require("./index.js");
const docX = {};
const stripNonNormalCharacters = (string) => {
return string.replace(/\n|\r|\t/g, "");
};
const expectNormalCharacters = (string1, string2) => {
return expect(stripNonNormalCharacters(string1)).to.be.equal(stripNonNormalCharacters(string2));
};
const loadFile = function (name) {
if ((fs.readFileSync != null)) { return fs.readFileSync(path.resolve(__dirname, "..", "examples", name), "binary"); }
const xhrDoc = new XMLHttpRequest();
xhrDoc.open("GET", "../examples/" + name, false);
if (xhrDoc.overrideMimeType) {
xhrDoc.overrideMimeType("text/plain; charset=x-user-defined");
}
xhrDoc.send();
return xhrDoc.response;
};
const loadAndRender = function (d, name, data) {
return d.load(docX[name].loadedContent).setData(data).render();
};
for (let i = 0, name; i < fileNames.length; i++) {
name = fileNames[i];
const content = loadFile(name);
docX[name] = new DocxGen();
docX[name].loadedContent = content;
}
describe("image adding with {% image} syntax", function () {
it("should work with one image", function () {
const name = "imageExample.docx";
const imageModule = new ImageModule(opts);
const doc = new DocxGen(docX[name].loadedContent);
doc.attachModule(imageModule);
const out = loadAndRender(doc, name, {image: "examples/image.png"});
const zip = out.getZip();
fs.writeFile("test7.docx", zip.generate({type: "nodebuffer"}));
const imageFile = zip.files["word/media/image_generated_1.png"];
expect(imageFile != null, "No image file found").to.equal(true);
expect(imageFile.asText().length).to.be.within(17417, 17440);
const relsFile = zip.files["word/_rels/document.xml.rels"];
expect(relsFile != null, "No rels file found").to.equal(true);
const relsFileContent = relsFile.asText();
expectNormalCharacters(relsFileContent, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/><Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering\" Target=\"numbering.xml\"/><Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\" Target=\"settings.xml\"/><Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes\" Target=\"footnotes.xml\"/><Relationship Id=\"rId5\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes\" Target=\"endnotes.xml\"/><Relationship Id=\"hId0\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header\" Target=\"header0.xml\"/><Relationship Id=\"rId6\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"media/image_generated_1.png\"/></Relationships>");
const documentFile = zip.files["word/document.xml"];
expect(documentFile != null, "No document file found").to.equal(true);
documentFile.asText();
});
it("should work without initial rels", function () {
const name = "withoutRels.docx";
const imageModule = new ImageModule(opts);
const doc = new DocxGen(docX[name].loadedContent);
doc.attachModule(imageModule);
const out = loadAndRender(doc, name, {image: "examples/image.png"});
const zip = out.getZip();
fs.writeFile("testWithoutRels.docx", zip.generate({type: "nodebuffer"}));
const imageFile = zip.files["word/media/image_generated_1.png"];
expect(imageFile != null, "No image file found").to.equal(true);
expect(imageFile.asText().length).to.be.within(17417, 17440);
const relsFile = zip.files["word/_rels/document.xml.rels"];
expect(relsFile != null, "No rels file found").to.equal(true);
const relsFileContent = relsFile.asText();
expectNormalCharacters(relsFileContent, '<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> <Relationship Target="numbering.xml" Id="docRId0" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"/> <Relationship Target="styles.xml" Id="docRId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image_generated_1.png"/></Relationships>');
const documentFile = zip.files["word/document.xml"];
expect(documentFile != null, "No document file found").to.equal(true);
documentFile.asText();
});
it("should work with image tag == null", function () {
const name = "imageExample.docx";
const imageModule = new ImageModule(opts);
const doc = new DocxGen(docX[name].loadedContent);
doc.attachModule(imageModule);
const out = loadAndRender(doc, name, {});
const zip = out.getZip();
fs.writeFile("test8.docx", zip.generate({type: "nodebuffer"}));
shouldBeSame(zip, "expectedNoImage.docx");
});
it("should work with centering", function () {
const d = new DocxGen();
const name = "imageExample.docx";
opts.centered = true;
const imageModule = new ImageModule(opts);
d.attachModule(imageModule);
const out = loadAndRender(d, name, {image: "examples/image.png"});
const zip = out.getZip();
fs.writeFile("test_center.docx", zip.generate({type: "nodebuffer"}));
const imageFile = zip.files["word/media/image_generated_1.png"];
expect(imageFile != null).to.equal(true);
expect(imageFile.asText().length).to.be.within(17417, 17440);
const relsFile = zip.files["word/_rels/document.xml.rels"];
expect(relsFile != null).to.equal(true);
const relsFileContent = relsFile.asText();
expectNormalCharacters(relsFileContent, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/><Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering\" Target=\"numbering.xml\"/><Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\" Target=\"settings.xml\"/><Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes\" Target=\"footnotes.xml\"/><Relationship Id=\"rId5\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes\" Target=\"endnotes.xml\"/><Relationship Id=\"hId0\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header\" Target=\"header0.xml\"/><Relationship Id=\"rId6\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"media/image_generated_1.png\"/></Relationships>");
const documentFile = zip.files["word/document.xml"];
expect(documentFile != null).to.equal(true);
documentFile.asText();
});
it("should work with loops", function () {
const name = "imageLoopExample.docx";
opts.centered = true; this.loadAndRender = function () {
const imageModule = new ImageModule(opts); this.doc = new Docxtemplater();
docX[name].attachModule(imageModule); const inputZip = new JSZip(testutils.docX[this.name].loadedContent);
const out = loadAndRender(docX[name], name, {images: ["examples/image.png", "examples/image2.png"]}); this.doc.loadZip(inputZip).setData(this.data);
const imageModule = new ImageModule(this.opts);
const zip = out.getZip(); this.doc.attachModule(imageModule);
this.renderedDoc = this.doc.render();
const imageFile = zip.files["word/media/image_generated_1.png"]; const doc = this.renderedDoc;
expect(imageFile != null).to.equal(true); shouldBeSame({doc, expectedName: this.expectedName});
expect(imageFile.asText().length).to.be.within(17417, 17440); };
const imageFile2 = zip.files["word/media/image_generated_2.png"];
expect(imageFile2 != null).to.equal(true);
expect(imageFile2.asText().length).to.be.within(7177, 7181);
const relsFile = zip.files["word/_rels/document.xml.rels"];
expect(relsFile != null).to.equal(true);
const relsFileContent = relsFile.asText();
expectNormalCharacters(relsFileContent, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/><Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering\" Target=\"numbering.xml\"/><Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\" Target=\"settings.xml\"/><Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes\" Target=\"footnotes.xml\"/><Relationship Id=\"rId5\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes\" Target=\"endnotes.xml\"/><Relationship Id=\"hId0\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header\" Target=\"header0.xml\"/><Relationship Id=\"rId6\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"media/image_generated_1.png\"/><Relationship Id=\"rId7\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"media/image_generated_2.png\"/></Relationships>");
const documentFile = zip.files["word/document.xml"];
expect(documentFile != null).to.equal(true);
const buffer = zip.generate({type: "nodebuffer"});
fs.writeFile("test_multi.docx", buffer);
});
it("should work with image in header/footer", function () {
const name = "imageHeaderFooterExample.docx";
const imageModule = new ImageModule(opts);
docX[name].attachModule(imageModule);
const out = loadAndRender(docX[name], name, {image: "examples/image.png"});
const zip = out.getZip();
const imageFile = zip.files["word/media/image_generated_1.png"];
expect(imageFile != null).to.equal(true);
expect(imageFile.asText().length).to.be.within(17417, 17440);
const imageFile2 = zip.files["word/media/image_generated_2.png"];
expect(imageFile2 != null).to.equal(true);
expect(imageFile2.asText().length).to.be.within(17417, 17440);
const relsFile = zip.files["word/_rels/document.xml.rels"];
expect(relsFile != null).to.equal(true);
const relsFileContent = relsFile.asText();
expectNormalCharacters(relsFileContent, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/><Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header\" Target=\"header1.xml\"/><Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer\" Target=\"footer1.xml\"/><Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\" Target=\"fontTable.xml\"/><Relationship Id=\"rId5\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\" Target=\"settings.xml\"/></Relationships>");
const headerRelsFile = zip.files["word/_rels/header1.xml.rels"];
expect(headerRelsFile != null).to.equal(true);
const headerRelsFileContent = headerRelsFile.asText();
expectNormalCharacters(headerRelsFileContent, `<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/><Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/><Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image_generated_2.png"/>
</Relationships>`);
const footerRelsFile = zip.files["word/_rels/footer1.xml.rels"];
expect(footerRelsFile != null).to.equal(true);
const footerRelsFileContent = footerRelsFile.asText();
expectNormalCharacters(footerRelsFileContent, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/><Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header\" Target=\"header1.xml\"/><Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer\" Target=\"footer1.xml\"/><Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\" Target=\"fontTable.xml\"/><Relationship Id=\"rId5\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\" Target=\"settings.xml\"/><Relationship Id=\"rId6\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"media/image_generated_1.png\"/></Relationships>");
const documentFile = zip.files["word/document.xml"];
expect(documentFile != null).to.equal(true);
const documentContent = documentFile.asText();
expectNormalCharacters(documentContent, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:document xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\"><w:body><w:p><w:pPr><w:pStyle w:val=\"Normal\"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr></w:r></w:p><w:sectPr><w:headerReference w:type=\"default\" r:id=\"rId2\"/><w:footerReference w:type=\"default\" r:id=\"rId3\"/><w:type w:val=\"nextPage\"/><w:pgSz w:w=\"12240\" w:h=\"15840\"/><w:pgMar w:left=\"1800\" w:right=\"1800\" w:header=\"720\" w:top=\"2810\" w:footer=\"1440\" w:bottom=\"2003\" w:gutter=\"0\"/><w:pgNumType w:fmt=\"decimal\"/><w:formProt w:val=\"false\"/><w:textDirection w:val=\"lrTb\"/><w:docGrid w:type=\"default\" w:linePitch=\"249\" w:charSpace=\"2047\"/></w:sectPr></w:body></w:document>");
fs.writeFile("test_header_footer.docx", zip.generate({type: "nodebuffer"}));
});
}); });
describe("qrcode replacing", function () { function testStart() {
describe("shoud work without loops", function () { // TODO test in browser
it("should work with simple", function (done) { describe("{%image}", function () {
const name = "qrExample.docx"; it("should work with one image", function () {
opts.qrCode = true; this.name = "imageExample.docx";
const imageModule = new ImageModule(opts); this.expectedName = "expectedOneImage.docx";
this.data = {image: "examples/image.png"};
imageModule.finished = function () { this.loadAndRender();
const zip = docX[name].getZip();
const buffer = zip.generate({type: "nodebuffer"});
fs.writeFileSync("test_qr.docx", buffer);
const images = zip.file(/media\/.*.png/);
expect(images.length).to.equal(2);
expect(images[0].asText().length).to.equal(826);
expect(images[1].asText().length).to.be.within(17417, 17440);
done();
};
docX[name].attachModule(imageModule);
loadAndRender(docX[name], name, {image: "examples/image"});
}); });
});
describe("should work with two", function () {
it("should work", function (done) {
const name = "qrExample2.docx";
opts.qrCode = true;
const imageModule = new ImageModule(opts);
imageModule.finished = function () { it("should work without initial rels", function () {
const zip = docX[name].getZip(); this.name = "withoutRels.docx";
const buffer = zip.generate({type: "nodebuffer"}); this.expectedName = "expectedWithoutRels.docx";
fs.writeFileSync("test_qr3.docx", buffer); this.data = {image: "examples/image.png"};
const images = zip.file(/media\/.*.png/); this.loadAndRender();
expect(images.length).to.equal(4);
expect(images[0].asText().length).to.equal(859);
expect(images[1].asText().length).to.equal(826);
expect(images[2].asText().length).to.be.within(17417, 17440);
expect(images[3].asText().length).to.be.within(7177, 7181);
done();
};
docX[name].attachModule(imageModule);
loadAndRender(docX[name], name, {image: "examples/image", image2: "examples/image2.png"});
}); });
});
describe("should work qr in headers without extra images", function () { it("should work with image tag == null", function () {
it("should work in a header too", function (done) { this.name = "imageExample.docx";
const name = "qrHeaderNoImage.docx"; this.expectedName = "expectedNoImage.docx";
opts.qrCode = true; this.data = {};
const imageModule = new ImageModule(opts); this.loadAndRender();
imageModule.finished = function () {
const zip = docX[name].getZip();
const buffer = zip.generate({type: "nodebuffer"});
fs.writeFile("test_qr_header_no_image.docx", buffer);
const images = zip.file(/media\/.*.png/);
expect(images.length).to.equal(3);
expect(images[0].asText().length).to.equal(826);
expect(images[1].asText().length).to.be.within(12888, 12900);
expect(images[2].asText().length).to.be.within(17417, 17440);
done();
};
docX[name].attachModule(imageModule);
loadAndRender(docX[name], name, {image: "examples/image", image2: "examples/image2.png"});
}); });
});
describe("should work qr in headers with extra images", function () {
it("should work in a header too", function (done) {
const name = "qrHeader.docx";
opts.qrCode = true; it("should work with centering", function () {
const imageModule = new ImageModule(opts); this.name = "imageExample.docx";
this.expectedName = "expectedCentered.docx";
imageModule.finished = function () { this.opts.centered = true;
const zip = docX[name].getZip(); this.data = {image: "examples/image.png"};
const buffer = zip.generate({type: "nodebuffer"}); this.loadAndRender();
fs.writeFile("test_qr_header.docx", buffer);
const images = zip.file(/media\/.*.png/);
expect(images.length).to.equal(3);
expect(images[0].asText().length).to.equal(826);
expect(images[1].asText().length).to.be.within(12888, 12900);
expect(images[2].asText().length).to.be.within(17417, 17440);
done();
};
docX[name].attachModule(imageModule);
loadAndRender(docX[name], name, {image: "examples/image", image2: "examples/image2.png"});
}); });
});
describe("should work with image after loop", function () {
it("should work with image after loop", function (done) {
const name = "imageAfterLoop.docx";
opts.qrCode = true; it("should work with loops", function () {
const imageModule = new ImageModule(opts); this.name = "imageLoopExample.docx";
this.expectedName = "expectedLoopCentered.docx";
imageModule.finished = function () { this.opts.centered = true;
const zip = docX[name].getZip(); this.data = {images: ["examples/image.png", "examples/image2.png"]};
const buffer = zip.generate({type: "nodebuffer"}); this.loadAndRender();
fs.writeFile("test_image_after_loop.docx", buffer); });
const images = zip.file(/media\/.*.png/);
expect(images.length).to.equal(2);
expect(images[0].asText().length).to.be.within(7177, 7181);
expect(images[1].asText().length).to.be.within(7177, 7181);
done();
};
docX[name].attachModule(imageModule); it("should work with image in header/footer", function () {
loadAndRender(docX[name], name, {image: "examples/image2.png", above: [{cell1: "foo", cell2: "bar"}], below: "foo"}); this.name = "imageHeaderFooterExample.docx";
this.expectedName = "expectedHeaderFooter.docx";
this.data = {image: "examples/image.png"};
this.loadAndRender();
}); });
}); });
}
testutils.setExamplesDirectory(path.resolve(__dirname, "..", "examples"));
testutils.setStartFunction(testStart);
fileNames.forEach(function (filename) {
testutils.loadFile(filename, testutils.loadDocx);
}); });
testutils.start();
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