Passed
Pull Request — master (#52)
by Stefan
04:05 queued 02:02
created

SizeCalculator   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 130
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 1
dl 0
loc 130
ccs 35
cts 35
cp 1
rs 10
c 0
b 0
f 0

7 Methods

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