Drawing.php 7.3 KB

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