From: Nick Burch Date: Tue, 21 Jun 2016 14:27:41 +0000 (+0000) Subject: #59717 POIXMLProperties helper methods for reading and changing OOXML document thumbnails X-Git-Tag: REL_3_15_BETA2~18 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=02ca37ca183f2deb63763e993d3a49e755073e26;p=poi.git #59717 POIXMLProperties helper methods for reading and changing OOXML document thumbnails git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1749528 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/ooxml/java/org/apache/poi/POIXMLProperties.java b/src/ooxml/java/org/apache/poi/POIXMLProperties.java index f55788de1a..0ce6ad6774 100644 --- a/src/ooxml/java/org/apache/poi/POIXMLProperties.java +++ b/src/ooxml/java/org/apache/poi/POIXMLProperties.java @@ -19,17 +19,20 @@ package org.apache.poi; import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; +import org.apache.poi.openxml4j.opc.ContentTypes; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.openxml4j.opc.PackagingURIHelper; +import org.apache.poi.openxml4j.opc.StreamHelper; import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; import org.apache.poi.openxml4j.util.Nullable; @@ -37,8 +40,9 @@ import org.apache.xmlbeans.XmlException; import org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperty; /** - * Wrapper around the two different kinds of OOXML properties - * a document can have + * Wrapper around the three different kinds of OOXML properties + * and metadata a document can have (Core, Extended and Custom), + * as well Thumbnails. */ public class POIXMLProperties { private OPCPackage pkg; @@ -121,6 +125,69 @@ public class POIXMLProperties { public CustomProperties getCustomProperties() { return cust; } + + /** + * Returns the {@link PackagePart} for the Document + * Thumbnail, or null if there isn't one + * + * @return The Document Thumbnail part or null + */ + protected PackagePart getThumbnailPart() { + PackageRelationshipCollection rels = + pkg.getRelationshipsByType(PackageRelationshipTypes.THUMBNAIL); + if(rels.size() == 1) { + return pkg.getPart(rels.getRelationship(0)); + } + return null; + } + /** + * Returns the name of the Document thumbnail, eg + * thumbnail.jpeg, or null if there + * isn't one. + * + * @return The thumbnail filename, or null + */ + public String getThumbnailFilename() { + PackagePart tPart = getThumbnailPart(); + if (tPart == null) return null; + String name = tPart.getPartName().getName(); + return name.substring(name.lastIndexOf('/')); + } + /** + * Returns the Document thumbnail image data, or + * null if there isn't one. + * + * @return The thumbnail data, or null + */ + public InputStream getThumbnailImage() throws IOException { + PackagePart tPart = getThumbnailPart(); + if (tPart == null) return null; + return tPart.getInputStream(); + } + + /** + * Sets the Thumbnail for the document, replacing any existing + * one. + * + * @param name The filename for the thumbnail image, eg thumbnail.jpg + * @param imageData The inputstream to read the thumbnail image from + */ + public void setThumbnail(String filename, InputStream imageData) throws IOException { + PackagePart tPart = getThumbnailPart(); + if (tPart == null) { + // New thumbnail + pkg.addThumbnail(filename, imageData); + } else { + // Change existing + String newType = ContentTypes.getContentTypeFromFileExtension(filename); + if (! newType.equals(tPart.getContentType())) { + throw new IllegalArgumentException("Can't set a Thumbnail of type " + + newType + " when existing one is of a different type " + + tPart.getContentType()); + } + StreamHelper.copyStream(imageData, tPart.getOutputStream()); + } + } /** * Commit changes to the underlying OPC package diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java index e84d83e3e6..e70496f3f4 100644 --- a/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java +++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java @@ -474,19 +474,32 @@ public abstract class OPCPackage implements RelationshipSource, Closeable { * the addition of a thumbnail in a package. You can do the same work by * using the traditionnal relationship and part mechanism. * - * @param path - * The full path to the image file. + * @param path The full path to the image file. */ public void addThumbnail(String path) throws IOException { + // Check parameter + if (path == null || path.isEmpty()) { + throw new IllegalArgumentException("path"); + } + String name = path.substring(path.lastIndexOf(File.separatorChar) + 1); + + FileInputStream is = new FileInputStream(path); + addThumbnail(name, is); + is.close(); + } + /** + * Add a thumbnail to the package. This method is provided to make easier + * the addition of a thumbnail in a package. You can do the same work by + * using the traditionnal relationship and part mechanism. + * + * @param path The full path to the image file. + */ + public void addThumbnail(String filename, InputStream data) throws IOException { // Check parameter - if ("".equals(path)) { - throw new IllegalArgumentException("path"); + if (filename == null || filename.isEmpty()) { + throw new IllegalArgumentException("filename"); } - // Get the filename from the path - String filename = path - .substring(path.lastIndexOf(File.separatorChar) + 1); - // Create the thumbnail part name String contentType = ContentTypes .getContentTypeFromFileExtension(filename); @@ -495,10 +508,10 @@ public abstract class OPCPackage implements RelationshipSource, Closeable { thumbnailPartName = PackagingURIHelper.createPartName("/docProps/" + filename); } catch (InvalidFormatException e) { + String partName = "/docProps/thumbnail" + + filename.substring(filename.lastIndexOf(".") + 1); try { - thumbnailPartName = PackagingURIHelper - .createPartName("/docProps/thumbnail" - + path.substring(path.lastIndexOf(".") + 1)); + thumbnailPartName = PackagingURIHelper.createPartName(partName); } catch (InvalidFormatException e2) { throw new InvalidOperationException( "Can't add a thumbnail file named '" + filename + "'", e2); @@ -519,10 +532,7 @@ public abstract class OPCPackage implements RelationshipSource, Closeable { PackageRelationshipTypes.THUMBNAIL); // Copy file data to the newly created part - FileInputStream is = new FileInputStream(path); - StreamHelper.copyStream(is, thumbnailPart - .getOutputStream()); - is.close(); + StreamHelper.copyStream(data, thumbnailPart.getOutputStream()); } /** diff --git a/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java b/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java index 1d9be8d1aa..0a34280154 100644 --- a/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java +++ b/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java @@ -19,9 +19,11 @@ package org.apache.poi; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Calendar; import java.util.Date; @@ -42,12 +44,16 @@ import org.junit.Test; */ public final class TestPOIXMLProperties { private XWPFDocument sampleDoc; + private XWPFDocument sampleNoThumb; private POIXMLProperties _props; private CoreProperties _coreProperties; @Before public void setUp() throws IOException { sampleDoc = XWPFTestDataSamples.openSampleDocument("documentProperties.docx"); + sampleNoThumb = XWPFTestDataSamples.openSampleDocument("SampleDoc.docx"); + assertNotNull(sampleDoc); + assertNotNull(sampleNoThumb); _props = sampleDoc.getProperties(); _coreProperties = _props.getCoreProperties(); assertNotNull(_props); @@ -56,6 +62,7 @@ public final class TestPOIXMLProperties { @After public void closeResources() throws Exception { sampleDoc.close(); + sampleNoThumb.close(); } @Test @@ -214,6 +221,35 @@ public final class TestPOIXMLProperties { return utcString.equals(dateTimeUtcString); } + + public void testThumbnails() throws Exception { + POIXMLProperties noThumbProps = sampleNoThumb.getProperties(); + + assertNotNull(_props.getThumbnailPart()); + assertNull(noThumbProps.getThumbnailPart()); + + assertNotNull(_props.getThumbnailFilename()); + assertNull(noThumbProps.getThumbnailFilename()); + + assertNotNull(_props.getThumbnailImage()); + assertNull(noThumbProps.getThumbnailImage()); + + assertEquals("thumbnail.jpeg", _props.getThumbnailFilename()); + + + // Adding / changing + noThumbProps.setThumbnail("Testing.png", new ByteArrayInputStream(new byte[1])); + assertNotNull(noThumbProps.getThumbnailPart()); + assertEquals("Testing.png", noThumbProps.getThumbnailFilename()); + assertNotNull(noThumbProps.getThumbnailImage()); + assertEquals(1, noThumbProps.getThumbnailImage().available()); + + noThumbProps.setThumbnail("Testing2.png", new ByteArrayInputStream(new byte[2])); + assertNotNull(noThumbProps.getThumbnailPart()); + assertEquals("Testing.png", noThumbProps.getThumbnailFilename()); + assertNotNull(noThumbProps.getThumbnailImage()); + assertEquals(2, noThumbProps.getThumbnailImage().available()); + } private static String zeroPad(long i) { if (i >= 0 && i <=9) {