Javaでプレゼンテーションのシェイプをカスタマイズ

編集ポイントを使用してシェイプを変更する

正方形を考えてみましょう。PowerPoint で 編集ポイント を使用すると、次のことができます

  • 正方形の角を内側または外側に動かす
  • 角または点の曲率を指定する
  • 正方形に新しい点を追加する
  • 正方形上の点を操作するなど

本質的に、これらの操作は任意のシェイプに対して実行できます。編集ポイントを使用すると、シェイプを変更したり、既存のシェイプから新しいシェイプを作成したりできます。

シェイプ編集のヒント

overview_image

編集ポイントを使用して PowerPoint のシェイプを編集し始める前に、シェイプに関して以下の点を考慮するとよいでしょう:

  • シェイプ(またはそのパス)は閉じている場合と開いている場合があります。
  • シェイプが閉じている場合、開始点や終了点がありません。シェイプが開いている場合、開始点と終了点があります。
  • すべてのシェイプは、少なくとも 2 つのアンカーポイントが線でつながれた構造です。
  • 線は直線または曲線のいずれかです。アンカーポイントが線の性質を決定します。
  • アンカーポイントは、コーナーポイント、ストレートポイント、スムーズポイントとして存在します:
    • コーナーポイントは、2 本の直線が角度を持って結合する点です。
    • スムーズポイントは、2 本のハンドルが同一直線上にあり、線分が滑らかな曲線で結合する点です。この場合、すべてのハンドルはアンカーポイントから等距離に分離しています。
    • ストレートポイントは、2 本のハンドルが同一直線上にあり、線分が滑らかな曲線で結合する点です。この場合、ハンドルはアンカーポイントから等距離である必要はありません。
  • アンカーポイントを移動または編集(線の角度が変わります)することで、シェイプの見た目を変更できます。

編集ポイントを使用して PowerPoint のシェイプを編集するには、Aspose.SlidesGeometryPath クラスと IGeometryPath インターフェイスを提供します。

シンプルな編集操作

この Java コードは次の方法を示します

線を追加 パスの末尾に

public void lineTo(java.awt.geom.Point2D.Float point);
public void lineTo(float x, float y);

線を追加 パスの指定位置に:

public void lineTo(java.awt.geom.Point2D.Float point, long index);
public void lineTo(float x, float y, long index);

3次ベジェ曲線を追加 パスの末尾に:

public void cubicBezierTo(java.awt.geom.Point2D.Float point1, java.awt.geom.Point2D.Float point2, java.awt.geom.Point2D.Float point3);
public void cubicBezierTo(float x1, float y1, float x2, float y2, float x3, float y3);

3次ベジェ曲線を追加 パスの指定位置に:

public void cubicBezierTo(java.awt.geom.Point2D.Float point1, java.awt.geom.Point2D.Float point2, java.awt.geom.Point2D.Float point3, long index);
public void cubicBezierTo(float x1, float y1, float x2, float y2, float x3, float y3, long index);

2次ベジェ曲線を追加 パスの末尾に:

public void quadraticBezierTo(java.awt.geom.Point2D.Float point1, java.awt.geom.Point2D.Float point2);
public void quadraticBezierTo(float x1, float y1, float x2, float y2);

2次ベジェ曲線を追加 パスの指定位置に:

public void quadraticBezierTo(java.awt.geom.Point2D.Float point1, java.awt.geom.Point2D.Float point2, long index);
public void quadraticBezierTo(float x1, float y1, float x2, float y2, long index);

指定された円弧を追加 パスへ:

public void arcTo(float width, float heigth, float startAngle, float sweepAngle);

現在の図形を閉じる パス:

public void closeFigure();

次の点の位置を設定:

public void moveTo(java.awt.geom.Point2D.Float point);
public void moveTo(float x, float y);

指定インデックスのパスセグメントを削除:

public void removeAt(int index);

シェイプにカスタムポイントを追加

  1. [GeometryShape] クラスのインスタンスを作成し、[ShapeType.Rectangle] タイプを設定します。
  2. シェイプから [GeometryPath] クラスのインスタンスを取得します。
  3. パス上の上部 2 点の間に新しい点を追加します。
  4. パス上の下部 2 点の間に新しい点を追加します。
  5. パスをシェイプに適用します。

この Java コードはシェイプにカスタムポイントを追加する方法を示します:

Presentation pres = new Presentation();
try {
    GeometryShape shape = (GeometryShape) pres.getSlides().get_Item(0).
            getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 200, 100);
    IGeometryPath geometryPath = shape.getGeometryPaths()[0];

    geometryPath.lineTo(100, 50, 1);
    geometryPath.lineTo(100, 50, 4);
    shape.setGeometryPath(geometryPath);
} finally {
    if (pres != null) pres.dispose();
}

