Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added column spacing in RichText & line spacing mode & spacing before/after for Paragraph #663

Merged
merged 1 commit into from
Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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