【问题标题】:Wrap Text in Apache POI(docx)?在 Apache POI(docx)中包装文本?
【发布时间】:2018-05-15 01:53:54
【问题描述】:

我想将图像添加到 docx 中,但我刚刚找到了简单的 apache poi 代码:

 XWPFDocument document = new XWPFDocument()
        XWPFParagraph paragraph = document.createParagraph()
        XWPFRun run = paragraph.createRun()
        run.addPicture(new FileInputStream(img), format, img, Units.toEMU(width), Units.toEMU(height))
        FileOutputStream outputStream = new FileOutputStream(doc)
        document.write(outputStream)

现在我想把图片设置在文字前面,但是找不到任何参考。

【问题讨论】:

  • 这是一个很好的问题,有趣的是在互联网上找到与此相关的任何资源是多么困难。我试图搜索但没有找到任何东西。 XWPFRun 似乎只有简单的文本格式。我找到的最接近的是:stackoverflow.com/q/47673133/2886891 - 但它是一个丑陋的解决方案:)
  • @Honza Zidek:我很好奇一个不那么丑陋的解决方案会是什么样子。我们能否希望您迟早会提供这样的服务?
  • @AxelRichter: 不,除非我的项目需要它 :) 我不怪 you 提供了一个丑陋的解决方案,我怪 POI 没有提供 API 来实现无需破解 XML 即可实现相同的目标。
  • @Honza Zidek:“无需破解 XML”:Office Open **XML**Microsoft Office 的新文件格式。这里的答案,至少我的答案,从未被认为是现成的生产代码,而是显示原则的最小工作示例。当然,在生产代码中,这应该更灵活,更少基于固定的 XML 字符串。但是,正如我在回答中所说,当使用org.openxmlformats.schemas.drawingml.x2006 的类时,您可能正在编写逐页代码。不适用于此处的答案。

标签: java apache-poi


【解决方案1】:

Office Open XML 格式以及 *.docx 本身是 ZIP 档案,其中包含 XML 文件和目录结构中的其他文件。因此,如果我们好奇,我们可以简单地解压缩它们并查看一下。

使用在/word/document.xml 中运行的将图片添加到文本的默认代码,我们发现类似:

<w:r>
 <w:t>Picture inline with text:</w:t>
 <w:drawing>
  <wp:inline distT="0" distR="0" distB="0" distL="0">
   <wp:extent cx="1905000" cy="254000"/>
   <wp:docPr id="0" name="Drawing 0" descr="samplePict.jpeg"/>
   <a:graphic>
    <a:graphicData ...

如果我们打开这个 usig Word 并将图片的文字换行更改为文字后面,那么在 /word/document.xml 中我们会找到类似的内容:

<w:r>
 <w:drawing>
  <wp:anchor allowOverlap="1" behindDoc="1" layoutInCell="1" locked="0" relativeHeight="0" simplePos="0">
   <wp:simplePos x="0" y="0"/>
   <wp:positionH relativeFrom="column"><wp:posOffset>0</wp:posOffset></wp:positionH>
   <wp:positionV relativeFrom="paragraph"><wp:posOffset>0</wp:posOffset></wp:positionV>
   <wp:extent cx="1905000" cy="508000"/>
   <wp:effectExtent b="0" l="0" r="0" t="0"/><wp:wrapNone/>
   <wp:docPr descr="samplePict.jpeg" id="1" name="Drawing 0"/><wp:cNvGraphicFramePr/>
   <a:graphic>
    <a:graphicData ...

如您所见,第一个在 wp:inline 元素内,而第二个在 wp:anchor 元素内。

很遗憾,直到现在,wp:anchor 元素无法使用 apache poi 应用。所以我们需要知道在哪里可以找到低级对象,apache poi 基于。我发现http://grepcode.com 是一个很好的参考。

现在我们可以根据这些低级对象编码所需的东西:

