10

I've created a simple docx-Document, using Java POI 3.7. XWPF. Then, I added a picture by using the Method XWPFDocument.addpicture(byte[] arg0, int arg1).

XWPFDocument docx = new XWPFDocument();  
XWPFParagraph par = docx.createParagraph();  
XWPFRun run = par.createRun();
run.setText("Hello, World. This is my first java generated docx-file. Have fun.");
run.setFontSize(13);

InputStream pic = new FileInputStream("logo.jpg");
byte [] picbytes = IOUtils.toByteArray(pic);
docx.addPicture(picbytes, Document.PICTURE_TYPE_JPEG);

Since file size of the docx grows, the picture was added "physically" to the document; but it is not displayed at all in MS Word. Seems like there is a reference to the picture missing in the document.

What's the way to do this? How is picture handling done with apache POI? And where are more tutorials on the web, there is nearly no documents or tutorials at all for XWPF, which explains handling of paragraphs, runs, etc.

The only thing I found about this is here: https://issues.apache.org/bugzilla/show_bug.cgi?id=49765 but it does not help at all.

Many thanks in advance.

Goatcat
  • 1,133
  • 2
  • 14
  • 31
tsd.tom
  • 101
  • 1
  • 2
  • 8
  • Have you tried with POI 3.8 beta 4? Some picture bugs have been fixed since 3.7 final, so it's worth seeing if the upgrade solves your issue – Gagravarr Oct 06 '11 at 16:44
  • Yes, the only difference is that in POI 3.8 beta 4 the method name XWPFDocument.addPicture(byte[] arg0, int arg1) is changed to XWPFDocument.addPictureData(byte[] arg0, int arg1) - maybe to outline that this method only adds the picture data to the document, but does not add the picture into a paragraph to be shown in word, etc. The question how to do this remains still unanswered. I think a CTPicture object ( org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) has to be created and added to a paragraph - however, I have not found out how to do this. – tsd.tom Oct 07 '11 at 06:58
  • Did you try calling [addPicture](http://poi.apache.org/apidocs/org/apache/poi/xwpf/usermodel/XWPFRun.html#addPicture%28java.io.InputStream,%20int,%20java.lang.String,%20int,%20int%29) on the text run where you want your picture to show up? – Gagravarr Oct 07 '11 at 09:29
  • 2
    `XWPFParagraph par = docx.createParagraph(); XWPFRun run = par.createRun(); run.addPicture(pic, XWPFDocument.PICTURE_TYPE_JPEG, "logo.JPG",300,300);` doesn't work, the document is not readable by MS Word. – tsd.tom Oct 07 '11 at 14:18

6 Answers6

13

I know this post is very old but still I am posting the answer so that all those who are searching for this answer can use it. For inserting the picture in the word document you have to write two programs. The first one is :-

package org.word.POI;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

/*
Romesh Soni
soni.romesh@gmail.com
*/

public class TestCustom
{

    public static void main(String []a) throws FileNotFoundException, IOException, InvalidFormatException
    {

        CustomXWPFDocument document = new CustomXWPFDocument(new FileInputStream(new File("C:\\Users\\amitabh\\Documents\\Apache POI\\Word File\\new.doc")));
        FileOutputStream fos = new FileOutputStream(new File("C:\\Users\\amitabh\\Documents\\Apache POI\\Word File\\new.doc"));

        String blipId = document.addPictureData(new FileInputStream(new File("C:\\Users\\amitabh\\Pictures\\pics\\3.jpg")), Document.PICTURE_TYPE_JPEG);

        System.out.println(document.getNextPicNameNumber(Document.PICTURE_TYPE_JPEG));

        //System.out.println(document.getNextPicNameNumber(Document.PICTURE_TYPE_JPEG));
        document.createPicture(blipId,document.getNextPicNameNumber(Document.PICTURE_TYPE_JPEG), 500, 500);


        document.write(fos);
        fos.flush();
        fos.close();

    }

}

Now here I have used "CustomeXwPFDocument" in this code and you will not get any imports through any jar file so you have to add another .java class in your package. the code for "CustomXWPFDocument" class goes like this:-

package org.word.POI;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;

import java.io.IOException;
import java.io.InputStream;

public class CustomXWPFDocument extends XWPFDocument
{
    public CustomXWPFDocument(InputStream in) throws IOException
    {
        super(in);
    }

    public void createPicture(String blipId,int id, int width, int height)
    {
        final int EMU = 9525;
        width *= EMU;
        height *= EMU;
        //String blipId = getAllPictures().get(id).getPackageRelationship().getId();


        CTInline inline = createParagraph().createRun().getCTR().addNewDrawing().addNewInline();

        String picXml = "" +
                "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
                "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                "         <pic:nvPicPr>" +
                "            <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
                "            <pic:cNvPicPr/>" +
                "         </pic:nvPicPr>" +
                "         <pic:blipFill>" +
                "            <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
                "            <a:stretch>" +
                "               <a:fillRect/>" +
                "            </a:stretch>" +
                "         </pic:blipFill>" +
                "         <pic:spPr>" +
                "            <a:xfrm>" +
                "               <a:off x=\"0\" y=\"0\"/>" +
                "               <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +
                "            </a:xfrm>" +
                "            <a:prstGeom prst=\"rect\">" +
                "               <a:avLst/>" +
                "            </a:prstGeom>" +
                "         </pic:spPr>" +
                "      </pic:pic>" +
                "   </a:graphicData>" +
                "</a:graphic>";

        //CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
        XmlToken xmlToken = null;
        try
        {
            xmlToken = XmlToken.Factory.parse(picXml);
        }
        catch(XmlException xe)
        {
            xe.printStackTrace();
        }
        inline.set(xmlToken);
        //graphicData.set(xmlToken);

        inline.setDistT(0);
        inline.setDistB(0);
        inline.setDistL(0);
        inline.setDistR(0);

        CTPositiveSize2D extent = inline.addNewExtent();
        extent.setCx(width);
        extent.setCy(height);

        CTNonVisualDrawingProps docPr = inline.addNewDocPr();
        docPr.setId(id);
        docPr.setName("Picture " + id);
        docPr.setDescr("Generated");
    }
}

Use POI 3.9 jars for this program. The best URL is:- http://www.apache.org/dyn/closer.cgi/poi/release/bin/poi-bin-3.9-20121203.zip

Now you are ready to fly. Best of luck.

Amitabh Ranjan
  • 1,500
  • 3
  • 23
  • 39
  • Thanks man, this helped a lot. However, you do not need to create two programs. You can simply use the code from the `createPicture` method as is anywhere you want. – Justin Skiles Apr 25 '14 at 14:20
  • @Amitabh Rajan: Is it possible to add picture in a particular page and line and also with center alignment? – softmage99 Jul 10 '14 at 06:42
  • @MageshBabu :- dude I think its possible but I am sorry that I wont be able to help you out on this one. I was working on POI last year on a very small assignment but I think what you are saying is possible. Kindly play around with code and I think you will get the answer.I am really sorry for not being able to help you out. – Amitabh Ranjan Jul 10 '14 at 10:25
  • @AmitabhRanjan your code helped a lot,but can you tell me how i can add an image in the header using this code – lucifer Dec 21 '14 at 03:30
  • apache poi 3.13 (feb 2016) still has the issue – Exceptyon Feb 09 '16 at 09:41
4

The elegant solution is coming, check out: https://issues.apache.org/bugzilla/show_bug.cgi?id=55476

You can either wait till my patch gets accepted and released or try applying the patch to the latest POI SVN checkout (http://poi.apache.org/subversion.html, read only access link will work) and building POI jars from sources.

The approach suggested by tsd.tom will work:

XWPFParagraph par = docx.createParagraph();
XWPFRun run = par.createRun();
run.addPicture(pic, XWPFDocument.PICTURE_TYPE_JPEG, "logo.JPG",300,300); 
Sumurai8
  • 20,333
  • 11
  • 66
  • 100
2

The bug link that you've provided actually has a working solution: https://issues.apache.org/bugzilla/show_bug.cgi?id=49765#c15

It requires some amount of hackery but I'm using it and it certainly works!

Wix
  • 21
  • 2
0

I have used docx4j and found it to be working.I tried with POI but not able to make it work.Please find the code for using docx4j.

public static void main(String[] args) throws Exception {
    WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
    //wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Title", "Hello World");
    //wordMLPackage.getMainDocumentPart().addParagraphOfText("Text");
     java.io.InputStream is = new java.io.FileInputStream("path\\to\\images.jpg");
// commons-io.jar
     byte[] bytes = IOUtils.toByteArray(is);
     String filenameHint = null;
     String altText = null;
     int id1 = 0;
     int id2 = 1;
     org.docx4j.wml.P p = newImage( wordMLPackage, bytes,filenameHint, altText,id1, id2,6000  );
     // Now add our p to the document
     wordMLPackage.getMainDocumentPart().addObject(p);
     wordMLPackage.save(new java.io.File("helloworld.docx") );
     is.close();
}



public static org.docx4j.wml.P newImage( WordprocessingMLPackage wordMLPackage,
        byte[] bytes,
        String filenameHint, String altText, 
        int id1, int id2, long cx) throws Exception {

        BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);

        Inline inline = imagePart.createImageInline(filenameHint, altText,id1, id2, cx,false);

    // Now add the inline in w:p/w:r/w:drawing
        org.docx4j.wml.ObjectFactory factory = new org.docx4j.wml.ObjectFactory();
        org.docx4j.wml.P  p = factory.createP();
        org.docx4j.wml.R  run = factory.createR();             
        p.getContent().add(run);       
        org.docx4j.wml.Drawing drawing = factory.createDrawing();               
        run.getContent().add(drawing);               
        drawing.getAnchorOrInline().add(inline);

        return p;

}

Pradeep
  • 31
  • 1
0
@Pradeep  Your code

    public static void main(String[] args) throws Exception {
    WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
    //wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Title", "Hello World");
    //wordMLPackage.getMainDocumentPart().addParagraphOfText("Text");
     java.io.InputStream is = new java.io.FileInputStream("path\\to\\images.jpg");
// commons-io.jar
     byte[] bytes = IOUtils.toByteArray(is);
     String filenameHint = null;
     String altText = null;
     int id1 = 0;
     int id2 = 1;
     org.docx4j.wml.P p = newImage( wordMLPackage, bytes,filenameHint, altText,id1, id2,6000  );
     // Now add our p to the document
     wordMLPackage.getMainDocumentPart().addObject(p);
     wordMLPackage.save(new java.io.File("helloworld.docx") );
     is.close();
}



public static org.docx4j.wml.P newImage( WordprocessingMLPackage wordMLPackage,
        byte[] bytes,
        String filenameHint, String altText, 
        int id1, int id2, long cx) throws Exception {

        BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);

        Inline inline = imagePart.createImageInline(filenameHint, altText,id1, id2, cx,false);

    // Now add the inline in w:p/w:r/w:drawing
        org.docx4j.wml.ObjectFactory factory = new org.docx4j.wml.ObjectFactory();
        org.docx4j.wml.P  p = factory.createP();
        org.docx4j.wml.R  run = factory.createR();             
        p.getContent().add(run);       
        org.docx4j.wml.Drawing drawing = factory.createDrawing();               
        run.getContent().add(drawing);               
        drawing.getAnchorOrInline().add(inline);

        return p;

 works , but all the above codes does not work, i tried it personally

thanks, a lot.
siva
  • 1
  • 1
-2

Because XWPFRun.addPicture does not work (it damage xdoc file) i manage to picture like this:

    private void addPicture(final String fileName, final int id, int width, int height, final XWPFRun run)
{
    FileInputStream fileInputStream = null;

    try
    {
        fileInputStream = new FileInputStream("/home/maq/ebworkspace/TeamForge_Tools/" + fileName);
        final String blipId = run.getDocument().addPictureData(fileInputStream, Document.PICTURE_TYPE_JPEG);

        final int EMU = 9525;
        width *= EMU;
        height *= EMU;
        //String blipId = getAllPictures().get(id).getPackageRelationship().getId();

        final CTInline inline = run.getCTR().addNewDrawing().addNewInline();

        final String picXml = "" + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
                + "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" + "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
                + "         <pic:nvPicPr>" + "            <pic:cNvPr id=\""
                + id
                + "\" name=\"Generated\"/>"
                + "            <pic:cNvPicPr/>"
                + "         </pic:nvPicPr>"
                + "         <pic:blipFill>"
                + "            <a:blip r:embed=\""
                + blipId
                + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
                + "            <a:stretch>"
                + "               <a:fillRect/>"
                + "            </a:stretch>"
                + "         </pic:blipFill>"
                + "         <pic:spPr>"
                + "            <a:xfrm>"
                + "               <a:off x=\"0\" y=\"0\"/>"
                + "               <a:ext cx=\""
                + width
                + "\" cy=\""
                + height
                + "\"/>"
                + "            </a:xfrm>"
                + "            <a:prstGeom prst=\"rect\">"
                + "               <a:avLst/>"
                + "            </a:prstGeom>"
                + "         </pic:spPr>"
                + "      </pic:pic>" + "   </a:graphicData>" + "</a:graphic>";

        //CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
        XmlToken xmlToken = null;
        xmlToken = XmlToken.Factory.parse(picXml);
        inline.set(xmlToken);
        //graphicData.set(xmlToken);

        inline.setDistT(0);
        inline.setDistB(0);
        inline.setDistL(0);
        inline.setDistR(0);

        final CTPositiveSize2D extent = inline.addNewExtent();
        extent.setCx(width);
        extent.setCy(height);

        final CTNonVisualDrawingProps docPr = inline.addNewDocPr();
        docPr.setId(id);
        docPr.setName("Picture " + id);
        docPr.setDescr("Generated");
    }
    catch (final Exception e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    finally
    {
        //close streams 
        if (fileInputStream != null)
        {
            try
            {
                fileInputStream.close();
            }
            catch (final IOException ioEx)
            {
                //can be ignored
            }
        }
    }

}

And running example:

 addPicture(filePath, xdoc.getNextPicNameNumber(Document.PICTURE_TYPE_JPEG), 100, 50, xRun);
Maq
  • 1