From 020121825c6b329282d9bad147a40bd15cf85e3b Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Fri, 15 Apr 2011 16:16:09 +0000 Subject: [PATCH] Add support for adding a picture to a XSSFRun git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1092755 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../poi/xwpf/usermodel/XWPFDocument.java | 12 +- .../apache/poi/xwpf/usermodel/XWPFRun.java | 164 +++++++++++++++--- .../poi/xwpf/usermodel/TestXWPFRun.java | 15 ++ 4 files changed, 167 insertions(+), 25 deletions(-) diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 1c398d0b96..76d616f47f 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 49765 - Support for adding a picture to a XSSFRun Rename/Move xssf.model.Table to xssf.usermodel.XSSFTable as it now has usermodel-like features 51061 - Correct target URI for new XSSF Tables Initial support for XSSF Charts. Provides easy access to the underlying CTChart object via the Sheet Drawing, but no high level interface onto the chart contents as yet. diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java index 4188cbdac1..f0f314cf98 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java @@ -928,10 +928,13 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } /** - * Adds a picture to the document. + * Adds a picture to the document. Users should normally call + * {@link XWPFRun#addPicture(InputStream, int)} + * * * @param is The stream to read image from - * @param format The format of the picture. + * @param format The format of the picture, eg {@link Document#PICTURE_TYPE_JPEG} + * * @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} . * @throws InvalidFormatException @@ -947,10 +950,11 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } /** - * Adds a picture to the document. + * Adds a picture to the document. Users should normally call + * {@link XWPFRun#addPicture(InputStream, int)} * * @param pictureData The bytes to read image from - * @param format The format of the picture. + * @param format The format of the picture, eg {@link Document#PICTURE_TYPE_JPEG} * * @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} . * @throws InvalidFormatException diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java index e8689a6b9e..a08823c195 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java @@ -16,6 +16,8 @@ ==================================================================== */ package org.apache.poi.xwpf.usermodel; +import java.io.IOException; +import java.io.InputStream; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; @@ -23,14 +25,29 @@ import java.util.List; import javax.xml.namespace.QName; import org.apache.poi.POIXMLException; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.util.Internal; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlString; +import org.apache.xmlbeans.XmlToken; import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; -import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture; +import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; +import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData; +import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; +import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualPictureProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; +import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; +import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBr; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTEmpty; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHpsMeasure; @@ -49,6 +66,8 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.STUnderline; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalAlignRun; import org.w3c.dom.NodeList; import org.w3c.dom.Text; +import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture; +import org.openxmlformats.schemas.drawingml.x2006.picture.CTPictureNonVisual; /** * XWPFRun object defines a region of text with a common set of properties @@ -94,28 +113,31 @@ public class XWPFRun { // (They're a different CTPicture, under the drawingml namespace) pictures = new ArrayList(); for(XmlObject o : pictTextObjs) { - XmlObject[] picts = o - .selectPath("declare namespace pic='http://schemas.openxmlformats.org/drawingml/2006/picture' .//pic:pic"); - for(XmlObject pict : picts) { - if(pict instanceof XmlAnyTypeImpl) { - // Pesky XmlBeans bug - see Bugzilla #49934 - try { - pict = org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture.Factory.parse( - pict.toString() - ); - } catch(XmlException e) { - throw new POIXMLException(e); - } - } - if(pict instanceof org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) { - XWPFPicture picture = new XWPFPicture( - (org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture)pict, p - ); - pictures.add(picture); - } + for(CTPicture pict : getCTPictures(o)) { + XWPFPicture picture = new XWPFPicture( pict, p ); + pictures.add(picture); } } } + + private List getCTPictures(XmlObject o) { + List pictures = new ArrayList(); + XmlObject[] picts = o.selectPath("declare namespace pic='"+CTPicture.type.getName().getNamespaceURI()+"' .//pic:pic"); + for(XmlObject pict : picts) { + if(pict instanceof XmlAnyTypeImpl) { + // Pesky XmlBeans bug - see Bugzilla #49934 + try { + pict = CTPicture.Factory.parse( pict.toString() ); + } catch(XmlException e) { + throw new POIXMLException(e); + } + } + if(pict instanceof CTPicture) { + pictures.add((CTPicture)pict); + } + } + return pictures; + } /** * Get the currently used CTR object @@ -561,7 +583,107 @@ public class XWPFRun { public void removeCarriageReturn() { //TODO - } + } + + /** + * Adds a picture to the run. This method handles + * attaching the picture data to the overall file. + * + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_EMF + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_WMF + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_PICT + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_JPEG + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_PNG + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_DIB + * + * @param pictureData The raw picture data + * @param pictureType The type of the picture, eg {@link Document#PICTURE_TYPE_JPEG} + * @throws IOException + * @throws org.apache.poi.openxml4j.exceptions.InvalidFormatException + * @throws IOException + */ + public XWPFPicture addPicture(InputStream pictureData, int pictureType, String filename, int width, int height) + throws InvalidFormatException, IOException { + XWPFDocument doc = paragraph.document; + + // Add the picture + relationship + int picNumber = doc.addPicture(pictureData, pictureType); + XWPFPictureData picData = doc.getAllPackagePictures().get(picNumber); + + // Create the drawing entry for it + try { + CTDrawing drawing = run.addNewDrawing(); + CTInline inline = drawing.addNewInline(); + + // Do the fiddly namespace bits on the inline + // (We need full control of what goes where and as what) + String xml = + "" + + "" + + "" + + "" + + ""; + inline.set(XmlToken.Factory.parse(xml)); + + // Setup the inline + inline.setDistT(0); + inline.setDistR(0); + inline.setDistB(0); + inline.setDistL(0); + + CTNonVisualDrawingProps docPr = inline.addNewDocPr(); + docPr.setId(picNumber); + docPr.setName("Picture " + picNumber); + docPr.setDescr(filename); + + CTPositiveSize2D extent = inline.addNewExtent(); + extent.setCx(width); + extent.setCy(height); + + // Grab the picture object + CTGraphicalObject graphic = inline.getGraphic(); + CTGraphicalObjectData graphicData = graphic.getGraphicData(); + CTPicture pic = getCTPictures(graphicData).get(0); + + // Set it up + CTPictureNonVisual nvPicPr = pic.addNewNvPicPr(); + + CTNonVisualDrawingProps cNvPr = nvPicPr.addNewCNvPr(); + cNvPr.setId(picNumber); + cNvPr.setName("Picture " + picNumber); + cNvPr.setDescr(filename); + + CTNonVisualPictureProperties cNvPicPr = nvPicPr.addNewCNvPicPr(); + cNvPicPr.addNewPicLocks().setNoChangeAspect(true); + + CTBlipFillProperties blipFill = pic.addNewBlipFill(); + CTBlip blip = blipFill.addNewBlip(); + blip.setEmbed( picData.getPackageRelationship().getId() ); + blipFill.addNewStretch().addNewFillRect(); + + CTShapeProperties spPr = pic.addNewSpPr(); + CTTransform2D xfrm = spPr.addNewXfrm(); + + CTPoint2D off = xfrm.addNewOff(); + off.setX(0); + off.setY(0); + + CTPositiveSize2D ext = xfrm.addNewExt(); + ext.setCx(width); + ext.setCy(height); + + CTPresetGeometry2D prstGeom = spPr.addNewPrstGeom(); + prstGeom.setPrst(STShapeType.RECT); + prstGeom.addNewAvLst(); + + // Finish up + XWPFPicture xwpfPicture = new XWPFPicture(pic, paragraph); + pictures.add(xwpfPicture); + return xwpfPicture; + } catch(XmlException e) { + throw new IllegalStateException(e); + } + } /** * Returns the embedded pictures of the run. These diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java index 8ca44c9e89..b12932c2ec 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java @@ -16,6 +16,7 @@ ==================================================================== */ package org.apache.poi.xwpf.usermodel; +import java.io.ByteArrayInputStream; import java.math.BigInteger; import java.util.List; @@ -352,4 +353,18 @@ public class TestXWPFRun extends TestCase { assertEquals(1, count); } + + public void testAddPicture() throws Exception { + XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("TestDocument.docx"); + XWPFParagraph p = doc.getParagraphArray(2); + XWPFRun r = p.getRuns().get(0); + + assertEquals(0, doc.getAllPictures().size()); + assertEquals(0, r.getEmbeddedPictures().size()); + + r.addPicture(new ByteArrayInputStream(new byte[0]), Document.PICTURE_TYPE_JPEG, "test.jpg", 21, 32); + + assertEquals(1, doc.getAllPictures().size()); + assertEquals(1, r.getEmbeddedPictures().size()); + } } -- 2.39.5