import java.io.*;

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 CreateWordImagesBehindAndInFrontText {

 private static CTAnchor getAnchorWithGraphic(CTDrawing drawing /*inline drawing*/ , 
  String drawingDescr, boolean behind) throws Exception {

  CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();
  long width = drawing.getInlineArray(0).getExtent().getCx();
  long height = drawing.getInlineArray(0).getExtent().getCy();

  String anchorXML = 
   "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
  +"simplePos=\"0\" relativeHeight=\"0\" behindDoc=\""+((behind)?1:0)+"\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
  +"<wp:simplePos x=\"0\" y=\"0\"/>"
  +"<wp:positionH relativeFrom=\"column\"><wp:posOffset>0</wp:posOffset></wp:positionH>"
  +"<wp:positionV relativeFrom=\"paragraph\"><wp:posOffset>0</wp:posOffset></wp:positionV>"
  +"<wp:extent cx=\""+width+"\" cy=\""+height+"\"/>"
  +"<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/><wp:wrapNone/>"
  +"<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\""+drawingDescr+"\"/><wp:cNvGraphicFramePr/>"
  +"</wp:anchor>";

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

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

  XWPFDocument doc= new XWPFDocument();
  XWPFParagraph paragraph;
  XWPFRun run; 
  InputStream in;
  CTDrawing drawing;
  CTAnchor anchor;

  //default
  paragraph = doc.createParagraph();
  run = paragraph.createRun();
  run.setText("Picture inline with text:");
  in = new FileInputStream("samplePict.jpeg");
  run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(150), Units.toEMU(40));
  in.close();  

  paragraph = doc.createParagraph();

  //behind text
  paragraph = doc.createParagraph();
  run = paragraph.createRun();
  in = new FileInputStream("samplePict.jpeg");
  run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(150), Units.toEMU(40));
  in.close();  
  drawing = run.getCTR().getDrawingArray(0);

  anchor = getAnchorWithGraphic(drawing, "samplePict.jpeg", true /*behind text*/);

  drawing.setAnchorArray(new CTAnchor[]{anchor});
  drawing.removeInline(0);
  run = paragraph.createRun();
  run.setText("The above picture is behind the text. ");

  paragraph = doc.createParagraph();

  //in front of text
  paragraph = doc.createParagraph();
  run = paragraph.createRun();
  in = new FileInputStream("samplePict.jpeg");
  run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(150), Units.toEMU(40));
  in.close();  
  drawing = run.getCTR().getDrawingArray(0);

  anchor = getAnchorWithGraphic(drawing, "samplePict.jpeg", false /*not behind text*/);

  drawing.setAnchorArray(new CTAnchor[]{anchor});
  drawing.removeInline(0);
  run = paragraph.createRun();
  run.setText("The above picture is in front of the text. ");

  paragraph = doc.createParagraph();

  doc.write(new FileOutputStream("CreateWordImagesBehindAndInFrontText.docx"));
  doc.close();

 }
}

【讨论】:

  • 我赞成你的回答。但是 - Office Open XML 是 MS Word 已有 11 年历史的文件格式,并且换行文本在 MS Word 中也存在很长时间了,这是一个重要的功能,没什么特别的。因此,在 POI 中实现这种格式的唯一方法是通过 hacking XML(这里 hacking 我只是指太低级别的访问)这一事实是 POI 库的耻辱。
  • @Honza Zidek:好吧,必须有人去做丑陋的低级事情。即使您使用的库会在内部执行此操作并隐藏,您也必须了解这些事情。编程库的用户与应用程序用户不是同一类用户,而是程序员。他们对整个软件产品负责。这包括使用过的库,除非在库的生产者和您(使用它的程序员)之间签订有保修条款的合同。我怀疑你会有这样的apache poi ;-)。
  • POI 缺少用于您需要在 MS Word 中执行的常见操作的高级 API 这一事实有何变化?而且我一直明白,API 的主要目的是添加一个额外的抽象层,这样 API 的用户就不必关心实现细节。对 Apache POI 没有充分完成他们的任务感到羞耻 :) (考虑到 图片换行选项 功能从用户的角度来看并不是什么特别的东西)。
猜你喜欢
  • 1970-01-01
  • 2021-08-06
  • 2012-07-25
  • 1970-01-01
  • 2020-02-27
  • 1970-01-01
  • 1970-01-01
  • 2020-12-13
  • 2012-03-04
相关资源
最近更新 更多