aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2015-09-07 20:04:58 +0100
committerMichael Williamson <mike@zwobble.org>2015-09-07 20:04:58 +0100
commite5e37a6f2cfa04e146d534028fbf291aac2a9fe2 (patch)
tree82f731589d4534b51b2dd1caf4b51848c0468eb1
parent97144ee9f557ef4886456972d36583b6b62685d2 (diff)
Add support for external images
-rw-r--r--lib/docx/body-reader.js15
-rw-r--r--lib/docx/docx-reader.js12
-rw-r--r--lib/index.js2
-rw-r--r--tests/docx/body-reader.tests.js42
-rw-r--r--tests/mammoth.tests.js8
-rw-r--r--tests/test-data/external-picture.docxbin0 -> 4120 bytes
-rw-r--r--tests/testing.js28
7 files changed, 88 insertions, 19 deletions
diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js
index 25a263a..4126fde 100644
--- a/lib/docx/body-reader.js
+++ b/lib/docx/body-reader.js
@@ -11,6 +11,7 @@ function BodyReader(options) {
var relationships = options.relationships;
var contentTypes = options.contentTypes;
var docxFile = options.docxFile;
+ var files = options.files;
var numbering = options.numbering;
var styles = options.styles;
@@ -216,9 +217,17 @@ function BodyReader(options) {
}
function readBlip(element, blip) {
- var relationshipId = blip.attributes["r:embed"];
- var imagePath = joinZipPath("word", relationships[relationshipId].target);
- var readImage = docxFile.read.bind(docxFile, imagePath);
+ var embedRelationshipId = blip.attributes["r:embed"];
+ var linkRelationshipid = blip.attributes["r:link"];
+ var imagePath;
+ var readImage;
+ if (embedRelationshipId) {
+ imagePath = joinZipPath("word", relationships[embedRelationshipId].target);
+ readImage = docxFile.read.bind(docxFile, imagePath);
+ } else {
+ imagePath = relationships[linkRelationshipid].target;
+ readImage = files.read.bind(files, imagePath);
+ }
var altText = element.first("wp:docPr").attributes.descr;
var contentType = contentTypes.findContentType(imagePath);
diff --git a/lib/docx/docx-reader.js b/lib/docx/docx-reader.js
index 9b1ec9a..8627022 100644
--- a/lib/docx/docx-reader.js
+++ b/lib/docx/docx-reader.js
@@ -1,5 +1,7 @@
exports.read = read;
+var path = require("path");
+
var promises = require("../promises");
var documents = require("../documents");
var Result = require("../results").Result;
@@ -12,14 +14,17 @@ var contentTypesReader = require("./content-types-reader");
var numberingXml = require("./numbering-xml");
var stylesReader = require("./styles-reader");
var notesReader = require("./notes-reader");
+var Files = require("./files").Files;
-function read(docxFile) {
+function read(docxFile, input) {
+ input = input || {};
return promises.props({
contentTypes: readContentTypesFromZipFile(docxFile),
numbering: readNumberingFromZipFile(docxFile),
styles: readStylesFromZipFile(docxFile),
- docxFile: docxFile
+ docxFile: docxFile,
+ files: new Files(input.path ? path.dirname(input.path) : null)
}).also(function(result) {
return {
footnotes: readXmlFileWithBody("footnotes", result, function(bodyReader, xml) {
@@ -80,7 +85,8 @@ function readXmlFileWithBody(name, options, func) {
contentTypes: options.contentTypes,
docxFile: options.docxFile,
numbering: options.numbering,
- styles: options.styles
+ styles: options.styles,
+ files: options.files
});
return readXmlFromZipFile(options.docxFile, "word/" + name + ".xml")
.then(function(xml) {
diff --git a/lib/index.js b/lib/index.js
index 5613312..69ab111 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -39,7 +39,7 @@ function convert(input, options) {
})
.then(function(docxFile) {
var fullOptions = readOptions(options);
- return docxReader.read(docxFile)
+ return docxReader.read(docxFile, input)
.then(function(documentResult) {
return documentResult.map(fullOptions.transformDocument);
})
diff --git a/tests/docx/body-reader.tests.js b/tests/docx/body-reader.tests.js
index ad2caa2..2e85d76 100644
--- a/tests/docx/body-reader.tests.js
+++ b/tests/docx/body-reader.tests.js
@@ -286,7 +286,7 @@ describe("readXmlElement: ", function() {
test("can read inline pictures", function() {
var drawing = createInlineImage({
- relationshipId: "rId5",
+ blip: createEmbeddedBlip("rId5"),
description: "It's a hat"
});
@@ -349,9 +349,37 @@ describe("readXmlElement: ", function() {
});
});
+ test("can read linked pictures", function() {
+ var drawing = createInlineImage({
+ blip: createLinkedBlip("rId5"),
+ description: "It's a hat"
+ });
+
+ var imageBuffer = new Buffer("Not an image at all!");
+ var reader = new BodyReader({
+ relationships: {
+ "rId5": {target: "file:///media/hat.png"}
+ },
+ contentTypes: fakeContentTypes,
+ files: testing.createFakeFiles({
+ "file:///media/hat.png": imageBuffer
+ })
+ });
+ var result = reader.readXmlElement(drawing);
+ assert.deepEqual(result.messages, []);
+ var element = single(result.value);
+ assert.equal("image", element.type);
+ assert.equal(element.altText, "It's a hat");
+ assert.equal(element.contentType, "image/png");
+ return element.read()
+ .then(function(readValue) {
+ assert.equal(readValue, imageBuffer);
+ });
+ });
+
test("warning if unsupported image type", function() {
var drawing = createInlineImage({
- relationshipId: "rId5",
+ blip: createEmbeddedBlip("rId5"),
description: "It's a hat"
});
@@ -514,7 +542,7 @@ function createInlineImage(options) {
new XmlElement("a:graphicData", {}, [
new XmlElement("pic:pic", {}, [
new XmlElement("pic:blipFill", {}, [
- new XmlElement("a:blip", {"r:embed": options.relationshipId})
+ options.blip
])
])
])
@@ -522,3 +550,11 @@ function createInlineImage(options) {
])
]);
}
+
+function createEmbeddedBlip(relationshipId) {
+ return new XmlElement("a:blip", {"r:embed": relationshipId});
+}
+
+function createLinkedBlip(relationshipId) {
+ return new XmlElement("a:blip", {"r:link": relationshipId});
+}
diff --git a/tests/mammoth.tests.js b/tests/mammoth.tests.js
index b7f4766..bb3dca2 100644
--- a/tests/mammoth.tests.js
+++ b/tests/mammoth.tests.js
@@ -184,6 +184,14 @@ describe('mammoth', function() {
});
});
+ test('images stored outside of document are included in output', function() {
+ var docxPath = path.join(__dirname, "test-data/external-picture.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, '<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAOvgAADr4B6kKxwAAAABNJREFUKFNj/M+ADzDhlWUYqdIAQSwBE8U+X40AAAAASUVORK5CYII=" /></p>');
+ assert.deepEqual([], result.messages);
+ });
+ });
+
test('simple list is converted to list elements', function() {
var docxPath = path.join(__dirname, "test-data/simple-list.docx");
return mammoth.convertToHtml({path: docxPath}).then(function(result) {
diff --git a/tests/test-data/external-picture.docx b/tests/test-data/external-picture.docx
new file mode 100644
index 0000000..3475626
--- /dev/null
+++ b/tests/test-data/external-picture.docx
Binary files differ
diff --git a/tests/testing.js b/tests/testing.js
index b8757c9..d70f86e 100644
--- a/tests/testing.js
+++ b/tests/testing.js
@@ -7,6 +7,7 @@ exports.test = test;
exports.testPath = testPath;
exports.testData = testData;
exports.createFakeDocxFile = createFakeDocxFile;
+exports.createFakeFiles = createFakeFiles;
function test(name, func) {
@@ -28,6 +29,23 @@ function testData(testDataPath) {
}
function createFakeDocxFile(files) {
+ function exists(path) {
+ return !!files[path];
+ }
+
+ return {
+ read: createRead(files),
+ exists: exists
+ };
+}
+
+function createFakeFiles(files) {
+ return {
+ read: createRead(files)
+ };
+}
+
+function createRead(files) {
function read(path, encoding) {
return promises.when(files[path], function(buffer) {
if (_.isString(buffer)) {
@@ -43,13 +61,5 @@ function createFakeDocxFile(files) {
}
});
}
-
- function exists(path) {
- return !!files[path];
- }
-
- return {
- read: read,
- exists: exists
- };
+ return read;
}