Přizpůsobení tvarů prezentace v Java

Přehled

Tento článek vysvětluje, jak přizpůsobit tvary prezentace v Aspose.Slides úpravou geometrie tvaru pomocí úpravových bodů a geometrických cest. Ukazuje, jak pracovat s GeometryPath a IGeometryPath pro úpravu existujících tvarů, provádění základních operací úprav cest, přidávání nebo odstraňování bodů a aplikaci aktualizované geometrie zpět na tvar.

Také demonstruje, jak vytvořit vlastní a složené tvary, sestavit tvary s zakulacenými rohy, zjistit, zda je geometrie tvaru uzavřená, prozkoumat prvky tvaru a převést obrysy textu Java AWT na geometrické cesty.

Změna tvaru pomocí úpravových bodů

V PowerPointu můžete použít Edit Points (úpravové body) k úpravě čtverce:

  • Posunout roh dovnitř nebo ven.
  • Upravit zakřivení v bodě.
  • Přidat nové body.

Úprava bodů vám umožňuje měnit obrys tvaru nebo použít existující tvar jako základ pro nový.

Tipy pro úpravu tvarů

overview_image

Při úpravě tvarů v PowerPointu si pamatujte následující pojmy:

  • Tvar (nebo jeho cesta) může být buď uzavřený, nebo otevřený.
  • Cesta tvaru se skládá z kotevních bodů spojených segmenty.
  • Segment může být přímý nebo zakřivený. Kotevní body a ovládací úchyty určují jeho tvar.
  • Kotevní body existují jako rohové body, přímé body nebo hladké body:
    • U rohového bodu se sousední segmenty mohou setkat pod úhlem.
    • U hladkého bodu jsou dva ovládací úchyty zarovnány a leží ve stejné vzdálenosti od kotevního bodu.
    • U přímého bodu jsou dva ovládací úchyty zarovnány, ale mohou mít různé vzdálenosti od kotevního bodu.
  • Posunutí kotevních bodů nebo úprava jejich úchytů mění obrys tvaru.

Pro úpravu tvarů v PowerPointu pomocí úpravových bodů poskytuje Aspose.Slides třídu GeometryPath a rozhraní IGeometryPath.

Jednoduché operace úprav

Použijte následující metody k úpravě geometrické cesty. Přetížení, která přijímají index, vloží segment na danou pozici (číslo indexu je nulové‑základní) v poli segmentů cesty.

Operace Metoda
Přidat nebo vložit přímou čáru. GeometryPath.lineTo
Přidat nebo vložit kubickou Bézierovu křivku se dvěma ovládacími body a koncovým bodem. GeometryPath.cubicBezierTo
Přidat nebo vložit kvadratickou Bézierovu křivku s jedním ovládacím bodem a koncovým bodem. GeometryPath.quadraticBezierTo
Přidat eliptický oblouk se zadanými rozměry a úhly ve stupních. GeometryPath.arcTo
Uzavřít aktuální figurou propojením koncového bodu se startovacím bodem. GeometryPath.closeFigure
Nastavit počáteční bod figury. GeometryPath.moveTo
Odebrat segment na nulové‑základní pozici. GeometryPath.removeAt

Přidání vlastních bodů do tvaru

Tento příklad vloží dva body do obdélníkového tvaru pomocí GeometryPath.lineTo a aplikuje upravenou cestu pomocí IGeometryShape.setGeometryPath. Souřadnice jsou lokální k tvaru: oba nové body jsou ve středu, 100 bodů od levého okraje a 50 bodů od horního okraje. Indexy segmentů 1 a 4 je umístí na horní a spodní okraj, čímž tyto okraje vtáhnou dovnitř.

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();
}

example1_image

Odebrání bodů z tvaru

Tento příklad upraví obrys ve tvaru srdce odstraněním segmentu na nulové‑základní pozici 2 pomocí GeometryPath.removeAt. Aplikací upravené cesty pomocí IGeometryShape.setGeometryPath se aktualizuje kontura tvaru.

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();
}

