Personalizza forme di presentazione in PHP
Panoramica
Questo articolo spiega come personalizzare le forme di presentazione in Aspose.Slides modificando la geometria delle forme tramite punti di modifica e percorsi geometrici. Mostra come lavorare con GeometryPath per modificare forme esistenti, eseguire operazioni di base di modifica del percorso, aggiungere o rimuovere punti e applicare la geometria aggiornata a una forma.
Dimostra inoltre come creare forme personalizzate e composite, costruire forme con angoli curvi, determinare se una geometria di forma è chiusa, ispezionare gli elementi della forma e convertire i contorni di testo Java AWT in percorsi geometrici.
Modifica una Forma con i Punti di Modifica
In PowerPoint è possibile utilizzare i Punti di Modifica per modificare un quadrato:
- Spostare un angolo verso l’interno o verso l’esterno.
- Regolare la curvatura in un punto.
- Aggiungere nuovi punti.
Modificare i punti consente di cambiare il contorno di una forma o di usare una forma esistente come base per una nuova.
Suggerimenti per la Modifica delle Forme

Quando si modificano le forme in PowerPoint, tenere presente i seguenti concetti:
- Una forma (o il suo percorso) può essere chiusa o aperta.
- Il percorso di una forma è costituito da punti di ancoraggio collegati da segmenti.
- Un segmento può essere rettilineo o curvo. I punti di ancoraggio e le maniglie di controllo determinano la sua forma.
- I punti di ancoraggio possono essere punti d’angolo, punti rettilinei o punti lisci:
- In un punto d’angolo, i segmenti adiacenti possono incontrarsi formando un angolo.
- In un punto liscio, le due maniglie di controllo sono allineate e alla stessa distanza dal punto di ancoraggio.
- In un punto rettilineo, le due maniglie di controllo sono allineate ma possono avere distanze diverse dal punto di ancoraggio.
- Spostare i punti di ancoraggio o regolare le loro maniglie cambia il contorno della forma.
Per modificare le forme di PowerPoint tramite i punti di modifica, Aspose.Slides mette a disposizione la classe GeometryPath.
- Un’istanza di GeometryPath rappresenta il percorso geometrico dell’oggetto GeometryShape.
- Per ottenere il GeometryPath da un’istanza di GeometryShape, è possibile utilizzare il metodo GeometryShape::getGeometryPaths.
- Per impostare il GeometryPath di una forma, è possibile usare questi metodi: GeometryShape::setGeometryPath per forme con un singolo percorso e GeometryShape::setGeometryPaths per forme con percorsi multipli.
- Per aggiungere segmenti, è possibile utilizzare i metodi sotto GeometryPath.
- Utilizzando i metodi GeometryPath::setStroke e GeometryPath::setFillMode, è possibile impostare l’aspetto di un percorso geometrico.
- Con il metodo GeometryPath::getPathData è possibile recuperare il percorso geometrico di un GeometryShape come array di segmenti di percorso.
- Per accedere ad ulteriori opzioni di personalizzazione della geometria della forma, è possibile leggere un oggetto java.awt.Shape attraverso il suo PathIterator e riprodurre i segmenti su un GeometryPath.
Operazioni di Modifica Semplici
Utilizzare i seguenti metodi per modificare un percorso geometrico. Le sovraccariche che accettano un indice inseriscono un segmento in quella posizione (zero‑based) nell’array di segmenti del percorso.
| Operazione | Metodo |
|---|---|
| Aggiungere o inserire una linea retta. | GeometryPath::lineTo |
| Aggiungere o inserire una curva Bézier cubica con due punti di controllo e un punto finale. | GeometryPath::cubicBezierTo |
| Aggiungere o inserire una curva Bézier quadratica con un punto di controllo e un punto finale. | GeometryPath::quadraticBezierTo |
| Aggiungere un arco ellittico con le dimensioni e gli angoli specificati in gradi. | GeometryPath::arcTo |
| Chiudere la figura corrente collegando il suo punto finale al punto iniziale. | GeometryPath::closeFigure |
| Impostare il punto di partenza di una figura. | GeometryPath::moveTo |
| Rimuovere un segmento in una posizione zero‑based. | GeometryPath::removeAt |
Aggiungere Punti Personalizzati a una Forma
Questo esempio inserisce due punti in una forma rettangolare usando GeometryPath::lineTo e applica il percorso modificato con GeometryShape::setGeometryPath. Le coordinate sono relative alla forma: entrambi i nuovi punti sono al suo centro, a 100 punti dal lato sinistro e a 50 punti dal lato superiore. Gli indici dei segmenti 1 e 4 li posizionano rispettivamente sui bordi superiore e inferiore, tirando questi bordi verso l’interno.
use aspose\slides\Presentation;
use aspose\slides\ShapeType;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->addAutoShape(ShapeType::Rectangle, 100, 100, 200, 100);
$geometryPath = $shape->getGeometryPaths()[0];
$geometryPath->lineTo(100, 50, 1);
$geometryPath->lineTo(100, 50, 4);
$shape->setGeometryPath($geometryPath);
} finally {
$presentation->dispose();
}

