Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]

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