Skip to content

Commit 10d5664

Browse files
committed
Add two cell anhor drawing.
1 parent e7b0497 commit 10d5664

File tree

5 files changed

+212
-19
lines changed

5 files changed

+212
-19
lines changed

phpstan-baseline.neon

+7-2
Original file line numberDiff line numberDiff line change
@@ -7200,6 +7200,11 @@ parameters:
72007200
count: 1
72017201
path: src/PhpSpreadsheet/Writer/Xlsx/DocProps.php
72027202

7203+
-
7204+
message: "#^Parameter \\#1 \\$coordinates of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:indexesFromString\\(\\) expects string, string\\|null given\\.$#"
7205+
count: 1
7206+
path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php
7207+
72037208
-
72047209
message: "#^Parameter \\#1 \\$index of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getChartByIndex\\(\\) expects string, int given\\.$#"
72057210
count: 1
@@ -7212,12 +7217,12 @@ parameters:
72127217

72137218
-
72147219
message: "#^Parameter \\#2 \\$content of method XMLWriter\\:\\:writeElement\\(\\) expects string\\|null, int given\\.$#"
7215-
count: 12
7220+
count: 20
72167221
path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php
72177222

72187223
-
72197224
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#"
7220-
count: 8
7225+
count: 10
72217226
path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php
72227227

72237228
-

src/PhpSpreadsheet/Reader/Xlsx.php

+6
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,12 @@ public function load(string $filename, int $flags = 0): Spreadsheet
13391339

13401340
$objDrawing->setOffsetX(Drawing::EMUToPixels($twoCellAnchor->from->colOff));
13411341
$objDrawing->setOffsetY(Drawing::EMUToPixels($twoCellAnchor->from->rowOff));
1342+
1343+
$objDrawing->setCoordinates2(Coordinate::stringFromColumnIndex(((int) $twoCellAnchor->to->col) + 1) . ($twoCellAnchor->to->row + 1));
1344+
1345+
$objDrawing->setOffsetX2(Drawing::EMUToPixels($twoCellAnchor->to->colOff));
1346+
$objDrawing->setOffsetY2(Drawing::EMUToPixels($twoCellAnchor->to->rowOff));
1347+
13421348
$objDrawing->setResizeProportional(false);
13431349

