#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
This commit is contained in:
Nick Burch 2016-06-21 14:27:41 +00:00
parent fdb7c7d1ff
commit 631ca92c16
3 changed files with 130 additions and 17 deletions

View File

@ -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;
@ -122,6 +126,69 @@ public class POIXMLProperties {
return cust;
}
/**
* Returns the {@link PackagePart} for the Document
* Thumbnail, or <code>null</code> 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
* <code>thumbnail.jpeg</code>, or <code>null</code> 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
* <code>null</code> 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 <code>thumbnail.jpg</code>
* @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
*

View File

@ -474,18 +474,31 @@ 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 ("".equals(path)) {
throw new IllegalArgumentException("path");
}
// Check parameter
if (path == null || path.isEmpty()) {
throw new IllegalArgumentException("path");
}
String name = path.substring(path.lastIndexOf(File.separatorChar) + 1);
// Get the filename from the path
String filename = 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 (filename == null || filename.isEmpty()) {
throw new IllegalArgumentException("filename");
}
// Create the thumbnail part name
String contentType = ContentTypes
@ -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());
}
/**

View File

@ -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
@ -215,6 +222,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) {
return "0" + i;