Skip to content

Commit 9fcfa4b

Browse files
authored
Xlsx Support Flipping of Image (#3801)
* Xlsx Support Flipping of Image Fix #731. Opened over 5 years ago, probably the second oldest problem I've worked on. Images attached to an Xlsx spreadsheet can be rotated, which is supported by PhpSpreadsheet. They can also be flipped along their horizontal and/or vertical axes, and that has not been supported. This PR adds that support. * Update CHANGELOG.md
1 parent 009e009 commit 9fcfa4b

File tree

6 files changed

+81
-0
lines changed

6 files changed

+81
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
2626
- Writer ODS : Write Border Style for cells [Issue #3690](https://github.com/PHPOffice/PhpSpreadsheet/issues/3690) [PR #3693](https://github.com/PHPOffice/PhpSpreadsheet/pull/3693)
2727
- Sheet Background Images [Issue #1649](https://github.com/PHPOffice/PhpSpreadsheet/issues/1649) [PR #3795](https://github.com/PHPOffice/PhpSpreadsheet/pull/3795)
2828
- Check if Coordinate is Inside Range [PR #3779](https://github.com/PHPOffice/PhpSpreadsheet/pull/3779)
29+
- Flipping Images [Issue #731](https://github.com/PHPOffice/PhpSpreadsheet/issues/731) [PR #3801](https://github.com/PHPOffice/PhpSpreadsheet/pull/3801)
30+
- Chart Dynamic Title and Font Properties [Issue #3797](https://github.com/PHPOffice/PhpSpreadsheet/issues/3797) [PR #3800](https://github.com/PHPOffice/PhpSpreadsheet/pull/3800)
2931

3032
### Changed
3133

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,8 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
14241424
$objDrawing->setHeight(Drawing::EMUToPixels(self::getArrayItem(self::getAttributes($oneCellAnchor->ext), 'cy')));
14251425
if ($xfrm) {
14261426
$objDrawing->setRotation((int) Drawing::angleToDegrees(self::getArrayItem(self::getAttributes($xfrm), 'rot')));
1427+
$objDrawing->setFlipVertical((bool) self::getArrayItem(self::getAttributes($xfrm), 'flipV'));
1428+
$objDrawing->setFlipHorizontal((bool) self::getArrayItem(self::getAttributes($xfrm), 'flipH'));
14271429
}
14281430
if ($outerShdw) {
14291431
$shadow = $objDrawing->getShadow();
@@ -1518,6 +1520,8 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
15181520
$objDrawing->setWidth(Drawing::EMUToPixels(self::getArrayItem(self::getAttributes($xfrm->ext), 'cx')));
15191521
$objDrawing->setHeight(Drawing::EMUToPixels(self::getArrayItem(self::getAttributes($xfrm->ext), 'cy')));
15201522
$objDrawing->setRotation(Drawing::angleToDegrees(self::getArrayItem(self::getAttributes($xfrm), 'rot')));
1523+
$objDrawing->setFlipVertical((bool) self::getArrayItem(self::getAttributes($xfrm), 'flipV'));
1524+
$objDrawing->setFlipHorizontal((bool) self::getArrayItem(self::getAttributes($xfrm), 'flipH'));
15211525
}
15221526
if ($outerShdw) {
15231527
$shadow = $objDrawing->getShadow();

src/PhpSpreadsheet/Worksheet/BaseDrawing.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ class BaseDrawing implements IComparable
131131
*/
132132
protected $rotation = 0;
133133

134+
protected bool $flipVertical = false;
135+
136+
protected bool $flipHorizontal = false;
137+
134138
/**
135139
* Shadow.
136140
*/
@@ -542,4 +546,28 @@ public function setSrcRect($srcRect): self
542546

543547
return $this;
544548
}
549+
550+
public function setFlipHorizontal(bool $flipHorizontal): self
551+
{
552+
$this->flipHorizontal = $flipHorizontal;
553+
554+
return $this;
555+
}
556+
557+
public function getFlipHorizontal(): bool
558+
{
559+
return $this->flipHorizontal;
560+
}
561+
562+
public function setFlipVertical(bool $flipVertical): self
563+
{
564+
$this->flipVertical = $flipVertical;
565+
566+
return $this;
567+
}
568+
569+
public function getFlipVertical(): bool
570+
{
571+
return $this->flipVertical;
572+
}
545573
}

src/PhpSpreadsheet/Writer/Xlsx/Drawing.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ public function writeDrawing(XMLWriter $objWriter, BaseDrawing $drawing, $relati
294294
// a:xfrm
295295
$objWriter->startElement('a:xfrm');
296296
$objWriter->writeAttribute('rot', (string) SharedDrawing::degreesToAngle($drawing->getRotation()));
297+
self::writeAttributeIf($objWriter, $drawing->getFlipVertical(), 'flipV', '1');
298+
self::writeAttributeIf($objWriter, $drawing->getFlipHorizontal(), 'flipH', '1');
297299
if ($isTwoCellAnchor) {
298300
$objWriter->startElement('a:ext');
299301
$objWriter->writeAttribute('cx', self::stringEmu($drawing->getWidth()));
@@ -579,4 +581,11 @@ private static function stringEmu(int $pixelValue): string
579581
{
580582
return (string) SharedDrawing::pixelsToEMU($pixelValue);
581583
}
584+
585+
private static function writeAttributeIf(XMLWriter $objWriter, ?bool $condition, string $attr, string $val): void
586+
{
587+
if ($condition) {
588+
$objWriter->writeAttribute($attr, $val);
589+
}
590+
}
582591
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
6+
7+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
8+
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
9+
10+
class Issue731Test extends AbstractFunctional
11+
{
12+
private static string $testbook = 'tests/data/Reader/XLSX/issue.731.xlsx';
13+
14+
public function testRotateAndFlipImages(): void
15+
{
16+
$reader = new Xlsx();
17+
$spreadsheet = $reader->load(self::$testbook);
18+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
19+
$spreadsheet->disconnectWorksheets();
20+
$reloadedSheet = $reloadedSpreadsheet->getActiveSheet();
21+
$expected = [
22+
[0, false, false],
23+
[90, false, false],
24+
[270, false, false],
25+
[0, false, true],
26+
[0, true, false],
27+
[20, false, false],
28+
[20, false, true],
29+
[0, true, true],
30+
];
31+
$actual = [];
32+
foreach ($reloadedSheet->getDrawingCollection() as $drawing) {
33+
$actual[] = [$drawing->getRotation(), $drawing->getFlipHorizontal(), $drawing->getFlipVertical()];
34+
}
35+
self::assertSame($expected, $actual);
36+
$reloadedSpreadsheet->disconnectWorksheets();
37+
}
38+
}

tests/data/Reader/XLSX/issue.731.xlsx

27.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)