首页 > 解决方案 > 在 PPTX 中绘制圆弧

问题描述

我想使用 Apache POI 绘制弧线。为此,尚不清楚我需要哪个 API 来设置用于绘图的点。

protected void draw(final XMLSlideShow ppt, final XSLFGroupShape containerGroupShape) {
    final XSLFFreeformShape shape = containerGroupShape.createFreeform();

    // Positioning
    double x = container.toPptX(pos.getX());
    double y = container.toPptY(pos.getY());
    double w = container.toPpt(pos.getW());
    double h = container.toPpt(pos.getH());

    // Set shape type & anchor
    shape.setShapeType(ShapeType.ARC);
    shape.setAnchor(new Rectangle2D.Double(x, y, w, h));

    shape.setFillColor(toAwtColor(fillColor));
    shape.setLineColor(toAwtColor(strokeColor));

    // Which API do I need here?
    Path2D.Double gp = new Path2D.Double();
    gp.moveTo(0, 0);
    gp.lineTo(10, 10);
    gp.closePath();
    shape.setPath(gp);
}

(注意:这是负责在 pptx 文件中创建弧的方法)

我知道 Polygons 使用Path2D.Double,但是那种不起作用(或者我的示例数据是错误的?)。我什至尝试查看 VCS 存储库,但我没有运气找到任何使用弧形的测试用例

有人知道弧数据(起始角度、弧长)是如何配置的吗?

编辑:

为避免将来混淆:

标签: javaapache-poipowerpoint

解决方案


如前所述您可以创建XSLFSimpleShape类型ShapeType.ARC。那里的默认弧是锚点描述的矩形中的四分之一圆。或者您使用路径创建自由形式的形状。但是你不能同时做这两个。

如果您创建一个默认值ShapeType.ARC并查看它,PowerPoint您将看到两个用于设置开始和结束角度的手柄。操作它们,然后保存文件,然后简单地解压缩*.pptx文件并查看/ppt/slides/slide1.xml. 在那里你会发现

<a:avLst>
 <a:gd name="adj1" fmla="val [startAngle]"/>
 <a:gd name="adj2" fmla="val [endAngle]"/>
</a:avLst>

所以我们需要AvLstwhich 是 a CTGeomGuideList,然后我们可以以编程方式操作这两个句柄(调整)。

另外我们必须知道的唯一一件事是开始角度和结束角度的可能值是多少。一些测试设置导致 0 点位于 3 点钟位置,整圈为 21,600,000。所以6点钟位置是5,400,000,9点钟位置是10,800,000,12点钟位置是16,200,000。这些值与整个圆的大小无关,如果矩形不是正方形,那么这些值甚至是正确的,因此弧是椭圆的。

下面的代码展示了如何使用它来绘制弧线ShapeType.ARC

它还展示了如何XSLFFreeformShape用于绘制圆弧。这里最简单的方法是绘制贝塞尔弧,因为java.awt.geom.Path2D.Double已经提供了创建贝塞尔路径的方法。

import java.io.FileOutputStream;

import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.sl.usermodel.*;

import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuideList;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;

import java.awt.Rectangle;
import java.awt.Color;

import java.awt.geom.Path2D;
import java.awt.geom.Path2D.Double;

public class CreatePPTXArcShape {

 private static XSLFAutoShape createArcShape(XSLFSlide slide, Rectangle positionAndSize, 
  int startAngle, int endAngle, Color color) {

  XSLFAutoShape arcShape = ((XSLFSlide)slide).createAutoShape();
  arcShape.setShapeType(ShapeType.ARC);
  arcShape.setLineColor(color);
  arcShape.setAnchor(positionAndSize);

  startAngle = startAngle % 360;
  endAngle = endAngle % 360;

  XmlObject xmlObject = arcShape.getXmlObject();
  CTShape ctShape = (CTShape)xmlObject;
  CTGeomGuideList ctGeomGuideList = ctShape.getSpPr().getPrstGeom().getAvLst();
  CTGeomGuide ctGeomGuide = ctGeomGuideList.addNewGd();
  ctGeomGuide.setName("adj1");
  ctGeomGuide.setFmla("val " + (21600000/360*startAngle));
  ctGeomGuide = ctGeomGuideList.addNewGd();
  ctGeomGuide.setName("adj2");
  ctGeomGuide.setFmla("val " + (21600000/360*endAngle));

  return arcShape;
 }

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

  SlideShow slideShow = new XMLSlideShow();

  Slide slide = slideShow.createSlide();

  XSLFAutoShape arcShape;

  //circle arcs
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(100, 100, 100, 100), 
   0, 90, Color.BLUE); //0 degrees = 3 o'clock position, 90 degrees = 6 o'clock position, 
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(150, 100, 100, 100), 
   180, 0, Color.BLUE); //180 degrees = 9 o'clock position
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(200, 100, 100, 100), 
   270, 90, Color.BLUE); //270 degrees = 12 o'clock position
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(300, 100, 100, 100), 
   180+45, 270+45, Color.BLUE); 
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(400, 100, 100, 100), 
   0, 359, Color.BLUE); 

  //elliptic arcs
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(100, 250, 100, 50), 
   0, 90, Color.BLUE); 
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(150, 250, 100, 50), 
   180, 0, Color.BLUE); 
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(200, 250, 100, 50), 
   270, 90, Color.BLUE); 
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(300, 250, 100, 50), 
   180+45, 270+45, Color.BLUE); 
  arcShape = createArcShape((XSLFSlide)slide, new Rectangle(400, 250, 100, 50), 
   0, 359, Color.BLUE); 

  //Bézier freeform arcs
  XSLFFreeformShape bezierShape = ((XSLFSlide)slide).createFreeform();
  bezierShape.setLineColor(Color.BLUE);
  Path2D.Double path = new Path2D.Double();
  path.moveTo(100d, 400d); // x = 100px from left of slide, y = 400px from top of slide
  path.curveTo(100d, 400d, 150d, 600d, 200d, 400d); // y of middle point is greater than y of baseline => arc downwards
  bezierShape.setPath(path);

  bezierShape = ((XSLFSlide)slide).createFreeform();
  bezierShape.setLineColor(Color.BLUE);
  path = new Path2D.Double();
  path.moveTo(300d, 400d);
  path.curveTo(300d, 400d, 350d, 200d, 400d, 400d); // y of middle point is less than y of baseline => arc upwards
  bezierShape.setPath(path);

  FileOutputStream out = new FileOutputStream("CreatePPTXArcShape.pptx");
  slideShow.write(out);
  out.close();
 }
}

推荐阅读