example2_image

Vytvoření vlastního tvaru

Tento příklad vytvoří pěticípou hvězdu pomocí GeometryPath. Střídavé vnější a vnitřní poloměry 100 a 50 bodů definují špičky a zanoření; krok 72 stupňů rovnoměrně rozmístí pět špiček. Cesta je uzavřena pomocí GeometryPath.closeFigure a aplikována na obdélníkový tvar pomocí IGeometryShape.setGeometryPath, čímž nahradí jeho obrys.

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();
}

example3_image

Vytvoření složeného vlastního tvaru

Tento příklad definuje dva uzavřené objekty GeometryPath pro horní a dolní třetinu tvaru. Aplikací obou cest pomocí IGeometryShape.setGeometryPaths vznikne jedinečný složený tvar se štěrbinou přes střední třetinu.

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();
}

example4_image

Vytvoření vlastního tvaru s zakulacenými rohy

Tento příklad kombinuje přímé segmenty s GeometryPath.arcTo k vytvoření tvaru s dovnitř zakřivenými rohy. Každá velikost rohu nastavuje šířku a výšku oblouku v bodech a úsek -90 stupňů vykreslí proti směru hodinových ručiček čtvrtý elipsový oblouk. Dokončená cesta je aplikována pomocí IGeometryShape.setGeometryPath, a prezentace je uložena ve formátu 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();
}

Zjistit, zda je geometrie tvaru uzavřená

Následující pomocná metoda kontroluje, zda každý neprázdný geometrický cestovní segment končí uzavíracím segmentem. Čte IGeometryPath.getPathData a porovnává poslední segmentův IPathSegment.getPathCommand s PathCommandType.Close. Vrací false, pokud neexistují neprázdné cesty. Metoda kontroluje poslední příkaz každé cesty; neprozkoumává každou podfiguru uvnitř cesty. Příklad vypíše true pro obdélník.

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();
}

Extrahovat a zkontrolovat prvky tvaru

Použijte IGeometryShape.createShapeElements k prozkoumání existujícího tvaru jako prvky obsahující body cesty a typy bodů. Přetypujte každé vrácené IShapeElement na ShapeElement a získejte pole bodů a typů pomocí metod getPathPoints a getPathTypes . Toto zobrazení je užitečné pro analýzu kontur nebo předání geometrie vlastním kreslicím nástrojům.

Příklad otevře input.pptx, najde první geometrický tvar přímo na první snímku a vypíše jeho segmenty cesty. Použijte prezentaci obsahující tvar se přímými i zakřivenými segmenty, abyste viděli oba typy výstupu. Nepřechází do skupin.

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; // Zachovat typ segmentu, kromě příznaků.
                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; // Spotřebovat oba ovládací body a koncový bod.
                        break;
                }

                if ((types[i] & 0x80) != 0) {
                    System.out.println("Close subpath back to its starting point.");
                }
            }
        }
    }
} finally {
    presentation.dispose();
}

Pole jsou seřazena podle indexu: points[i] je bod a types[i] popisuje jeho roli. Typ 0 zahajuje figurku a typ 1 kreslí čáru z předchozího bodu na aktuální bod. Kubický Bézierův segment začíná na předchozím koncovém bodě a používá tři po sobě jdoucí položky typu 3: dva ovládací body a nový koncový bod. Smyčka tyto tři položky spotřebuje najednou a kontroluje koncový bod, zda uzavírá.

Typy bodů také obsahují příznaky. Maskujte s 0x07 pro identifikaci typu segmentu a testujte 0x80 samostatně k detekci uzavřené podcesty. Například 129 (0x81) znamená koncový bod čáry, který uzavírá podcestu, a 131 (0x83) znamená Bézierův koncový bod, který uzavírá. Java ukládá tyto příznaky v podepsaných bajtech; maskování zachovává zamýšlené bitové hodnoty. Porovnání surové hodnoty jen s 1 nebo 3 by tyto případy přehlédlo. Další příznaky, jako pomlčka (0x10) a značka (0x20), nemění základní typ segmentu.

Souřadnice a transformace. Body jsou měřeny v bodech (1/72 palce), přičemž X roste vpravo a Y směrem dolů. Pro ne-skupinový tvar již extrahované souřadnice zahrnují pozici vrácenou metodou getX a getY a odrážejí jeho aktuální šířku a výšku. Například neotočený obdélník v (100, 200) s rozměry 120 × 80 má okrajové souřadnice (100, 200)–(220, 280). Nepřičítávejte pozici tvaru znovu. Odečtěte jeho X a Y, abyste získali souřadnice relativní k jeho neotočenému rámci.

Extrahované body neaplikují rotaci tvaru, vrácenou metodou getRotation, ani horizontální a vertikální převrácení. Pro reprodukci zobrazené kontury aplikujte tyto transformace kolem středu tvaru. U skupinových tvarů také zohledněte mapování souřadnic skupiny a transformace; nepředpokládejte, že extrahované body jsou finální vykreslené souřadnice snímku, a neaplikujte translaci nebo měřítko dvakrát, pokud už jsou zahrnuty v rámci dítěte.

Kontrola vs. úprava. Extrahovaná pole popisují konturu; jejich změna neaktualizuje původní tvar. Zvolte tento přístup, když vaše analýza nebo kreslicí kód potřebuje pole bodů/typů. Použijte getGeometryPaths pokud potřebujete geometrické příkazy v lokálním souřadnicovém systému tvaru nebo chcete upravit jeho geometriku. Aplikujte upravené cesty pomocí setGeometryPath nebo setGeometryPaths .

Převod Java AWT tvaru na GeometryPath

Tento příklad kombinuje obdélníkový obrys s textem převedeným na geometrii. Metoda obrysu setFillMode zakáže jeho výplň. GlyphVector vytvoří obrys textu v java.awt.Shape. Jeho PathIterator dodává segmenty move, line, quadratic, cubic a closing, které příklad přehrává na GeometryPath .

Text používá písmo Arial 40 bodů. Obrys je posunut o 20 bodů vodorovně a umístěn tak, aby jeho vizuální horní okraj byl 10 bodů pod horním okrajem tvaru. Cesta textu je vyplněna, zatímco původní obdélník zůstává jen obrysem. Aplikací obou cest pomocí IGeometryShape.setGeometryPaths vznikne jeden tvar obsahující obdélník i text.

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 {
    // Vytvořit nový tvar
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 300, 100);

    // Získat geometrickou cestu tvaru
    IGeometryPath originalPath = shape.getGeometryPaths()[0];
    originalPath.setFillMode(PathFillModeType.None);

    // Vytvořit novou grafickou cestu s textem
    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();
    }

    // Převést grafickou cestu na geometrickou cestu
    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);

    // Nastavit kombinaci nové geometrické cesty a původní geometrické cesty na tvar
    shape.setGeometryPaths(new IGeometryPath[] { originalPath, textPath });
} finally {
    presentation.dispose();
}

example5_image

Často kladené otázky

Co se stane s výplní a obrysem po nahrazení geometrie?

Styl zůstává u tvaru; mění se jen kontura. Výplň a obrys jsou automaticky aplikovány na novou geometrii.

Jak správně otočit vlastní tvar spolu s jeho geometrií?

Použijte metodu tvaru setRotation; geometrie se otáčí s tvarem, protože je svázána s jeho vlastním souřadnicovým systémem.

Mohu převést vlastní tvar na obrázek, aby byl “uzamčen” výsledek?

Ano. Exportujte požadovanou snímek nebo samotný tvar do rastrového formátu; to usnadní další práci s komplexními geometriemi.