Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
635 views
in Technique[技术] by (71.8m points)

java - Change image layout or wrap in DOCX with Apache POI

I paste image into docx programmatically. But in result the layout does not suit me. Faced a lack of documentation. I need to change image wrap (layout). For example now I have this:

enter image description here

But want this:

enter image description here

UPD1: What I do: iterate through the paragraphs, then through the runs and find certain run with special bookmark. In this run I add picture:

XWPFPicture pic =  run.addPicture(
        new ByteArrayInputStream(picSource),
        Document.PICTURE_TYPE_PNG,
        "pic",
        Units.toEMU(100),
        Units.toEMU(30));

UPD2: Investigated something interesting inside this class:

org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor

method setWrapTight(CTWrapTight var1). May be is it. By still don't know how to apply it to my code.

UPD3: Finally I came to this (currentRun - run with our picture):

    CTWrapTight ctWrapTight = currentRun.getCTR().getDrawingList().get(0).addNewAnchor().addNewWrapTight();
 CTWrapPath ctWrapPath = ctWrapTight.addNewWrapPolygon();

 CTPoint2D ctStart = ctWrapPath.addNewStart();
 ctStart.setX(0L);
 ctStart.setY(0L);

 CTPoint2D ctLineTo1 = ctWrapPath.addNewLineTo();
 CTPoint2D ctLineTo2 = ctWrapPath.addNewLineTo();
 CTPoint2D ctLineTo3 = ctWrapPath.addNewLineTo();

 ctLineTo1.setX(21384L);
 ctLineTo1.setY(20520L);

 ctLineTo2.setX(21384L);
 ctLineTo2.setY(0L);

 ctLineTo3.setX(0L);
 ctLineTo3.setY(0L);

ctWrapTight.setWrapText(STWrapText.BOTH_SIDES);

But it's break down document when I try to open it:

We're sorry. We can't open document because we found a problem with its contents.

Dependency are:

<dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.17</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>3.17</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>ooxml-schemas</artifactId>
        <version>1.3</version>
    </dependency>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

While you already found the right classes to use - CTAnchor and successors - there is also the need considering the XML Schema definition of anchor. And this states there are many more duty elements required than only the ones which are defining wrapping. So using class by class of org.openxmlformats.schemas.drawingml.x2006 you are probably coding page wise code. My preferred solution for such problems is providing XML having all needed elements updated by some variables. This XML then can be parsed to get the needed object.

Example:

import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;

import org.apache.poi.xwpf.usermodel.*;

import org.apache.poi.util.Units;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;

public class WordInsertPictures {

 private static CTAnchor getAnchorWithGraphic(CTGraphicalObject graphicalobject, 
                                              String drawingDescr, int width, int height,
                                              int left, int top) throws Exception {

  String anchorXML = 
   "<wp:anchor xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" "
  +"simplePos="0" relativeHeight="0" behindDoc="1" locked="0" layoutInCell="1" allowOverlap="1">"
  +"<wp:simplePos x="0" y="0"/>"
  +"<wp:positionH relativeFrom="column"><wp:posOffset>"+left+"</wp:posOffset></wp:positionH>"
  +"<wp:positionV relativeFrom="paragraph"><wp:posOffset>"+top+"</wp:posOffset></wp:positionV>"
  +"<wp:extent cx=""+width+"" cy=""+height+""/>"
  +"<wp:effectExtent l="0" t="0" r="0" b="0"/>"
  +"<wp:wrapTight wrapText="bothSides">"
  +"<wp:wrapPolygon edited="0">"
  +"<wp:start x="0" y="0"/>"
  +"<wp:lineTo x="0" y="21600"/>" //Square polygon 21600 x 21600 leads to wrap points in fully width x height
  +"<wp:lineTo x="21600" y="21600"/>"// Why? I don't know. Try & error ;-).
  +"<wp:lineTo x="21600" y="0"/>"
  +"<wp:lineTo x="0" y="0"/>"
  +"</wp:wrapPolygon>"
  +"</wp:wrapTight>"
  +"<wp:docPr id="1" name="Drawing 0" descr=""+drawingDescr+""/><wp:cNvGraphicFramePr/>"
  +"</wp:anchor>";

  CTDrawing drawing = CTDrawing.Factory.parse(anchorXML);
  CTAnchor anchor = drawing.getAnchorArray(0);
  anchor.setGraphic(graphicalobject);
  return anchor;  
 }

 public static void main(String[] args) throws Exception {

  XWPFDocument document = new XWPFDocument();
  XWPFParagraph paragraph = document.createParagraph();
  XWPFRun run = paragraph.createRun();

  run.setText("The picture in line: ");

  InputStream in = new FileInputStream("samplePict.jpeg");
  run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(100), Units.toEMU(30));
  in.close();  

  run.setText(" text after the picture.");

  paragraph = document.createParagraph();

  run = paragraph.createRun();
  in = new FileInputStream("samplePict.jpeg");
  run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(100), Units.toEMU(30));
  in.close();  
  CTDrawing drawing = run.getCTR().getDrawingArray(0);
  CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();
  CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "samplePict.jpeg", 
                                         Units.toEMU(100), Units.toEMU(30), 
                                         Units.toEMU(30), Units.toEMU(0));
  drawing.setAnchorArray(new CTAnchor[]{anchor});
  drawing.removeInline(0);

  run = paragraph.createRun();
  run.setText("The previous picture is anchored wrapTight. The previous picture is anchored wrapTight. The previous picture is anchored wrapTight. The previous picture is anchored wrapTight. The previous picture is anchored wrapTight. The previous picture is anchored wrapTight.");

  document.write(new FileOutputStream("WordInsertPictures.docx"));
  document.close();
 }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...