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;
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;
public CustomProperties getCustomProperties() {
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
* 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);
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);
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());
}
/**
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;
*/
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);
@After
public void closeResources() throws Exception {
sampleDoc.close();
+ sampleNoThumb.close();
}
@Test
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) {