Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
docxtemplater-image-module
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
npm
docxtemplater-image-module
Commits
2a0c660c
Commit
2a0c660c
authored
Nov 26, 2016
by
Edgar HIPP
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update algorithm
parent
b868beeb
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
268 additions
and
876 deletions
+268
-876
es6/base64.js
+0
-33
es6/docUtils.js
+1
-61
es6/docxQrCode.js
+0
-45
es6/imgManager.js
+50
-94
es6/imgReplacer.js
+0
-117
es6/index.js
+145
-195
es6/test.js
+72
-331
No files found.
es6/base64.js
deleted
100644 → 0
View file @
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
;
};
es6/docUtils.js
View file @
2a0c660c
"use strict"
;
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
;
};
const
DocUtils
=
require
(
"docxtemplater"
).
DocUtils
;
module
.
exports
=
DocUtils
;
es6/docxQrCode.js
deleted
100644 → 0
View file @
b868beeb
"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
);
}
};
es6/imgManager.js
View file @
2a0c660c
"use strict"
;
const
DocUtils
=
require
(
"./docUtils"
);
const
imageExtensions
=
[
"gif"
,
"jpeg"
,
"jpg"
,
"emf"
,
"png"
];
const
imageListRegex
=
/
[^
.
]
+
\.([^
.
]
+
)
/
;
const
extensionRegex
=
/
[^
.
]
+
\.([^
.
]
+
)
/
;
module
.
exports
=
class
ImgManager
{
constructor
(
zip
,
fileName
)
{
constructor
(
zip
,
fileName
,
xmlDocuments
)
{
this
.
zip
=
zip
;
this
.
fileName
=
fileName
;
this
.
endFileName
=
this
.
fileName
.
replace
(
/^.*
?([
a-z0-9
]
+
)\.
xml$/
,
"$1"
);
}
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
;
this
.
xmlDocuments
=
xmlDocuments
;
const
relsFileName
=
this
.
getRelsFile
(
fileName
);
this
.
relsDoc
=
xmlDocuments
[
relsFileName
]
||
this
.
createEmptyRelsDoc
(
xmlDocuments
,
relsFileName
);
}
setImage
(
fileName
,
data
,
options
)
{
options
=
options
||
{};
this
.
zip
.
remove
(
fileName
);
return
this
.
zip
.
file
(
fileName
,
data
,
options
);
getRelsFile
(
fileName
)
{
let
fileParts
=
fileName
.
split
(
"/"
);
fileParts
[
fileParts
.
length
-
1
]
=
fileParts
[
fileParts
.
length
-
1
]
+
".rels"
;
fileParts
=
[
fileParts
[
0
],
"_rels"
].
concat
(
fileParts
.
slice
(
1
));
return
fileParts
.
join
(
"/"
);
}
hasImage
(
fileName
)
{
return
this
.
zip
.
files
[
fileName
]
!=
null
;
createEmptyRelsDoc
(
xmlDocuments
,
relsFileName
)
{
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
()
{
const
file
=
this
.
zip
.
files
[
`word/_rels/
${
this
.
endFileName
}
.xml.rels`
]
||
this
.
zip
.
files
[
"word/_rels/document.xml.rels"
];
if
(
file
==
null
)
{
return
;
}
const
content
=
DocUtils
.
decodeUtf8
(
file
.
asText
());
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"
);
const
iterable
=
this
.
relsDoc
.
getElementsByTagName
(
"Relationship"
);
return
Array
.
prototype
.
reduce
.
call
(
iterable
,
function
(
max
,
relationship
)
{
const
id
=
relationship
.
getAttribute
(
"Id"
);
if
(
/^rId
[
0-9
]
+$/
.
test
(
id
))
{
RidArray
.
push
(
parseInt
(
id
.
substr
(
3
),
10
));
return
Math
.
max
(
max
,
parseInt
(
id
.
substr
(
3
),
10
));
}
}
this
.
maxRid
=
DocUtils
.
maxArray
(
RidArray
);
this
.
imageRels
=
[];
return
this
;
return
max
;
},
0
);
}
// 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
)
{
const
content
=
this
.
zip
.
files
[
"[Content_Types].xml"
].
asText
();
const
xmlDoc
=
DocUtils
.
str2xml
(
content
);
let
addTag
=
true
;
const
defaultTags
=
xmlDoc
.
getElementsByTagName
(
"Default"
);
for
(
let
i
=
0
,
tag
;
i
<
defaultTags
.
length
;
i
++
)
{
tag
=
defaultTags
[
i
];
if
(
tag
.
getAttribute
(
"Extension"
)
===
extension
)
{
addTag
=
false
;
}
}
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
contentTypeDoc
=
this
.
xmlDocuments
[
"[Content_Types].xml"
];
const
defaultTags
=
contentTypeDoc
.
getElementsByTagName
(
"Default"
);
const
extensionRegistered
=
Array
.
prototype
.
some
.
call
(
defaultTags
,
function
(
tag
)
{
return
tag
.
getAttribute
(
"Extension"
)
===
extension
;
});
if
(
extensionRegistered
)
{
return
;
}
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
);
}
// Add
ing
an image and returns it's Rid
// Add an image and returns it's Rid
addImageRels
(
imageName
,
imageData
,
i
)
{
if
(
i
==
null
)
{
i
=
0
;
}
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
);
}
this
.
maxRid
++
;
const
file
=
{
const
image
=
{
name
:
`word/media/
${
realImageName
}
`
,
data
:
imageData
,
options
:
{
base64
:
false
,
binary
:
true
,
compression
:
null
,
date
:
new
Date
(),
dir
:
false
,
},
};
this
.
zip
.
file
(
file
.
name
,
file
.
data
,
fil
e
.
options
);
const
extension
=
realImageName
.
replace
(
/
[^
.
]
+
\.([^
.
]
+
)
/
,
"$1"
);
this
.
zip
.
file
(
image
.
name
,
image
.
data
,
imag
e
.
options
);
const
extension
=
realImageName
.
replace
(
extensionRegex
,
"$1"
);
this
.
addExtensionRels
(
`image/
${
extension
}
`
,
extension
);
const
relationships
=
this
.
xml
Doc
.
getElementsByTagName
(
"Relationships"
)[
0
];
const
newTag
=
this
.
xml
Doc
.
createElement
(
"Relationship"
);
const
relationships
=
this
.
rels
Doc
.
getElementsByTagName
(
"Relationships"
)[
0
];
const
newTag
=
this
.
rels
Doc
.
createElement
(
"Relationship"
);
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
(
"Target"
,
`media/
${
realImageName
}
`
);
relationships
.
appendChild
(
newTag
);
this
.
setImage
(
`word/_rels/
${
this
.
endFileName
}
.xml.rels`
,
DocUtils
.
encodeUtf8
(
DocUtils
.
xml2Str
(
this
.
xmlDoc
)));
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"
);
return
maxRid
;
}
};
es6/imgReplacer.js
deleted
100644 → 0
View file @
b868beeb
"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
);
}
};
es6/index.js
View file @
2a0c660c
"use strict"
;
const
isNaN
=
function
(
number
)
{
const
DocUtils
=
require
(
"docxtemplater"
).
DocUtils
;
function
isNaN
(
number
)
{
return
!
(
number
===
number
);
}
;
}
const
SubContent
=
require
(
"docxtemplater"
).
SubContent
;
const
ImgManager
=
require
(
"./imgManager"
);
const
ImgReplacer
=
require
(
"./imgReplacer"
);
const
moduleName
=
"open-xml-templating/docxtemplater-image-module"
;
function
getInner
({
part
})
{
return
part
;
}
class
ImageModule
{
constructor
(
options
)
{
...
...
@@ -17,230 +21,176 @@ class ImageModule {
this
.
qrQueue
=
[];
this
.
imageNumber
=
1
;
}
handleEvent
(
event
,
eventData
)
{
if
(
event
===
"rendering-file"
)
{
this
.
renderingFileName
=
eventData
;
const
gen
=
this
.
manager
.
getInstance
(
"gen"
);
this
.
imgManager
=
new
ImgManager
(
gen
.
zip
,
this
.
renderingFileName
);
this
.
imgManager
.
loadImageRels
();
optionsTransformer
(
options
,
docxtemplater
)
{
const
relsFiles
=
docxtemplater
.
zip
.
file
(
/
\.
xml
\.
rels/
)
.
concat
(
docxtemplater
.
zip
.
file
(
/
\[
Content_Types
\]
.xml/
))
.
map
((
file
)
=>
file
.
name
);
this
.
fileTypeConfig
=
docxtemplater
.
fileTypeConfig
;
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
(
this
.
qrQueue
.
length
===
0
)
{
return
this
.
finished
();
}
if
(
options
.
xmlDocuments
)
{
this
.
xmlDocuments
=
options
.
xmlDocuments
;
}
}
get
(
data
)
{
if
(
data
===
"loopType"
)
{
const
templaterState
=
this
.
manager
.
getInstance
(
"templaterState"
);
if
(
templaterState
.
textInsideTag
[
0
]
===
"%"
)
{
return
"image"
;
}
parse
(
placeHolderContent
)
{
const
module
=
moduleName
;
const
type
=
"placeholder"
;
if
(
placeHolderContent
[
0
]
===
"%"
)
{
return
{
type
,
value
:
placeHolderContent
.
substr
(
1
),
module
};
}
return
null
;
}
getNextImageName
()
{
const
name
=
`image_generated_
${
this
.
imageNumber
}
.png`
;
this
.
imageNumber
++
;
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
);
postparse
(
parsed
)
{
const
expandTo
=
this
.
options
.
centered
?
"w:p"
:
"w:t"
;
return
DocUtils
.
traits
.
expandToOne
(
parsed
,
{
moduleName
,
getInner
,
expandTo
});
}
convertPixelsToEmus
(
pixel
)
{
return
Math
.
round
(
pixel
*
9525
);
}
replaceTag
()
{
const
scopeManager
=
this
.
manager
.
getInstance
(
"scopeManager"
);
const
templaterState
=
this
.
manager
.
getInstance
(
"templaterState"
);
const
xmlTemplater
=
this
.
manager
.
getInstance
(
"xmlTemplater"
);
const
tagXml
=
xmlTemplater
.
fileTypeConfig
.
tagsXmlArray
[
0
];
const
tagXmlParagraph
=
tagXml
.
substr
(
0
,
1
)
+
":p"
;
render
(
part
,
options
)
{
this
.
imgManager
=
new
ImgManager
(
this
.
zip
,
options
.
filePath
,
this
.
xmlDocuments
);
if
(
!
part
.
type
===
"placeholder"
||
part
.
module
!==
moduleName
)
{
return
null
;
}
const
tagValue
=
options
.
scopeManager
.
getValue
(
part
.
value
);
const
tag
=
templaterState
.
textInsideTag
.
substr
(
1
);
const
tagValue
=
scopeManager
.
getValue
(
tag
);
const
startEnd
=
`<
${
tagXml
}
></
${
tagXml
}
>`
;
const
outsideElement
=
this
.
options
.
centered
?
tagXmlParagraph
:
tagXml
;
const
tagXml
=
this
.
fileTypeConfig
.
tagTextXml
;
if
(
tagValue
==
null
)
{
return
this
.
replaceBy
(
startEnd
,
tagXml
)
;
return
{
value
:
tagXml
}
;
}
let
imgBuffer
;
try
{
imgBuffer
=
this
.
options
.
getImage
(
tagValue
,
tag
);
imgBuffer
=
this
.
options
.
getImage
(
tagValue
,
part
.
value
);
}
catch
(
e
)
{
return
this
.
replaceBy
(
startEnd
,
tagXml
)
;
return
{
value
:
tagXml
}
;
}
const
imageRels
=
this
.
imgManager
.
loadImageRels
();
if
(
!
imageRels
)
{
return
;
}
const
rId
=
imageRels
.
addImageRels
(
this
.
getNextImageName
(),
imgBuffer
);
const
sizePixel
=
this
.
options
.
getSize
(
imgBuffer
,
tagValue
,
tag
);
const
rId
=
this
.
imgManager
.
addImageRels
(
this
.
getNextImageName
(),
imgBuffer
);
const
sizePixel
=
this
.
options
.
getSize
(
imgBuffer
,
tagValue
,
part
.
value
);
const
size
=
[
this
.
convertPixelsToEmus
(
sizePixel
[
0
]),
this
.
convertPixelsToEmus
(
sizePixel
[
1
])];
const
newText
=
this
.
options
.
centered
?
this
.
getImageXmlCentered
(
rId
,
size
)
:
this
.
getImageXml
(
rId
,
size
);
return
this
.
replaceBy
(
newText
,
outsideElement
)
;
return
{
value
:
newText
}
;
}
replaceQr
()
{
const
xmlTemplater
=
this
.
manager
.
getInstance
(
"xmlTemplater"
);
const
imR
=
new
ImgReplacer
(
xmlTemplater
,
this
.
imgManager
);
imR
.
getDataFromString
=
(
result
,
cb
)
=>
{
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
;
}
getNextImageName
()
{
const
name
=
`image_generated_
${
this
.
imageNumber
}
.png`
;
this
.
imageNumber
++
;
return
name
;
}
handle
(
type
,
data
)
{
if
(
type
===
"replaceTag"
&&
data
===
"image"
)
{
this
.
replaceTag
();
}
if
(
type
===
"xmlRendered"
&&
this
.
options
.
qrCode
)
{
this
.
replaceQr
();
}
return
null
;
convertPixelsToEmus
(
pixel
)
{
return
Math
.
round
(
pixel
*
9525
);
}
getImageXml
(
rId
,
size
)
{
if
(
isNaN
(
rId
))
{
throw
new
Error
(
"rId is NaN, aborting"
);
}
return
`<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="
${
size
[
0
]}
" cy="
${
size
[
1
]}
"/>
<wp:effectExtent l="0" t="0" r="0" b="0"/>
<wp:docPr id="2" name="Image 2" descr="image"/>
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="Picture 1" descr="image"/>
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rId
${
rId
}
">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
</a:ext>
</a:extLst>
</a:blip>
<a:srcRect/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="
${
size
[
0
]}
" cy="
${
size
[
1
]}
"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
<a:noFill/>
<a:ln>
<a:noFill/>
</a:ln>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
`
;
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="
${
size
[
0
]}
" cy="
${
size
[
1
]}
"/>
<wp:effectExtent l="0" t="0" r="0" b="0"/>
<wp:docPr id="2" name="Image 2" descr="image"/>
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="Picture 1" descr="image"/>
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rId
${
rId
}
">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
</a:ext>
</a:extLst>
</a:blip>
<a:srcRect/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="
${
size
[
0
]}
" cy="
${
size
[
1
]}
"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
<a:noFill/>
<a:ln>
<a:noFill/>
</a:ln>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
`
.
replace
(
/
\t
|
\n
/g
,
""
)
;
}
getImageXmlCentered
(
rId
,
size
)
{
if
(
isNaN
(
rId
))
{
throw
new
Error
(
"rId is NaN, aborting"
);
}
return
`
<w:p>
<w:pPr>
<w:jc w:val="center"/>
</w:pPr>
<w:r>
<w:rPr/>
<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="
${
size
[
0
]}
" cy="
${
size
[
1
]}
"/>
<wp:docPr id="0" name="Picture" descr=""/>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="Picture" descr=""/>
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rId
${
rId
}
"/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="
${
size
[
0
]}
" cy="
${
size
[
1
]}
"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
<a:noFill/>
<a:ln w="9525">
<a:noFill/>
<a:miter lim="800000"/>
<a:headEnd/>
<a:tailEnd/>
</a:ln>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</w:r>
return
`<w:p>
<w:pPr>
<w:jc w:val="center"/>
</w:pPr>
<w:r>
<w:rPr/>
<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="
${
size
[
0
]}
" cy="
${
size
[
1
]}
"/>
<wp:docPr id="0" name="Picture" descr=""/>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="Picture" descr=""/>
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rId
${
rId
}
"/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="
${
size
[
0
]}
" cy="
${
size
[
1
]}
"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
<a:noFill/>
<a:ln w="9525">
<a:noFill/>
<a:miter lim="800000"/>
<a:headEnd/>
<a:tailEnd/>
</a:ln>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</w:r>
</w:p>
`
;
`
.
replace
(
/
\t
|
\n
/g
,
""
)
;
}
}
...
...
es6/test.js
View file @
2a0c660c
"use strict"
;
/* eslint-disable no-console */
const
fs
=
require
(
"fs"
);
const
DocxGen
=
require
(
"docxtemplater"
);
const
expect
=
require
(
"chai"
).
expect
;
const
Docxtemplater
=
require
(
"docxtemplater"
);
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
=
[
"imageAfterLoop.docx"
,
"imageExample.docx"
,
"imageHeaderFooterExample.docx"
,
"imageInlineExample.docx"
,
"imageLoopExample.docx"
,
"noImage.docx"
,
"qrExample.docx"
,
"qrExample2.docx"
,
"qrHeader.docx"
,
"qrHeaderNoImage.docx"
,
"expectedNoImage.docx"
,
"expectedHeaderFooter.docx"
,
"expectedOneImage.docx"
,
"expectedCentered.docx"
,
"expectedLoopCentered.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
()
{
opts
=
{};
opts
.
getImage
=
function
(
tagValue
)
{
return
fs
.
readFileSync
(
tagValue
,
"binary"
);
};
opts
.
getSize
=
function
()
{
return
[
150
,
150
];
this
.
opts
=
{
getImage
:
function
(
tagValue
)
{
return
fs
.
readFileSync
(
tagValue
,
"binary"
);
},
getSize
:
function
()
{
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
;
const
imageModule
=
new
ImageModule
(
opts
);
docX
[
name
].
attachModule
(
imageModule
);
const
out
=
loadAndRender
(
docX
[
name
],
name
,
{
images
:
[
"examples/image.png"
,
"examples/image2.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
(
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"
}));
});
this
.
loadAndRender
=
function
()
{
this
.
doc
=
new
Docxtemplater
();
const
inputZip
=
new
JSZip
(
testutils
.
docX
[
this
.
name
].
loadedContent
);
this
.
doc
.
loadZip
(
inputZip
).
setData
(
this
.
data
);
const
imageModule
=
new
ImageModule
(
this
.
opts
);
this
.
doc
.
attachModule
(
imageModule
);
this
.
renderedDoc
=
this
.
doc
.
render
();
const
doc
=
this
.
renderedDoc
;
shouldBeSame
({
doc
,
expectedName
:
this
.
expectedName
});
};
});
describe
(
"qrcode replacing"
,
function
()
{
describe
(
"shoud work without loops"
,
function
()
{
it
(
"should work with simple"
,
function
(
done
)
{
const
name
=
"qrExample.docx"
;
opts
.
qrCode
=
true
;
const
imageModule
=
new
ImageModule
(
opts
);
imageModule
.
finished
=
function
()
{
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"
});
function
testStart
()
{
// TODO test in browser
describe
(
"{%image}"
,
function
()
{
it
(
"should work with one image"
,
function
()
{
this
.
name
=
"imageExample.docx"
;
this
.
expectedName
=
"expectedOneImage.docx"
;
this
.
data
=
{
image
:
"examples/image.png"
};
this
.
loadAndRender
();
});
});
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
()
{
const
zip
=
docX
[
name
].
getZip
();
const
buffer
=
zip
.
generate
({
type
:
"nodebuffer"
});
fs
.
writeFileSync
(
"test_qr3.docx"
,
buffer
);
const
images
=
zip
.
file
(
/media
\/
.*.png/
);
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"
});
it
(
"should work without initial rels"
,
function
()
{
this
.
name
=
"withoutRels.docx"
;
this
.
expectedName
=
"expectedWithoutRels.docx"
;
this
.
data
=
{
image
:
"examples/image.png"
};
this
.
loadAndRender
();
});
});
describe
(
"should work qr in headers without extra images"
,
function
()
{
it
(
"should work in a header too"
,
function
(
done
)
{
const
name
=
"qrHeaderNoImage.docx"
;
opts
.
qrCode
=
true
;
const
imageModule
=
new
ImageModule
(
opts
);
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"
});
it
(
"should work with image tag == null"
,
function
()
{
this
.
name
=
"imageExample.docx"
;
this
.
expectedName
=
"expectedNoImage.docx"
;
this
.
data
=
{};
this
.
loadAndRender
();
});
});
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
;
const
imageModule
=
new
ImageModule
(
opts
);
imageModule
.
finished
=
function
()
{
const
zip
=
docX
[
name
].
getZip
();
const
buffer
=
zip
.
generate
({
type
:
"nodebuffer"
});
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"
});
it
(
"should work with centering"
,
function
()
{
this
.
name
=
"imageExample.docx"
;
this
.
expectedName
=
"expectedCentered.docx"
;
this
.
opts
.
centered
=
true
;
this
.
data
=
{
image
:
"examples/image.png"
};
this
.
loadAndRender
();
});
});
describe
(
"should work with image after loop"
,
function
()
{
it
(
"should work with image after loop"
,
function
(
done
)
{
const
name
=
"imageAfterLoop.docx"
;
opts
.
qrCode
=
true
;
const
imageModule
=
new
ImageModule
(
opts
);
imageModule
.
finished
=
function
()
{
const
zip
=
docX
[
name
].
getZip
();
const
buffer
=
zip
.
generate
({
type
:
"nodebuffer"
});
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
();
};
it
(
"should work with loops"
,
function
()
{
this
.
name
=
"imageLoopExample.docx"
;
this
.
expectedName
=
"expectedLoopCentered.docx"
;
this
.
opts
.
centered
=
true
;
this
.
data
=
{
images
:
[
"examples/image.png"
,
"examples/image2.png"
]};
this
.
loadAndRender
();
});
docX
[
name
].
attachModule
(
imageModule
);
loadAndRender
(
docX
[
name
],
name
,
{
image
:
"examples/image2.png"
,
above
:
[{
cell1
:
"foo"
,
cell2
:
"bar"
}],
below
:
"foo"
});
it
(
"should work with image in header/footer"
,
function
()
{
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
();
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment