Aanpassen van presentatievormen in Java

Overzicht

Dit artikel legt uit hoe u presentaties‑vormen kunt aanpassen in Aspose.Slides door de vormgeometrie te bewerken via bewerkingspunten en geometriepaden. Het laat zien hoe u kunt werken met GeometryPath en IGeometryPath om bestaande vormen te wijzigen, basisbewerkingen op paden uit te voeren, punten toe te voegen of te verwijderen, en de bijgewerkte geometrie terug toe te passen op een vorm.

Het demonstreert ook hoe u aangepaste en samengestelde vormen kunt maken, vormen met afgeronde hoeken kunt bouwen, kunt bepalen of een vormgeometrie gesloten is, vormelementen kunt inspecteren, en Java AWT‑tekstuitleggen kunt omzetten naar geometriepaden.

Vorm wijzigen met bewerkingspunten

In PowerPoint kunt u Bewerkingspunten gebruiken om een vierkant te wijzigen:

  • Een hoek naar binnen of naar buiten verplaatsen.
  • De kromming op een punt aanpassen.
  • Nieuwe punten toevoegen.

Bewerkingspunten laten u de omtrek van een vorm aanpassen of een bestaande vorm als basis voor een nieuwe gebruiken.

Tips voor het bewerken van vormen

overview_image

Bij het bewerken van PowerPoint‑vormen, houd deze concepten in gedachten:

  • Een vorm (of het pad) kan gesloten of open zijn.
  • Het pad van een vorm bestaat uit ankerpunten die met segmenten verbonden zijn.
  • Een segment kan recht of gebogen zijn. Ankerpunten en controlehandvatten bepalen de vorm.
  • Ankerpunten bestaan als hoekpunten, rechte punten of gladde punten:
    • Bij een hoekpunt kunnen aangrenzende segmenten elkaar onder een hoek ontmoeten.
    • Bij een glad punt zijn de twee controlehandvatten uitgelijnd en even ver van het ankerpunt.
    • Bij een recht punt zijn de twee controlehandvatten uitgelijnd maar kunnen ze verschillende afstanden tot het ankerpunt hebben.
  • Het verplaatsen van ankerpunten of het aanpassen van hun handvatten verandert de vorm van de omtrek.

Om PowerPoint‑vormen via bewerkingspunten te bewerken, biedt Aspose.Slides de GeometryPath‑klasse en de IGeometryPath‑interface.

Eenvoudige bewerkingsbewerkingen

Gebruik de volgende methoden om een geometriepad te bewerken. Overloads die een index accepteren, voegen een segment in op die nul‑gebaseerde positie in de segment‑array van het pad.

Bewerking Method
Een rechte lijn toevoegen of invoegen. GeometryPath.lineTo
Een kubieke Bézier‑curve met twee controlepunten en een eindpunt toevoegen of invoegen. GeometryPath.cubicBezierTo
Een kwadratische Bézier‑curve met één controlepunt en een eindpunt toevoegen of invoegen. GeometryPath.quadraticBezierTo
Een ellipsvormige boog met de opgegeven afmetingen en hoeken in graden toevoegen. GeometryPath.arcTo
De huidige figuur sluiten door het eindpunt met het startpunt te verbinden. GeometryPath.closeFigure
Het startpunt van een figuur instellen. GeometryPath.moveTo
Een segment verwijderen op een nul‑gebaseerde index. GeometryPath.removeAt

Aangepaste punten aan een vorm toevoegen

Dit voorbeeld voegt twee punten toe aan een rechthoekige vorm met behulp van GeometryPath.lineTo en past het bewerkte pad toe met IGeometryShape.setGeometryPath. De coördinaten zijn lokaal ten opzichte van de vorm: beide nieuwe punten liggen in het midden, 100 punten van de linkerkant en 50 punten van de bovenkant. Segment‑indices 1 en 4 plaatsen ze op respectievelijk de boven‑ en onderrand, waardoor die randen naar binnen worden getrokken.

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

Punten van een vorm verwijderen