Rimuovere Punti da una Forma
Questo esempio modifica il contorno a forma di cuore rimuovendo il segmento all’indice zero‑based 2 con GeometryPath::removeAt. L’applicazione del percorso modificato con GeometryShape::setGeometryPath aggiorna il contorno della forma.
use aspose\slides\Presentation;
use aspose\slides\ShapeType;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->addAutoShape(ShapeType::Heart, 100, 100, 300, 300);
$path = $shape->getGeometryPaths()[0];
$path->removeAt(2);
$shape->setGeometryPath($path);
} finally {
$presentation->dispose();
}

Creare una Forma Personalizzata
Questo esempio costruisce una stella a cinque punte con GeometryPath. Raggi esterni e interni alternati di 100 e 50 punti definiscono le punte e le rientranze; un passo di 72 gradi distribuisce uniformemente le cinque punte. Il percorso è chiuso con GeometryPath::closeFigure e applicato a una forma rettangolare tramite GeometryShape::setGeometryPath, sostituendone il contorno.
use aspose\slides\GeometryPath;
use aspose\slides\Presentation;
use aspose\slides\ShapeType;
$points = [];
$outerRadius = 100;
$innerRadius = 50;
$angleStep = 72;
for ($angle = -90; $angle < 270; $angle += $angleStep) {
$radians = deg2rad($angle);
$points[] = [$outerRadius * cos($radians) + $outerRadius, $outerRadius * sin($radians) + $outerRadius];
$radians = deg2rad($angle + $angleStep / 2);
$points[] = [$innerRadius * cos($radians) + $outerRadius, $innerRadius * sin($radians) + $outerRadius];
}
$starPath = new GeometryPath();
$starPath->moveTo($points[0][0], $points[0][1]);
for ($i = 1; $i < count($points); $i++) {
$starPath->lineTo($points[$i][0], $points[$i][1]);
}
$starPath->closeFigure();
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->addAutoShape(ShapeType::Rectangle, 100, 100, $outerRadius * 2, $outerRadius * 2);
$shape->setGeometryPath($starPath);
} finally {
$presentation->dispose();
}

Creare una Forma Personalizzata Composita
Questo esempio definisce due GeometryPath chiusi per il terzo superiore e quello inferiore di una forma. L’applicazione di entrambi i percorsi con GeometryShape::setGeometryPaths crea una singola forma composita con uno spazio libero nella sua zona mediana.
use aspose\slides\GeometryPath;
use aspose\slides\Presentation;
use aspose\slides\ShapeType;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->addAutoShape(ShapeType::Rectangle, 100, 100, 200, 100);
$topPath = new GeometryPath();
$topPath->moveTo(0, 0);
$topPath->lineTo(java_values($shape->getWidth()), 0);
$topPath->lineTo(java_values($shape->getWidth()), java_values($shape->getHeight()) / 3);
$topPath->lineTo(0, java_values($shape->getHeight()) / 3);
$topPath->closeFigure();
$bottomPath = new GeometryPath();
$bottomPath->moveTo(0, java_values($shape->getHeight()) / 3 * 2);
$bottomPath->lineTo(java_values($shape->getWidth()), java_values($shape->getHeight()) / 3 * 2);
$bottomPath->lineTo(java_values($shape->getWidth()), java_values($shape->getHeight()));
$bottomPath->lineTo(0, java_values($shape->getHeight()));
$bottomPath->closeFigure();
$shape->setGeometryPaths([$topPath, $bottomPath]);
} finally {
$presentation->dispose();
}

