Completed
Push — remove-default-font-scanning-a... ( fa3134 )
by Stefan
02:41
created

SizeCalculator::findFonts()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
ccs 12
cts 12
cp 1
rs 8.8571
cc 5
eloc 9
nc 5
nop 1
crap 5
1
<?php
2
3
namespace OneSheet\Size;
4
5
/**
6
 * Class SizeCalculator to calculate the approximate width
7
 * of cells based on the current font, size and content.
8
 *
9
 * @package OneSheet\Size
10
 */
11
class SizeCalculator
12
{
13
    /**
14
     * @var array
15
     */
16
    private $fonts = [];
17
18
    /**
19
     * @var array
20
     */
21
    private $sizes = [];
22
23
    /**
24
     * @param string|null $fontsDirectory
25
     * @throws \Exception
26
     */
27 19
    public function __construct($fontsDirectory = null)
28
    {
29 19
        if (is_dir($fontsDirectory)) {
30 1
            $this->findFonts($fontsDirectory);
31 1
        }
32 19
    }
33
34
    /**
35
     * Find fonts/paths in a given directory recursively.
36
     *
37
     * @param string|null $path
38
     * @return string|null
39
     * @throws \Exception
40
     */
41 1
    public function findFonts($path = null)
42
    {
43 1
        foreach (glob($path . DIRECTORY_SEPARATOR . '*') as $path) {
44 1
            if (is_dir($path)) {
45 1
                $path = $this->findFonts($path);
46 1
            } elseif (preg_match('~(.+\..tf)$~i', $path, $m)) {
47 1
                $meta = new FontMeta($path);
48 1
                if (strlen($meta->getFontName())) {
49 1
                    $this->fonts[$meta->getFontName()] = $path;
50 1
                }
51 1
            }
52 1
        }
53
54 1
        return $path;
55
    }
56
57
    /**
58
     * Return array of available font names and paths.
59
     *
60
     * @return array
61
     */
62 2
    public function getFonts()
63
    {
64 2
        return $this->fonts;
65
    }
66
67
    /**
68
     * Get the calculated cell width for a given value.
69
     *
70
     * @param string $fontName
71
     * @param int    $fontSize
72
     * @param mixed  $value
73
     *
74
     * @return float|int
75
     */
76 6
    public function getCellWidth($fontName, $fontSize, $value)
77
    {
78 6
        $width = 1;
79 6
        foreach ($this->getSingleCharacterArray($value) as $char) {
80 6
            $width += $this->getCharacterWidth($fontName, $fontSize, $char);
81 6
        }
82
83 6
        return $width;
84
    }
85
86
    /**
87
     * Get width of a single character. Calculate & cache if necessary.
88
     *
89
     * @param string $fontName
90
     * @param int    $fontSize
91
     * @param string $char
92
     *
93
     * @return float
94
     */
95 6
    private function getCharacterWidth($fontName, $fontSize, $char)
96
    {
97 6
        if (!isset($this->sizes[$fontName][$fontSize][$char])) {
98 6
            $this->sizes[$fontName][$fontSize][$char] =
99 6
                $this->calculateCharacterWith($fontName, $fontSize, $char);
100 6
        }
101
102 6
        return $this->sizes[$fontName][$fontSize][$char];
103
    }
104
105
    /**
106
     * Calculate the width of a single character for the given fontname and size.
107
     * Create image that contains the character 100 times to get more accurate results.
108
     *
109
     * @param string $fontName
110
     * @param int    $fontSize
111
     * @param string $char
112
     *
113
     * @return float
114
     */
115 6
    private function calculateCharacterWith($fontName, $fontSize, $char)
116
    {
117 6
        if (isset($this->fonts[$fontName])) {
118 1
            $box = imageftbbox($fontSize, 0, $this->fonts[$fontName], str_repeat($char, 100));
119 1
            $width = abs($box[4] - $box[0]) / 6.73 / 100;
120 1
            return round($width, 3);
121
        }
122
123 5
        return 0.1 * $fontSize;
124
    }
125
126
    /**
127
     * Split value into individual characters.
128
     *
129
     * @param mixed $value
130
     * @return array
131
     */
132 6
    private function getSingleCharacterArray($value)
133
    {
134 6
        if (mb_strlen($value) == strlen($value)) {
135 5
            return str_split($value);
136
        }
137
138 1
        return preg_split('~~u', $value, -1, PREG_SPLIT_NO_EMPTY);
139
    }
140
}
141