Dit voorbeeld wijzigt de omtrek van een hartvorm door het segment op nul‑gebaseerde index 2 te verwijderen met GeometryPath.removeAt. Het toepassen van het aangepaste pad met IGeometryShape.setGeometryPath werkt de contour van de vorm bij.

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

Een aangepaste vorm maken

Dit voorbeeld bouwt een vijfpuntige ster met GeometryPath. Afwisselend buiten- en binnenstraal van 100 en 50 punten definiëren de punten en inkepingen; een stap van 72 graden verdeelt de vijf punten gelijkmatig. Het pad wordt gesloten met GeometryPath.closeFigure en toegepast op een rechthoekige vorm met IGeometryShape.setGeometryPath, waardoor de oorspronkelijke omtrek wordt vervangen.

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

Een samengestelde aangepaste vorm maken

Dit voorbeeld definieert twee gesloten GeometryPath‑objecten voor respectievelijk het boven‑ en onderste derde deel van een vorm. Beide paden toepassen met IGeometryShape.setGeometryPaths creëert één samengestelde vorm met een opening door het middelste derde deel.

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

Een aangepaste vorm met afgeronde hoeken maken

Dit voorbeeld combineert rechte segmenten met GeometryPath.arcTo om een vorm met naar binnen gebogen hoeken te creëren. Elke hoekgrootte bepaalt de breedte en hoogte van de boog in punten, en de -90‑graden sweep tekent een tegen de klok in gaande kwart‑ellipse. Het voltooide pad wordt toegepast met IGeometryShape.setGeometryPath, en de presentatie wordt opgeslagen in PPTX‑formaat.

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

Nagaan of een vormgeometrie gesloten is

De volgende helper controleert of elke niet‑lege geometriepad eindigt met een sluitsegment. Hij leest IGeometryPath.getPathData en vergelijkt het laatste segment‑IPathSegment.getPathCommand met PathCommandType.Close. Hij geeft false terug wanneer er geen niet‑leeg pad bestaat. Deze controle kijkt naar het laatste commando van elk pad; hij inspecteert niet elk sub‑figure binnen een pad. Het voorbeeld print true voor een rechthoek.

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

Vormelementen extraheren en inspecteren

Gebruik IGeometryShape.createShapeElements om een bestaande vorm te inspecteren als elementen die padpunten en punt‑typen bevatten. Cast elk geretourneerd IShapeElement naar ShapeElement om de punt‑ en type‑arrays op te halen via getPathPoints en getPathTypes methoden. Deze representatie is nuttig voor contouranalyse of voor het doorgeven van geometrie aan aangepaste tekengereedschappen.

Het voorbeeld opent input.pptx, vindt de eerste geometrievorm direct op de eerste dia, en print zijn padsegmenten. Gebruik een presentatie met een vorm die zowel rechte als gebogen segmenten bevat om beide soorten uitvoer te zien. Het doorzoekt geen groepen.

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; // Houd het segmenttype, exclusief vlaggen.
                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; // Verbruik beide controlepunten en het eindpunt.
                        break;
                }

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

De arrays corresponderen op index: points[i] is een punt en types[i] beschrijft de rol. Type 0 start een figure, en type 1 tekent een lijn van het vorige punt naar het huidige punt. Een kubieke Bézier‑segment start bij het vorige eindpunt en gebruikt drie opeenvolgende type‑3‑items: twee controlepunten gevolgd door het nieuwe eindpunt. De lus consumeert deze drie items samen en controleert het eindpunt op sluiting.

Punt‑typen bevatten ook vlaggen. Maskeer met 0x07 om het segmenttype te identificeren, en test 0x80 apart om een gesloten subpad te detecteren. Bijvoorbeeld, 129 (0x81) betekent een lijneindpunt dat een subpad sluit, en 131 (0x83) betekent een Bézier‑eindpunt dat een subpad sluit. Java slaat deze vlaggen op in ondertekende bytes; maskeren behoudt de bedoelde bitwaarden. Alleen vergelijken met 1 of 3 zou deze gevallen missen. Andere vlaggen, zoals dash (0x10) en marker (0x20), wijzigen het basissegmenttype niet.

