Canvas   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 57
c 2
b 0
f 0
dl 0
loc 120
ccs 0
cts 79
cp 0
rs 10
wmc 13

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A toImage() 0 7 1
B write() 0 57 6
A splitText() 0 32 5
1
<?php
2
3
/**
4
 * This file is part of PhpAidc LabelPrinter package.
5
 *
6
 * © Appwilio (https://appwilio.com)
7
 * © JhaoDa (https://github.com/jhaoda)
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
declare(strict_types=1);
14
15
namespace PhpAidc\LabelPrinter\Emulation;
16
17
use PhpAidc\LabelPrinter\Enum\Angle;
18
use PhpAidc\LabelPrinter\Enum\Anchor;
19
20
final class Canvas
21
{
22
    /** @var int|null */
23
    private $width;
24
25
    /** @var int|null */
26
    private $height;
27
28
    /** @var \Imagick */
29
    private $image;
30
31
    public function __construct(?int $width = null, ?int $height = null)
32
    {
33
        $this->width = $width;
34
        $this->height = $height;
35
36
        $this->image = new \Imagick();
37
    }
38
39
    public function write(
40
        string $text,
41
        string $font,
42
        float $size,
43
        Angle $rotation,
44
        ?Anchor $anchor,
45
        bool $inverted = false,
46
        ?int $spacing = null
47
    ): void {
48
        $canvas = new \ImagickDraw();
49
50
        $canvas->setFont($font);
51
        $canvas->setFontSize($size);
52
        $canvas->setTextAntialias(true);
53
54
        $canvas->setGravity($anchor ? $anchor->getValue() : \Imagick::GRAVITY_NORTHWEST);
55
56
        if ($spacing !== null) {
57
            $canvas->setTextInterLineSpacing($spacing);
58
        }
59
60
        if ($inverted) {
61
            $foreground = new \ImagickPixel('#FFF');
62
            $background = new \ImagickPixel('#00000000');
63
64
            $canvas->setTextUnderColor(new \ImagickPixel('#000000'));
65
        } else {
66
            $foreground = new \ImagickPixel('#000');
67
            $background = new \ImagickPixel('#FFF');
68
        }
69
70
        $canvas->setFillColor($foreground);
71
72
        $metrics = $this->image->queryFontMetrics($canvas, $text, true);
73
74
        if ($metrics['textWidth'] > $this->width) {
75
            [$realWidth, $lines] = $this->splitText($canvas, $text);
76
77
            $realWidth = $this->width ?? $realWidth;
78
            $realHeight = $this->height ?? $metrics['textHeight'] * \count($lines);
79
80
            $text = \implode("\n", $lines);
81
        } else {
82
            $metrics = $this->image->queryFontMetrics($canvas, $text, false);
83
84
            $realWidth = \max($this->width, $metrics['textWidth']);
85
            $realHeight = \max($this->height, $metrics['textHeight']);
86
        }
87
88
        $canvas->annotation(0, 0, $text);
89
90
        $this->image->newImage((int) $realWidth, (int) $realHeight, $background);
91
92
        $this->image->drawImage($canvas);
93
94
        if ($rotation->getDegrees()) {
95
            $this->image->rotateImage($background, $rotation->getDegrees());
96
        }
97
    }
98
99
    public function toImage(): \Imagick
100
    {
101
        $this->image->setImageFormat('png');
102
103
        $this->image->setImageType(\Imagick::IMGTYPE_GRAYSCALE);
104
105
        return $this->image;
106
    }
107
108
    private function splitText(\ImagickDraw $canvas, string $text): array
109
    {
110
        $words = \preg_split('~\s~u', \trim($text), -1, \PREG_SPLIT_NO_EMPTY);
111
112
        if (empty($words)) {
113
            return [
114
                $this->image->queryFontMetrics($canvas, $text)['textWidth'],
115
                [$text],
116
            ];
117
        }
118
119
        $i = 1;
120
        $lines = [];
121
        $lineWidth = [];
122
123
        while(\count($words) > 0) {
124
            $metrics = $this->image->queryFontMetrics($canvas, \implode(' ', \array_slice($words, 0, $i)));
125
126
            if ($metrics['textWidth'] > $this->width || \count($words) < $i) {
127
                $lineWidth[] = $metrics['textWidth'];
128
129
                $lines[] = \implode(' ', \array_slice($words, 0, \max($i - 1, 1)));
130
131
                $words = \array_slice($words, \max($i - 1, 1));
132
133
                $i = 0;
134
            }
135
136
            $i++;
137
        }
138
139
        return [\max($lineWidth), $lines];
140
    }
141
}
142