PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.9.7
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.9.7
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Writer / Xls / Escher.php

Escher.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.9.7, at vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xls/Escher.php

511 lines 16.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace PhpOffice\PhpSpreadsheet\Writer\Xls;
4
5 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
6 use PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer;
7 use PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer\SpgrContainer;
8 use PhpOffice\PhpSpreadsheet\Shared\Escher\DgContainer\SpgrContainer\SpContainer;
9 use PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer;
10 use PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer;
11 use PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE;
12 use PhpOffice\PhpSpreadsheet\Shared\Escher\DggContainer\BstoreContainer\BSE\Blip;
13
14 class Escher
15 {
16 /**
17 * The object we are writing.
18 */
19 private $object;
20
21 /**
22 * The written binary data.
23 */
24 private $data;
25
26 /**
27 * Shape offsets. Positions in binary stream where a new shape record begins.
28 *
29 * @var array
30 */
31 private $spOffsets;
32
33 /**
34 * Shape types.
35 *
36 * @var array
37 */
38 private $spTypes;
39
40 /**
41 * Constructor.
42 *
43 * @param mixed $object
44 */
45 public function __construct($object)
46 {
47 $this->object = $object;
48 }
49
50 /**
51 * Process the object to be written.
52 *
53 * @return string
54 */
55 public function close()
56 {
57 // initialize
58 $this->data = '';
59
60 switch (get_class($this->object)) {
61 case \PhpOffice\PhpSpreadsheet\Shared\Escher::class:
62 if ($dggContainer = $this->object->getDggContainer()) {
63 $writer = new self($dggContainer);
64 $this->data = $writer->close();
65 } elseif ($dgContainer = $this->object->getDgContainer()) {
66 $writer = new self($dgContainer);
67 $this->data = $writer->close();
68 $this->spOffsets = $writer->getSpOffsets();
69 $this->spTypes = $writer->getSpTypes();
70 }
71
72 break;
73 case DggContainer::class:
74 // this is a container record
75
76 // initialize
77 $innerData = '';
78
79 // write the dgg
80 $recVer = 0x0;
81 $recInstance = 0x0000;
82 $recType = 0xF006;
83
84 $recVerInstance = $recVer;
85 $recVerInstance |= $recInstance << 4;
86
87 // dgg data
88 $dggData =
89 pack(
90 'VVVV',
91 $this->object->getSpIdMax(), // maximum shape identifier increased by one
92 $this->object->getCDgSaved() + 1, // number of file identifier clusters increased by one
93 $this->object->getCSpSaved(),
94 $this->object->getCDgSaved() // count total number of drawings saved
95 );
96
97 // add file identifier clusters (one per drawing)
98 $IDCLs = $this->object->getIDCLs();
99
100 foreach ($IDCLs as $dgId => $maxReducedSpId) {
101 $dggData .= pack('VV', $dgId, $maxReducedSpId + 1);
102 }
103
104 $header = pack('vvV', $recVerInstance, $recType, strlen($dggData));
105 $innerData .= $header . $dggData;
106
107 // write the bstoreContainer
108 if ($bstoreContainer = $this->object->getBstoreContainer()) {
109 $writer = new self($bstoreContainer);
110 $innerData .= $writer->close();
111 }
112
113 // write the record
114 $recVer = 0xF;
115 $recInstance = 0x0000;
116 $recType = 0xF000;
117 $length = strlen($innerData);
118
119 $recVerInstance = $recVer;
120 $recVerInstance |= $recInstance << 4;
121
122 $header = pack('vvV', $recVerInstance, $recType, $length);
123
124 $this->data = $header . $innerData;
125
126 break;
127 case BstoreContainer::class:
128 // this is a container record
129
130 // initialize
131 $innerData = '';
132
133 // treat the inner data
134 if ($BSECollection = $this->object->getBSECollection()) {
135 foreach ($BSECollection as $BSE) {
136 $writer = new self($BSE);
137 $innerData .= $writer->close();
138 }
139 }
140
141 // write the record
142 $recVer = 0xF;
143 $recInstance = count($this->object->getBSECollection());
144 $recType = 0xF001;
145 $length = strlen($innerData);
146
147 $recVerInstance = $recVer;
148 $recVerInstance |= $recInstance << 4;
149
150 $header = pack('vvV', $recVerInstance, $recType, $length);
151
152 $this->data = $header . $innerData;
153
154 break;
155 case BSE::class:
156 // this is a semi-container record
157
158 // initialize
159 $innerData = '';
160
161 // here we treat the inner data
162 if ($blip = $this->object->getBlip()) {
163 $writer = new self($blip);
164 $innerData .= $writer->close();
165 }
166
167 // initialize
168 $data = '';
169
170 $btWin32 = $this->object->getBlipType();
171 $btMacOS = $this->object->getBlipType();
172 $data .= pack('CC', $btWin32, $btMacOS);
173
174 $rgbUid = pack('VVVV', 0, 0, 0, 0); // todo
175 $data .= $rgbUid;
176
177 $tag = 0;
178 $size = strlen($innerData);
179 $cRef = 1;
180 $foDelay = 0; //todo
181 $unused1 = 0x0;
182 $cbName = 0x0;
183 $unused2 = 0x0;
184 $unused3 = 0x0;
185 $data .= pack('vVVVCCCC', $tag, $size, $cRef, $foDelay, $unused1, $cbName, $unused2, $unused3);
186
187 $data .= $innerData;
188
189 // write the record
190 $recVer = 0x2;
191 $recInstance = $this->object->getBlipType();
192 $recType = 0xF007;
193 $length = strlen($data);
194
195 $recVerInstance = $recVer;
196 $recVerInstance |= $recInstance << 4;
197
198 $header = pack('vvV', $recVerInstance, $recType, $length);
199
200 $this->data = $header;
201
202 $this->data .= $data;
203
204 break;
205 case Blip::class:
206 // this is an atom record
207
208 // write the record
209 switch ($this->object->getParent()->getBlipType()) {
210 case BSE::BLIPTYPE_JPEG:
211 // initialize
212 $innerData = '';
213
214 $rgbUid1 = pack('VVVV', 0, 0, 0, 0); // todo
215 $innerData .= $rgbUid1;
216
217 $tag = 0xFF; // todo
218 $innerData .= pack('C', $tag);
219
220 $innerData .= $this->object->getData();
221
222 $recVer = 0x0;
223 $recInstance = 0x46A;
224 $recType = 0xF01D;
225 $length = strlen($innerData);
226
227 $recVerInstance = $recVer;
228 $recVerInstance |= $recInstance << 4;
229
230 $header = pack('vvV', $recVerInstance, $recType, $length);
231
232 $this->data = $header;
233
234 $this->data .= $innerData;
235
236 break;
237 case BSE::BLIPTYPE_PNG:
238 // initialize
239 $innerData = '';
240
241 $rgbUid1 = pack('VVVV', 0, 0, 0, 0); // todo
242 $innerData .= $rgbUid1;
243
244 $tag = 0xFF; // todo
245 $innerData .= pack('C', $tag);
246
247 $innerData .= $this->object->getData();
248
249 $recVer = 0x0;
250 $recInstance = 0x6E0;
251 $recType = 0xF01E;
252 $length = strlen($innerData);
253
254 $recVerInstance = $recVer;
255 $recVerInstance |= $recInstance << 4;
256
257 $header = pack('vvV', $recVerInstance, $recType, $length);
258
259 $this->data = $header;
260
261 $this->data .= $innerData;
262
263 break;
264 }
265
266 break;
267 case DgContainer::class:
268 // this is a container record
269
270 // initialize
271 $innerData = '';
272
273 // write the dg
274 $recVer = 0x0;
275 $recInstance = $this->object->getDgId();
276 $recType = 0xF008;
277 $length = 8;
278
279 $recVerInstance = $recVer;
280 $recVerInstance |= $recInstance << 4;
281
282 $header = pack('vvV', $recVerInstance, $recType, $length);
283
284 // number of shapes in this drawing (including group shape)
285 $countShapes = count($this->object->getSpgrContainer()->getChildren());
286 $innerData .= $header . pack('VV', $countShapes, $this->object->getLastSpId());
287
288 // write the spgrContainer
289 if ($spgrContainer = $this->object->getSpgrContainer()) {
290 $writer = new self($spgrContainer);
291 $innerData .= $writer->close();
292
293 // get the shape offsets relative to the spgrContainer record
294 $spOffsets = $writer->getSpOffsets();
295 $spTypes = $writer->getSpTypes();
296
297 // save the shape offsets relative to dgContainer
298 foreach ($spOffsets as &$spOffset) {
299 $spOffset += 24; // add length of dgContainer header data (8 bytes) plus dg data (16 bytes)
300 }
301
302 $this->spOffsets = $spOffsets;
303 $this->spTypes = $spTypes;
304 }
305
306 // write the record
307 $recVer = 0xF;
308 $recInstance = 0x0000;
309 $recType = 0xF002;
310 $length = strlen($innerData);
311
312 $recVerInstance = $recVer;
313 $recVerInstance |= $recInstance << 4;
314
315 $header = pack('vvV', $recVerInstance, $recType, $length);
316
317 $this->data = $header . $innerData;
318
319 break;
320 case SpgrContainer::class:
321 // this is a container record
322
323 // initialize
324 $innerData = '';
325
326 // initialize spape offsets
327 $totalSize = 8;
328 $spOffsets = [];
329 $spTypes = [];
330
331 // treat the inner data
332 foreach ($this->object->getChildren() as $spContainer) {
333 $writer = new self($spContainer);
334 $spData = $writer->close();
335 $innerData .= $spData;
336
337 // save the shape offsets (where new shape records begin)
338 $totalSize += strlen($spData);
339 $spOffsets[] = $totalSize;
340
341 $spTypes = array_merge($spTypes, $writer->getSpTypes());
342 }
343
344 // write the record
345 $recVer = 0xF;
346 $recInstance = 0x0000;
347 $recType = 0xF003;
348 $length = strlen($innerData);
349
350 $recVerInstance = $recVer;
351 $recVerInstance |= $recInstance << 4;
352
353 $header = pack('vvV', $recVerInstance, $recType, $length);
354
355 $this->data = $header . $innerData;
356 $this->spOffsets = $spOffsets;
357 $this->spTypes = $spTypes;
358
359 break;
360 case SpContainer::class:
361 // initialize
362 $data = '';
363
364 // build the data
365
366 // write group shape record, if necessary?
367 if ($this->object->getSpgr()) {
368 $recVer = 0x1;
369 $recInstance = 0x0000;
370 $recType = 0xF009;
371 $length = 0x00000010;
372
373 $recVerInstance = $recVer;
374 $recVerInstance |= $recInstance << 4;
375
376 $header = pack('vvV', $recVerInstance, $recType, $length);
377
378 $data .= $header . pack('VVVV', 0, 0, 0, 0);
379 }
380 $this->spTypes[] = ($this->object->getSpType());
381
382 // write the shape record
383 $recVer = 0x2;
384 $recInstance = $this->object->getSpType(); // shape type
385 $recType = 0xF00A;
386 $length = 0x00000008;
387
388 $recVerInstance = $recVer;
389 $recVerInstance |= $recInstance << 4;
390
391 $header = pack('vvV', $recVerInstance, $recType, $length);
392
393 $data .= $header . pack('VV', $this->object->getSpId(), $this->object->getSpgr() ? 0x0005 : 0x0A00);
394
395 // the options
396 if ($this->object->getOPTCollection()) {
397 $optData = '';
398
399 $recVer = 0x3;
400 $recInstance = count($this->object->getOPTCollection());
401 $recType = 0xF00B;
402 foreach ($this->object->getOPTCollection() as $property => $value) {
403 $optData .= pack('vV', $property, $value);
404 }
405 $length = strlen($optData);
406
407 $recVerInstance = $recVer;
408 $recVerInstance |= $recInstance << 4;
409
410 $header = pack('vvV', $recVerInstance, $recType, $length);
411 $data .= $header . $optData;
412 }
413
414 // the client anchor
415 if ($this->object->getStartCoordinates()) {
416 $clientAnchorData = '';
417
418 $recVer = 0x0;
419 $recInstance = 0x0;
420 $recType = 0xF010;
421
422 // start coordinates
423 list($column, $row) = Coordinate::coordinateFromString($this->object->getStartCoordinates());
424 $c1 = Coordinate::columnIndexFromString($column) - 1;
425 $r1 = $row - 1;
426
427 // start offsetX
428 $startOffsetX = $this->object->getStartOffsetX();
429
430 // start offsetY
431 $startOffsetY = $this->object->getStartOffsetY();
432
433 // end coordinates
434 list($column, $row) = Coordinate::coordinateFromString($this->object->getEndCoordinates());
435 $c2 = Coordinate::columnIndexFromString($column) - 1;
436 $r2 = $row - 1;
437
438 // end offsetX
439 $endOffsetX = $this->object->getEndOffsetX();
440
441 // end offsetY
442 $endOffsetY = $this->object->getEndOffsetY();
443
444 $clientAnchorData = pack('vvvvvvvvv', $this->object->getSpFlag(), $c1, $startOffsetX, $r1, $startOffsetY, $c2, $endOffsetX, $r2, $endOffsetY);
445
446 $length = strlen($clientAnchorData);
447
448 $recVerInstance = $recVer;
449 $recVerInstance |= $recInstance << 4;
450
451 $header = pack('vvV', $recVerInstance, $recType, $length);
452 $data .= $header . $clientAnchorData;
453 }
454
455 // the client data, just empty for now
456 if (!$this->object->getSpgr()) {
457 $clientDataData = '';
458
459 $recVer = 0x0;
460 $recInstance = 0x0;
461 $recType = 0xF011;
462
463 $length = strlen($clientDataData);
464
465 $recVerInstance = $recVer;
466 $recVerInstance |= $recInstance << 4;
467
468 $header = pack('vvV', $recVerInstance, $recType, $length);
469 $data .= $header . $clientDataData;
470 }
471
472 // write the record
473 $recVer = 0xF;
474 $recInstance = 0x0000;
475 $recType = 0xF004;
476 $length = strlen($data);
477
478 $recVerInstance = $recVer;
479 $recVerInstance |= $recInstance << 4;
480
481 $header = pack('vvV', $recVerInstance, $recType, $length);
482
483 $this->data = $header . $data;
484
485 break;
486 }
487
488 return $this->data;
489 }
490
491 /**
492 * Gets the shape offsets.
493 *
494 * @return array
495 */
496 public function getSpOffsets()
497 {
498 return $this->spOffsets;
499 }
500
501 /**
502 * Gets the shape types.
503 *
504 * @return array
505 */
506 public function getSpTypes()
507 {
508 return $this->spTypes;
509 }
510 }
511