Coördinaten en transformaties. Punten worden gemeten in points (1/72 inch), waarbij X naar rechts toeneemt en Y naar beneden. Voor een niet‑gegroepeerde vorm omvatten de geëxtraheerde coördinaten al de positie die wordt geretourneerd door getX en getY en weerspiegelen ze de huidige breedte en hoogte. Een ongeroteerde rechthoek op (100, 200) met afmeting 120 × 80 heeft contourgrenzen (100, 200)–(220, 280). Voeg de positie van de vorm niet nogmaals toe. Trek X en Y af om coördinaten te verkrijgen relatief ten opzichte van het ongeroteerde frame.

De geëxtraheerde punten houden geen rekening met de rotatie van de vorm, geretourneerd door getRotation, of horizontale en verticale spiegels. Om de weergegeven contour te reproduceren, past u die transformaties toe rond het middelpunt van de vorm. Voor gegroepeerde vormen moet ook de coördinaten‑mapping en transformaties van de groep in aanmerking worden genomen; ga er niet van uit dat de geëxtraheerde punten de definitieve weergave‑dia‑coördinaten zijn, en vermijd een dubbellevertaling of -schaal als dit al in het kinderframe is verwerkt.

Inspectie versus bewerking. De geëxtraheerde arrays beschrijven de contour; wijzigen hiervan werkt de oorspronkelijke vorm niet bij. Kies deze aanpak wanneer uw analyse‑ of tekencode punt‑/type‑arrays nodig heeft. Gebruik getGeometryPaths wanneer u geometrie‑commando’s in het lokale coördinatensysteem van de vorm nodig heeft of de geometrie wilt bewerken. Pas bewerkte paden toe via setGeometryPath of setGeometryPaths.

Een Java AWT‑vorm converteren naar GeometryPath

Dit voorbeeld combineert een rechthoekige omtrek met tekst die is omgezet naar geometrie. De setFillMode‑methode van de omtrek schakelt de vulling uit. Een GlyphVector creëert de tekstomtrek in een java.awt.Shape. De PathIterator levert verplaatsings‑, lijn‑, kwadratische, kubieke en sluit‑segmenten, die het voorbeeld opnieuw afspeelt op een GeometryPath.

De tekst gebruikt een Arial‑lettertype van 40 points. De omtrek wordt horizontaal 20 points verschoven en verticaal zodanig gepositioneerd dat de visuele bovenkant 10 points onder de bovenrand van de vorm ligt. Het tekstpad wordt gevuld, terwijl de oorspronkelijke rechthoek een omtrek blijft. Beide paden toepassen met IGeometryShape.setGeometryPaths levert één vorm op die zowel de rechthoek als de tekst bevat.

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 {
    // Nieuwe vorm maken
    ISlide slide = presentation.getSlides().get_Item(0);

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

    // Geometriepad van de vorm ophalen
    IGeometryPath originalPath = shape.getGeometryPaths()[0];
    originalPath.setFillMode(PathFillModeType.None);

    // Nieuw grafisch pad maken met tekst
    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();
    }

    // Grafisch pad omzetten naar geometriepad
    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);

    // Combinatie van nieuw geometriepad en origineel geometriepad instellen op de vorm
    shape.setGeometryPaths(new IGeometryPath[] { originalPath, textPath });
} finally {
    presentation.dispose();
}

example5_image

FAQ

Wat gebeurt er met de vulling en omtrek nadat de geometrie is vervangen?

De stijl blijft bij de vorm; alleen de contour verandert. De vulling en omtrek worden automatisch toegepast op de nieuwe geometrie.

Hoe roteer ik een aangepaste vorm correct samen met de geometrie?

Gebruik de setRotation‑methode van de vorm; de geometrie roteert mee omdat deze aan het eigen coördinatensysteem van de vorm is gekoppeld.

Kan ik een aangepaste vorm naar een afbeelding converteren om het resultaat vast te zetten?

Ja. Exporteer het gewenste dia‑gebied of de vorm zelf naar een rasterformaat; dit vereenvoudigt later werk met complexe geometrieën.