13441350
if ($xfrm) {

src/PhpSpreadsheet/Worksheet/BaseDrawing.php

+99
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,27 @@ class BaseDrawing implements IComparable
6464
*/
6565
protected $offsetY;
6666

67+
/**
68+
* Coordinates2.
69+
*
70+
* @var null|string
71+
*/
72+
protected $coordinates2;
73+
74+
/**
75+
* Offset X2.
76+
*
77+
* @var int
78+
*/
79+
protected $offsetX2;
80+
81+
/**
82+
* Offset Y2.
83+
*
84+
* @var int
85+
*/
86+
protected $offsetY2;
87+
6788
/**
6889
* Width.
6990
*
@@ -125,6 +146,9 @@ public function __construct()
125146
$this->coordinates = 'A1';
126147
$this->offsetX = 0;
127148
$this->offsetY = 0;
149+
$this->coordinates2 = null;
150+
$this->offsetX2 = 0;
151+
$this->offsetY2 = 0;
128152
$this->width = 0;
129153
$this->height = 0;
130154
$this->resizeProportional = true;
@@ -301,6 +325,78 @@ public function getOffsetY()
301325
return $this->offsetY;
302326
}
303327

328+
/**
329+
* Get Coordinates2.
330+
*
331+
* @return null|string
332+
*/
333+
public function getCoordinates2()
334+
{
335+
return $this->coordinates2;
336+
}
337+
338+
/**
339+
* Set Coordinates2.
340+
*
341+
* @param null|string $coordinates2 eg: 'A1'
342+
*
343+
* @return $this
344+
*/
345+
public function setCoordinates2($coordinates2)
346+
{
347+
$this->coordinates2 = $coordinates2;
348+
349+
return $this;
350+
}
351+
352+
/**
353+
* Get OffsetX2.
354+
*
355+
* @return int
356+
*/
357+
public function getOffsetX2()
358+
{
359+
return $this->offsetX2;
360+
}
361+
362+
/**
363+
* Set OffsetX2.
364+
*
365+
* @param int $offsetX2
366+
*
367+
* @return $this
368+
*/
369+
public function setOffsetX2($offsetX2)
370+
{
371+
$this->offsetX2 = $offsetX2;
372+
373+
return $this;
374+
}
375+
376+
/**
377+
* Get OffsetY2.
378+
*
379+
* @return int
380+
*/
381+
public function getOffsetY2()
382+
{
383+
return $this->offsetY2;
384+
}
385+
386+
/**
387+
* Set OffsetY2.
388+
*
389+
* @param int $offsetY2
390+
*
391+
* @return $this
392+
*/
393+
public function setOffsetY2($offsetY2)
394+
{
395+
$this->offsetY2 = $offsetY2;
396+
397+
return $this;
398+
}
399+
304400
/**
305401
* Set OffsetY.
306402
*
@@ -497,6 +593,9 @@ public function getHashCode()
497593
$this->coordinates .
498594
$this->offsetX .
499595
$this->offsetY .
596+
$this->coordinates2 .
597+
$this->offsetX2 .
598+
$this->offsetY2 .
500599
$this->width .
501600
$this->height .
502601
$this->rotation .

src/PhpSpreadsheet/Writer/Xlsx/Drawing.php

+48-17
Original file line numberDiff line numberDiff line change
@@ -153,24 +153,49 @@ public function writeChart(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Chart
153153
public function writeDrawing(XMLWriter $objWriter, BaseDrawing $drawing, $relationId = -1, $hlinkClickId = null): void
154154
{
155155
if ($relationId >= 0) {
156-
// xdr:oneCellAnchor
157-
$objWriter->startElement('xdr:oneCellAnchor');
158-
// Image location
159-
$aCoordinates = Coordinate::indexesFromString($drawing->getCoordinates());
160-
161-
// xdr:from
162-
$objWriter->startElement('xdr:from');
163-
$objWriter->writeElement('xdr:col', $aCoordinates[0] - 1);
164-
$objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetX()));
165-
$objWriter->writeElement('xdr:row', $aCoordinates[1] - 1);
166-
$objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetY()));
167-
$objWriter->endElement();
156+
$isTwoCellAnchor = $drawing->getCoordinates2() !== null;
157+
if ($isTwoCellAnchor) {
158+
// xdr:twoCellAnchor
159+
$objWriter->startElement('xdr:twoCellAnchor');
160+
// Image location
161+
$aCoordinates = Coordinate::indexesFromString($drawing->getCoordinates());
162+
$aCoordinates2 = Coordinate::indexesFromString($drawing->getCoordinates2());
163+
164+
// xdr:from
165+
$objWriter->startElement('xdr:from');
166+
$objWriter->writeElement('xdr:col', $aCoordinates[0] - 1);
167+
$objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetX()));
168+
$objWriter->writeElement('xdr:row', $aCoordinates[1] - 1);
169+
$objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetY()));
170+
$objWriter->endElement();
168171

169-
// xdr:ext
170-
$objWriter->startElement('xdr:ext');
171-
$objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getWidth()));
172-
$objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getHeight()));
173-
$objWriter->endElement();
172+
// xdr:to
173+
$objWriter->startElement('xdr:to');
174+
$objWriter->writeElement('xdr:col', $aCoordinates2[0] - 1);
175+
$objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetX2()));
176+
$objWriter->writeElement('xdr:row', $aCoordinates2[1] - 1);
177+
$objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetY2()));
178+
$objWriter->endElement();
179+
} else {
180+
// xdr:oneCellAnchor
181+
$objWriter->startElement('xdr:oneCellAnchor');
182+
// Image location
183+
$aCoordinates = Coordinate::indexesFromString($drawing->getCoordinates());
184+
185+
// xdr:from
186+
$objWriter->startElement('xdr:from');
187+
$objWriter->writeElement('xdr:col', $aCoordinates[0] - 1);
188+
$objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetX()));
189+
$objWriter->writeElement('xdr:row', $aCoordinates[1] - 1);
190+
$objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetY()));
191+
$objWriter->endElement();
192+
193+
// xdr:ext
194+
$objWriter->startElement('xdr:ext');
195+
$objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getWidth()));
196+
$objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getHeight()));
197+
$objWriter->endElement();
198+
}
174199

175200
// xdr:pic
176201
$objWriter->startElement('xdr:pic');
@@ -223,6 +248,12 @@ public function writeDrawing(XMLWriter $objWriter, BaseDrawing $drawing, $relati
223248
// a:xfrm
224249
$objWriter->startElement('a:xfrm');
225250
$objWriter->writeAttribute('rot', \PhpOffice\PhpSpreadsheet\Shared\Drawing::degreesToAngle($drawing->getRotation()));
251+
if ($isTwoCellAnchor) {
252+
$objWriter->startElement('a:ext');
253+
$objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getWidth()));
254+
$objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getHeight()));
255+
$objWriter->endElement();
256+
}
226257
$objWriter->endElement();
227258

228259
// a:prstGeom

tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php

+52
Original file line numberDiff line numberDiff line change
@@ -430,4 +430,56 @@ public function testBuildWithDifferentImageFormats(): void
430430

431431
self::assertNotNull($reloadedSpreadsheet);
432432
}
433+
434+
/**
435+
* Test save and load XLSX file with drawing image that coordinate is two cell anchor.
436+
*/
437+
public function testTwoCellAnchorDrawing(): void
438+
{
439+
$reader = new Xlsx();
440+
$spreadsheet = new Spreadsheet();
441+
$sheet = $spreadsheet->getActiveSheet();
442+
443+
// Add gif image that coordinates is two cell anchor.
444+
$drawing = new Drawing();
445+
$drawing->setName('Green Square');
446+
$drawing->setPath('tests/data/Writer/XLSX/green_square.gif');
447+
self::assertEquals($drawing->getWidth(), 150);
448+
self::assertEquals($drawing->getHeight(), 150);
449+
$drawing->setCoordinates('A1');
450+
$drawing->setOffsetX(30);
451+
$drawing->setOffsetY(10);
452+
$drawing->setCoordinates2('E8');
453+
$drawing->setOffsetX2(-50);
454+
$drawing->setOffsetY2(-20);
455+
$drawing->setWorksheet($sheet);
456+
457+
// Write file
458+
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
459+
$tempFileName = File::sysGetTempDir() . '/drawings_image_that_two_cell_anchor.xlsx';
460+
$writer->save($tempFileName);
461+
462+
// Read new file
463+
$reloadedSpreadsheet = $reader->load($tempFileName);
464+
$sheet = $reloadedSpreadsheet->getActiveSheet();
465+
466+
// Check image coordinates.
467+
$drawingCollection = $sheet->getDrawingCollection();
468+
$drawing = $drawingCollection[0];
469+
self::assertNotNull($drawing);
470+
471+
self::assertEquals($drawing->getWidth(), 150);
472+
self::assertEquals($drawing->getHeight(), 150);
473+
self::assertEquals($drawing->getCoordinates(), 'A1');
474+
self::assertEquals($drawing->getOffsetX(), 30);
475+
self::assertEquals($drawing->getOffsetY(), 10);
476+
self::assertEquals($drawing->getCoordinates2(), 'E8');
477+
self::assertEquals($drawing->getOffsetX2(), -50);
478+
self::assertEquals($drawing->getOffsetY2(), -20);
479+
self::assertEquals($drawing->getWorksheet(), $sheet);
480+
481+
unlink($tempFileName);
482+
483+
self::assertNotNull($reloadedSpreadsheet);
484+
}
433485
}

0 commit comments

Comments
 (0)