Creare una Forma Personalizzata con Angoli Curvi
Questo esempio combina segmenti rettilinei con GeometryPath::arcTo per creare una forma con angoli curvi verso l’interno. Ogni dimensione d’angolo imposta la larghezza e l’altezza dell’arco in punti, e l’angolo di rotazione di –90 gradi disegna un quarto di ellisse in senso antiorario. Il percorso completato è applicato con GeometryShape::setGeometryPath, e la presentazione viene salvata in formato PPTX.
use aspose\slides\GeometryPath;
use aspose\slides\Point2DFloat;
use aspose\slides\Presentation;
use aspose\slides\SaveFormat;
use aspose\slides\ShapeType;
$shapeX = 20;
$shapeY = 20;
$shapeWidth = 300;
$shapeHeight = 200;
$leftTopSize = 50;
$rightTopSize = 20;
$rightBottomSize = 40;
$leftBottomSize = 10;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->addAutoShape(ShapeType::Custom, $shapeX, $shapeY, $shapeWidth, $shapeHeight);
$topLeft = new Point2DFloat($leftTopSize, 0);
$topRight = new Point2DFloat($shapeWidth - $rightTopSize, 0);
$rightBottom = new Point2DFloat($shapeWidth, $shapeHeight - $rightBottomSize);
$bottomLeft = new Point2DFloat($leftBottomSize, $shapeHeight);
$leftTop = new Point2DFloat(0, $leftTopSize);
$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();
}
Verificare se una Geometria di Forma è Chiusa
Il seguente helper verifica se ogni percorso geometrico non vuoto termina con un segmento di chiusura. Legge GeometryPath::getPathData e confronta il comando del segmento finale, ottenuto con PathSegment::getPathCommand, con PathCommandType::Close. Restituisce false quando non esistono percorsi non vuoti. Questa verifica il comando finale di ciascun percorso; non analizza ogni sotto‑figura all’interno di un percorso. L’esempio stampa true per un rettangolo.
use aspose\slides\PathCommandType;
use aspose\slides\Presentation;
use aspose\slides\ShapeType;
function isGeometryClosed($geometryShape)
{
$hasNonemptyPath = false;
foreach ($geometryShape->getGeometryPaths() as $geometryPath) {
$segments = java_values($geometryPath->getPathData());
if (count($segments) === 0) {
continue;
}
$hasNonemptyPath = true;
$lastSegment = $segments[count($segments) - 1];
if (java_values($lastSegment->getPathCommand()) !== PathCommandType::Close) {
return false;
}
}
return $hasNonemptyPath;
}
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->addAutoShape(ShapeType::Rectangle, 100, 100, 200, 100);
$closed = isGeometryClosed($shape);
echo ($closed ? "true" : "false") . PHP_EOL;
} finally {
$presentation->dispose();
}
Estrarre e Analizzare gli Elementi della Forma
Usare GeometryShape::createShapeElements per analizzare una forma esistente come elementi contenenti punti di percorso e tipi di punto. Utilizzare ogni ShapeElement restituito per ottenere gli array di punti e di tipi tramite i metodi getPathPoints e getPathTypes. Questa rappresentazione è utile per l’analisi del contorno o per passare la geometria a strumenti di disegno personalizzati.
L’esempio apre input.pptx, individua la prima forma geometrica nella prima diapositiva e stampa i suoi segmenti di percorso. Utilizzare una presentazione contenente una forma con segmenti rettilinei e curvi per vedere entrambi i tipi di output. Non ricerca all’interno dei gruppi.
use aspose\slides\Presentation;
$presentation = new Presentation("input.pptx");
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = null;
$shapes = $slide->getShapes();
for ($shapeIndex = 0; $shapeIndex < java_values($shapes->size()); $shapeIndex++) {
$candidate = $shapes->get_Item($shapeIndex);
if (java_instanceof($candidate, java("com.aspose.slides.GeometryShape"))) {
$shape = $candidate;
break;
}
}
if ($shape === null) {
echo "No geometry shape found on the first slide." . PHP_EOL;
} else {
foreach ($shape->createShapeElements() as $element) {
$points = java_values($element->getPathPoints());
$types = array_values(unpack("C*", java_values($element->getPathTypes())));
echo "Shape element:" . PHP_EOL;
for ($i = 0; $i < count($points); $i++) {
$pointType = $types[$i] & 0x07; // Mantieni il tipo di segmento, escludendo i flag.
switch ($pointType) {
case 0:
echo "Start figure at " . $points[$i] . PHP_EOL;
break;
case 1:
echo "Line to " . $points[$i] . PHP_EOL;
break;
case 3:
echo "Cubic Bezier: controls " . $points[$i] . ", " . $points[$i + 1] . "; end " . $points[$i + 2] . PHP_EOL;
$i += 2; // Consuma entrambi i punti di controllo e il punto finale.
break;
}
if (($types[$i] & 0x80) !== 0) {
echo "Close subpath back to its starting point." . PHP_EOL;
}
}
}
}
} finally {
$presentation->dispose();
}
Gli array corrispondono per indice: $points[$i] è un punto e $types[$i] ne descrive il ruolo. Il tipo 0 avvia una figura, e il tipo 1 traccia una linea dal punto precedente al punto corrente. Un segmento Bézier cubico inizia dal punto finale precedente e utilizza tre voci di tipo 3 consecutive: due punti di controllo seguiti dal nuovo punto finale. Il ciclo consuma queste tre voci insieme e verifica il punto finale per la chiusura.
I tipi di punto contengono anche flag. Mascherare con 0x07 per identificare il tipo di segmento e testare 0x80 separatamente per rilevare un sotto‑percorso chiuso. Per esempio, 129 (0x81) indica un punto finale di linea che chiude un sotto‑percorso, e 131 (0x83) indica un punto finale Bézier che chiude uno. Il bridge PHP/Java restituisce l’array di byte come stringa binaria; l’unpacking con "C*" produce valori byte non firmati. La mascheratura preserva i valori di bit desiderati. Confrontare il valore grezzo solo con 1 o 3 tralascerebbe questi casi. Altri flag, come il dash (0x10) e il marker (0x20), non alterano il tipo di segmento di base.
Coordinate e trasformazioni. I punti sono misurati in punti (1/72 di pollice), con X che aumenta verso destra e Y che aumenta verso il basso. Per una forma non raggruppata, le coordinate estratte includono già la posizione restituita da getX e getY e riflettono la larghezza e altezza correnti. Per esempio, un rettangolo non ruotato a (100, 200) con dimensione 120 × 80 ha i limiti del contorno (100, 200)–(220, 280). Non aggiungere nuovamente la posizione della forma. Sottrarre X e Y per ottenere coordinate relative al suo frame non ruotato.
I punti estratti non considerano la rotazione della forma, restituita da getRotation, né le inversioni orizzontali e verticali. Per riprodurre il contorno visualizzato, applicare quelle trasformazioni intorno al centro della forma. Per le forme raggruppate, considerare anche la mappatura delle coordinate del gruppo e le trasformazioni; non presumere che i punti estratti siano le coordinate finali visualizzate sulla diapositiva né applicare una traduzione o scala due volte se già riflessa nel frame del figlio.
Ispezione versus modifica. Gli array estratti descrivono il contorno; modificarli non aggiorna la forma originale. Scegliere questo approccio quando l’analisi o il codice di disegno richiedono array di punti/tipo. Utilizzare getGeometryPaths quando occorrono comandi di geometria nel sistema di coordinate locale della forma o si desidera modificare la sua geometria. Applicare i percorsi modificati tramite setGeometryPath o setGeometryPaths.
Convertire una Forma Java AWT in GeometryPath
Questo esempio combina un contorno rettangolare con testo convertito in geometria. Il metodo setFillMode del contorno ne disabilita il riempimento. Un GlyphVector crea il contorno testuale in un java.awt.Shape. Il suo PathIterator fornisce segmenti di spostamento, linea, quadratica, cubica e chiusura, che l’esempio riproduce su un GeometryPath.
L’esempio utilizza un array di float Java così che il bridge PHP/Java mantenga le coordinate scritte dall’iteratore. Il testo usa un carattere Arial da 40 punti. Il contorno è spostato di 20 punti orizzontalmente e posizionato con la sua parte alta visiva 10 punti sotto il bordo superiore della forma. Il percorso del testo è riempito, mentre il rettangolo originale resta solo un contorno. L’applicazione di entrambi i percorsi con GeometryShape::setGeometryPaths produce una singola forma contenente il rettangolo e il testo.
use aspose\slides\GeometryPath;
use aspose\slides\PathFillModeType;
use aspose\slides\Presentation;
use aspose\slides\ShapeType;
$presentation = new Presentation();
try {
$slide = $presentation->getSlides()->get_Item(0);
$shape = $slide->getShapes()->addAutoShape(ShapeType::Rectangle, 100, 100, 300, 100);
$originalPath = $shape->getGeometryPaths()[0];
$originalPath->setFillMode(PathFillModeType::None);
$fontClass = java("java.awt.Font");
$imageClass = java("java.awt.image.BufferedImage");
$font = new Java("java.awt.Font", "Arial", $fontClass->PLAIN, 40);
$image = new Java("java.awt.image.BufferedImage", 100, 100, $imageClass->TYPE_INT_ARGB);
$graphics = $image->createGraphics();
try {
$fontContext = $graphics->getFontRenderContext();
$glyphVector = $font->createGlyphVector($fontContext, "Text in shape");
$textBounds = $glyphVector->getVisualBounds();
$baseline = -java_values($textBounds->getY()) + 10;
$graphicsPath = $glyphVector->getOutline(20.0, $baseline);
} finally {
$graphics->dispose();
}
$textPath = new GeometryPath();
$pathIterator = $graphicsPath->getPathIterator(null);
$iteratorClass = java("java.awt.geom.PathIterator");
$arrayClass = java("java.lang.reflect.Array");
$floatClass = java("java.lang.Float");
$coordinates = $arrayClass->newInstance($floatClass->TYPE, 6);
while (!java_values($pathIterator->isDone())) {
$segmentType = java_values($pathIterator->currentSegment($coordinates));
$points = java_values($coordinates);
switch ($segmentType) {
case java_values($iteratorClass->SEG_MOVETO):
$textPath->moveTo($points[0], $points[1]);
break;
case java_values($iteratorClass->SEG_LINETO):
$textPath->lineTo($points[0], $points[1]);
break;
case java_values($iteratorClass->SEG_QUADTO):
$textPath->quadraticBezierTo($points[0], $points[1], $points[2], $points[3]);
break;
case java_values($iteratorClass->SEG_CUBICTO):
$textPath->cubicBezierTo($points[0], $points[1], $points[2], $points[3], $points[4], $points[5]);
break;
case java_values($iteratorClass->SEG_CLOSE):
$textPath->closeFigure();
break;
}
$pathIterator->next();
}
$textPath->setFillMode(PathFillModeType::Normal);
$shape->setGeometryPaths([$originalPath, $textPath]);
} finally {
$presentation->dispose();
}

FAQ
Cosa accade al riempimento e al contorno dopo aver sostituito la geometria?
Lo stile rimane associato alla forma; cambia solo il contorno. Il riempimento e il contorno vengono applicati automaticamente alla nuova geometria.
Come ruoto correttamente una forma personalizzata insieme alla sua geometria?
Utilizzare il metodo setRotation della forma; la geometria ruota con la forma perché è legata al sistema di coordinate della stessa.
Posso convertire una forma personalizzata in un’immagine per “bloccare” il risultato?
Sì. Esportare l’diapositiva o la forma stessa in formato raster; questo semplifica il lavoro successivo con geometrie complesse.