ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Font.php
Go to the documentation of this file.
1<?php
2
4
5use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
8
9class Font
10{
11 // Methods for resolving autosize value
12 const AUTOSIZE_METHOD_APPROX = 'approx';
13 const AUTOSIZE_METHOD_EXACT = 'exact';
14
15 private static $autoSizeMethods = [
18 ];
19
21 const CHARSET_ANSI_LATIN = 0x00;
23 const CHARSET_SYMBOL = 0x02;
24 const CHARSET_APPLE_ROMAN = 0x4D;
28 const CHARSET_ANSI_CHINESE_SIMIPLIFIED = 0x86; // gb2312
30 const CHARSET_ANSI_GREEK = 0xA1;
33 const CHARSET_ANSI_HEBREW = 0xB1;
34 const CHARSET_ANSI_ARABIC = 0xB2;
35 const CHARSET_ANSI_BALTIC = 0xBA;
37 const CHARSET_ANSI_THAI = 0xDD;
39 const CHARSET_OEM_LATIN_I = 0xFF;
40
41 // XXX: Constants created!
43 const ARIAL = 'arial.ttf';
44 const ARIAL_BOLD = 'arialbd.ttf';
45 const ARIAL_ITALIC = 'ariali.ttf';
46 const ARIAL_BOLD_ITALIC = 'arialbi.ttf';
47
48 const CALIBRI = 'CALIBRI.TTF';
49 const CALIBRI_BOLD = 'CALIBRIB.TTF';
50 const CALIBRI_ITALIC = 'CALIBRII.TTF';
51 const CALIBRI_BOLD_ITALIC = 'CALIBRIZ.TTF';
52
53 const COMIC_SANS_MS = 'comic.ttf';
54 const COMIC_SANS_MS_BOLD = 'comicbd.ttf';
55
56 const COURIER_NEW = 'cour.ttf';
57 const COURIER_NEW_BOLD = 'courbd.ttf';
58 const COURIER_NEW_ITALIC = 'couri.ttf';
59 const COURIER_NEW_BOLD_ITALIC = 'courbi.ttf';
60
61 const GEORGIA = 'georgia.ttf';
62 const GEORGIA_BOLD = 'georgiab.ttf';
63 const GEORGIA_ITALIC = 'georgiai.ttf';
64 const GEORGIA_BOLD_ITALIC = 'georgiaz.ttf';
65
66 const IMPACT = 'impact.ttf';
67
68 const LIBERATION_SANS = 'LiberationSans-Regular.ttf';
69 const LIBERATION_SANS_BOLD = 'LiberationSans-Bold.ttf';
70 const LIBERATION_SANS_ITALIC = 'LiberationSans-Italic.ttf';
71 const LIBERATION_SANS_BOLD_ITALIC = 'LiberationSans-BoldItalic.ttf';
72
73 const LUCIDA_CONSOLE = 'lucon.ttf';
74 const LUCIDA_SANS_UNICODE = 'l_10646.ttf';
75
76 const MICROSOFT_SANS_SERIF = 'micross.ttf';
77
78 const PALATINO_LINOTYPE = 'pala.ttf';
79 const PALATINO_LINOTYPE_BOLD = 'palab.ttf';
80 const PALATINO_LINOTYPE_ITALIC = 'palai.ttf';
81 const PALATINO_LINOTYPE_BOLD_ITALIC = 'palabi.ttf';
82
83 const SYMBOL = 'symbol.ttf';
84
85 const TAHOMA = 'tahoma.ttf';
86 const TAHOMA_BOLD = 'tahomabd.ttf';
87
88 const TIMES_NEW_ROMAN = 'times.ttf';
89 const TIMES_NEW_ROMAN_BOLD = 'timesbd.ttf';
90 const TIMES_NEW_ROMAN_ITALIC = 'timesi.ttf';
91 const TIMES_NEW_ROMAN_BOLD_ITALIC = 'timesbi.ttf';
92
93 const TREBUCHET_MS = 'trebuc.ttf';
94 const TREBUCHET_MS_BOLD = 'trebucbd.ttf';
95 const TREBUCHET_MS_ITALIC = 'trebucit.ttf';
96 const TREBUCHET_MS_BOLD_ITALIC = 'trebucbi.ttf';
97
98 const VERDANA = 'verdana.ttf';
99 const VERDANA_BOLD = 'verdanab.ttf';
100 const VERDANA_ITALIC = 'verdanai.ttf';
101 const VERDANA_BOLD_ITALIC = 'verdanaz.ttf';
102
109
115 private static $trueTypeFontPath = null;
116
124 public static $defaultColumnWidths = [
125 'Arial' => [
126 1 => ['px' => 24, 'width' => 12.00000000],
127 2 => ['px' => 24, 'width' => 12.00000000],
128 3 => ['px' => 32, 'width' => 10.66406250],
129 4 => ['px' => 32, 'width' => 10.66406250],
130 5 => ['px' => 40, 'width' => 10.00000000],
131 6 => ['px' => 48, 'width' => 9.59765625],
132 7 => ['px' => 48, 'width' => 9.59765625],
133 8 => ['px' => 56, 'width' => 9.33203125],
134 9 => ['px' => 64, 'width' => 9.14062500],
135 10 => ['px' => 64, 'width' => 9.14062500],
136 ],
137 'Calibri' => [
138 1 => ['px' => 24, 'width' => 12.00000000],
139 2 => ['px' => 24, 'width' => 12.00000000],
140 3 => ['px' => 32, 'width' => 10.66406250],
141 4 => ['px' => 32, 'width' => 10.66406250],
142 5 => ['px' => 40, 'width' => 10.00000000],
143 6 => ['px' => 48, 'width' => 9.59765625],
144 7 => ['px' => 48, 'width' => 9.59765625],
145 8 => ['px' => 56, 'width' => 9.33203125],
146 9 => ['px' => 56, 'width' => 9.33203125],
147 10 => ['px' => 64, 'width' => 9.14062500],
148 11 => ['px' => 64, 'width' => 9.14062500],
149 ],
150 'Verdana' => [
151 1 => ['px' => 24, 'width' => 12.00000000],
152 2 => ['px' => 24, 'width' => 12.00000000],
153 3 => ['px' => 32, 'width' => 10.66406250],
154 4 => ['px' => 32, 'width' => 10.66406250],
155 5 => ['px' => 40, 'width' => 10.00000000],
156 6 => ['px' => 48, 'width' => 9.59765625],
157 7 => ['px' => 48, 'width' => 9.59765625],
158 8 => ['px' => 64, 'width' => 9.14062500],
159 9 => ['px' => 72, 'width' => 9.00000000],
160 10 => ['px' => 72, 'width' => 9.00000000],
161 ],
162 ];
163
171 public static function setAutoSizeMethod($pValue)
172 {
173 if (!in_array($pValue, self::$autoSizeMethods)) {
174 return false;
175 }
176 self::$autoSizeMethod = $pValue;
177
178 return true;
179 }
180
186 public static function getAutoSizeMethod()
187 {
189 }
190
202 public static function setTrueTypeFontPath($pValue): void
203 {
204 self::$trueTypeFontPath = $pValue;
205 }
206
212 public static function getTrueTypeFontPath()
213 {
215 }
216
227 public static function calculateColumnWidth(\PhpOffice\PhpSpreadsheet\Style\Font $font, $cellText = '', $rotation = 0, ?\PhpOffice\PhpSpreadsheet\Style\Font $defaultFont = null)
228 {
229 // If it is rich text, use plain text
230 if ($cellText instanceof RichText) {
231 $cellText = $cellText->getPlainText();
232 }
233
234 // Special case if there are one or more newline characters ("\n")
235 if (strpos($cellText ?? '', "\n") !== false) {
236 $lineTexts = explode("\n", $cellText);
237 $lineWidths = [];
238 foreach ($lineTexts as $lineText) {
239 $lineWidths[] = self::calculateColumnWidth($font, $lineText, $rotation = 0, $defaultFont);
240 }
241
242 return max($lineWidths); // width of longest line in cell
243 }
244
245 // Try to get the exact text width in pixels
246 $approximate = self::$autoSizeMethod == self::AUTOSIZE_METHOD_APPROX;
247 $columnWidth = 0;
248 if (!$approximate) {
249 $columnWidthAdjust = ceil(self::getTextWidthPixelsExact('n', $font, 0) * 1.07);
250
251 try {
252 // Width of text in pixels excl. padding
253 // and addition because Excel adds some padding, just use approx width of 'n' glyph
254 $columnWidth = self::getTextWidthPixelsExact($cellText, $font, $rotation) + $columnWidthAdjust;
255 } catch (PhpSpreadsheetException $e) {
256 $approximate = true;
257 }
258 }
259
260 if ($approximate) {
261 $columnWidthAdjust = self::getTextWidthPixelsApprox('n', $font, 0);
262 // Width of text in pixels excl. padding, approximation
263 // and addition because Excel adds some padding, just use approx width of 'n' glyph
264 $columnWidth = self::getTextWidthPixelsApprox($cellText, $font, $rotation) + $columnWidthAdjust;
265 }
266
267 // Convert from pixel width to column width
268 $columnWidth = Drawing::pixelsToCellDimension($columnWidth, $defaultFont);
269
270 // Return
271 return (int) round($columnWidth, 6);
272 }
273
277 public static function getTextWidthPixelsExact(string $text, \PhpOffice\PhpSpreadsheet\Style\Font $font, int $rotation = 0): int
278 {
279 if (!function_exists('imagettfbbox')) {
280 throw new PhpSpreadsheetException('GD library needs to be enabled');
281 }
282
283 // font size should really be supplied in pixels in GD2,
284 // but since GD2 seems to assume 72dpi, pixels and points are the same
285 $fontFile = self::getTrueTypeFontFileFromFont($font);
286 $textBox = imagettfbbox($font->getSize(), $rotation, $fontFile, $text);
287
288 // Get corners positions
289 $lowerLeftCornerX = $textBox[0];
290 $lowerRightCornerX = $textBox[2];
291 $upperRightCornerX = $textBox[4];
292 $upperLeftCornerX = $textBox[6];
293
294 // Consider the rotation when calculating the width
295 return max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX);
296 }
297
306 public static function getTextWidthPixelsApprox($columnText, \PhpOffice\PhpSpreadsheet\Style\Font $font, $rotation = 0)
307 {
308 $fontName = $font->getName();
309 $fontSize = $font->getSize();
310
311 // Calculate column width in pixels. We assume fixed glyph width. Result varies with font name and size.
312 switch ($fontName) {
313 case 'Calibri':
314 // value 8.26 was found via interpolation by inspecting real Excel files with Calibri 11 font.
315 $columnWidth = (int) (8.26 * StringHelper::countCharacters($columnText));
316 $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
317
318 break;
319 case 'Arial':
320 // value 8 was set because of experience in different exports at Arial 10 font.
321 $columnWidth = (int) (8 * StringHelper::countCharacters($columnText));
322 $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
323
324 break;
325 case 'Verdana':
326 // value 8 was found via interpolation by inspecting real Excel files with Verdana 10 font.
327 $columnWidth = (int) (8 * StringHelper::countCharacters($columnText));
328 $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
329
330 break;
331 default:
332 // just assume Calibri
333 $columnWidth = (int) (8.26 * StringHelper::countCharacters($columnText));
334 $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
335
336 break;
337 }
338
339 // Calculate approximate rotated column width
340 if ($rotation !== 0) {
342 // stacked text
343 $columnWidth = 4; // approximation
344 } else {
345 // rotated text
346 $columnWidth = $columnWidth * cos(deg2rad($rotation))
347 + $fontSize * abs(sin(deg2rad($rotation))) / 5; // approximation
348 }
349 }
350
351 // pixel width is an integer
352 return (int) $columnWidth;
353 }
354
362 public static function fontSizeToPixels($fontSizeInPoints)
363 {
364 return (int) ((4 / 3) * $fontSizeInPoints);
365 }
366
374 public static function inchSizeToPixels($sizeInInch)
375 {
376 return $sizeInInch * 96;
377 }
378
386 public static function centimeterSizeToPixels($sizeInCm)
387 {
388 return $sizeInCm * 37.795275591;
389 }
390
398 public static function getTrueTypeFontFileFromFont($font)
399 {
400 if (!file_exists(self::$trueTypeFontPath) || !is_dir(self::$trueTypeFontPath)) {
401 throw new PhpSpreadsheetException('Valid directory to TrueType Font files not specified');
402 }
403
404 $name = $font->getName();
405 $bold = $font->getBold();
406 $italic = $font->getItalic();
407
408 // Check if we can map font to true type font file
409 switch ($name) {
410 case 'Arial':
411 $fontFile = (
412 $bold ? ($italic ? self::ARIAL_BOLD_ITALIC : self::ARIAL_BOLD)
413 : ($italic ? self::ARIAL_ITALIC : self::ARIAL)
414 );
415
416 break;
417 case 'Calibri':
418 $fontFile = (
420 : ($italic ? self::CALIBRI_ITALIC : self::CALIBRI)
421 );
422
423 break;
424 case 'Courier New':
425 $fontFile = (
427 : ($italic ? self::COURIER_NEW_ITALIC : self::COURIER_NEW)
428 );
429
430 break;
431 case 'Comic Sans MS':
432 $fontFile = (
434 );
435
436 break;
437 case 'Georgia':
438 $fontFile = (
440 : ($italic ? self::GEORGIA_ITALIC : self::GEORGIA)
441 );
442
443 break;
444 case 'Impact':
445 $fontFile = self::IMPACT;
446
447 break;
448 case 'Liberation Sans':
449 $fontFile = (
451 : ($italic ? self::LIBERATION_SANS_ITALIC : self::LIBERATION_SANS)
452 );
453
454 break;
455 case 'Lucida Console':
456 $fontFile = self::LUCIDA_CONSOLE;
457
458 break;
459 case 'Lucida Sans Unicode':
460 $fontFile = self::LUCIDA_SANS_UNICODE;
461
462 break;
463 case 'Microsoft Sans Serif':
464 $fontFile = self::MICROSOFT_SANS_SERIF;
465
466 break;
467 case 'Palatino Linotype':
468 $fontFile = (
470 : ($italic ? self::PALATINO_LINOTYPE_ITALIC : self::PALATINO_LINOTYPE)
471 );
472
473 break;
474 case 'Symbol':
475 $fontFile = self::SYMBOL;
476
477 break;
478 case 'Tahoma':
479 $fontFile = (
481 );
482
483 break;
484 case 'Times New Roman':
485 $fontFile = (
487 : ($italic ? self::TIMES_NEW_ROMAN_ITALIC : self::TIMES_NEW_ROMAN)
488 );
489
490 break;
491 case 'Trebuchet MS':
492 $fontFile = (
494 : ($italic ? self::TREBUCHET_MS_ITALIC : self::TREBUCHET_MS)
495 );
496
497 break;
498 case 'Verdana':
499 $fontFile = (
501 : ($italic ? self::VERDANA_ITALIC : self::VERDANA)
502 );
503
504 break;
505 default:
506 throw new PhpSpreadsheetException('Unknown font name "' . $name . '". Cannot map to TrueType font file');
507
508 break;
509 }
510
511 $fontFile = self::$trueTypeFontPath . $fontFile;
512
513 // Check if file actually exists
514 if (!file_exists($fontFile)) {
515 throw new PhpSpreadsheetException('TrueType Font file not found');
516 }
517
518 return $fontFile;
519 }
520
528 public static function getCharsetFromFontName($name)
529 {
530 switch ($name) {
531 // Add more cases. Check FONT records in real Excel files.
532 case 'EucrosiaUPC':
534 case 'Wingdings':
536 case 'Wingdings 2':
538 case 'Wingdings 3':
540 default:
542 }
543 }
544
554 public static function getDefaultColumnWidthByFont(\PhpOffice\PhpSpreadsheet\Style\Font $font, $pPixels = false)
555 {
556 if (isset(self::$defaultColumnWidths[$font->getName()][$font->getSize()])) {
557 // Exact width can be determined
558 $columnWidth = $pPixels ?
559 self::$defaultColumnWidths[$font->getName()][$font->getSize()]['px']
560 : self::$defaultColumnWidths[$font->getName()][$font->getSize()]['width'];
561 } else {
562 // We don't have data for this particular font and size, use approximation by
563 // extrapolating from Calibri 11
564 $columnWidth = $pPixels ?
565 self::$defaultColumnWidths['Calibri'][11]['px']
566 : self::$defaultColumnWidths['Calibri'][11]['width'];
567 $columnWidth = $columnWidth * $font->getSize() / 11;
568
569 // Round pixels to closest integer
570 if ($pPixels) {
571 $columnWidth = (int) round($columnWidth);
572 }
573 }
574
575 return $columnWidth;
576 }
577
586 public static function getDefaultRowHeightByFont(\PhpOffice\PhpSpreadsheet\Style\Font $font)
587 {
588 switch ($font->getName()) {
589 case 'Arial':
590 switch ($font->getSize()) {
591 case 10:
592 // inspection of Arial 10 workbook says 12.75pt ~17px
593 $rowHeight = 12.75;
594
595 break;
596 case 9:
597 // inspection of Arial 9 workbook says 12.00pt ~16px
598 $rowHeight = 12;
599
600 break;
601 case 8:
602 // inspection of Arial 8 workbook says 11.25pt ~15px
603 $rowHeight = 11.25;
604
605 break;
606 case 7:
607 // inspection of Arial 7 workbook says 9.00pt ~12px
608 $rowHeight = 9;
609
610 break;
611 case 6:
612 case 5:
613 // inspection of Arial 5,6 workbook says 8.25pt ~11px
614 $rowHeight = 8.25;
615
616 break;
617 case 4:
618 // inspection of Arial 4 workbook says 6.75pt ~9px
619 $rowHeight = 6.75;
620
621 break;
622 case 3:
623 // inspection of Arial 3 workbook says 6.00pt ~8px
624 $rowHeight = 6;
625
626 break;
627 case 2:
628 case 1:
629 // inspection of Arial 1,2 workbook says 5.25pt ~7px
630 $rowHeight = 5.25;
631
632 break;
633 default:
634 // use Arial 10 workbook as an approximation, extrapolation
635 $rowHeight = 12.75 * $font->getSize() / 10;
636
637 break;
638 }
639
640 break;
641 case 'Calibri':
642 switch ($font->getSize()) {
643 case 11:
644 // inspection of Calibri 11 workbook says 15.00pt ~20px
645 $rowHeight = 15;
646
647 break;
648 case 10:
649 // inspection of Calibri 10 workbook says 12.75pt ~17px
650 $rowHeight = 12.75;
651
652 break;
653 case 9:
654 // inspection of Calibri 9 workbook says 12.00pt ~16px
655 $rowHeight = 12;
656
657 break;
658 case 8:
659 // inspection of Calibri 8 workbook says 11.25pt ~15px
660 $rowHeight = 11.25;
661
662 break;
663 case 7:
664 // inspection of Calibri 7 workbook says 9.00pt ~12px
665 $rowHeight = 9;
666
667 break;
668 case 6:
669 case 5:
670 // inspection of Calibri 5,6 workbook says 8.25pt ~11px
671 $rowHeight = 8.25;
672
673 break;
674 case 4:
675 // inspection of Calibri 4 workbook says 6.75pt ~9px
676 $rowHeight = 6.75;
677
678 break;
679 case 3:
680 // inspection of Calibri 3 workbook says 6.00pt ~8px
681 $rowHeight = 6.00;
682
683 break;
684 case 2:
685 case 1:
686 // inspection of Calibri 1,2 workbook says 5.25pt ~7px
687 $rowHeight = 5.25;
688
689 break;
690 default:
691 // use Calibri 11 workbook as an approximation, extrapolation
692 $rowHeight = 15 * $font->getSize() / 11;
693
694 break;
695 }
696
697 break;
698 case 'Verdana':
699 switch ($font->getSize()) {
700 case 10:
701 // inspection of Verdana 10 workbook says 12.75pt ~17px
702 $rowHeight = 12.75;
703
704 break;
705 case 9:
706 // inspection of Verdana 9 workbook says 11.25pt ~15px
707 $rowHeight = 11.25;
708
709 break;
710 case 8:
711 // inspection of Verdana 8 workbook says 10.50pt ~14px
712 $rowHeight = 10.50;
713
714 break;
715 case 7:
716 // inspection of Verdana 7 workbook says 9.00pt ~12px
717 $rowHeight = 9.00;
718
719 break;
720 case 6:
721 case 5:
722 // inspection of Verdana 5,6 workbook says 8.25pt ~11px
723 $rowHeight = 8.25;
724
725 break;
726 case 4:
727 // inspection of Verdana 4 workbook says 6.75pt ~9px
728 $rowHeight = 6.75;
729
730 break;
731 case 3:
732 // inspection of Verdana 3 workbook says 6.00pt ~8px
733 $rowHeight = 6;
734
735 break;
736 case 2:
737 case 1:
738 // inspection of Verdana 1,2 workbook says 5.25pt ~7px
739 $rowHeight = 5.25;
740
741 break;
742 default:
743 // use Verdana 10 workbook as an approximation, extrapolation
744 $rowHeight = 12.75 * $font->getSize() / 10;
745
746 break;
747 }
748
749 break;
750 default:
751 // just use Calibri as an approximation
752 $rowHeight = 15 * $font->getSize() / 11;
753
754 break;
755 }
756
757 return $rowHeight;
758 }
759}
An exception for terminatinating execution or to throw for unit testing.
static pixelsToCellDimension($pValue, \PhpOffice\PhpSpreadsheet\Style\Font $pDefaultFont)
Convert pixels to column width.
Definition: Drawing.php:47
static getDefaultColumnWidthByFont(\PhpOffice\PhpSpreadsheet\Style\Font $font, $pPixels=false)
Get the effective column width for columns without a column dimension or column with width -1 For exa...
Definition: Font.php:554
static getAutoSizeMethod()
Get autoSize method.
Definition: Font.php:186
static inchSizeToPixels($sizeInInch)
Calculate an (approximate) pixel size, based on inch size.
Definition: Font.php:374
static calculateColumnWidth(\PhpOffice\PhpSpreadsheet\Style\Font $font, $cellText='', $rotation=0, ?\PhpOffice\PhpSpreadsheet\Style\Font $defaultFont=null)
Calculate an (approximate) OpenXML column width, based on font size and text contained.
Definition: Font.php:227
static getTrueTypeFontPath()
Get the path to the folder containing .ttf files.
Definition: Font.php:212
static getTextWidthPixelsApprox($columnText, \PhpOffice\PhpSpreadsheet\Style\Font $font, $rotation=0)
Get approximate width in pixels for a string of text in a certain font at a certain rotation angle.
Definition: Font.php:306
static getTrueTypeFontFileFromFont($font)
Returns the font path given the font.
Definition: Font.php:398
static centimeterSizeToPixels($sizeInCm)
Calculate an (approximate) pixel size, based on centimeter size.
Definition: Font.php:386
static getTextWidthPixelsExact(string $text, \PhpOffice\PhpSpreadsheet\Style\Font $font, int $rotation=0)
Get GD text width in pixels for a string of text in a certain font at a certain rotation angle.
Definition: Font.php:277
static getDefaultRowHeightByFont(\PhpOffice\PhpSpreadsheet\Style\Font $font)
Get the effective row height for rows without a row dimension or rows with height -1 For example,...
Definition: Font.php:586
static fontSizeToPixels($fontSizeInPoints)
Calculate an (approximate) pixel size, based on a font points size.
Definition: Font.php:362
static setAutoSizeMethod($pValue)
Set autoSize method.
Definition: Font.php:171
static setTrueTypeFontPath($pValue)
Set the path to the folder containing .ttf files.
Definition: Font.php:202
const CHARSET_ANSI_LATIN
Character set codes used by BIFF5-8 in Font records.
Definition: Font.php:21
static getCharsetFromFontName($name)
Returns the associated charset for the font name.
Definition: Font.php:528
const ARIAL
Font filenames.
Definition: Font.php:43
static countCharacters($value, $enc='UTF-8')
Get character count.
$text
Definition: errorreport.php:18