Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
7 changes: 7 additions & 0 deletions src/PhpSpreadsheet/Cell/Cell.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Style\Protection;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Table;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Stringable;
Expand Down Expand Up @@ -307,6 +308,12 @@ public function setValueExplicit(mixed $value, string $dataType = DataType::TYPE
$this->value = SharedDate::convertIsoDate($value);
$dataType = DataType::TYPE_NUMERIC;

break;
case DataType::TYPE_DRAWING_IN_CELL:
if ($value instanceof BaseDrawing) {
$this->value = $value;
}

break;
case DataType::TYPE_ERROR:
$this->value = DataType::checkErrorCode($value);
Expand Down
1 change: 1 addition & 0 deletions src/PhpSpreadsheet/Cell/DataType.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class DataType
const TYPE_INLINE = 'inlineStr';
const TYPE_ERROR = 'e';
const TYPE_ISO_DATE = 'd';
const TYPE_DRAWING_IN_CELL = 'drawingCell';

/**
* List of error codes.
Expand Down
36 changes: 36 additions & 0 deletions src/PhpSpreadsheet/Reader/Xlsx.php
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,19 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet

$charts = $chartDetails = [];

// Add richData (contains relation of in-cell images)
$richData = [];
$relationsFileName = $dir . '/richData/_rels/richValueRel.xml.rels';
if ($zip->locateName($relationsFileName)) {
$relsWorksheet = $this->loadZip($relationsFileName, Namespaces::RELATIONSHIPS);
foreach ($relsWorksheet->Relationship as $elex) {
$ele = self::getAttributes($elex);
if ($ele['Type'] == Namespaces::IMAGE) {
$richData['image'][(string) $ele['Id']] = (string) $ele['Target'];
}
}
}

$sheetCreated = false;
if ($xmlWorkbookNS->sheets) {
foreach ($xmlWorkbookNS->sheets->sheet as $eleSheet) {
Expand Down Expand Up @@ -940,6 +953,29 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet

break;
case DataType::TYPE_ERROR:
if (isset($cAttr->vm, $richData['image']['rId' . $cAttr->vm]) && !$useFormula) {
$imagePath = $dir . '/' . str_replace('../', '', $richData['image']['rId' . $cAttr->vm]);
$objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$objDrawing->setPath(
'zip://' . File::realpath($filename) . '#' . $imagePath,
false,
$zip
);

$objDrawing->setCoordinates($r);
$objDrawing->setOffsetX(0);
$objDrawing->setOffsetY(0);
Copy link

@rapaelector rapaelector Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those can be remove as it is by default as 0

$objDrawing->setResizeProportional(false);
$objDrawing->setInCell(true);
$objDrawing->setWorksheet($docSheet);

$value = $objDrawing;
$cellDataType = DataType::TYPE_DRAWING_IN_CELL;
$c->t = DataType::TYPE_ERROR;

break;
}

if (!$useFormula) {
$value = self::castToError($c);
} else {
Expand Down
8 changes: 8 additions & 0 deletions src/PhpSpreadsheet/Reader/Xlsx/Namespaces.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,12 @@ class Namespaces
const DYNAMIC_ARRAY = 'http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray';

const DYNAMIC_ARRAY_RICHDATA = 'http://schemas.microsoft.com/office/spreadsheetml/2017/richdata';

const RELATIONSHIPS_RICH_VALUE_TYPES = 'http://schemas.microsoft.com/office/2017/06/relationships/rdRichValueTypes';

const RELATIONSHIPS_RICH_VALUE_STRUCTURE = 'http://schemas.microsoft.com/office/2017/06/relationships/rdRichValueStructure';

const RELATIONSHIPS_RICH_VALUE = 'http://schemas.microsoft.com/office/2017/06/relationships/rdRichValue';

const RELATIONSHIPS_RICH_VALUE_REL = 'http://schemas.microsoft.com/office/2022/10/relationships/richValueRel';
}
15 changes: 15 additions & 0 deletions src/PhpSpreadsheet/Spreadsheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,21 @@ public function hasRibbonBinObjects(): bool
return $this->ribbonBinObjects !== null;
}

/**
* This workbook has in cell images.
*/
public function hasInCellDrawings(): bool
{
$sheetCount = $this->getSheetCount();
for ($i = 0; $i < $sheetCount; ++$i) {
if ($this->getSheet($i)->getInCellDrawingCollection()->count() > 0) {
return true;
}
}

return false;
}

/**
* Check if a sheet with a specified code name already exists.
*
Expand Down
37 changes: 35 additions & 2 deletions src/PhpSpreadsheet/Worksheet/BaseDrawing.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ class BaseDrawing implements IComparable
*/
protected ?int $opacity = null;

protected bool $inCell = false;

protected int $index = 0;

/**
* Create a new BaseDrawing.
*/
Expand Down Expand Up @@ -203,8 +207,13 @@ public function setWorksheet(?Worksheet $worksheet = null, bool $overrideOld = f
if (!($this instanceof Drawing && $this->getPath() === '')) {
$this->worksheet->getCell($this->coordinates);
}
$this->worksheet->getDrawingCollection()
->append($this);
if ($this->inCell) {
$this->worksheet->getInCellDrawingCollection()
->append($this);
} else {
$this->worksheet->getDrawingCollection()
->append($this);
}
}
} else {
if ($overrideOld) {
Expand Down Expand Up @@ -572,4 +581,28 @@ public function getOpacity(): ?int
{
return $this->opacity;
}

public function setInCell(bool $inCell): self
{
$this->inCell = $inCell;

return $this;
}

public function isInCell(): ?bool
{
return $this->inCell;
}

public function setIndex(int $index): self
{
$this->index = $index;

return $this;
}

public function getIndex(): int
{
return $this->index;
}
}
28 changes: 27 additions & 1 deletion src/PhpSpreadsheet/Worksheet/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ class Worksheet
*/
private ArrayObject $drawingCollection;

/**
* Collection of drawings.
*
* @var ArrayObject<int, BaseDrawing>
*/
private ArrayObject $inCellDrawingCollection;

/**
* Collection of Chart objects.
*
Expand Down Expand Up @@ -334,6 +341,8 @@ public function __construct(?Spreadsheet $parent = null, string $title = 'Worksh
$this->sheetView = new SheetView();
// Drawing collection
$this->drawingCollection = new ArrayObject();
// In Cell Drawing collection
$this->inCellDrawingCollection = new ArrayObject();
// Chart collection
$this->chartCollection = new ArrayObject();
// Protection
Expand Down Expand Up @@ -371,7 +380,7 @@ public function __destruct()
?->clearCalculationCacheForWorksheet($this->title);

$this->disconnectCells();
unset($this->rowDimensions, $this->columnDimensions, $this->tableCollection, $this->drawingCollection, $this->chartCollection, $this->autoFilter);
unset($this->rowDimensions, $this->columnDimensions, $this->tableCollection, $this->drawingCollection, $this->inCellDrawingCollection, $this->chartCollection, $this->autoFilter);
}

/**
Expand Down Expand Up @@ -519,6 +528,16 @@ public function getDrawingCollection(): ArrayObject
return $this->drawingCollection;
}

/**
* Get collection of drawings.
*
* @return ArrayObject<int, BaseDrawing>
*/
public function getInCellDrawingCollection(): ArrayObject
{
return $this->inCellDrawingCollection;
}

/**
* Get collection of charts.
*
Expand Down Expand Up @@ -3730,6 +3749,13 @@ public function __clone()
$newDrawing = clone $item;
$newDrawing->setWorksheet($this);
}
} elseif ($key === 'inCellDrawingCollection') {
$currentCollection = $this->inCellDrawingCollection;
$this->inCellDrawingCollection = new ArrayObject();
foreach ($currentCollection as $item) {
$newDrawing = clone $item;
$newDrawing->setWorksheet($this);
}
} elseif ($key === 'tableCollection') {
$currentCollection = $this->tableCollection;
$this->tableCollection = new ArrayObject();
Expand Down
16 changes: 15 additions & 1 deletion src/PhpSpreadsheet/Writer/Xlsx.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Rels;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\RelsRibbon;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\RelsVBA;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\RichDataDrawing;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\StringTable;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Style;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Table;
Expand Down Expand Up @@ -329,9 +330,22 @@ public function save($filename, int $flags = 0): void

/** @var string[] */
$zipContent = [];
$richDataCount = 0;

if ($this->spreadSheet->hasInCellDrawings()) {
$richDataDrawing = new RichDataDrawing();
$richDataFiles = $richDataDrawing->generateFiles($this->spreadSheet);
$richDataCount = count($richDataFiles);

// Add all Rich Data files to ZIP
foreach ($richDataFiles as $path => $content) {
$zipContent[$path] = $content;
}
}

// Add [Content_Types].xml to ZIP file
$zipContent['[Content_Types].xml'] = $this->getWriterPartContentTypes()->writeContentTypes($this->spreadSheet, $this->includeCharts);
$metadataData = (new Xlsx\Metadata($this))->writeMetadata();
$metadataData = (new Xlsx\Metadata($this))->writeMetadata($richDataCount);
if ($metadataData !== '') {
$zipContent['xl/metadata.xml'] = $metadataData;
}
Expand Down
8 changes: 8 additions & 0 deletions src/PhpSpreadsheet/Writer/Xlsx/ContentTypes.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ public function writeContentTypes(Spreadsheet $spreadsheet, bool $includeCharts
$this->writeDefaultContentType($objWriter, $extension, $mimeType);
}
}

