Kustomisasi Bentuk Presentasi di Java
Gambaran Umum
Artikel ini menjelaskan cara menyesuaikan bentuk presentasi di Aspose.Slides dengan menyunting geometri bentuk melalui titik penyuntingan dan jalur geometri. Ini menunjukkan cara bekerja dengan GeometryPath dan IGeometryPath untuk memodifikasi bentuk yang ada, melakukan operasi penyuntingan jalur dasar, menambah atau menghapus titik, dan menerapkan geometri yang diperbarui kembali ke sebuah bentuk.
Itu juga mendemonstrasikan cara membuat bentuk kustom dan komposit, membangun bentuk dengan sudut melengkung, menentukan apakah geometri bentuk tertutup, memeriksa elemen bentuk, dan mengonversi outline teks Java AWT menjadi jalur geometri.
Ubah Bentuk dengan Titik Penyuntingan
Di PowerPoint, Anda dapat menggunakan Edit Points untuk memodifikasi sebuah kotak:
- Pindahkan sudut ke dalam atau ke luar.
- Sesuaikan kelengkungan pada sebuah titik.
- Tambahkan titik baru.
Menyunting titik memungkinkan Anda memodifikasi kontur bentuk atau menggunakan bentuk yang ada sebagai dasar untuk bentuk baru.
Tips Penyuntingan Bentuk

Saat menyunting bentuk PowerPoint, ingat konsep-konsep berikut:
- Sebuah bentuk (atau jalurnya) dapat berupa tertutup atau terbuka.
- Jalur bentuk terdiri dari titik jangkar yang terhubung oleh segmen.
- Segmen dapat lurus atau melengkung. Titik jangkar dan pegangan kontrol menentukan bentuknya.
- Titik jangkar ada sebagai titik sudut, titik lurus, atau titik halus:
- Pada titik sudut, segmen yang berdekatan dapat bertemu dengan satu sudut.
- Pada titik halus, dua pegangan kontrol sejajar dan berjarak sama dari titik jangkar.
- Pada titik lurus, dua pegangan kontrol sejajar tetapi dapat memiliki jarak yang berbeda dari titik jangkar.
- Memindahkan titik jangkar atau menyesuaikan pegangan mereka mengubah kontur bentuk.
Untuk menyunting bentuk PowerPoint melalui titik penyuntingan, Aspose.Slides menyediakan kelas GeometryPath dan antarmuka IGeometryPath.
- Sebuah instance GeometryPath mewakili jalur geometri dari objek IGeometryShape.
- Untuk mengambil GeometryPath dari instance IGeometryShape, Anda dapat menggunakan metode IGeometryShape.getGeometryPaths .
- Untuk menetapkan GeometryPath ke sebuah bentuk, Anda dapat menggunakan metode ini: IGeometryShape.setGeometryPath untuk bentuk dengan satu jalur dan IGeometryShape.setGeometryPaths untuk bentuk dengan beberapa jalur.
- Untuk menambahkan segmen, Anda dapat menggunakan metode di bawah IGeometryPath .
- Dengan menggunakan metode IGeometryPath.setStroke dan IGeometryPath.setFillMode, Anda dapat mengatur tampilan untuk sebuah jalur geometri.
- Dengan menggunakan metode IGeometryPath.getPathData , Anda dapat mengambil jalur geometri dari sebuah GeometryShape sebagai array segmen jalur.
- Untuk mengakses opsi kustomisasi geometri bentuk tambahan, Anda dapat membaca sebuah java.awt.Shape melalui PathIterator‑nya dan memutar ulang segmen‑segmen tersebut pada sebuah GeometryPath .
Operasi Penyuntingan Sederhana
Gunakan metode berikut untuk menyunting sebuah jalur geometri. Overload yang menerima indeks menyisipkan segmen pada posisi berbasis nol dalam array segmen jalur.
| Operasi | Metode |
|---|---|
| Tambahkan atau sisipkan garis lurus. | GeometryPath.lineTo |
| Tambahkan atau sisipkan kurva Bézier kubik dengan dua titik kontrol dan satu titik akhir. | GeometryPath.cubicBezierTo |
| Tambahkan atau sisipkan kurva Bézier kuadratik dengan satu titik kontrol dan satu titik akhir. | GeometryPath.quadraticBezierTo |
| Tambahkan busur elips dengan dimensi dan sudut yang ditentukan dalam derajat. | GeometryPath.arcTo |
| Tutup gambar saat ini dengan menghubungkan titik akhirnya ke titik awalnya. | GeometryPath.closeFigure |
| Atur titik awal sebuah gambar. | GeometryPath.moveTo |
| Hapus segmen pada indeks berbasis nol. | GeometryPath.removeAt |
Tambah Titik Kustom ke Bentuk
Contoh ini menyisipkan dua titik ke dalam bentuk persegi panjang menggunakan GeometryPath.lineTo dan menerapkan jalur yang diedit dengan IGeometryShape.setGeometryPath . Koordinat bersifat lokal untuk bentuk: kedua titik baru berada di tengahnya, 100 poin dari kiri dan 50 poin dari atas. Indeks segmen 1 dan 4 menempatkannya pada tepi atas dan bawah, menarik tepi‑tepi tersebut ke dalam.
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.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 {
presentation.dispose();
}

