最新的Word 版本使用wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" 表示形状。但是低级别的ooxml-schemas和apache poi都不支持它。只有在非常底层的基础上直接操作 XML 才有可能。
但Word 也使用Vector Markup Language (VML) 作为后备。这可以通过ooxml-schemas-1.4 提供com.microsoft.schemas.vml 来完成。这也将是最兼容的方式。
您可以阅读有关Vector Markup Language (VML) 的信息。最简单的标注形状如下XML
<w:pict>
<v:shape coordsize="21600,21600" adj="7200,21600" path="m 1,1 l 1,14400, 7200,14400, @0,@1, 14400,14400, 21600,14400, 21600,1 x e" style="position:absolute;margin-left:1in;margin-top:-150px;width:100px;height:150px;z-index:251659264;visibility:visible;rotation:0;" strokecolor="#0000FF" fillcolor="yellow">
<v:formulas>
<v:f eqn="val #0"/>
<v:f eqn="val #1"/>
</v:formulas>
<v:handles><v:h position="#0,#1"/></v:handles>
<v:path textboxrect="1,1,21600,14400"/>
<v:textbox>
<w:txbxContent><w:p><w:r><w:t>The callout</w:t><w:br/></w:r><w:r><w:t>text...</w:t><w:br/></w:r></w:p>
</w:txbxContent>
</v:textbox>
</v:shape>
</w:pict>
如您所见,形状的轮廓由path 确定。因此,如果了解path 的工作原理,也可以创建其他形状。
创建标注形状的示例代码:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTxbxContent;
import com.microsoft.schemas.vml.CTGroup;
import com.microsoft.schemas.vml.CTShape;
import com.microsoft.schemas.vml.CTFormulas;
import com.microsoft.schemas.vml.CTTextbox;
import org.w3c.dom.Node;
public class CreateWordShapes {
public static void appendCalloutShape(XWPFRun run, String left, String top, String width, String height,
String strokecolor, String fillcolor, String calloutext, boolean hashandles) throws Exception {
CTGroup ctGroup = CTGroup.Factory.newInstance();
CTShape ctShape = ctGroup.addNewShape();
ctShape.setCoordsize("21600,21600");
if (hashandles) { //is not Libreoffice Writer compatible
ctShape.setAdj("" + 21600*1/3 + ",21600");
CTFormulas cTFormulas = ctShape.addNewFormulas();
cTFormulas.addNewF().setEqn("val #0");
cTFormulas.addNewF().setEqn("val #1");
ctShape.setPath2("m 1,1 l 1," + 21600*2/3 + ", " + 21600*1/3 + "," + 21600*2/3 + ", @0,@1, " + 21600*2/3 + "," + 21600*2/3 + ", 21600," + 21600*2/3 + ", 21600,1 x e");
ctShape.addNewHandles().addNewH().setPosition("#0,#1");
} else { // is Libreoffice Writer compatible
ctShape.setPath2("m 1,1 l 1," + 21600*2/3 + ", " + 21600*1/3 + "," + 21600*2/3 + ", " + 21600*1/3 + ",21600, " + 21600*2/3 + "," + 21600*2/3 + ", 21600," + 21600*2/3 + ", 21600,1 x e");
}
ctShape.addNewPath().setTextboxrect("1,1,21600," + 21600*2/3);
ctShape.setStyle("position:absolute;margin-left:" + left + ";margin-top:" + top + ";width:" + width + ";height:" + height + ";z-index:251659264;visibility:visible;rotation:0;");
ctShape.setStrokecolor(strokecolor);
ctShape.setFillcolor(fillcolor);
CTTextbox cTTextbox = ctShape.addNewTextbox();
CTTxbxContent ctTxbxContent = cTTextbox.addNewTxbxContent();
XWPFParagraph textboxparagraph = new XWPFParagraph(ctTxbxContent.addNewP(), run.getDocument());
XWPFRun textboxrun = null;
String[] lines = calloutext.split("\n");
for (int i = 0; i < lines.length; i++) {
textboxrun = textboxparagraph.createRun();
textboxrun.setText(lines[i]);
textboxrun.addBreak();
}
Node ctGroupNode = ctGroup.getDomNode();
CTPicture ctPicture = CTPicture.Factory.parse(ctGroupNode);
CTR cTR = run.getCTR();
cTR.addNewPict();
cTR.setPictArray(0, ctPicture);
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("Callout shape over text: Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor Lorem ipsum semit dolor.");
appendCalloutShape(run, "200pt", "0", "1in", "1in", "black", "#00FF00", "The callout\ntext...", false);
paragraph = document.createParagraph();
paragraph = document.createParagraph();
paragraph = document.createParagraph();
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Callout shape:");
appendCalloutShape(run, "1in", "-150px", "100px", "150px", "#0000FF", "yellow", "The callout\ntext...", true);
FileOutputStream out = new FileOutputStream("test.docx");
document.write(out);
out.close();
document.close();
}
}
结果:
注意:这需要 apache poi 4.0.1 和 ooxml-schemas-1.4.jar 在类路径中。