Completed
Push — rendered-cell-sizes ( a9b1a2...a767c5 )
by Stefan
02:34
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
     */
26 17
    public function __construct($fontsDirectory)
27
    {
28 17
        $this->findFonts($this->determineFontsDir($fontsDirectory));
29 17
    }
30
31
    /**
32
     * Find fonts/paths in a given directory recursively.
33
     *
34
     * @param string|null $path
35
     * @return string|null
36
     */
37 17
    public function findFonts($path = null)
38
    {
39 17
        foreach (glob($path . DIRECTORY_SEPARATOR . '*') as $path) {
40 17
            if (is_dir($path)) {
41 17
                $path = $this->findFonts($path);
42 17
            } elseif (preg_match('~(.+\..tf)$~i', $path, $m)) {
43 17
                $meta = new FontMeta($path);
44 17
                if (strlen($meta->getFontName())) {
45 17
                    $this->fonts[$meta->getFontName()] = $path;
46 17
                }
47 17
            }
48 17
        }
49
50 17
        return $path;
51
    }
52
53
    /**
54
     * Return array of available font names and paths.
55
     *
56
     * @return array
57
     */
58 1
    public function getFonts()
59
    {
60 1
        return $this->fonts;
61
    }
62
63
    /**
64
     * Get the calculated cell width for a given value.
65
     *
66
     * @param string $fontName
67
     * @param int    $fontSize
68
     * @param mixed  $value
69
     *
70
     * @return float|int
71
     */
72 6
    public function getCellWidth($fontName, $fontSize, $value)
73
    {
74 6
        $width = 1;
75 6
        foreach ($this->getSingleCharacterArray($value) as $char) {
76 6
            $width += $this->getCharacterWidth($fontName, $fontSize, $char);
77 6
        }
78
79 6
        return $width;
80
    }
81
82
    /**
83
     * Get width of a single character. Calculate & cache if necessary.
84
     *
85
     * @param string $fontName
86
     * @param int    $fontSize
87
     * @param string $char
88
     *
89
     * @return float
90
     */
91 6
    private function getCharacterWidth($fontName, $fontSize, $char)
92
    {
93 6
        if (!isset($this->sizes[$fontName][$fontSize][$char])) {
94 6
            $this->sizes[$fontName][$fontSize][$char] =
95 6
                $this->calculateCharacterWith($fontName, $fontSize, $char);
96 6
        }
97
98 6
        return $this->sizes[$fontName][$fontSize][$char];
99
    }
100
101
    /**
102
     * Calculate the width of a single character for the given fontname and size.
103
     * Create image that contains the character 100 times to get more accurate results.
104
     *
105
     * @param string $fontName
106
     * @param int    $fontSize
107
     * @param string $char
108
     *
109
     * @return float
110
     */
111 6
    private function calculateCharacterWith($fontName, $fontSize, $char)
112
    {
113 6
        if (isset($this->fonts[$fontName])) {
114 1
            $box = imageftbbox($fontSize, 0, $this->fonts[$fontName], str_repeat($char, 100));
115 1
            $width = abs($box[4] - $box[0]) / 6.73 / 100;
116 1
            return round($width, 3);
117
        }
118
119 5
        return 0.1 * $fontSize;
120
    }
121
122
    /**
123
     * Split value into individual characters.
124
     *
125
     * @param mixed $value
126
     * @return array
127
     */
128 6
    private function getSingleCharacterArray($value)
129
    {
130 6
        if (mb_strlen($value) == strlen($value)) {
131 5
            return str_split($value);
132
        }
133
134 1
        return preg_split('~~u', $value, -1, PREG_SPLIT_NO_EMPTY);
135
    }
136
137
    /**
138
     * Determine glob pattern by fonts directory.
139
     *
140
     * @param $fontsDirectory
141
     * @return string
142
     */
143 17
    private function determineFontsDir($fontsDirectory)
144
    {
145 17
        if (!isset($fontsDirectory) || !is_dir($fontsDirectory)) {
146 17
            $fontsDirectory = '/usr/share/fonts/truetype';
147 17
            if (false !== stripos(php_uname(), 'win')) {
148
                $fontsDirectory = 'C:/Windows/Fonts';
149
            }
150 17
        }
151
152 17
        return rtrim($fontsDirectory, DIRECTORY_SEPARATOR);
153
    }
154
}
155