Hapus Titik dari Bentuk
Contoh ini mengubah outline berbentuk hati dengan menghapus segmen pada indeks berbasis nol 2 menggunakan GeometryPath.removeAt . Menerapkan jalur yang dimodifikasi dengan IGeometryShape.setGeometryPath memperbarui kontur bentuk.
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Heart, 100, 100, 300, 300);
IGeometryPath path = shape.getGeometryPaths()[0];
path.removeAt(2);
shape.setGeometryPath(path);
} finally {
presentation.dispose();
}

Buat Bentuk Kustom
Contoh ini membangun bintang lima sudut dengan GeometryPath . Jari‑jari luar dan dalam bergantian 100 dan 50 poin menentukan puncak dan cekungan; langkah 72 derajat menempatkan kelima puncak secara merata. Jalur ditutup dengan GeometryPath.closeFigure dan diterapkan ke bentuk persegi panjang menggunakan IGeometryShape.setGeometryPath , menggantikan outline‑nya.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
List<Point2D.Float> points = new ArrayList<>();
float outerRadius = 100f;
float innerRadius = 50f;
int angleStep = 72;
for (int angle = -90; angle < 270; angle += angleStep)
{
double radians = angle * (Math.PI / 180f);
double x = outerRadius * Math.cos(radians);
double y = outerRadius * Math.sin(radians);
Point2D.Float point = new Point2D.Float((float)x + outerRadius, (float)y + outerRadius);
points.add(point);
radians = Math.PI * (angle + angleStep / 2) / 180.0;
x = innerRadius * Math.cos(radians);
y = innerRadius * Math.sin(radians);
point = new Point2D.Float((float)x + outerRadius, (float)y + outerRadius);
points.add(point);
}
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 presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, outerRadius * 2, outerRadius * 2);
shape.setGeometryPath(starPath);
} finally {
presentation.dispose();
}

Buat Bentuk Kustom Komposit
Contoh ini mendefinisikan dua objek GeometryPath tertutup untuk sepertiga atas dan bawah sebuah bentuk. Menerapkan kedua jalur dengan IGeometryShape.setGeometryPaths membuat satu bentuk komposit dengan celah di sepertiga tengahnya.
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 200, 100);
GeometryPath topPath = new GeometryPath();
topPath.moveTo(0, 0);
topPath.lineTo(shape.getWidth(), 0);
topPath.lineTo(shape.getWidth(), shape.getHeight() / 3);
topPath.lineTo(0, shape.getHeight() / 3);
topPath.closeFigure();
GeometryPath bottomPath = new GeometryPath();
bottomPath.moveTo(0, shape.getHeight() / 3 * 2);
bottomPath.lineTo(shape.getWidth(), shape.getHeight() / 3 * 2);
bottomPath.lineTo(shape.getWidth(), shape.getHeight());
bottomPath.lineTo(0, shape.getHeight());
bottomPath.closeFigure();
shape.setGeometryPaths(new GeometryPath[] { topPath, bottomPath });
} finally {
presentation.dispose();
}

