aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-02-13 23:32:26 +0000
committerMichael Williamson <mike@zwobble.org>2016-02-13 23:32:26 +0000
commitc46ec78de9524a7b7df0b475b1447a83b4f857fe (patch)
treec98c58f6d4aa8cde8824bbfe3b73131143f1d3cc /src
parent6dd319ca5eebe1f97b9558b5b45bbccf402eb319 (diff)
Read linked blips
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/mammoth/Mammoth.java10
-rw-r--r--src/main/java/org/zwobble/mammoth/docx/BodyXmlReader.java21
-rw-r--r--src/main/java/org/zwobble/mammoth/docx/FileReader.java8
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlReaderMakers.java7
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java25
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/InMemoryFileReader.java24
6 files changed, 88 insertions, 7 deletions
diff --git a/src/main/java/org/zwobble/mammoth/Mammoth.java b/src/main/java/org/zwobble/mammoth/Mammoth.java
index 0651944..63a313f 100644
--- a/src/main/java/org/zwobble/mammoth/Mammoth.java
+++ b/src/main/java/org/zwobble/mammoth/Mammoth.java
@@ -8,6 +8,7 @@ import org.zwobble.mammoth.xml.XmlElement;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.util.zip.ZipFile;
import static com.google.common.collect.Iterables.transform;
@@ -21,12 +22,19 @@ public class Mammoth {
Numbering numbering = Numbering.EMPTY;
Relationships relationships = Relationships.EMPTY;
ContentTypes contentTypes = ContentTypes.DEFAULT;
+ FileReader fileReader = new FileReader() {
+ @Override
+ public InputStream getInputStream(String uri) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ };
DocumentXmlReader reader = new DocumentXmlReader(new BodyXmlReader(
styles,
numbering,
relationships,
contentTypes,
- zipFile));
+ zipFile,
+ fileReader));
return reader.readElement(documentXml)
.map(Mammoth::convertToHtml);
} catch (IOException e) {
diff --git a/src/main/java/org/zwobble/mammoth/docx/BodyXmlReader.java b/src/main/java/org/zwobble/mammoth/docx/BodyXmlReader.java
index e911a63..0d49809 100644
--- a/src/main/java/org/zwobble/mammoth/docx/BodyXmlReader.java
+++ b/src/main/java/org/zwobble/mammoth/docx/BodyXmlReader.java
@@ -27,25 +27,27 @@ public class BodyXmlReader {
private static final Set<String> IMAGE_TYPES_SUPPORTED_BY_BROWSERS = ImmutableSet.of(
"image/png", "image/gif", "image/jpeg", "image/svg+xml", "image/tiff");
-
private final Styles styles;
private final Numbering numbering;
private final Relationships relationships;
private final ContentTypes contentTypes;
private final DocxFile file;
+ private final FileReader fileReader;
public BodyXmlReader(
Styles styles,
Numbering numbering,
Relationships relationships,
ContentTypes contentTypes,
- DocxFile file)
+ DocxFile file,
+ FileReader fileReader)
{
this.styles = styles;
this.numbering = numbering;
this.relationships = relationships;
this.contentTypes = contentTypes;
this.file = file;
+ this.fileReader = fileReader;
}
public ReadResult readElement(XmlElement element) {
@@ -276,9 +278,18 @@ public class BodyXmlReader {
}
private ReadResult readBlip(XmlElement blip, Optional<String> altText) {
- String relationshipId = blip.getAttribute("r:embed");
- String imagePath = relationshipIdToDocxPath(relationshipId);
- return readImage(imagePath, altText, () -> file.getInputStream(imagePath));
+ Optional<String> embedRelationshipId = blip.getAttributeOrNone("r:embed");
+ Optional<String> linkRelationshipId = blip.getAttributeOrNone("r:link");
+ if (embedRelationshipId.isPresent()) {
+ String imagePath = relationshipIdToDocxPath(embedRelationshipId.get());
+ return readImage(imagePath, altText, () -> file.getInputStream(imagePath));
+ } else if (linkRelationshipId.isPresent()) {
+ String imagePath = relationships.findRelationshipById(linkRelationshipId.get()).getTarget();
+ return readImage(imagePath, altText, () -> fileReader.getInputStream(imagePath));
+ } else {
+ // TODO: emit warning
+ return ReadResult.EMPTY_SUCCESS;
+ }
}
private ReadResult readImage(String imagePath, Optional<String> altText, InputStreamSupplier open) {
diff --git a/src/main/java/org/zwobble/mammoth/docx/FileReader.java b/src/main/java/org/zwobble/mammoth/docx/FileReader.java
new file mode 100644
index 0000000..9bb5b25
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/docx/FileReader.java
@@ -0,0 +1,8 @@
+package org.zwobble.mammoth.docx;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface FileReader {
+ InputStream getInputStream(String uri) throws IOException;
+}
diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlReaderMakers.java b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlReaderMakers.java
index 41cefd5..f19f505 100644
--- a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlReaderMakers.java
+++ b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlReaderMakers.java
@@ -15,6 +15,7 @@ public class BodyXmlReaderMakers {
public static final Property<BodyXmlReader, Relationships> RELATIONSHIPS = newProperty();
public static final Property<BodyXmlReader, ContentTypes> CONTENT_TYPES = newProperty();
public static final Property<BodyXmlReader, DocxFile> DOCX_FILE = newProperty();
+ public static final Property<BodyXmlReader, FileReader> FILE_READER = newProperty();
public static final Instantiator<BodyXmlReader> bodyReader =
propertyLookup -> new BodyXmlReader(
@@ -31,5 +32,11 @@ public class BodyXmlReaderMakers {
@Override
public void close() throws IOException {
}
+ }),
+ propertyLookup.valueOf(FILE_READER, new FileReader() {
+ @Override
+ public InputStream getInputStream(String uri) throws IOException {
+ throw new UnsupportedOperationException();
+ }
}));
}
diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
index 49542ec..5c4c40d 100644
--- a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
+++ b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
@@ -419,7 +419,7 @@ public class BodyXmlTests {
hasProperty("contentType", deepEquals(Optional.of("image/png")))));
assertThat(
CharStreams.toString(new InputStreamReader(image.open())),
- equalTo("Not an image at all!"));
+ equalTo(imageBytes));
}
private class EmbeddedImage {
@@ -446,11 +446,30 @@ public class BodyXmlTests {
with(DOCX_FILE, file),
with(CONTENT_TYPES, contentTypes)),
element);
+
assertThat(
result,
hasProperty("warnings", deepEquals(list(warning("Image of type image/x-emf is unlikely to display in web browsers")))));
}
+ @Test
+ public void canReadLinkedPictures() throws IOException {
+ XmlElement element = inlineImageXml(linkedBlipXml("rId5"), "");
+ Relationships relationships = new Relationships(map(
+ "rId5", new Relationship("file:///media/hat.png")));
+ String imageBytes = "Not an image at all!";
+
+ Image image = (Image) readSuccess(
+ a(bodyReader,
+ with(RELATIONSHIPS, relationships),
+ with(FILE_READER, new InMemoryFileReader(map("file:///media/hat.png", imageBytes)))),
+ element);
+
+ assertThat(
+ CharStreams.toString(new InputStreamReader(image.open())),
+ equalTo(imageBytes));
+ }
+
private XmlElement inlineImageXml(XmlElement blip, String description) {
return element("w:drawing", list(
element("wp:inline", imageXml(blip, description))));
@@ -474,6 +493,10 @@ public class BodyXmlTests {
return blipXml(map("r:embed", relationshipId));
}
+ private XmlElement linkedBlipXml(String relationshipId) {
+ return blipXml(map("r:link", relationshipId));
+ }
+
private XmlElement blipXml(Map<String, String> attributes) {
return element("a:blip", attributes);
}
diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/InMemoryFileReader.java b/src/test/java/org/zwobble/mammoth/tests/docx/InMemoryFileReader.java
new file mode 100644
index 0000000..7b716cc
--- /dev/null
+++ b/src/test/java/org/zwobble/mammoth/tests/docx/InMemoryFileReader.java
@@ -0,0 +1,24 @@
+package org.zwobble.mammoth.tests.docx;
+
+import org.zwobble.mammoth.docx.FileReader;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.Optional;
+
+public class InMemoryFileReader implements FileReader {
+ private final Map<String, String> entries;
+
+ public InMemoryFileReader(Map<String, String> entries) {
+ this.entries = entries;
+ }
+
+ @Override
+ public InputStream getInputStream(String name) throws IOException {
+ String value = Optional.ofNullable(entries.get(name)).get();
+ return new ByteArrayInputStream(value.getBytes(StandardCharsets.UTF_8));
+ }
+}