1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; |
4
|
|
|
|
5
|
|
|
use PhpOffice\PhpSpreadsheet\Cell\Coordinate; |
6
|
|
|
use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Namespaces; |
7
|
|
|
use PhpOffice\PhpSpreadsheet\Shared\Drawing as SharedDrawing; |
8
|
|
|
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; |
9
|
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet; |
10
|
|
|
use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing; |
11
|
|
|
use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing; |
12
|
|
|
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; |
13
|
|
|
|
14
|
|
|
class Drawing extends WriterPart |
15
|
|
|
{ |
16
|
|
|
/** |
17
|
|
|
* Write drawings to XML format. |
18
|
|
|
* |
19
|
|
|
* @param bool $includeCharts Flag indicating if we should include drawing details for charts |
20
|
|
|
* |
21
|
|
|
* @return string XML Output |
22
|
|
|
*/ |
23
|
114 |
|
public function writeDrawings(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, bool $includeCharts = false): string |
24
|
|
|
{ |
25
|
|
|
// Create XML writer |
26
|
114 |
|
$objWriter = null; |
27
|
114 |
|
if ($this->getParentWriter()->getUseDiskCaching()) { |
28
|
|
|
$objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); |
29
|
|
|
} else { |
30
|
114 |
|
$objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
// XML header |
34
|
114 |
|
$objWriter->startDocument('1.0', 'UTF-8', 'yes'); |
35
|
|
|
|
36
|
|
|
// xdr:wsDr |
37
|
114 |
|
$objWriter->startElement('xdr:wsDr'); |
38
|
114 |
|
$objWriter->writeAttribute('xmlns:xdr', Namespaces::SPREADSHEET_DRAWING); |
39
|
114 |
|
$objWriter->writeAttribute('xmlns:a', Namespaces::DRAWINGML); |
40
|
|
|
|
41
|
|
|
// Loop through images and write drawings |
42
|
114 |
|
$i = 1; |
43
|
114 |
|
$iterator = $worksheet->getDrawingCollection()->getIterator(); |
44
|
114 |
|
while ($iterator->valid()) { |
45
|
|
|
/** @var BaseDrawing $pDrawing */ |
46
|
50 |
|
$pDrawing = $iterator->current(); |
47
|
50 |
|
$pRelationId = $i; |
48
|
50 |
|
$hlinkClickId = $pDrawing->getHyperlink() === null ? null : ++$i; |
49
|
|
|
|
50
|
50 |
|
$this->writeDrawing($objWriter, $pDrawing, $pRelationId, $hlinkClickId); |
51
|
|
|
|
52
|
50 |
|
$iterator->next(); |
53
|
50 |
|
++$i; |
54
|
|
|
} |
55
|
|
|
|
56
|
114 |
|
if ($includeCharts) { |
57
|
73 |
|
$chartCount = $worksheet->getChartCount(); |
58
|
|
|
// Loop through charts and write the chart position |
59
|
73 |
|
if ($chartCount > 0) { |
60
|
73 |
|
for ($c = 0; $c < $chartCount; ++$c) { |
61
|
73 |
|
$chart = $worksheet->getChartByIndex((string) $c); |
62
|
73 |
|
if ($chart !== false) { |
63
|
73 |
|
$this->writeChart($objWriter, $chart, $c + $i); |
64
|
|
|
} |
65
|
|
|
} |
66
|
|
|
} |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
// unparsed AlternateContent |
70
|
114 |
|
$unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData(); |
71
|
114 |
|
if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingAlternateContents'])) { |
72
|
4 |
|
foreach ($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingAlternateContents'] as $drawingAlternateContent) { |
73
|
4 |
|
$objWriter->writeRaw($drawingAlternateContent); |
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
|
77
|
114 |
|
$objWriter->endElement(); |
78
|
|
|
|
79
|
|
|
// Return |
80
|
114 |
|
return $objWriter->getData(); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Write drawings to XML format. |
85
|
|
|
*/ |
86
|
73 |
|
public function writeChart(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Chart\Chart $chart, int $relationId = -1): void |
87
|
|
|
{ |
88
|
73 |
|
$tl = $chart->getTopLeftPosition(); |
89
|
73 |
|
$tlColRow = Coordinate::indexesFromString($tl['cell']); |
90
|
73 |
|
$br = $chart->getBottomRightPosition(); |
91
|
|
|
|
92
|
73 |
|
$isTwoCellAnchor = $br['cell'] !== ''; |
93
|
73 |
|
if ($isTwoCellAnchor) { |
94
|
71 |
|
$brColRow = Coordinate::indexesFromString($br['cell']); |
95
|
|
|
|
96
|
71 |
|
$objWriter->startElement('xdr:twoCellAnchor'); |
97
|
|
|
|
98
|
71 |
|
$objWriter->startElement('xdr:from'); |
99
|
71 |
|
$objWriter->writeElement('xdr:col', (string) ($tlColRow[0] - 1)); |
100
|
71 |
|
$objWriter->writeElement('xdr:colOff', self::stringEmu($tl['xOffset'])); |
101
|
71 |
|
$objWriter->writeElement('xdr:row', (string) ($tlColRow[1] - 1)); |
102
|
71 |
|
$objWriter->writeElement('xdr:rowOff', self::stringEmu($tl['yOffset'])); |
103
|
71 |
|
$objWriter->endElement(); |
104
|
71 |
|
$objWriter->startElement('xdr:to'); |
105
|
71 |
|
$objWriter->writeElement('xdr:col', (string) ($brColRow[0] - 1)); |
106
|
71 |
|
$objWriter->writeElement('xdr:colOff', self::stringEmu($br['xOffset'])); |
107
|
71 |
|
$objWriter->writeElement('xdr:row', (string) ($brColRow[1] - 1)); |
108
|
71 |
|
$objWriter->writeElement('xdr:rowOff', self::stringEmu($br['yOffset'])); |
109
|
71 |
|
$objWriter->endElement(); |
110
|
3 |
|
} elseif ($chart->getOneCellAnchor()) { |
111
|
1 |
|
$objWriter->startElement('xdr:oneCellAnchor'); |
112
|
|
|
|
113
|
1 |
|
$objWriter->startElement('xdr:from'); |
114
|
1 |
|
$objWriter->writeElement('xdr:col', (string) ($tlColRow[0] - 1)); |
115
|
1 |
|
$objWriter->writeElement('xdr:colOff', self::stringEmu($tl['xOffset'])); |
116
|
1 |
|
$objWriter->writeElement('xdr:row', (string) ($tlColRow[1] - 1)); |
117
|
1 |
|
$objWriter->writeElement('xdr:rowOff', self::stringEmu($tl['yOffset'])); |
118
|
1 |
|
$objWriter->endElement(); |
119
|
1 |
|
$objWriter->startElement('xdr:ext'); |
120
|
1 |
|
$objWriter->writeAttribute('cx', self::stringEmu($br['xOffset'])); |
121
|
1 |
|
$objWriter->writeAttribute('cy', self::stringEmu($br['yOffset'])); |
122
|
1 |
|
$objWriter->endElement(); |
123
|
|
|
} else { |
124
|
2 |
|
$objWriter->startElement('xdr:absoluteAnchor'); |
125
|
2 |
|
$objWriter->startElement('xdr:pos'); |
126
|
2 |
|
$objWriter->writeAttribute('x', '0'); |
127
|
2 |
|
$objWriter->writeAttribute('y', '0'); |
128
|
2 |
|
$objWriter->endElement(); |
129
|
2 |
|
$objWriter->startElement('xdr:ext'); |
130
|
2 |
|
$objWriter->writeAttribute('cx', self::stringEmu($br['xOffset'])); |
131
|
2 |
|
$objWriter->writeAttribute('cy', self::stringEmu($br['yOffset'])); |
132
|
2 |
|
$objWriter->endElement(); |
133
|
|
|
} |
134
|
|
|
|
135
|
73 |
|
$objWriter->startElement('xdr:graphicFrame'); |
136
|
73 |
|
$objWriter->writeAttribute('macro', ''); |
137
|
73 |
|
$objWriter->startElement('xdr:nvGraphicFramePr'); |
138
|
73 |
|
$objWriter->startElement('xdr:cNvPr'); |
139
|
73 |
|
$objWriter->writeAttribute('name', 'Chart ' . $relationId); |
140
|
73 |
|
$objWriter->writeAttribute('id', (string) (1025 * $relationId)); |
141
|
73 |
|
$objWriter->endElement(); |
142
|
73 |
|
$objWriter->startElement('xdr:cNvGraphicFramePr'); |
143
|
73 |
|
$objWriter->startElement('a:graphicFrameLocks'); |
144
|
73 |
|
$objWriter->endElement(); |
145
|
73 |
|
$objWriter->endElement(); |
146
|
73 |
|
$objWriter->endElement(); |
147
|
|
|
|
148
|
73 |
|
$objWriter->startElement('xdr:xfrm'); |
149
|
73 |
|
$objWriter->startElement('a:off'); |
150
|
73 |
|
$objWriter->writeAttribute('x', '0'); |
151
|
73 |
|
$objWriter->writeAttribute('y', '0'); |
152
|
73 |
|
$objWriter->endElement(); |
153
|
73 |
|
$objWriter->startElement('a:ext'); |
154
|
73 |
|
$objWriter->writeAttribute('cx', '0'); |
155
|
73 |
|
$objWriter->writeAttribute('cy', '0'); |
156
|
73 |
|
$objWriter->endElement(); |
157
|
73 |
|
$objWriter->endElement(); |
158
|
|
|
|
159
|
73 |
|
$objWriter->startElement('a:graphic'); |
160
|
73 |
|
$objWriter->startElement('a:graphicData'); |
161
|
73 |
|
$objWriter->writeAttribute('uri', Namespaces::CHART); |
162
|
73 |
|
$objWriter->startElement('c:chart'); |
163
|
73 |
|
$objWriter->writeAttribute('xmlns:c', Namespaces::CHART); |
164
|
73 |
|
$objWriter->writeAttribute('xmlns:r', Namespaces::SCHEMA_OFFICE_DOCUMENT); |
165
|
73 |
|
$objWriter->writeAttribute('r:id', 'rId' . $relationId); |
166
|
73 |
|
$objWriter->endElement(); |
167
|
73 |
|
$objWriter->endElement(); |
168
|
73 |
|
$objWriter->endElement(); |
169
|
73 |
|
$objWriter->endElement(); |
170
|
|
|
|
171
|
73 |
|
$objWriter->startElement('xdr:clientData'); |
172
|
73 |
|
$objWriter->endElement(); |
173
|
|
|
|
174
|
73 |
|
$objWriter->endElement(); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Write drawings to XML format. |
179
|
|
|
*/ |
180
|
50 |
|
public function writeDrawing(XMLWriter $objWriter, BaseDrawing $drawing, int $relationId = -1, ?int $hlinkClickId = null): void |
181
|
|
|
{ |
182
|
50 |
|
if ($relationId >= 0) { |
183
|
50 |
|
$isTwoCellAnchor = $drawing->getCoordinates2() !== ''; |
184
|
50 |
|
if ($isTwoCellAnchor) { |
185
|
|
|
// xdr:twoCellAnchor |
186
|
30 |
|
$objWriter->startElement('xdr:twoCellAnchor'); |
187
|
30 |
|
if ($drawing->validEditAs()) { |
188
|
25 |
|
$objWriter->writeAttribute('editAs', $drawing->getEditAs()); |
189
|
|
|
} |
190
|
|
|
// Image location |
191
|
30 |
|
$aCoordinates = Coordinate::indexesFromString($drawing->getCoordinates()); |
192
|
30 |
|
$aCoordinates2 = Coordinate::indexesFromString($drawing->getCoordinates2()); |
193
|
|
|
|
194
|
|
|
// xdr:from |
195
|
30 |
|
$objWriter->startElement('xdr:from'); |
196
|
30 |
|
$objWriter->writeElement('xdr:col', (string) ($aCoordinates[0] - 1)); |
197
|
30 |
|
$objWriter->writeElement('xdr:colOff', self::stringEmu($drawing->getOffsetX())); |
198
|
30 |
|
$objWriter->writeElement('xdr:row', (string) ($aCoordinates[1] - 1)); |
199
|
30 |
|
$objWriter->writeElement('xdr:rowOff', self::stringEmu($drawing->getOffsetY())); |
200
|
30 |
|
$objWriter->endElement(); |
201
|
|
|
|
202
|
|
|
// xdr:to |
203
|
30 |
|
$objWriter->startElement('xdr:to'); |
204
|
30 |
|
$objWriter->writeElement('xdr:col', (string) ($aCoordinates2[0] - 1)); |
205
|
30 |
|
$objWriter->writeElement('xdr:colOff', self::stringEmu($drawing->getOffsetX2())); |
206
|
30 |
|
$objWriter->writeElement('xdr:row', (string) ($aCoordinates2[1] - 1)); |
207
|
30 |
|
$objWriter->writeElement('xdr:rowOff', self::stringEmu($drawing->getOffsetY2())); |
208
|
30 |
|
$objWriter->endElement(); |
209
|
|
|
} else { |
210
|
|
|
// xdr:oneCellAnchor |
211
|
22 |
|
$objWriter->startElement('xdr:oneCellAnchor'); |
212
|
|
|
// Image location |
213
|
22 |
|
$aCoordinates = Coordinate::indexesFromString($drawing->getCoordinates()); |
214
|
|
|
|
215
|
|
|
// xdr:from |
216
|
22 |
|
$objWriter->startElement('xdr:from'); |
217
|
22 |
|
$objWriter->writeElement('xdr:col', (string) ($aCoordinates[0] - 1)); |
218
|
22 |
|
$objWriter->writeElement('xdr:colOff', self::stringEmu($drawing->getOffsetX())); |
219
|
22 |
|
$objWriter->writeElement('xdr:row', (string) ($aCoordinates[1] - 1)); |
220
|
22 |
|
$objWriter->writeElement('xdr:rowOff', self::stringEmu($drawing->getOffsetY())); |
221
|
22 |
|
$objWriter->endElement(); |
222
|
|
|
|
223
|
|
|
// xdr:ext |
224
|
22 |
|
$objWriter->startElement('xdr:ext'); |
225
|
22 |
|
$objWriter->writeAttribute('cx', self::stringEmu($drawing->getWidth())); |
226
|
22 |
|
$objWriter->writeAttribute('cy', self::stringEmu($drawing->getHeight())); |
227
|
22 |
|
$objWriter->endElement(); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
// xdr:pic |
231
|
50 |
|
$objWriter->startElement('xdr:pic'); |
232
|
|
|
|
233
|
|
|
// xdr:nvPicPr |
234
|
50 |
|
$objWriter->startElement('xdr:nvPicPr'); |
235
|
|
|
|
236
|
|
|
// xdr:cNvPr |
237
|
50 |
|
$objWriter->startElement('xdr:cNvPr'); |
238
|
50 |
|
$objWriter->writeAttribute('id', (string) $relationId); |
239
|
50 |
|
$objWriter->writeAttribute('name', $drawing->getName()); |
240
|
50 |
|
$objWriter->writeAttribute('descr', $drawing->getDescription()); |
241
|
|
|
|
242
|
|
|
//a:hlinkClick |
243
|
50 |
|
$this->writeHyperLinkDrawing($objWriter, $hlinkClickId); |
244
|
|
|
|
245
|
50 |
|
$objWriter->endElement(); |
246
|
|
|
|
247
|
|
|
// xdr:cNvPicPr |
248
|
50 |
|
$objWriter->startElement('xdr:cNvPicPr'); |
249
|
|
|
|
250
|
|
|
// a:picLocks |
251
|
50 |
|
$objWriter->startElement('a:picLocks'); |
252
|
50 |
|
$objWriter->writeAttribute('noChangeAspect', '1'); |
253
|
50 |
|
$objWriter->endElement(); |
254
|
|
|
|
255
|
50 |
|
$objWriter->endElement(); |
256
|
|
|
|
257
|
50 |
|
$objWriter->endElement(); |
258
|
|
|
|
259
|
|
|
// xdr:blipFill |
260
|
50 |
|
$objWriter->startElement('xdr:blipFill'); |
261
|
|
|
|
262
|
|
|
// a:blip |
263
|
50 |
|
$objWriter->startElement('a:blip'); |
264
|
50 |
|
$objWriter->writeAttribute('xmlns:r', Namespaces::SCHEMA_OFFICE_DOCUMENT); |
265
|
50 |
|
$objWriter->writeAttribute('r:embed', 'rId' . $relationId); |
266
|
50 |
|
$temp = $drawing->getOpacity(); |
267
|
50 |
|
if (is_int($temp) && $temp >= 0 && $temp <= 100000) { |
268
|
4 |
|
$objWriter->startElement('a:alphaModFix'); |
269
|
4 |
|
$objWriter->writeAttribute('amt', "$temp"); |
270
|
4 |
|
$objWriter->endElement(); // a:alphaModFix |
271
|
|
|
} |
272
|
50 |
|
$objWriter->endElement(); // a:blip |
273
|
|
|
|
274
|
50 |
|
$srcRect = $drawing->getSrcRect(); |
275
|
50 |
|
if (!empty($srcRect)) { |
276
|
2 |
|
$objWriter->startElement('a:srcRect'); |
277
|
2 |
|
foreach ($srcRect as $key => $value) { |
278
|
2 |
|
$objWriter->writeAttribute($key, (string) $value); |
279
|
|
|
} |
280
|
2 |
|
$objWriter->endElement(); // a:srcRect |
281
|
2 |
|
$objWriter->startElement('a:stretch'); |
282
|
2 |
|
$objWriter->endElement(); // a:stretch |
283
|
|
|
} else { |
284
|
|
|
// a:stretch |
285
|
48 |
|
$objWriter->startElement('a:stretch'); |
286
|
48 |
|
$objWriter->writeElement('a:fillRect', null); |
287
|
48 |
|
$objWriter->endElement(); |
288
|
|
|
} |
289
|
|
|
|
290
|
50 |
|
$objWriter->endElement(); |
291
|
|
|
|
292
|
|
|
// xdr:spPr |
293
|
50 |
|
$objWriter->startElement('xdr:spPr'); |
294
|
|
|
|
295
|
|
|
// a:xfrm |
296
|
50 |
|
$objWriter->startElement('a:xfrm'); |
297
|
50 |
|
$objWriter->writeAttribute('rot', (string) SharedDrawing::degreesToAngle($drawing->getRotation())); |
298
|
50 |
|
self::writeAttributeIf($objWriter, $drawing->getFlipVertical(), 'flipV', '1'); |
299
|
50 |
|
self::writeAttributeIf($objWriter, $drawing->getFlipHorizontal(), 'flipH', '1'); |
300
|
50 |
|
if ($isTwoCellAnchor) { |
301
|
30 |
|
$objWriter->startElement('a:ext'); |
302
|
30 |
|
$objWriter->writeAttribute('cx', self::stringEmu($drawing->getWidth())); |
303
|
30 |
|
$objWriter->writeAttribute('cy', self::stringEmu($drawing->getHeight())); |
304
|
30 |
|
$objWriter->endElement(); |
305
|
|
|
} |
306
|
50 |
|
$objWriter->endElement(); |
307
|
|
|
|
308
|
|
|
// a:prstGeom |
309
|
50 |
|
$objWriter->startElement('a:prstGeom'); |
310
|
50 |
|
$objWriter->writeAttribute('prst', 'rect'); |
311
|
|
|
|
312
|
|
|
// a:avLst |
313
|
50 |
|
$objWriter->writeElement('a:avLst', null); |
314
|
|
|
|
315
|
50 |
|
$objWriter->endElement(); |
316
|
|
|
|
317
|
50 |
|
if ($drawing->getShadow()->getVisible()) { |
318
|
|
|
// a:effectLst |
319
|
6 |
|
$objWriter->startElement('a:effectLst'); |
320
|
|
|
|
321
|
|
|
// a:outerShdw |
322
|
6 |
|
$objWriter->startElement('a:outerShdw'); |
323
|
6 |
|
$objWriter->writeAttribute('blurRad', self::stringEmu($drawing->getShadow()->getBlurRadius())); |
324
|
6 |
|
$objWriter->writeAttribute('dist', self::stringEmu($drawing->getShadow()->getDistance())); |
325
|
6 |
|
$objWriter->writeAttribute('dir', (string) SharedDrawing::degreesToAngle($drawing->getShadow()->getDirection())); |
326
|
6 |
|
$objWriter->writeAttribute('algn', $drawing->getShadow()->getAlignment()); |
327
|
6 |
|
$objWriter->writeAttribute('rotWithShape', '0'); |
328
|
|
|
|
329
|
|
|
// a:srgbClr |
330
|
6 |
|
$objWriter->startElement('a:srgbClr'); |
331
|
6 |
|
$objWriter->writeAttribute('val', $drawing->getShadow()->getColor()->getRGB()); |
332
|
|
|
|
333
|
|
|
// a:alpha |
334
|
6 |
|
$objWriter->startElement('a:alpha'); |
335
|
6 |
|
$objWriter->writeAttribute('val', (string) ($drawing->getShadow()->getAlpha() * 1000)); |
336
|
6 |
|
$objWriter->endElement(); |
337
|
|
|
|
338
|
6 |
|
$objWriter->endElement(); |
339
|
|
|
|
340
|
6 |
|
$objWriter->endElement(); |
341
|
|
|
|
342
|
6 |
|
$objWriter->endElement(); |
343
|
|
|
} |
344
|
50 |
|
$objWriter->endElement(); |
345
|
|
|
|
346
|
50 |
|
$objWriter->endElement(); |
347
|
|
|
|
348
|
|
|
// xdr:clientData |
349
|
50 |
|
$objWriter->writeElement('xdr:clientData', null); |
350
|
|
|
|
351
|
50 |
|
$objWriter->endElement(); |
352
|
|
|
} else { |
353
|
|
|
throw new WriterException('Invalid parameters passed.'); |
354
|
|
|
} |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
/** |
358
|
|
|
* Write VML header/footer images to XML format. |
359
|
|
|
* |
360
|
|
|
* @return string XML Output |
361
|
|
|
*/ |
362
|
3 |
|
public function writeVMLHeaderFooterImages(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet): string |
363
|
|
|
{ |
364
|
|
|
// Create XML writer |
365
|
3 |
|
$objWriter = null; |
366
|
3 |
|
if ($this->getParentWriter()->getUseDiskCaching()) { |
367
|
|
|
$objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); |
368
|
|
|
} else { |
369
|
3 |
|
$objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
// XML header |
373
|
3 |
|
$objWriter->startDocument('1.0', 'UTF-8', 'yes'); |
374
|
|
|
|
375
|
|
|
// Header/footer images |
376
|
3 |
|
$images = $worksheet->getHeaderFooter()->getImages(); |
377
|
|
|
|
378
|
|
|
// xml |
379
|
3 |
|
$objWriter->startElement('xml'); |
380
|
3 |
|
$objWriter->writeAttribute('xmlns:v', Namespaces::URN_VML); |
381
|
3 |
|
$objWriter->writeAttribute('xmlns:o', Namespaces::URN_MSOFFICE); |
382
|
3 |
|
$objWriter->writeAttribute('xmlns:x', Namespaces::URN_EXCEL); |
383
|
|
|
|
384
|
|
|
// o:shapelayout |
385
|
3 |
|
$objWriter->startElement('o:shapelayout'); |
386
|
3 |
|
$objWriter->writeAttribute('v:ext', 'edit'); |
387
|
|
|
|
388
|
|
|
// o:idmap |
389
|
3 |
|
$objWriter->startElement('o:idmap'); |
390
|
3 |
|
$objWriter->writeAttribute('v:ext', 'edit'); |
391
|
3 |
|
$objWriter->writeAttribute('data', '1'); |
392
|
3 |
|
$objWriter->endElement(); |
393
|
|
|
|
394
|
3 |
|
$objWriter->endElement(); |
395
|
|
|
|
396
|
|
|
// v:shapetype |
397
|
3 |
|
$objWriter->startElement('v:shapetype'); |
398
|
3 |
|
$objWriter->writeAttribute('id', '_x0000_t75'); |
399
|
3 |
|
$objWriter->writeAttribute('coordsize', '21600,21600'); |
400
|
3 |
|
$objWriter->writeAttribute('o:spt', '75'); |
401
|
3 |
|
$objWriter->writeAttribute('o:preferrelative', 't'); |
402
|
3 |
|
$objWriter->writeAttribute('path', 'm@4@5l@4@11@9@11@9@5xe'); |
403
|
3 |
|
$objWriter->writeAttribute('filled', 'f'); |
404
|
3 |
|
$objWriter->writeAttribute('stroked', 'f'); |
405
|
|
|
|
406
|
|
|
// v:stroke |
407
|
3 |
|
$objWriter->startElement('v:stroke'); |
408
|
3 |
|
$objWriter->writeAttribute('joinstyle', 'miter'); |
409
|
3 |
|
$objWriter->endElement(); |
410
|
|
|
|
411
|
|
|
// v:formulas |
412
|
3 |
|
$objWriter->startElement('v:formulas'); |
413
|
|
|
|
414
|
|
|
// v:f |
415
|
3 |
|
$objWriter->startElement('v:f'); |
416
|
3 |
|
$objWriter->writeAttribute('eqn', 'if lineDrawn pixelLineWidth 0'); |
417
|
3 |
|
$objWriter->endElement(); |
418
|
|
|
|
419
|
|
|
// v:f |
420
|
3 |
|
$objWriter->startElement('v:f'); |
421
|
3 |
|
$objWriter->writeAttribute('eqn', 'sum @0 1 0'); |
422
|
3 |
|
$objWriter->endElement(); |
423
|
|
|
|
424
|
|
|
// v:f |
425
|
3 |
|
$objWriter->startElement('v:f'); |
426
|
3 |
|
$objWriter->writeAttribute('eqn', 'sum 0 0 @1'); |
427
|
3 |
|
$objWriter->endElement(); |
428
|
|
|
|
429
|
|
|
// v:f |
430
|
3 |
|
$objWriter->startElement('v:f'); |
431
|
3 |
|
$objWriter->writeAttribute('eqn', 'prod @2 1 2'); |
432
|
3 |
|
$objWriter->endElement(); |
433
|
|
|
|
434
|
|
|
// v:f |
435
|
3 |
|
$objWriter->startElement('v:f'); |
436
|
3 |
|
$objWriter->writeAttribute('eqn', 'prod @3 21600 pixelWidth'); |
437
|
3 |
|
$objWriter->endElement(); |
438
|
|
|
|
439
|
|
|
// v:f |
440
|
3 |
|
$objWriter->startElement('v:f'); |
441
|
3 |
|
$objWriter->writeAttribute('eqn', 'prod @3 21600 pixelHeight'); |
442
|
3 |
|
$objWriter->endElement(); |
443
|
|
|
|
444
|
|
|
// v:f |
445
|
3 |
|
$objWriter->startElement('v:f'); |
446
|
3 |
|
$objWriter->writeAttribute('eqn', 'sum @0 0 1'); |
447
|
3 |
|
$objWriter->endElement(); |
448
|
|
|
|
449
|
|
|
// v:f |
450
|
3 |
|
$objWriter->startElement('v:f'); |
451
|
3 |
|
$objWriter->writeAttribute('eqn', 'prod @6 1 2'); |
452
|
3 |
|
$objWriter->endElement(); |
453
|
|
|
|
454
|
|
|
// v:f |
455
|
3 |
|
$objWriter->startElement('v:f'); |
456
|
3 |
|
$objWriter->writeAttribute('eqn', 'prod @7 21600 pixelWidth'); |
457
|
3 |
|
$objWriter->endElement(); |
458
|
|
|
|
459
|
|
|
// v:f |
460
|
3 |
|
$objWriter->startElement('v:f'); |
461
|
3 |
|
$objWriter->writeAttribute('eqn', 'sum @8 21600 0'); |
462
|
3 |
|
$objWriter->endElement(); |
463
|
|
|
|
464
|
|
|
// v:f |
465
|
3 |
|
$objWriter->startElement('v:f'); |
466
|
3 |
|
$objWriter->writeAttribute('eqn', 'prod @7 21600 pixelHeight'); |
467
|
3 |
|
$objWriter->endElement(); |
468
|
|
|
|
469
|
|
|
// v:f |
470
|
3 |
|
$objWriter->startElement('v:f'); |
471
|
3 |
|
$objWriter->writeAttribute('eqn', 'sum @10 21600 0'); |
472
|
3 |
|
$objWriter->endElement(); |
473
|
|
|
|
474
|
3 |
|
$objWriter->endElement(); |
475
|
|
|
|
476
|
|
|
// v:path |
477
|
3 |
|
$objWriter->startElement('v:path'); |
478
|
3 |
|
$objWriter->writeAttribute('o:extrusionok', 'f'); |
479
|
3 |
|
$objWriter->writeAttribute('gradientshapeok', 't'); |
480
|
3 |
|
$objWriter->writeAttribute('o:connecttype', 'rect'); |
481
|
3 |
|
$objWriter->endElement(); |
482
|
|
|
|
483
|
|
|
// o:lock |
484
|
3 |
|
$objWriter->startElement('o:lock'); |
485
|
3 |
|
$objWriter->writeAttribute('v:ext', 'edit'); |
486
|
3 |
|
$objWriter->writeAttribute('aspectratio', 't'); |
487
|
3 |
|
$objWriter->endElement(); |
488
|
|
|
|
489
|
3 |
|
$objWriter->endElement(); |
490
|
|
|
|
491
|
|
|
// Loop through images |
492
|
3 |
|
foreach ($images as $key => $value) { |
493
|
3 |
|
$this->writeVMLHeaderFooterImage($objWriter, $key, $value); |
494
|
|
|
} |
495
|
|
|
|
496
|
3 |
|
$objWriter->endElement(); |
497
|
|
|
|
498
|
|
|
// Return |
499
|
3 |
|
return $objWriter->getData(); |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
/** |
503
|
|
|
* Write VML comment to XML format. |
504
|
|
|
* |
505
|
|
|
* @param string $reference Reference |
506
|
|
|
*/ |
507
|
3 |
|
private function writeVMLHeaderFooterImage(XMLWriter $objWriter, string $reference, HeaderFooterDrawing $image): void |
508
|
|
|
{ |
509
|
|
|
// Calculate object id |
510
|
3 |
|
preg_match('{(\d+)}', md5($reference), $m); |
511
|
3 |
|
$id = 1500 + ((int) substr($m[1], 0, 2) * 1); |
512
|
|
|
|
513
|
|
|
// Calculate offset |
514
|
3 |
|
$width = $image->getWidth(); |
515
|
3 |
|
$height = $image->getHeight(); |
516
|
3 |
|
$marginLeft = $image->getOffsetX(); |
517
|
3 |
|
$marginTop = $image->getOffsetY(); |
518
|
|
|
|
519
|
|
|
// v:shape |
520
|
3 |
|
$objWriter->startElement('v:shape'); |
521
|
3 |
|
$objWriter->writeAttribute('id', $reference); |
522
|
3 |
|
$objWriter->writeAttribute('o:spid', '_x0000_s' . $id); |
523
|
3 |
|
$objWriter->writeAttribute('type', '#_x0000_t75'); |
524
|
3 |
|
$objWriter->writeAttribute('style', "position:absolute;margin-left:{$marginLeft}px;margin-top:{$marginTop}px;width:{$width}px;height:{$height}px;z-index:1"); |
525
|
|
|
|
526
|
|
|
// v:imagedata |
527
|
3 |
|
$objWriter->startElement('v:imagedata'); |
528
|
3 |
|
$objWriter->writeAttribute('o:relid', 'rId' . $reference); |
529
|
3 |
|
$objWriter->writeAttribute('o:title', $image->getName()); |
530
|
3 |
|
$objWriter->endElement(); |
531
|
|
|
|
532
|
|
|
// o:lock |
533
|
3 |
|
$objWriter->startElement('o:lock'); |
534
|
3 |
|
$objWriter->writeAttribute('v:ext', 'edit'); |
535
|
3 |
|
$objWriter->writeAttribute('textRotation', 't'); |
536
|
3 |
|
$objWriter->endElement(); |
537
|
|
|
|
538
|
3 |
|
$objWriter->endElement(); |
539
|
|
|
} |
540
|
|
|
|
541
|
|
|
/** |
542
|
|
|
* Get an array of all drawings. |
543
|
|
|
* |
544
|
|
|
* @return BaseDrawing[] All drawings in PhpSpreadsheet |
545
|
|
|
*/ |
546
|
350 |
|
public function allDrawings(Spreadsheet $spreadsheet): array |
547
|
|
|
{ |
548
|
|
|
// Get an array of all drawings |
549
|
350 |
|
$aDrawings = []; |
550
|
|
|
|
551
|
|
|
// Loop through PhpSpreadsheet |
552
|
350 |
|
$sheetCount = $spreadsheet->getSheetCount(); |
553
|
350 |
|
for ($i = 0; $i < $sheetCount; ++$i) { |
554
|
|
|
// Loop through images and add to array |
555
|
350 |
|
$iterator = $spreadsheet->getSheet($i)->getDrawingCollection()->getIterator(); |
556
|
350 |
|
while ($iterator->valid()) { |
557
|
50 |
|
$aDrawings[] = $iterator->current(); |
558
|
|
|
|
559
|
50 |
|
$iterator->next(); |
560
|
|
|
} |
561
|
|
|
} |
562
|
|
|
|
563
|
350 |
|
return $aDrawings; |
564
|
|
|
} |
565
|
|
|
|
566
|
50 |
|
private function writeHyperLinkDrawing(XMLWriter $objWriter, ?int $hlinkClickId): void |
567
|
|
|
{ |
568
|
50 |
|
if ($hlinkClickId === null) { |
569
|
48 |
|
return; |
570
|
|
|
} |
571
|
|
|
|
572
|
2 |
|
$objWriter->startElement('a:hlinkClick'); |
573
|
2 |
|
$objWriter->writeAttribute('xmlns:r', Namespaces::SCHEMA_OFFICE_DOCUMENT); |
574
|
2 |
|
$objWriter->writeAttribute('r:id', 'rId' . $hlinkClickId); |
575
|
2 |
|
$objWriter->endElement(); |
576
|
|
|
} |
577
|
|
|
|
578
|
112 |
|
private static function stringEmu(int $pixelValue): string |
579
|
|
|
{ |
580
|
112 |
|
return (string) SharedDrawing::pixelsToEMU($pixelValue); |
581
|
|
|
} |
582
|
|
|
|
583
|
50 |
|
private static function writeAttributeIf(XMLWriter $objWriter, ?bool $condition, string $attr, string $val): void |
584
|
|
|
{ |
585
|
50 |
|
if ($condition) { |
586
|
1 |
|
$objWriter->writeAttribute($attr, $val); |
587
|
|
|
} |
588
|
|
|
} |
589
|
|
|
} |
590
|
|
|
|