Buat Bentuk Kustom dengan Sudut Melengkung
Contoh ini menggabungkan segmen lurus dengan GeometryPath.arcTo untuk membuat bentuk dengan sudut melengkung ke dalam. Setiap ukuran sudut menetapkan lebar dan tinggi busur dalam poin, dan sweep –90 derajat menggambar seperempat elips berlawanan arah jarum jam. Jalur yang selesai diterapkan dengan IGeometryShape.setGeometryPath , dan presentasi disimpan dalam format PPTX.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
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 presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Custom, shapeX, shapeY, shapeWidth, shapeHeight);
Point2D.Float topLeft = new Point2D.Float(leftTopSize, 0);
Point2D.Float topRight = new Point2D.Float(shapeWidth - rightTopSize, 0);
Point2D.Float rightBottom = new Point2D.Float(shapeWidth, shapeHeight - rightBottomSize);
Point2D.Float bottomLeft = new Point2D.Float(leftBottomSize, shapeHeight);
Point2D.Float leftTop = new Point2D.Float(0, leftTopSize);
GeometryPath geometryPath = new GeometryPath();
geometryPath.moveTo(topLeft);
geometryPath.lineTo(topRight);
geometryPath.arcTo(rightTopSize, rightTopSize, 180, -90);
geometryPath.lineTo(rightBottom);
geometryPath.arcTo(rightBottomSize, rightBottomSize, -90, -90);
geometryPath.lineTo(bottomLeft);
geometryPath.arcTo(leftBottomSize, leftBottomSize, 0, -90);
geometryPath.lineTo(leftTop);
geometryPath.arcTo(leftTopSize, leftTopSize, 90, -90);
geometryPath.closeFigure();
shape.setGeometryPath(geometryPath);
presentation.save("output.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
Temukan Apakah Geometri Bentuk Tertutup
Penolong berikut memeriksa apakah setiap jalur geometri yang tidak kosong diakhiri dengan segmen penutup. Ia membaca IGeometryPath.getPathData dan membandingkan perintah IPathSegment.getPathCommand akhir dengan PathCommandType.Close . Ia mengembalikan false bila tidak ada jalur yang tidak kosong. Pemeriksaan ini hanya memeriksa perintah akhir setiap jalur; tidak memeriksa setiap sub‑gambar di dalam jalur. Contoh mencetak true untuk sebuah persegi panjang.
import com.aspose.slides.*;
class GeometryInspector {
boolean isGeometryClosed(IGeometryShape geometryShape) {
boolean hasNonemptyPath = false;
for (IGeometryPath geometryPath : geometryShape.getGeometryPaths()) {
IPathSegment[] segments = geometryPath.getPathData();
if (segments.length == 0) {
continue;
}
hasNonemptyPath = true;
IPathSegment lastSegment = segments[segments.length - 1];
if (lastSegment.getPathCommand() != PathCommandType.Close) {
return false;
}
}
return hasNonemptyPath;
}
}
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 200, 100);
GeometryInspector inspector = new GeometryInspector();
boolean closed = inspector.isGeometryClosed(shape);
System.out.println(closed);
} finally {
presentation.dispose();
}
Ekstrak dan Periksa Elemen Bentuk
Gunakan IGeometryShape.createShapeElements untuk memeriksa bentuk yang ada sebagai elemen yang berisi titik‑titik jalur dan tipe‑tipe titik. Cast setiap IShapeElement yang dikembalikan ke ShapeElement untuk mengambil array titik dan tipe melalui metode getPathPoints dan getPathTypes . Representasi ini berguna untuk analisis kontur atau mengirimkan geometri ke alat menggambar kustom.
Contoh membuka input.pptx, menemukan bentuk geometri pertama langsung pada slide pertama, dan mencetak segmen‑segmen jalurnya. Gunakan presentasi yang berisi bentuk dengan segmen lurus dan melengkung untuk melihat kedua jenis output. Ia tidak mencari di dalam grup.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
Presentation presentation = new Presentation("input.pptx");
try {
ISlide slide = presentation.getSlides().get_Item(0);
IGeometryShape shape = null;
for (IShape candidate : slide.getShapes()) {
if (candidate instanceof IGeometryShape) {
shape = (IGeometryShape) candidate;
break;
}
}
if (shape == null) {
System.out.println("No geometry shape found on the first slide.");
} else {
for (IShapeElement element : shape.createShapeElements()) {
ShapeElement shapeElement = (ShapeElement) element;
Point2D.Float[] points = shapeElement.getPathPoints();
byte[] types = shapeElement.getPathTypes();
System.out.println("Shape element:");
for (int i = 0; i < points.length; i++) {
int pointType = types[i] & 0x07; // Pertahankan jenis segmen, kecuali flag.
switch (pointType) {
case 0:
System.out.println("Start figure at " + points[i]);
break;
case 1:
System.out.println("Line to " + points[i]);
break;
case 3:
System.out.println("Cubic Bezier: controls " + points[i] + ", " + points[i + 1] + "; end " + points[i + 2]);
i += 2; // Consume both control points and the endpoint.
break;
}
if ((types[i] & 0x80) != 0) {
System.out.println("Close subpath back to its starting point.");
}
}
}
}
} finally {
presentation.dispose();
}
Array‑array tersebut berkorespondensi berdasarkan indeks: points[i] adalah sebuah titik dan types[i] menjelaskan perannya. Tipe 0 memulai sebuah gambar, dan tipe 1 menggambar garis dari titik sebelumnya ke titik saat ini. Segmen Bézier kubik dimulai pada titik akhir sebelumnya dan menggunakan tiga entri tipe 3 berurutan: dua titik kontrol diikuti oleh titik akhir baru. Loop mengonsumsi ketiga entri tersebut sekaligus dan memeriksa titik akhir untuk penutupan.
Tipe‑tipe titik juga mengandung flag. Mask dengan 0x07 untuk mengidentifikasi tipe segmen, dan uji 0x80 secara terpisah untuk mendeteksi sub‑path tertutup. Misalnya, 129 (0x81) berarti titik akhir garis yang menutup sub‑path, dan 131 (0x83) berarti titik akhir Bézier yang menutup satu. Java menyimpan flag ini dalam byte bertanda; masking mempertahankan nilai bit yang dimaksud. Membandingkan nilai mentah hanya dengan 1 atau 3 akan melewatkan kasus ini. Flag lain, seperti dash (0x10) dan marker (0x20), tidak mengubah tipe segmen dasar.
Koordinat dan transformasi. Titik diukur dalam poin (1/72 inci), dengan X meningkat ke kanan dan Y meningkat ke bawah. Untuk bentuk yang tidak dikelompokkan, koordinat yang diekstrak sudah mencakup posisi yang dikembalikan oleh getX dan getY serta mencerminkan lebar dan tinggi saat ini. Misalnya, sebuah persegi panjang tak berotasi pada (100, 200) dengan ukuran 120 × 80 memiliki batas kontur (100, 200)–(220, 280). Jangan menambahkan posisi bentuk lagi. Kurangi X dan Y‑nya untuk memperoleh koordinat relatif terhadap kerangka tak berotasi.
Titik‑titik yang diekstrak tidak menerapkan rotasi bentuk, yang dikembalikan oleh getRotation , atau flip horizontal dan vertikal. Untuk mereproduksi kontur yang ditampilkan, terapkan transformasi tersebut di sekitar pusat bentuk. Untuk bentuk yang dikelompokkan, juga perhitungkan pemetaan koordinat grup dan transformasinya; jangan mengasumsikan bahwa titik yang diekstrak adalah koordinat slide yang dirender akhir atau menerapkan translasi atau skala dua kali bila sudah tercermin dalam kerangka anak.
Inspeksi vs penyuntingan. Array yang diekstrak mendeskripsikan kontur; mengubahnya tidak memperbarui bentuk asli. Pilih pendekatan ini ketika analisis atau kode menggambar Anda memerlukan array titik/tipe. Gunakan getGeometryPaths bila Anda membutuhkan perintah geometri dalam sistem koordinat lokal bentuk atau ingin menyunting geometri tersebut. Terapkan jalur yang diedit melalui setGeometryPath atau setGeometryPaths .
Konversi Bentuk Java AWT ke GeometryPath
Contoh ini menggabungkan outline persegi panjang dengan teks yang dikonversi menjadi geometri. Metode setFillMode pada outline menonaktifkan isinya. Sebuah GlyphVector membuat outline teks dalam sebuah java.awt.Shape. PathIterator‑nya menyuplai segmen move, line, quadratic, cubic, dan closing, yang contoh ini memutar ulang pada sebuah GeometryPath .
Teks menggunakan font Arial 40 poin. Outline dipindahkan 20 poin secara horizontal dan diposisikan dengan bagian atas visualnya 10 poin di bawah tepi atas bentuk. Jalur teks diisi, sementara persegi panjang asli tetap menjadi outline. Menerapkan kedua jalur dengan IGeometryShape.setGeometryPaths menghasilkan satu bentuk yang berisi persegi panjang dan teks.
import com.aspose.slides.*;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.font.GlyphVector;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.geom.PathIterator;
import java.awt.image.BufferedImage;
Presentation presentation = new Presentation();
try {
// Buat bentuk baru
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 300, 100);
// Dapatkan jalur geometri bentuk
IGeometryPath originalPath = shape.getGeometryPaths()[0];
originalPath.setFillMode(PathFillModeType.None);
// Buat jalur grafis baru dengan teks
Shape graphicsPath;
Font font = new Font("Arial", Font.PLAIN, 40);
String text = "Text in shape";
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
try
{
FontRenderContext fontContext = graphics.getFontRenderContext();
GlyphVector glyphVector = font.createGlyphVector(fontContext, text);
Rectangle2D textBounds = glyphVector.getVisualBounds();
float baseline = (float) -textBounds.getY() + 10;
graphicsPath = glyphVector.getOutline(20f, baseline);
}
finally {
graphics.dispose();
}
// Konversi jalur grafis ke jalur geometri
IGeometryPath textPath = new GeometryPath();
PathIterator pathIterator = graphicsPath.getPathIterator(null);
float[] points = new float[6];
while (!pathIterator.isDone())
{
int segmentType = pathIterator.currentSegment(points);
switch (segmentType)
{
case PathIterator.SEG_MOVETO:
textPath.moveTo(points[0], points[1]);
break;
case PathIterator.SEG_LINETO:
textPath.lineTo(points[0], points[1]);
break;
case PathIterator.SEG_QUADTO:
textPath.quadraticBezierTo(points[0], points[1], points[2], points[3]);
break;
case PathIterator.SEG_CUBICTO:
textPath.cubicBezierTo(points[0], points[1], points[2], points[3], points[4], points[5]);
break;
case PathIterator.SEG_CLOSE:
textPath.closeFigure();
break;
}
pathIterator.next();
}
textPath.setFillMode(PathFillModeType.Normal);
// Atur kombinasi jalur geometri baru dan jalur geometri asal ke bentuk
shape.setGeometryPaths(new IGeometryPath[] { originalPath, textPath });
} finally {
presentation.dispose();
}

FAQ
Apa yang akan terjadi pada isian dan kontur setelah mengganti geometri?
Gaya tetap melekat pada bentuk; hanya kontur yang berubah. Isian dan kontur otomatis diterapkan pada geometri baru.
Bagaimana cara memutar bentuk kustom dengan benar bersama geometri nya?
Gunakan metode setRotation pada bentuk; geometri berputar bersama bentuk karena terikat pada sistem koordinat bentuk itu sendiri.
Bisakah saya mengkonversi bentuk kustom menjadi gambar untuk “mengunci” hasilnya?
Ya. Ekspor area slide yang diperlukan atau shape itu sendiri ke format raster; ini memudahkan pekerjaan lanjutan dengan geometri yang kompleks.