if ($spreadsheet->hasInCellDrawings()) {
$this->writeOverrideContentType($objWriter, '/xl/richData/richValueRel.xml', 'application/vnd.ms-excel.richvaluerel+xml');
$this->writeOverrideContentType($objWriter, '/xl/richData/rdrichvalue.xml', 'application/vnd.ms-excel.rdrichvalue+xml');
$this->writeOverrideContentType($objWriter, '/xl/richData/rdrichvaluestructure.xml', 'application/vnd.ms-excel.rdrichvaluestructure+xml');
$this->writeOverrideContentType($objWriter, '/xl/richData/rdRichValueTypes.xml', 'application/vnd.ms-excel.rdrichvaluetypes+xml');
}

if ($spreadsheet->hasRibbonBinObjects()) {
// Some additional objects in the ribbon ?
// we need to write "Extension" but not already write for media content
Expand Down
6 changes: 6 additions & 0 deletions src/PhpSpreadsheet/Writer/Xlsx/Drawing.php
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,12 @@ public function allDrawings(Spreadsheet $spreadsheet): array
while ($iterator->valid()) {
$aDrawings[] = $iterator->current();

$iterator->next();
}
$iterator = $spreadsheet->getSheet($i)->getInCellDrawingCollection()->getIterator();
while ($iterator->valid()) {
$aDrawings[] = $iterator->current();

$iterator->next();
}
}
Expand Down
Loading