example1_image

シェイプからポイントを削除

  1. [GeometryShape] クラスのインスタンスを作成し、[ShapeType.Heart] タイプを設定します。
  2. シェイプから [GeometryPath] クラスのインスタンスを取得します。
  3. パスのセグメントを削除します。
  4. パスをシェイプに適用します。

この Java コードはシェイプからポイントを削除する方法を示します:

Presentation pres = new Presentation();
try {
    GeometryShape shape = (GeometryShape) pres.getSlides().get_Item(0).
            getShapes().addAutoShape(ShapeType.Heart, 100, 100, 300, 300);

    IGeometryPath path = shape.getGeometryPaths()[0];
    path.removeAt(2);
    shape.setGeometryPath(path);
} finally {
    if (pres != null) pres.dispose();
}

example2_image

カスタムシェイプを作成

  1. シェイプのポイントを計算します。
  2. [GeometryPath] クラスのインスタンスを作成します。
  3. ポイントでパスを埋めます。
  4. [GeometryShape] クラスのインスタンスを作成します。
  5. パスをシェイプに適用します。

この Java はカスタムシェイプを作成する方法を示します:

List<Point2D.Float> points = new ArrayList<Point2D.Float>();

float R = 100, r = 50;
int step = 72;

for (int angle = -90; angle < 270; angle += step)
{
    double radians = angle * (Math.PI / 180f);
    double x = R * Math.cos(radians);
    double y = R * Math.sin(radians);
    points.add(new Point2D.Float((float)x + R, (float)y + R));

    radians = Math.PI * (angle + step / 2) / 180.0;
    x = r * Math.cos(radians);
    y = r * Math.sin(radians);
    points.add(new Point2D.Float((float)x + R, (float)y + R));
}

GeometryPath starPath = new GeometryPath();
starPath.moveTo(points.get(0));

for (int i = 1; i < points.size(); i++)
{
    starPath.lineTo(points.get(i));
}

starPath.closeFigure();

Presentation pres = new Presentation();
try {
    GeometryShape shape = (GeometryShape) pres.getSlides().get_Item(0).
            getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, R * 2, R * 2);

    shape.setGeometryPath(starPath);
} finally {
    if (pres != null) pres.dispose();
}

example3_image

複合カスタムシェイプを作成

  1. [GeometryShape] クラスのインスタンスを作成します。
  2. 最初の [GeometryPath] クラスのインスタンスを作成します。
  3. 二番目の [GeometryPath] クラスのインスタンスを作成します。
  4. パスをシェイプに適用します。

この Java コードは、複合カスタムシェイプを作成する方法を示します:

Presentation pres = new Presentation();
try {
    GeometryShape shape = (GeometryShape) pres.getSlides().get_Item(0).
            getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 200, 100);

    GeometryPath geometryPath0 = new GeometryPath();
    geometryPath0.moveTo(0, 0);
    geometryPath0.lineTo(shape.getWidth(), 0);
    geometryPath0.lineTo(shape.getWidth(), shape.getHeight()/3);
    geometryPath0.lineTo(0, shape.getHeight() / 3);
    geometryPath0.closeFigure();

    GeometryPath geometryPath1 = new GeometryPath();
    geometryPath1.moveTo(0, shape.getHeight()/3 * 2);
    geometryPath1.lineTo(shape.getWidth(), shape.getHeight() / 3 * 2);
    geometryPath1.lineTo(shape.getWidth(), shape.getHeight());
    geometryPath1.lineTo(0, shape.getHeight());
    geometryPath1.closeFigure();

    shape.setGeometryPaths(new GeometryPath[] { geometryPath0, geometryPath1});
} finally {
    if (pres != null) pres.dispose();
}

example4_image

曲線コーナー付きカスタムシェイプを作成

この Java コードは、内向きの曲線コーナーを持つカスタムシェイプを作成する方法を示します;

float shapeX = 20f;
float shapeY = 20f;
float shapeWidth = 300f;
float shapeHeight = 200f;

float leftTopSize = 50f;
float rightTopSize = 20f;
float rightBottomSize = 40f;
float leftBottomSize = 10f;

