Skip to content

Commit f414142

Browse files
author
Thomas Lallement
committed
Finalize XLSX In-Cell Drawing Writer
1 parent 4ccf9c0 commit f414142

File tree

16 files changed

+345
-137
lines changed

16 files changed

+345
-137
lines changed

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -966,8 +966,8 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
966966
$objDrawing->setOffsetX(0);
967967
$objDrawing->setOffsetY(0);
968968
$objDrawing->setResizeProportional(false);
969-
$objDrawing->setWorksheet($docSheet);
970969
$objDrawing->setInCell(true);
970+
$objDrawing->setWorksheet($docSheet);
971971

972972
$value = $objDrawing;
973973
$cellDataType = DataType::TYPE_DRAWING_IN_CELL;

src/PhpSpreadsheet/Reader/Xlsx/Namespaces.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,12 @@ class Namespaces
121121
const DYNAMIC_ARRAY = 'http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray';
122122

123123
const DYNAMIC_ARRAY_RICHDATA = 'http://schemas.microsoft.com/office/spreadsheetml/2017/richdata';
124+
125+
const RELATIONSHIPS_RICH_VALUE_TYPES = 'http://schemas.microsoft.com/office/2017/06/relationships/rdRichValueTypes';
126+
127+
const RELATIONSHIPS_RICH_VALUE_STRUCTURE = 'http://schemas.microsoft.com/office/2017/06/relationships/rdRichValueStructure';
128+
129+
const RELATIONSHIPS_RICH_VALUE = 'http://schemas.microsoft.com/office/2017/06/relationships/rdRichValue';
130+
131+
const RELATIONSHIPS_RICH_VALUE_REL = 'http://schemas.microsoft.com/office/2022/10/relationships/richValueRel';
124132
}

src/PhpSpreadsheet/Spreadsheet.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,21 @@ public function hasRibbonBinObjects(): bool
412412
return $this->ribbonBinObjects !== null;
413413
}
414414

415+
/**
416+
* This workbook have in cell images
417+
*/
418+
public function hasInCellDrawings(): bool
419+
{
420+
$sheetCount = $this->getSheetCount();
421+
for ($i = 0; $i < $sheetCount; ++$i) {
422+
if ($this->getSheet($i)->getInCellDrawingCollection()->count() > 0) {
423+
return true;
424+
}
425+
}
426+
427+
return false;
428+
}
429+
415430
/**
416431
* Check if a sheet with a specified code name already exists.
417432
*

src/PhpSpreadsheet/Worksheet/BaseDrawing.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ class BaseDrawing implements IComparable
139139

140140
protected bool $inCell = false;
141141

142+
protected int $index = 0;
143+
142144
/**
143145
* Create a new BaseDrawing.
144146
*/
@@ -205,8 +207,13 @@ public function setWorksheet(?Worksheet $worksheet = null, bool $overrideOld = f
205207
if (!($this instanceof Drawing && $this->getPath() === '')) {
206208
$this->worksheet->getCell($this->coordinates);
207209
}
208-
$this->worksheet->getDrawingCollection()
209-
->append($this);
210+
if ($this->inCell) {
211+
$this->worksheet->getInCellDrawingCollection()
212+
->append($this);
213+
} else {
214+
$this->worksheet->getDrawingCollection()
215+
->append($this);
216+
}
210217
}
211218
} else {
212219
if ($overrideOld) {
@@ -586,4 +593,16 @@ public function isInCell(): ?bool
586593
{
587594
return $this->inCell;
588595
}
596+
597+
public function setIndex(int $index): self
598+
{
599+
$this->index = $index;
600+
601+
return $this;
602+
}
603+
604+
public function getIndex(): int
605+
{
606+
return $this->index;
607+
}
589608
}

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ class Worksheet
108108
*/
109109
private ArrayObject $drawingCollection;
110110

111+
/**
112+
* Collection of drawings.
113+
*
114+
* @var ArrayObject<int, BaseDrawing>
115+
*/
116+
private ArrayObject $inCellDrawingCollection;
117+
111118
/**
112119
* Collection of Chart objects.
113120
*
@@ -334,6 +341,8 @@ public function __construct(?Spreadsheet $parent = null, string $title = 'Worksh
334341
$this->sheetView = new SheetView();
335342
// Drawing collection
336343
$this->drawingCollection = new ArrayObject();
344+
// In Cell Drawing collection
345+
$this->inCellDrawingCollection = new ArrayObject();
337346
// Chart collection
338347
$this->chartCollection = new ArrayObject();
339348
// Protection
@@ -371,7 +380,7 @@ public function __destruct()
371380
?->clearCalculationCacheForWorksheet($this->title);
372381

373382
$this->disconnectCells();
374-
unset($this->rowDimensions, $this->columnDimensions, $this->tableCollection, $this->drawingCollection, $this->chartCollection, $this->autoFilter);
383+
unset($this->rowDimensions, $this->columnDimensions, $this->tableCollection, $this->drawingCollection, $this->inCellDrawingCollection, $this->chartCollection, $this->autoFilter);
375384
}
376385

377386
/**
@@ -519,6 +528,16 @@ public function getDrawingCollection(): ArrayObject
519528
return $this->drawingCollection;
520529
}
521530

531+
/**
532+
* Get collection of drawings.
533+
*
534+
* @return ArrayObject<int, BaseDrawing>
535+
*/
536+
public function getInCellDrawingCollection(): ArrayObject
537+
{
538+
return $this->inCellDrawingCollection;
539+
}
540+
522541
/**
523542
* Get collection of charts.
524543
*
@@ -3730,6 +3749,13 @@ public function __clone()
37303749
$newDrawing = clone $item;
37313750
$newDrawing->setWorksheet($this);
37323751
}
3752+
} elseif ($key === 'inCellDrawingCollection') {
3753+
$currentCollection = $this->inCellDrawingCollection;
3754+
$this->inCellDrawingCollection = new ArrayObject();
3755+
foreach ($currentCollection as $item) {
3756+
$newDrawing = clone $item;
3757+
$newDrawing->setWorksheet($this);
3758+
}
37333759
} elseif ($key === 'tableCollection') {
37343760
$currentCollection = $this->tableCollection;
37353761
$this->tableCollection = new ArrayObject();

src/PhpSpreadsheet/Writer/Xlsx.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,22 @@ public function save($filename, int $flags = 0): void
330330

331331
/** @var string[] */
332332
$zipContent = [];
333+
$richDataCount = 0;
334+
335+
if ($this->spreadSheet->hasInCellDrawings()) {
336+
$richDataDrawing = new RichDataDrawing();
337+
$richDataFiles = $richDataDrawing->generateFiles($this->spreadSheet);
338+
$richDataCount = count($richDataFiles);
339+
340+
// Add all Rich Data files to ZIP
341+
foreach ($richDataFiles as $path => $content) {
342+
$zipContent[$path] = $content;
343+
}
344+
}
345+
333346
// Add [Content_Types].xml to ZIP file
334347
$zipContent['[Content_Types].xml'] = $this->getWriterPartContentTypes()->writeContentTypes($this->spreadSheet, $this->includeCharts);
335-
$metadataData = (new Xlsx\Metadata($this))->writeMetadata();
348+
$metadataData = (new Xlsx\Metadata($this))->writeMetadata($richDataCount);
336349
if ($metadataData !== '') {
337350
$zipContent['xl/metadata.xml'] = $metadataData;
338351
}
@@ -464,14 +477,6 @@ public function save($filename, int $flags = 0): void
464477
$zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = '<xml></xml>';
465478
}
466479

