Skip to content

Commit

Permalink
Merge pull request #663 from Progi1984/develop
Browse files Browse the repository at this point in the history
Added column spacing in RichText & line spacing mode & spacing before/after for Paragraph
  • Loading branch information
Progi1984 authored Aug 2, 2021
2 parents 7932eb1 + b9e1934 commit a0c665c
Show file tree
Hide file tree
Showing 20 changed files with 729 additions and 221 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"php": "^7.1|^8.0",
"ext-xml": "*",
"ext-zip": "*",
"phpoffice/common": "0.2.*",
"phpoffice/common": "dev-develop",
"phpoffice/phpspreadsheet": "^1.9.0"
},
"require-dev": {
Expand Down
8 changes: 8 additions & 0 deletions docs/changes/1.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@
- Support for line smooth for line and scatter chart - @ksmeeks0001 GH-626 & @Progi1984 GH-662
- ODPresentation Writer
- PowerPoint2007 Writer
- Support for column spacing for RichText - @zoff83 GH-617 & @Progi1984 GH-663
- PowerPoint2007 Reader
- PowerPoint2007 Writer
- Support for line spacing mode & spacing before/after for Paragraph - @zoff83 GH-617 & @Progi1984 GH-663
- ODPresentation Reader
- ODPresentation Writer
- PowerPoint2007 Reader
- PowerPoint2007 Writer

## Project Management
- Migrated from Travis CI to Github Actions - @Progi1984 GH-635
Expand Down
52 changes: 49 additions & 3 deletions docs/usage/shapes/richtext.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

Rich text shapes contain paragraphs of texts. To create a rich text shape, use `createRichTextShape` method of slide.

Each rich text can contain multiples paragraphs.
Each paragraph can contain:
- a `TextElement`
- a `BreakElement`
- a `Run`

Below are the properties that you can set for a rich text shape.

- `wrap`
Expand All @@ -19,15 +25,33 @@ Below are the properties that you can set for a rich text shape.
- `topInset` in pixels
- `autoShrinkHorizontal` (boolean)
- `autoShrinkVertical` (boolean)
- `columnSpacing` see *Column Spacing*

Properties that can be set for each paragraphs are as follow.

- `alignment` <!-- see *[Alignment](#alignment)*-->
- `bulletStyle` see *[Bullet](#bullet)*
- `lineSpacing` see *[LineSpacing](#linespacing)*
- `lineSpacing` see *Line Spacing*
- `font` <!-- see *[Font](#font)*-->

## Bullet
## Column Spacing

For a paragraph, you can define the column spacing.

Example:

``` php
<?php

use PhpOffice\PhpPresentation\Shape\RichText;

$richText = new RichText();
$richText->setColumnSpacing(200);
$columnSpacing = $richText->getColumnSpacing();
```

## Paragraph
### Bullet

For a paragraph, you can define the bullet style.

Expand Down Expand Up @@ -58,9 +82,10 @@ $paragraph->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET);
$paragraph->getBulletStyle()->setBulletColor(new Color(Color::COLOR_RED));
```

## LineSpacing
### Line Spacing

For a paragraph, you can define the line spacing.
By default, mode is in percent (`Paragraph::LINE_SPACING_MODE_PERCENT`), but you can use the point mode (`Paragraph::LINE_SPACING_MODE_POINT`).

Example:

Expand All @@ -72,6 +97,27 @@ use PhpOffice\PhpPresentation\Shape\RichText\Paragraph;
$paragraph = new Paragraph();
$paragraph->setLineSpacing(200);
$lineSpacing = $paragraph->getLineSpacing();

$paragraph->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_POINT);
$lineSpacingMode = $paragraph->getLineSpacingMode();
```

### Spacing

For a paragraph, you can define the spacing before and after the paragraph in point
Example:

``` php
<?php

use PhpOffice\PhpPresentation\Shape\RichText\Paragraph;

$paragraph = new Paragraph();
$paragraph->setSpacingAfter(12);
$spacingAfter = $paragraph->getSpacingAfter();

$paragraph->setSpacingBefore(34);
$spacingBefore = $paragraph->getSpacingBefore();
```

## Run
Expand Down
2 changes: 1 addition & 1 deletion samples/Sample_01_Simple.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
$shape = $currentSlide->createDrawingShape();
$shape->setName('PHPPresentation logo')
->setDescription('PHPPresentation logo')
->setPath('./resources/phppowerpoint_logo.gif')
->setPath(__DIR__ . '/resources/phppowerpoint_logo.gif')
->setHeight(36)
->setOffsetX(10)
->setOffsetY(10);
Expand Down
96 changes: 79 additions & 17 deletions src/PhpPresentation/Reader/ODPresentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ protected function loadStyle(DOMElement $nodeStyle)
$distance = ($offsetY < 0 ? $offsetY * -1 : $offsetY);
}
$oShadow->setDirection((int) rad2deg(atan2($offsetY, $offsetX)));
$oShadow->setDistance((int) round(CommonDrawing::centimetersToPixels($distance)));
$oShadow->setDistance(CommonDrawing::centimetersToPixels($distance));
}
}
// Read Fill
Expand Down Expand Up @@ -365,6 +365,19 @@ protected function loadStyle(DOMElement $nodeStyle)

$nodeParagraphProps = $this->oXMLReader->getElement('style:paragraph-properties', $nodeStyle);
if ($nodeParagraphProps instanceof DOMElement) {
if ($nodeParagraphProps->hasAttribute('fo:line-height')) {
$lineHeightUnit = $this->getExpressionUnit($nodeParagraphProps->getAttribute('fo:margin-bottom'));
$lineSpacingMode = $lineHeightUnit == '%' ? Paragraph::LINE_SPACING_MODE_PERCENT : Paragraph::LINE_SPACING_MODE_POINT;
$lineSpacing = $this->getExpressionValue($nodeParagraphProps->getAttribute('fo:margin-bottom'));
}
if ($nodeParagraphProps->hasAttribute('fo:margin-bottom')) {
$spacingAfter = (float) substr($nodeParagraphProps->getAttribute('fo:margin-bottom'), 0, -2);
$spacingAfter = CommonDrawing::centimetersToPoints($spacingAfter);
}
if ($nodeParagraphProps->hasAttribute('fo:margin-top')) {
$spacingBefore = (float) substr($nodeParagraphProps->getAttribute('fo:margin-top'), 0, -2);
$spacingBefore = CommonDrawing::centimetersToPoints($spacingBefore);
}
$oAlignment = new Alignment();
if ($nodeParagraphProps->hasAttribute('fo:text-align')) {
$oAlignment->setHorizontal($nodeParagraphProps->getAttribute('fo:text-align'));
Expand Down Expand Up @@ -407,10 +420,10 @@ protected function loadStyle(DOMElement $nodeStyle)
$oNodeListProperties = $this->oXMLReader->getElement('style:list-level-properties', $oNodeListLevel);
if ($oNodeListProperties instanceof DOMElement) {
if ($oNodeListProperties->hasAttribute('text:min-label-width')) {
$oAlignment->setIndent((int) round(CommonDrawing::centimetersToPixels(substr($oNodeListProperties->getAttribute('text:min-label-width'), 0, -2))));
$oAlignment->setIndent(CommonDrawing::centimetersToPixels((float) substr($oNodeListProperties->getAttribute('text:min-label-width'), 0, -2)));
}
if ($oNodeListProperties->hasAttribute('text:space-before')) {
$iSpaceBefore = (int) CommonDrawing::centimetersToPixels(substr($oNodeListProperties->getAttribute('text:space-before'), 0, -2));
$iSpaceBefore = CommonDrawing::centimetersToPixels((float) substr($oNodeListProperties->getAttribute('text:space-before'), 0, -2));
$iMarginLeft = $iSpaceBefore + $oAlignment->getIndent();
$oAlignment->setMarginLeft($iMarginLeft);
}
Expand All @@ -432,12 +445,16 @@ protected function loadStyle(DOMElement $nodeStyle)
}

$this->arrayStyles[$keyStyle] = [
'alignment' => isset($oAlignment) ? $oAlignment : null,
'background' => isset($oBackground) ? $oBackground : null,
'fill' => isset($oFill) ? $oFill : null,
'font' => isset($oFont) ? $oFont : null,
'shadow' => isset($oShadow) ? $oShadow : null,
'listStyle' => isset($arrayListStyle) ? $arrayListStyle : null,
'alignment' => $oAlignment ?? null,
'background' => $oBackground ?? null,
'fill' => $oFill ?? null,
'font' => $oFont ?? null,
'shadow' => $oShadow ?? null,
'listStyle' => $arrayListStyle ?? null,
'spacingAfter' => $spacingAfter ?? null,
'spacingBefore' => $spacingBefore ?? null,
'lineSpacingMode' => $lineSpacingMode ?? null,
'lineSpacing' => $lineSpacing ?? null,
];

return true;
Expand Down Expand Up @@ -507,11 +524,11 @@ protected function loadShapeDrawing(DOMElement $oNodeFrame): void
$oShape->setName($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : '');
$oShape->setDescription($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : '');
$oShape->setResizeProportional(false);
$oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? (int) round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:width'), 0, -2))) : '');
$oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? (int) round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:height'), 0, -2))) : '');
$oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:width'), 0, -2)) : 0);
$oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:height'), 0, -2)) : 0);
$oShape->setResizeProportional(true);
$oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? (int) round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:x'), 0, -2))) : '');
$oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? (int) round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:y'), 0, -2))) : '');
$oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:x'), 0, -2)) : 0);
$oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:y'), 0, -2)) : 0);

if ($oNodeFrame->hasAttribute('draw:style-name')) {
$keyStyle = $oNodeFrame->getAttribute('draw:style-name');
Expand All @@ -535,10 +552,10 @@ protected function loadShapeRichText(DOMElement $oNodeFrame): void
$oShape = $this->oPhpPresentation->getActiveSlide()->createRichTextShape();
$oShape->setParagraphs([]);

$oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? (int) round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:width'), 0, -2))) : '');
$oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? (int) round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:height'), 0, -2))) : '');
$oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? (int) round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:x'), 0, -2))) : '');
$oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? (int) round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:y'), 0, -2))) : '');
$oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:width'), 0, -2)) : 0);
$oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:height'), 0, -2)) : 0);
$oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:x'), 0, -2)) : 0);
$oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:y'), 0, -2)) : 0);

foreach ($this->oXMLReader->getElements('draw:text-box/*', $oNodeFrame) as $oNodeParagraph) {
$this->levelParagraph = 0;
Expand All @@ -565,6 +582,23 @@ protected function loadShapeRichText(DOMElement $oNodeFrame): void
protected function readParagraph(RichText $oShape, DOMElement $oNodeParent): void
{
$oParagraph = $oShape->createParagraph();
if ($oNodeParent->hasAttribute('text:style-name')) {
$keyStyle = $oNodeParent->getAttribute('text:style-name');
if (isset($this->arrayStyles[$keyStyle])) {
if (!empty($this->arrayStyles[$keyStyle]['spacingAfter'])) {
$oParagraph->setSpacingAfter($this->arrayStyles[$keyStyle]['spacingAfter']);
}
if (!empty($this->arrayStyles[$keyStyle]['spacingBefore'])) {
$oParagraph->setSpacingBefore($this->arrayStyles[$keyStyle]['spacingBefore']);
}
if (!empty($this->arrayStyles[$keyStyle]['lineSpacingMode'])) {
$oParagraph->setLineSpacingMode($this->arrayStyles[$keyStyle]['lineSpacingMode']);
}
if (!empty($this->arrayStyles[$keyStyle]['lineSpacing'])) {
$oParagraph->setLineSpacing($this->arrayStyles[$keyStyle]['lineSpacing']);
}
}
}
$oDomList = $this->oXMLReader->getElements('text:span', $oNodeParent);
$oDomTextNodes = $this->oXMLReader->getElements('text()', $oNodeParent);
foreach ($oDomTextNodes as $oDomTextNode) {
Expand Down Expand Up @@ -666,4 +700,32 @@ protected function loadStylesFile(): void
}
}
}

/**
* @param string $expr
*
* @return string
*/
private function getExpressionUnit(string $expr): string
{
if (substr($expr, -1) == '%') {
return '%';
}

return substr($expr, -2);
}

/**
* @param string $expr
*
* @return string
*/
private function getExpressionValue(string $expr): string
{
if (substr($expr, -1) == '%') {
return substr($expr, 0, -1);
}

return substr($expr, 0, -2);
}
}
25 changes: 22 additions & 3 deletions src/PhpPresentation/Reader/PowerPoint2007.php
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ protected function loadShapeDrawing(XMLReader $document, DOMElement $node, Abstr
$oElement = $document->getElement('p:spPr/a:xfrm', $node);
if ($oElement instanceof DOMElement) {
if ($oElement->hasAttribute('rot')) {
$oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
$oShape->setRotation((int) CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
}
}

Expand Down Expand Up @@ -835,7 +835,7 @@ protected function loadShapeDrawing(XMLReader $document, DOMElement $node, Abstr
$oShape->getShadow()->setDistance(CommonDrawing::emuToPixels($oSubElement->getAttribute('dist')));
}
if ($oSubElement->hasAttribute('dir')) {
$oShape->getShadow()->setDirection(CommonDrawing::angleToDegrees($oSubElement->getAttribute('dir')));
$oShape->getShadow()->setDirection((int) CommonDrawing::angleToDegrees($oSubElement->getAttribute('dir')));
}
if ($oSubElement->hasAttribute('algn')) {
$oShape->getShadow()->setAlignment($oSubElement->getAttribute('algn'));
Expand Down Expand Up @@ -880,7 +880,7 @@ protected function loadShapeRichText(XMLReader $document, DOMElement $node, Abst

$oElement = $document->getElement('p:spPr/a:xfrm', $node);
if ($oElement instanceof DOMElement && $oElement->hasAttribute('rot')) {
$oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
$oShape->setRotation((int) CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
}

$oElement = $document->getElement('p:spPr/a:xfrm/a:off', $node);
Expand Down Expand Up @@ -1098,6 +1098,25 @@ protected function loadParagraph(XMLReader $document, DOMElement $oElement, $oSh
$oParagraph->getAlignment()->setIsRTL((bool) $oSubElement->getAttribute('rtl'));
}

$oElementLineSpacingPoints = $document->getElement('a:lnSpc/a:spcPts', $oSubElement);
if ($oElementLineSpacingPoints instanceof DOMElement) {
$oParagraph->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_POINT);
$oParagraph->setLineSpacing($oElementLineSpacingPoints->getAttribute('val') / 100);
}
$oElementLineSpacingPercent = $document->getElement('a:lnSpc/a:spcPct', $oSubElement);
if ($oElementLineSpacingPercent instanceof DOMElement) {
$oParagraph->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_PERCENT);
$oParagraph->setLineSpacing($oElementLineSpacingPercent->getAttribute('val') / 1000);
}
$oElementSpacingBefore = $document->getElement('a:spcBef/a:spcPts', $oSubElement);
if ($oElementSpacingBefore instanceof DOMElement) {
$oParagraph->setSpacingBefore($oElementSpacingBefore->getAttribute('val') / 100);
}
$oElementSpacingAfter = $document->getElement('a:spcAft/a:spcPts', $oSubElement);
if ($oElementSpacingAfter instanceof DOMElement) {
$oParagraph->setSpacingAfter($oElementSpacingAfter->getAttribute('val') / 100);
}

$oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_NONE);

$oElementBuFont = $document->getElement('a:buFont', $oSubElement);
Expand Down
Loading

0 comments on commit a0c665c

Please sign in to comment.