Presentation pres = new Presentation();
try {
    IAutoShape childShape = pres.getSlides().get_Item(0).getShapes().addAutoShape(
            ShapeType.Custom, shapeX, shapeY, shapeWidth, shapeHeight);

    GeometryPath geometryPath = new GeometryPath();

    Point2D.Float point1 = new Point2D.Float(leftTopSize, 0);
    Point2D.Float point2 = new Point2D.Float(shapeWidth - rightTopSize, 0);
    Point2D.Float point3 = new Point2D.Float(shapeWidth, shapeHeight - rightBottomSize);
    Point2D.Float point4 = new Point2D.Float(leftBottomSize, shapeHeight);
    Point2D.Float point5 = new Point2D.Float(0, leftTopSize);

    geometryPath.moveTo(point1);
    geometryPath.lineTo(point2);
    geometryPath.arcTo(rightTopSize, rightTopSize, 180, -90);
    geometryPath.lineTo(point3);
    geometryPath.arcTo(rightBottomSize, rightBottomSize, -90, -90);
    geometryPath.lineTo(point4);
    geometryPath.arcTo(leftBottomSize, leftBottomSize, 0, -90);
    geometryPath.lineTo(point5);
    geometryPath.arcTo(leftTopSize, leftTopSize, 90, -90);

    geometryPath.closeFigure();

    childShape.setGeometryPath(geometryPath);

    pres.save("output.pptx", SaveFormat.Pptx);
} finally {
    if (pres!= null) pres.dispose();
}

シェイプジオメトリが閉じているか確認

閉じたシェイプは、すべての辺が接続され、隙間のない単一の境界を形成したものとして定義されます。このようなシェイプは、単純な幾何形状または複雑なカスタム輪郭のいずれかです。次のコード例は、シェイプジオメトリが閉じているかどうかをチェックする方法を示します:

boolean isGeometryClosed(IGeometryShape geometryShape)
{
    Boolean isClosed = null;

    for (IGeometryPath geometryPath : geometryShape.getGeometryPaths()) {
        int dataLength = geometryPath.getPathData().length;
        if (dataLength == 0)
            continue;

        IPathSegment lastSegment = geometryPath.getPathData()[dataLength - 1];
        isClosed = lastSegment.getPathCommand() == PathCommandType.Close;

        if (isClosed == false)
            return false;
    }

    return isClosed == true;
}

GeometryPath を java.awt.Shape に変換

  1. [GeometryShape] クラスのインスタンスを作成します。
  2. [java.awt.Shape] クラスのインスタンスを作成します。
  3. ShapeUtil を使用して、[java.awt.Shape] インスタンスを [GeometryPath] インスタンスに変換します。
  4. パスをシェイプに適用します。

この Java コードは、上記手順の実装であり、GeometryPath から GraphicsPath への変換プロセスを示します:

Presentation pres = new Presentation();
try {
    // 新しいシェイプを作成
    GeometryShape shape = (GeometryShape)pres.getSlides().get_Item(0).
            getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 300, 100);

    // シェイプのジオメトリパスを取得
    IGeometryPath originalPath = shape.getGeometryPaths()[0];
    originalPath.setFillMode(PathFillModeType.None);

    // テキスト付きの新しいグラフィックパスを作成
    Shape graphicsPath;
    Font font = new java.awt.Font("Arial", Font.PLAIN, 40);
    String text = "Text in shape";
    BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = img.createGraphics();

    try
    {
        GlyphVector glyphVector = font.createGlyphVector(g2.getFontRenderContext(), text);
        graphicsPath = glyphVector.getOutline(20f, ((float) -glyphVector.getVisualBounds().getY()) + 10);
    }
    finally {
        g2.dispose();
    }

    // グラフィックパスをジオメトリパスに変換
    IGeometryPath textPath = ShapeUtil.graphicsPathToGeometryPath(graphicsPath);
    textPath.setFillMode(PathFillModeType.Normal);

    // 新しいジオメトリパスと元のジオメトリパスの組み合わせをシェイプに設定
    shape.setGeometryPaths(new IGeometryPath[] { originalPath, textPath });
} finally {
    if (pres != null) pres.dispose();
}

example5_image

FAQ

ジオメトリを置き換えた後、塗りつぶしとアウトラインはどうなりますか?

スタイルはシェイプに残り、輪郭だけが変更されます。塗りつぶしとアウトラインは自動的に新しいジオメトリに適用されます。

ジオメトリと共にカスタムシェイプを正しく回転させるにはどうすればよいですか?

setRotation メソッドを使用します。ジオメトリはシェイプにバインドされているため、シェイプと共に回転します。

カスタムシェイプを画像に変換して結果を「固定」できますか?

はい。必要な slide エリアまたは shape 自体をラスタ形式でエクスポートできます。これにより、重いジオメトリの作業が容易になります。