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\Shared;
   4  
   5  use GdImage;
   6  use SimpleXMLElement;
   7  
   8  class Drawing
   9  {
  10      /**
  11       * Convert pixels to EMU.
  12       *
  13       * @param int $pixelValue Value in pixels
  14       *
  15       * @return int Value in EMU
  16       */
  17      public static function pixelsToEMU($pixelValue)
  18      {
  19          return $pixelValue * 9525;
  20      }
  21  
  22      /**
  23       * Convert EMU to pixels.
  24       *
  25       * @param int|SimpleXMLElement $emuValue Value in EMU
  26       *
  27       * @return int Value in pixels
  28       */
  29      public static function EMUToPixels($emuValue)
  30      {
  31          $emuValue = (int) $emuValue;
  32          if ($emuValue != 0) {
  33              return (int) round($emuValue / 9525);
  34          }
  35  
  36          return 0;
  37      }
  38  
  39      /**
  40       * Convert pixels to column width. Exact algorithm not known.
  41       * By inspection of a real Excel file using Calibri 11, one finds 1000px ~ 142.85546875
  42       * This gives a conversion factor of 7. Also, we assume that pixels and font size are proportional.
  43       *
  44       * @param int $pixelValue Value in pixels
  45       *
  46       * @return float|int Value in cell dimension
  47       */
  48      public static function pixelsToCellDimension($pixelValue, \PhpOffice\PhpSpreadsheet\Style\Font $defaultFont)
  49      {
  50          // Font name and size
  51          $name = $defaultFont->getName();
  52          $size = $defaultFont->getSize();
  53  
  54          if (isset(Font::$defaultColumnWidths[$name][$size])) {
  55              // Exact width can be determined
  56              return $pixelValue * Font::$defaultColumnWidths[$name][$size]['width']
  57                  / Font::$defaultColumnWidths[$name][$size]['px'];
  58          }
  59  
  60          // We don't have data for this particular font and size, use approximation by
  61          // extrapolating from Calibri 11
  62          return $pixelValue * 11 * Font::$defaultColumnWidths['Calibri'][11]['width']
  63              / Font::$defaultColumnWidths['Calibri'][11]['px'] / $size;
  64      }
  65  
  66      /**
  67       * Convert column width from (intrinsic) Excel units to pixels.
  68       *
  69       * @param float $cellWidth Value in cell dimension
  70       * @param \PhpOffice\PhpSpreadsheet\Style\Font $defaultFont Default font of the workbook
  71       *
  72       * @return int Value in pixels
  73       */
  74      public static function cellDimensionToPixels($cellWidth, \PhpOffice\PhpSpreadsheet\Style\Font $defaultFont)
  75      {
  76          // Font name and size
  77          $name = $defaultFont->getName();
  78          $size = $defaultFont->getSize();
  79  
  80          if (isset(Font::$defaultColumnWidths[$name][$size])) {
  81              // Exact width can be determined
  82              $colWidth = $cellWidth * Font::$defaultColumnWidths[$name][$size]['px']
  83                  / Font::$defaultColumnWidths[$name][$size]['width'];
  84          } else {
  85              // We don't have data for this particular font and size, use approximation by
  86              // extrapolating from Calibri 11
  87              $colWidth = $cellWidth * $size * Font::$defaultColumnWidths['Calibri'][11]['px']
  88                  / Font::$defaultColumnWidths['Calibri'][11]['width'] / 11;
  89          }
  90  
  91          // Round pixels to closest integer
  92          $colWidth = (int) round($colWidth);
  93  
  94          return $colWidth;
  95      }
  96  
  97      /**
  98       * Convert pixels to points.
  99       *
 100       * @param int $pixelValue Value in pixels
 101       *
 102       * @return float Value in points
 103       */
 104      public static function pixelsToPoints($pixelValue)
 105      {
 106          return $pixelValue * 0.75;
 107      }
 108  
 109      /**
 110       * Convert points to pixels.
 111       *
 112       * @param int $pointValue Value in points
 113       *
 114       * @return int Value in pixels
 115       */
 116      public static function pointsToPixels($pointValue)
 117      {
 118          if ($pointValue != 0) {
 119              return (int) ceil($pointValue / 0.75);
 120          }
 121  
 122          return 0;
 123      }
 124  
 125      /**
 126       * Convert degrees to angle.
 127       *
 128       * @param int $degrees Degrees
 129       *
 130       * @return int Angle
 131       */
 132      public static function degreesToAngle($degrees)
 133      {
 134          return (int) round($degrees * 60000);
 135      }
 136  
 137      /**
 138       * Convert angle to degrees.
 139       *
 140       * @param int|SimpleXMLElement $angle Angle
 141       *
 142       * @return int Degrees
 143       */
 144      public static function angleToDegrees($angle)
 145      {
 146          $angle = (int) $angle;
 147          if ($angle != 0) {
 148              return (int) round($angle / 60000);
 149          }
 150  
 151          return 0;
 152      }
 153  
 154      /**
 155       * Create a new image from file. By alexander at alexauto dot nl.
 156       *
 157       * @see http://www.php.net/manual/en/function.imagecreatefromwbmp.php#86214
 158       *
 159       * @param string $bmpFilename Path to Windows DIB (BMP) image
 160       *
 161       * @return GdImage|resource
 162       */
 163      public static function imagecreatefrombmp($bmpFilename)
 164      {
 165          //    Load the image into a string
 166          $file = fopen($bmpFilename, 'rb');
 167          /** @phpstan-ignore-next-line */
 168          $read = fread($file, 10);
 169          // @phpstan-ignore-next-line
 170          while (!feof($file) && ($read != '')) {
 171              // @phpstan-ignore-next-line
 172              $read .= fread($file, 1024);
 173          }
 174  
 175          /** @phpstan-ignore-next-line */
 176          $temp = unpack('H*', $read);
 177          $hex = $temp[1];
 178          $header = substr($hex, 0, 108);
 179  
 180          //    Process the header
 181          //    Structure: http://www.fastgraph.com/help/bmp_header_format.html
 182          $width = 0;
 183          $height = 0;
 184          if (substr($header, 0, 4) == '424d') {
 185              //    Cut it in parts of 2 bytes
 186              $header_parts = str_split($header, 2);
 187  
 188              //    Get the width        4 bytes
 189              $width = hexdec($header_parts[19] . $header_parts[18]);
 190  
 191              //    Get the height        4 bytes
 192              $height = hexdec($header_parts[23] . $header_parts[22]);
 193  
 194              //    Unset the header params
 195              unset($header_parts);
 196          }
 197  
 198          //    Define starting X and Y
 199          $x = 0;
 200          $y = 1;
 201  
 202          //    Create newimage
 203  
 204          /** @phpstan-ignore-next-line */
 205          $image = imagecreatetruecolor($width, $height);
 206  
 207          //    Grab the body from the image
 208          $body = substr($hex, 108);
 209  
 210          //    Calculate if padding at the end-line is needed
 211          //    Divided by two to keep overview.
 212          //    1 byte = 2 HEX-chars
 213          $body_size = (strlen($body) / 2);
 214          $header_size = ($width * $height);
 215  
 216          //    Use end-line padding? Only when needed
 217          $usePadding = ($body_size > ($header_size * 3) + 4);
 218  
 219          //    Using a for-loop with index-calculation instaid of str_split to avoid large memory consumption
 220          //    Calculate the next DWORD-position in the body
 221          for ($i = 0; $i < $body_size; $i += 3) {
 222              //    Calculate line-ending and padding
 223              if ($x >= $width) {
 224                  // If padding needed, ignore image-padding
 225                  // Shift i to the ending of the current 32-bit-block
 226                  if ($usePadding) {
 227                      $i += $width % 4;
 228                  }
 229  
 230                  //    Reset horizontal position
 231                  $x = 0;
 232  
 233                  //    Raise the height-position (bottom-up)
 234                  ++$y;
 235  
 236                  //    Reached the image-height? Break the for-loop
 237                  if ($y > $height) {
 238                      break;
 239                  }
 240              }
 241  
 242              // Calculation of the RGB-pixel (defined as BGR in image-data)
 243              // Define $i_pos as absolute position in the body
 244              $i_pos = $i * 2;
 245              $r = hexdec($body[$i_pos + 4] . $body[$i_pos + 5]);
 246              $g = hexdec($body[$i_pos + 2] . $body[$i_pos + 3]);
 247              $b = hexdec($body[$i_pos] . $body[$i_pos + 1]);
 248  
 249              // Calculate and draw the pixel
 250  
 251              /** @phpstan-ignore-next-line */
 252              $color = imagecolorallocate($image, $r, $g, $b);
 253              // @phpstan-ignore-next-line
 254              imagesetpixel($image, $x, $height - $y, $color);
 255  
 256              // Raise the horizontal position
 257              ++$x;
 258          }
 259  
 260          // Unset the body / free the memory
 261          unset($body);
 262  
 263          //    Return image-object
 264          // @phpstan-ignore-next-line
 265          return $image;
 266      }
 267  }