PluginProbe
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin / 6.5.1.7
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin v6.5.1.7
6.5.1.7 6.5.1.6 6.5.1.5 6.5.1.4 6.5.1.3 6.5.1.2 6.5.1.1 6.5.0.9 6.5.0.8 6.5.0.7 6.5.0.6 trunk 3.4.2.40 3.4.2.41 3.4.2.42 3.4.2.43 3.4.2.44 3.4.2.45 3.4.2.46 3.4.2.47 3.4.2.48 3.4.2.49 3.4.2.50 6.3.2 6.3.3.1 All 47 releases
wpdatatables / lib / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Shared / Font.php

Font.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin 6.5.1.7, at lib/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Font.php

676 lines 24.1 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\Shared;
4
5 use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
6 use PhpOffice\PhpSpreadsheet\RichText\RichText;
7 use PhpOffice\PhpSpreadsheet\Style\Alignment;
8 use PhpOffice\PhpSpreadsheet\Style\Font as FontStyle;
9
10 class Font
11 {
12 // Methods for resolving autosize value
13 const AUTOSIZE_METHOD_APPROX = 'approx';
14 const AUTOSIZE_METHOD_EXACT = 'exact';
15
16 private const AUTOSIZE_METHODS = [
17 self::AUTOSIZE_METHOD_APPROX,
18 self::AUTOSIZE_METHOD_EXACT,
19 ];
20
21 /** Character set codes used by BIFF5-8 in Font records */
22 const CHARSET_ANSI_LATIN = 0x00;
23 const CHARSET_SYSTEM_DEFAULT = 0x01;
24 const CHARSET_SYMBOL = 0x02;
25 const CHARSET_APPLE_ROMAN = 0x4D;
26 const CHARSET_ANSI_JAPANESE_SHIFTJIS = 0x80;
27 const CHARSET_ANSI_KOREAN_HANGUL = 0x81;
28 const CHARSET_ANSI_KOREAN_JOHAB = 0x82;
29 const CHARSET_ANSI_CHINESE_SIMIPLIFIED = 0x86; // gb2312
30 const CHARSET_ANSI_CHINESE_TRADITIONAL = 0x88; // big5
31 const CHARSET_ANSI_GREEK = 0xA1;
32 const CHARSET_ANSI_TURKISH = 0xA2;
33 const CHARSET_ANSI_VIETNAMESE = 0xA3;
34 const CHARSET_ANSI_HEBREW = 0xB1;
35 const CHARSET_ANSI_ARABIC = 0xB2;
36 const CHARSET_ANSI_BALTIC = 0xBA;
37 const CHARSET_ANSI_CYRILLIC = 0xCC;
38 const CHARSET_ANSI_THAI = 0xDD;
39 const CHARSET_ANSI_LATIN_II = 0xEE;
40 const CHARSET_OEM_LATIN_I = 0xFF;
41
42 // XXX: Constants created!
43 /** Font filenames */
44 const ARIAL = 'arial.ttf';
45 const ARIAL_BOLD = 'arialbd.ttf';
46 const ARIAL_ITALIC = 'ariali.ttf';
47 const ARIAL_BOLD_ITALIC = 'arialbi.ttf';
48
49 const CALIBRI = 'calibri.ttf';
50 const CALIBRI_BOLD = 'calibrib.ttf';
51 const CALIBRI_ITALIC = 'calibrii.ttf';
52 const CALIBRI_BOLD_ITALIC = 'calibriz.ttf';
53
54 const COMIC_SANS_MS = 'comic.ttf';
55 const COMIC_SANS_MS_BOLD = 'comicbd.ttf';
56
57 const COURIER_NEW = 'cour.ttf';
58 const COURIER_NEW_BOLD = 'courbd.ttf';
59 const COURIER_NEW_ITALIC = 'couri.ttf';
60 const COURIER_NEW_BOLD_ITALIC = 'courbi.ttf';
61
62 const GEORGIA = 'georgia.ttf';
63 const GEORGIA_BOLD = 'georgiab.ttf';
64 const GEORGIA_ITALIC = 'georgiai.ttf';
65 const GEORGIA_BOLD_ITALIC = 'georgiaz.ttf';
66
67 const IMPACT = 'impact.ttf';
68
69 const LIBERATION_SANS = 'LiberationSans-Regular.ttf';
70 const LIBERATION_SANS_BOLD = 'LiberationSans-Bold.ttf';
71 const LIBERATION_SANS_ITALIC = 'LiberationSans-Italic.ttf';
72 const LIBERATION_SANS_BOLD_ITALIC = 'LiberationSans-BoldItalic.ttf';
73
74 const LUCIDA_CONSOLE = 'lucon.ttf';
75 const LUCIDA_SANS_UNICODE = 'l_10646.ttf';
76
77 const MICROSOFT_SANS_SERIF = 'micross.ttf';
78
79 const PALATINO_LINOTYPE = 'pala.ttf';
80 const PALATINO_LINOTYPE_BOLD = 'palab.ttf';
81 const PALATINO_LINOTYPE_ITALIC = 'palai.ttf';
82 const PALATINO_LINOTYPE_BOLD_ITALIC = 'palabi.ttf';
83
84 const SYMBOL = 'symbol.ttf';
85
86 const TAHOMA = 'tahoma.ttf';
87 const TAHOMA_BOLD = 'tahomabd.ttf';
88
89 const TIMES_NEW_ROMAN = 'times.ttf';
90 const TIMES_NEW_ROMAN_BOLD = 'timesbd.ttf';
91 const TIMES_NEW_ROMAN_ITALIC = 'timesi.ttf';
92 const TIMES_NEW_ROMAN_BOLD_ITALIC = 'timesbi.ttf';
93
94 const TREBUCHET_MS = 'trebuc.ttf';
95 const TREBUCHET_MS_BOLD = 'trebucbd.ttf';
96 const TREBUCHET_MS_ITALIC = 'trebucit.ttf';
97 const TREBUCHET_MS_BOLD_ITALIC = 'trebucbi.ttf';
98
99 const VERDANA = 'verdana.ttf';
100 const VERDANA_BOLD = 'verdanab.ttf';
101 const VERDANA_ITALIC = 'verdanai.ttf';
102 const VERDANA_BOLD_ITALIC = 'verdanaz.ttf';
103
104 const FONT_FILE_NAMES = [
105 'Arial' => [
106 'x' => self::ARIAL,
107 'xb' => self::ARIAL_BOLD,
108 'xi' => self::ARIAL_ITALIC,
109 'xbi' => self::ARIAL_BOLD_ITALIC,
110 ],
111 'Calibri' => [
112 'x' => self::CALIBRI,
113 'xb' => self::CALIBRI_BOLD,
114 'xi' => self::CALIBRI_ITALIC,
115 'xbi' => self::CALIBRI_BOLD_ITALIC,
116 ],
117 'Comic Sans MS' => [
118 'x' => self::COMIC_SANS_MS,
119 'xb' => self::COMIC_SANS_MS_BOLD,
120 'xi' => self::COMIC_SANS_MS,
121 'xbi' => self::COMIC_SANS_MS_BOLD,
122 ],
123 'Courier New' => [
124 'x' => self::COURIER_NEW,
125 'xb' => self::COURIER_NEW_BOLD,
126 'xi' => self::COURIER_NEW_ITALIC,
127 'xbi' => self::COURIER_NEW_BOLD_ITALIC,
128 ],
129 'Georgia' => [
130 'x' => self::GEORGIA,
131 'xb' => self::GEORGIA_BOLD,
132 'xi' => self::GEORGIA_ITALIC,
133 'xbi' => self::GEORGIA_BOLD_ITALIC,
134 ],
135 'Impact' => [
136 'x' => self::IMPACT,
137 'xb' => self::IMPACT,
138 'xi' => self::IMPACT,
139 'xbi' => self::IMPACT,
140 ],
141 'Liberation Sans' => [
142 'x' => self::LIBERATION_SANS,
143 'xb' => self::LIBERATION_SANS_BOLD,
144 'xi' => self::LIBERATION_SANS_ITALIC,
145 'xbi' => self::LIBERATION_SANS_BOLD_ITALIC,
146 ],
147 'Lucida Console' => [
148 'x' => self::LUCIDA_CONSOLE,
149 'xb' => self::LUCIDA_CONSOLE,
150 'xi' => self::LUCIDA_CONSOLE,
151 'xbi' => self::LUCIDA_CONSOLE,
152 ],
153 'Lucida Sans Unicode' => [
154 'x' => self::LUCIDA_SANS_UNICODE,
155 'xb' => self::LUCIDA_SANS_UNICODE,
156 'xi' => self::LUCIDA_SANS_UNICODE,
157 'xbi' => self::LUCIDA_SANS_UNICODE,
158 ],
159 'Microsoft Sans Serif' => [
160 'x' => self::MICROSOFT_SANS_SERIF,
161 'xb' => self::MICROSOFT_SANS_SERIF,
162 'xi' => self::MICROSOFT_SANS_SERIF,
163 'xbi' => self::MICROSOFT_SANS_SERIF,
164 ],
165 'Palatino Linotype' => [
166 'x' => self::PALATINO_LINOTYPE,
167 'xb' => self::PALATINO_LINOTYPE_BOLD,
168 'xi' => self::PALATINO_LINOTYPE_ITALIC,
169 'xbi' => self::PALATINO_LINOTYPE_BOLD_ITALIC,
170 ],
171 'Symbol' => [
172 'x' => self::SYMBOL,
173 'xb' => self::SYMBOL,
174 'xi' => self::SYMBOL,
175 'xbi' => self::SYMBOL,
176 ],
177 'Tahoma' => [
178 'x' => self::TAHOMA,
179 'xb' => self::TAHOMA_BOLD,
180 'xi' => self::TAHOMA,
181 'xbi' => self::TAHOMA_BOLD,
182 ],
183 'Times New Roman' => [
184 'x' => self::TIMES_NEW_ROMAN,
185 'xb' => self::TIMES_NEW_ROMAN_BOLD,
186 'xi' => self::TIMES_NEW_ROMAN_ITALIC,
187 'xbi' => self::TIMES_NEW_ROMAN_BOLD_ITALIC,
188 ],
189 'Trebuchet MS' => [
190 'x' => self::TREBUCHET_MS,
191 'xb' => self::TREBUCHET_MS_BOLD,
192 'xi' => self::TREBUCHET_MS_ITALIC,
193 'xbi' => self::TREBUCHET_MS_BOLD_ITALIC,
194 ],
195 'Verdana' => [
196 'x' => self::VERDANA,
197 'xb' => self::VERDANA_BOLD,
198 'xi' => self::VERDANA_ITALIC,
199 'xbi' => self::VERDANA_BOLD_ITALIC,
200 ],
201 ];
202
203 /**
204 * Array that can be used to supplement FONT_FILE_NAMES for calculating exact width.
205 *
206 * @var array
207 */
208 private static $extraFontArray = [];
209
210 public static function setExtraFontArray(array $extraFontArray): void
211 {
212 self::$extraFontArray = $extraFontArray;
213 }
214
215 public static function getExtraFontArray(): array
216 {
217 return self::$extraFontArray;
218 }
219
220 /**
221 * AutoSize method.
222 *
223 * @var string
224 */
225 private static $autoSizeMethod = self::AUTOSIZE_METHOD_APPROX;
226
227 /**
228 * Path to folder containing TrueType font .ttf files.
229 *
230 * @var string
231 */
232 private static $trueTypeFontPath = '';
233
234 /**
235 * How wide is a default column for a given default font and size?
236 * Empirical data found by inspecting real Excel files and reading off the pixel width
237 * in Microsoft Office Excel 2007.
238 * Added height in points.
239 */
240 public const DEFAULT_COLUMN_WIDTHS = [
241 'Arial' => [
242 1 => ['px' => 24, 'width' => 12.00000000, 'height' => 5.25],
243 2 => ['px' => 24, 'width' => 12.00000000, 'height' => 5.25],
244 3 => ['px' => 32, 'width' => 10.66406250, 'height' => 6.0],
245
246 4 => ['px' => 32, 'width' => 10.66406250, 'height' => 6.75],
247 5 => ['px' => 40, 'width' => 10.00000000, 'height' => 8.25],
248 6 => ['px' => 48, 'width' => 9.59765625, 'height' => 8.25],
249 7 => ['px' => 48, 'width' => 9.59765625, 'height' => 9.0],
250 8 => ['px' => 56, 'width' => 9.33203125, 'height' => 11.25],
251 9 => ['px' => 64, 'width' => 9.14062500, 'height' => 12.0],
252 10 => ['px' => 64, 'width' => 9.14062500, 'height' => 12.75],
253 ],
254 'Calibri' => [
255 1 => ['px' => 24, 'width' => 12.00000000, 'height' => 5.25],
256 2 => ['px' => 24, 'width' => 12.00000000, 'height' => 5.25],
257 3 => ['px' => 32, 'width' => 10.66406250, 'height' => 6.00],
258 4 => ['px' => 32, 'width' => 10.66406250, 'height' => 6.75],
259 5 => ['px' => 40, 'width' => 10.00000000, 'height' => 8.25],
260 6 => ['px' => 48, 'width' => 9.59765625, 'height' => 8.25],
261 7 => ['px' => 48, 'width' => 9.59765625, 'height' => 9.0],
262 8 => ['px' => 56, 'width' => 9.33203125, 'height' => 11.25],
263 9 => ['px' => 56, 'width' => 9.33203125, 'height' => 12.0],
264 10 => ['px' => 64, 'width' => 9.14062500, 'height' => 12.75],
265 11 => ['px' => 64, 'width' => 9.14062500, 'height' => 15.0],
266 ],
267 'Verdana' => [
268 1 => ['px' => 24, 'width' => 12.00000000, 'height' => 5.25],
269 2 => ['px' => 24, 'width' => 12.00000000, 'height' => 5.25],
270 3 => ['px' => 32, 'width' => 10.66406250, 'height' => 6.0],
271 4 => ['px' => 32, 'width' => 10.66406250, 'height' => 6.75],
272 5 => ['px' => 40, 'width' => 10.00000000, 'height' => 8.25],
273 6 => ['px' => 48, 'width' => 9.59765625, 'height' => 8.25],
274 7 => ['px' => 48, 'width' => 9.59765625, 'height' => 9.0],
275 8 => ['px' => 64, 'width' => 9.14062500, 'height' => 10.5],
276 9 => ['px' => 72, 'width' => 9.00000000, 'height' => 11.25],
277 10 => ['px' => 72, 'width' => 9.00000000, 'height' => 12.75],
278 ],
279 ];
280
281 /**
282 * List of column widths. Replaced by constant;
283 * previously it was public and updateable, allowing
284 * user to make inappropriate alterations.
285 *
286 * @deprecated 1.25.0 Use DEFAULT_COLUMN_WIDTHS constant instead.
287 *
288 * @var array
289 */
290 public static $defaultColumnWidths = self::DEFAULT_COLUMN_WIDTHS;
291
292 /**
293 * Set autoSize method.
294 *
295 * @param string $method see self::AUTOSIZE_METHOD_*
296 *
297 * @return bool Success or failure
298 */
299 public static function setAutoSizeMethod($method)
300 {
301 if (!in_array($method, self::AUTOSIZE_METHODS)) {
302 return false;
303 }
304 self::$autoSizeMethod = $method;
305
306 return true;
307 }
308
309 /**
310 * Get autoSize method.
311 *
312 * @return string
313 */
314 public static function getAutoSizeMethod()
315 {
316 return self::$autoSizeMethod;
317 }
318
319 /**
320 * Set the path to the folder containing .ttf files. There should be a trailing slash.
321 * Typical locations on variout some platforms:
322 * <ul>
323 * <li>C:/Windows/Fonts/</li>
324 * <li>/usr/share/fonts/truetype/</li>
325 * <li>~/.fonts/</li>
326 * </ul>.
327 *
328 * @param string $folderPath
329 */
330 public static function setTrueTypeFontPath($folderPath): void
331 {
332 self::$trueTypeFontPath = $folderPath;
333 }
334
335 /**
336 * Get the path to the folder containing .ttf files.
337 *
338 * @return string
339 */
340 public static function getTrueTypeFontPath()
341 {
342 return self::$trueTypeFontPath;
343 }
344
345 /**
346 * Calculate an (approximate) OpenXML column width, based on font size and text contained.
347 *
348 * @param FontStyle $font Font object
349 * @param null|RichText|string $cellText Text to calculate width
350 * @param int $rotation Rotation angle
351 * @param null|FontStyle $defaultFont Font object
352 * @param bool $filterAdjustment Add space for Autofilter or Table dropdown
353 */
354 public static function calculateColumnWidth(
355 FontStyle $font,
356 $cellText = '',
357 $rotation = 0,
358 ?FontStyle $defaultFont = null,
359 bool $filterAdjustment = false,
360 int $indentAdjustment = 0
361 ): float {
362 // If it is rich text, use plain text
363 if ($cellText instanceof RichText) {
364 $cellText = $cellText->getPlainText();
365 }
366
367 // Special case if there are one or more newline characters ("\n")
368 $cellText = (string) $cellText;
369 if (strpos($cellText, "\n") !== false) {
370 $lineTexts = explode("\n", $cellText);
371 $lineWidths = [];
372 foreach ($lineTexts as $lineText) {
373 $lineWidths[] = self::calculateColumnWidth($font, $lineText, $rotation = 0, $defaultFont, $filterAdjustment);
374 }
375
376 return max($lineWidths); // width of longest line in cell
377 }
378
379 // Try to get the exact text width in pixels
380 $approximate = self::$autoSizeMethod === self::AUTOSIZE_METHOD_APPROX;
381 $columnWidth = 0;
382 if (!$approximate) {
383 try {
384 $columnWidthAdjust = ceil(
385 self::getTextWidthPixelsExact(
386 str_repeat('n', 1 * (($filterAdjustment ? 3 : 1) + ($indentAdjustment * 2))),
387 $font,
388 0
389 ) * 1.07
390 );
391
392 // Width of text in pixels excl. padding
393 // and addition because Excel adds some padding, just use approx width of 'n' glyph
394 $columnWidth = self::getTextWidthPixelsExact($cellText, $font, $rotation) + $columnWidthAdjust;
395 } catch (PhpSpreadsheetException $e) {
396 $approximate = true;
397 }
398 }
399
400 if ($approximate) {
401 $columnWidthAdjust = self::getTextWidthPixelsApprox(
402 str_repeat('n', 1 * (($filterAdjustment ? 3 : 1) + ($indentAdjustment * 2))),
403 $font,
404 0
405 );
406 // Width of text in pixels excl. padding, approximation
407 // and addition because Excel adds some padding, just use approx width of 'n' glyph
408 $columnWidth = self::getTextWidthPixelsApprox($cellText, $font, $rotation) + $columnWidthAdjust;
409 }
410
411 // Convert from pixel width to column width
412 $columnWidth = Drawing::pixelsToCellDimension((int) $columnWidth, $defaultFont ?? new FontStyle());
413
414 // Return
415 return round($columnWidth, 4);
416 }
417
418 /**
419 * Get GD text width in pixels for a string of text in a certain font at a certain rotation angle.
420 */
421 public static function getTextWidthPixelsExact(string $text, FontStyle $font, int $rotation = 0): float
422 {
423 // font size should really be supplied in pixels in GD2,
424 // but since GD2 seems to assume 72dpi, pixels and points are the same
425 $fontFile = self::getTrueTypeFontFileFromFont($font);
426 $textBox = imagettfbbox($font->getSize() ?? 10.0, $rotation, $fontFile, $text);
427 if ($textBox === false) {
428 // @codeCoverageIgnoreStart
429 throw new PhpSpreadsheetException('imagettfbbox failed');
430 // @codeCoverageIgnoreEnd
431 }
432
433 // Get corners positions
434 $lowerLeftCornerX = $textBox[0];
435 $lowerRightCornerX = $textBox[2];
436 $upperRightCornerX = $textBox[4];
437 $upperLeftCornerX = $textBox[6];
438
439 // Consider the rotation when calculating the width
440 return round(max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX), 4);
441 }
442
443 /**
444 * Get approximate width in pixels for a string of text in a certain font at a certain rotation angle.
445 *
446 * @param string $columnText
447 * @param int $rotation
448 *
449 * @return int Text width in pixels (no padding added)
450 */
451 public static function getTextWidthPixelsApprox($columnText, FontStyle $font, $rotation = 0)
452 {
453 $fontName = $font->getName();
454 $fontSize = $font->getSize();
455
456 // Calculate column width in pixels.
457 // We assume fixed glyph width, but count double for "fullwidth" characters.
458 // Result varies with font name and size.
459 switch ($fontName) {
460 case 'Arial':
461 // value 8 was set because of experience in different exports at Arial 10 font.
462 $columnWidth = (int) (8 * StringHelper::countCharactersDbcs($columnText));
463 $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
464
465 break;
466 case 'Verdana':
467 // value 8 was found via interpolation by inspecting real Excel files with Verdana 10 font.
468 $columnWidth = (int) (8 * StringHelper::countCharactersDbcs($columnText));
469 $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
470
471 break;
472 default:
473 // just assume Calibri
474 // value 8.26 was found via interpolation by inspecting real Excel files with Calibri 11 font.
475 $columnWidth = (int) (8.26 * StringHelper::countCharactersDbcs($columnText));
476 $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
477
478 break;
479 }
480
481 // Calculate approximate rotated column width
482 if ($rotation !== 0) {
483 if ($rotation == Alignment::TEXTROTATION_STACK_PHPSPREADSHEET) {
484 // stacked text
485 $columnWidth = 4; // approximation
486 } else {
487 // rotated text
488 $columnWidth = $columnWidth * cos(deg2rad($rotation))
489 + $fontSize * abs(sin(deg2rad($rotation))) / 5; // approximation
490 }
491 }
492
493 // pixel width is an integer
494 return (int) $columnWidth;
495 }
496
497 /**
498 * Calculate an (approximate) pixel size, based on a font points size.
499 *
500 * @param int $fontSizeInPoints Font size (in points)
501 *
502 * @return int Font size (in pixels)
503 */
504 public static function fontSizeToPixels($fontSizeInPoints)
505 {
506 return (int) ((4 / 3) * $fontSizeInPoints);
507 }
508
509 /**
510 * Calculate an (approximate) pixel size, based on inch size.
511 *
512 * @param int $sizeInInch Font size (in inch)
513 *
514 * @return int Size (in pixels)
515 */
516 public static function inchSizeToPixels($sizeInInch)
517 {
518 return $sizeInInch * 96;
519 }
520
521 /**
522 * Calculate an (approximate) pixel size, based on centimeter size.
523 *
524 * @param int $sizeInCm Font size (in centimeters)
525 *
526 * @return float Size (in pixels)
527 */
528 public static function centimeterSizeToPixels($sizeInCm)
529 {
530 return $sizeInCm * 37.795275591;
531 }
532
533 /**
534 * Returns the font path given the font.
535 *
536 * @return string Path to TrueType font file
537 */
538 public static function getTrueTypeFontFileFromFont(FontStyle $font, bool $checkPath = true)
539 {
540 if ($checkPath && (!file_exists(self::$trueTypeFontPath) || !is_dir(self::$trueTypeFontPath))) {
541 throw new PhpSpreadsheetException('Valid directory to TrueType Font files not specified');
542 }
543
544 $name = $font->getName();
545 $fontArray = array_merge(self::FONT_FILE_NAMES, self::$extraFontArray);
546 if (!isset($fontArray[$name])) {
547 throw new PhpSpreadsheetException('Unknown font name "' . $name . '". Cannot map to TrueType font file');
548 }
549 $bold = $font->getBold();
550 $italic = $font->getItalic();
551 $index = 'x';
552 if ($bold) {
553 $index .= 'b';
554 }
555 if ($italic) {
556 $index .= 'i';
557 }
558 $fontFile = $fontArray[$name][$index];
559
560 $separator = '';
561 if (mb_strlen(self::$trueTypeFontPath) > 1 && mb_substr(self::$trueTypeFontPath, -1) !== '/' && mb_substr(self::$trueTypeFontPath, -1) !== '\\') {
562 $separator = DIRECTORY_SEPARATOR;
563 }
564 $fontFileAbsolute = preg_match('~^([A-Za-z]:)?[/\\\]~', $fontFile) === 1;
565 if (!$fontFileAbsolute) {
566 $fontFile = self::$trueTypeFontPath . $separator . $fontFile;
567 }
568
569 // Check if file actually exists
570 if ($checkPath && !file_exists($fontFile) && !$fontFileAbsolute) {
571 $alternateName = $name;
572 if ($index !== 'x' && $fontArray[$name][$index] !== $fontArray[$name]['x']) {
573 // Bold but no italic:
574 // Comic Sans
575 // Tahoma
576 // Neither bold nor italic:
577 // Impact
578 // Lucida Console
579 // Lucida Sans Unicode
580 // Microsoft Sans Serif
581 // Symbol
582 if ($index === 'xb') {
583 $alternateName .= ' Bold';
584 } elseif ($index === 'xi') {
585 $alternateName .= ' Italic';
586 } elseif ($fontArray[$name]['xb'] === $fontArray[$name]['xbi']) {
587 $alternateName .= ' Bold';
588 } else {
589 $alternateName .= ' Bold Italic';
590 }
591 }
592 $fontFile = self::$trueTypeFontPath . $separator . $alternateName . '.ttf';
593 if (!file_exists($fontFile)) {
594 throw new PhpSpreadsheetException('TrueType Font file not found');
595 }
596 }
597
598 return $fontFile;
599 }
600
601 public const CHARSET_FROM_FONT_NAME = [
602 'EucrosiaUPC' => self::CHARSET_ANSI_THAI,
603 'Wingdings' => self::CHARSET_SYMBOL,
604 'Wingdings 2' => self::CHARSET_SYMBOL,
605 'Wingdings 3' => self::CHARSET_SYMBOL,
606 ];
607
608 /**
609 * Returns the associated charset for the font name.
610 *
611 * @param string $fontName Font name
612 *
613 * @return int Character set code
614 */
615 public static function getCharsetFromFontName($fontName)
616 {
617 return self::CHARSET_FROM_FONT_NAME[$fontName] ?? self::CHARSET_ANSI_LATIN;
618 }
619
620 /**
621 * Get the effective column width for columns without a column dimension or column with width -1
622 * For example, for Calibri 11 this is 9.140625 (64 px).
623 *
624 * @param FontStyle $font The workbooks default font
625 * @param bool $returnAsPixels true = return column width in pixels, false = return in OOXML units
626 *
627 * @return mixed Column width
628 */
629 public static function getDefaultColumnWidthByFont(FontStyle $font, $returnAsPixels = false)
630 {
631 if (isset(self::DEFAULT_COLUMN_WIDTHS[$font->getName()][$font->getSize()])) {
632 // Exact width can be determined
633 $columnWidth = $returnAsPixels ?
634 self::DEFAULT_COLUMN_WIDTHS[$font->getName()][$font->getSize()]['px']
635 : self::DEFAULT_COLUMN_WIDTHS[$font->getName()][$font->getSize()]['width'];
636 } else {
637 // We don't have data for this particular font and size, use approximation by
638 // extrapolating from Calibri 11
639 $columnWidth = $returnAsPixels ?
640 self::DEFAULT_COLUMN_WIDTHS['Calibri'][11]['px']
641 : self::DEFAULT_COLUMN_WIDTHS['Calibri'][11]['width'];
642 $columnWidth = $columnWidth * $font->getSize() / 11;
643
644 // Round pixels to closest integer
645 if ($returnAsPixels) {
646 $columnWidth = (int) round($columnWidth);
647 }
648 }
649
650 return $columnWidth;
651 }
652
653 /**
654 * Get the effective row height for rows without a row dimension or rows with height -1
655 * For example, for Calibri 11 this is 15 points.
656 *
657 * @param FontStyle $font The workbooks default font
658 *
659 * @return float Row height in points
660 */
661 public static function getDefaultRowHeightByFont(FontStyle $font)
662 {
663 $name = $font->getName();
664 $size = $font->getSize();
665 if (isset(self::DEFAULT_COLUMN_WIDTHS[$name][$size])) {
666 $rowHeight = self::DEFAULT_COLUMN_WIDTHS[$name][$size]['height'];
667 } elseif ($name === 'Arial' || $name === 'Verdana') {
668 $rowHeight = self::DEFAULT_COLUMN_WIDTHS[$name][10]['height'] * $size / 10.0;
669 } else {
670 $rowHeight = self::DEFAULT_COLUMN_WIDTHS['Calibri'][11]['height'] * $size / 11.0;
671 }
672
673 return $rowHeight;
674 }
675 }
676