467-
$richDataDrawing = new RichDataDrawing();
468-
$richDataFiles = $richDataDrawing->generateFiles($this->spreadSheet->getSheet($i));
469-
470-
// Add all Rich Data files to ZIP
471-
foreach ($richDataFiles as $path => $content) {
472-
$zipContent[$path] = $content;
473-
}
474-
475480
// Add comment relationship parts
476481
/** @var mixed[][] */
477482
$legacyTemp = $unparsedLoadedData['sheets'] ?? [];

src/PhpSpreadsheet/Writer/Xlsx/ContentTypes.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ public function writeContentTypes(Spreadsheet $spreadsheet, bool $includeCharts
156156
$this->writeDefaultContentType($objWriter, $extension, $mimeType);
157157
}
158158
}
159+
160+
if ($spreadsheet->hasInCellDrawings()) {
161+
$this->writeOverrideContentType($objWriter, '/xl/richData/richValueRel.xml', 'application/vnd.ms-excel.richvaluerel+xml');
162+
$this->writeOverrideContentType($objWriter, '/xl/richData/rdrichvalue.xml', 'application/vnd.ms-excel.rdrichvalue+xml');
163+
$this->writeOverrideContentType($objWriter, '/xl/richData/rdrichvaluestructure.xml', 'application/vnd.ms-excel.rdrichvaluestructure+xml');
164+
$this->writeOverrideContentType($objWriter, '/xl/richData/rdRichValueTypes.xml', 'application/vnd.ms-excel.rdrichvaluetypes+xml');
165+
}
166+
159167
if ($spreadsheet->hasRibbonBinObjects()) {
160168
// Some additional objects in the ribbon ?
161169
// we need to write "Extension" but not already write for media content

src/PhpSpreadsheet/Writer/Xlsx/Drawing.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,10 @@ public function writeDrawings(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $wor
4848
$pRelationId = $i;
4949
$hlinkClickId = $pDrawing->getHyperlink() === null ? null : ++$i;
5050

51-
if (!$pDrawing->isInCell()) {
52-
$this->writeDrawing($objWriter, $pDrawing, $pRelationId, $hlinkClickId);
53-
++$i;
54-
}
51+
$this->writeDrawing($objWriter, $pDrawing, $pRelationId, $hlinkClickId);
52+
5553
$iterator->next();
54+
++$i;
5655
}
5756

5857
if ($includeCharts) {
@@ -563,6 +562,12 @@ public function allDrawings(Spreadsheet $spreadsheet): array
563562
while ($iterator->valid()) {
564563
$aDrawings[] = $iterator->current();
565564

565+
$iterator->next();
566+
}
567+
$iterator = $spreadsheet->getSheet($i)->getInCellDrawingCollection()->getIterator();
568+
while ($iterator->valid()) {
569+
$aDrawings[] = $iterator->current();
570+
566571
$iterator->next();
567572
}
568573
}

0 commit comments

Comments
 (0)