Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
61 / 61
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
BarAbstract
100.00% covered (success)
100.00%
61 / 61
100.00% covered (success)
100.00%
6 / 6
20
100.00% covered (success)
100.00%
1 / 1
 get
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isValidString
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 generateCodeString
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 createImage
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
1 / 1
8
 calculateCodeLength
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 calculateDimensions
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Utils\Barcode
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Utils\Barcode;
16
17/**
18 * Code 128 abstract class.
19 *
20 * @package phpOMS\Utils\Barcode
21 * @license OMS License 2.0
22 * @link    https://jingga.app
23 * @since   1.0.0
24 *
25 * @SuppressWarnings(PHPMD.CamelCasePropertyName)
26 * @SuppressWarnings(PHPMD.CamelCaseVariableName)
27 */
28abstract class BarAbstract extends CodeAbstract
29{
30    /**
31     * Checksum.
32     *
33     * @var int
34     * @since 1.0.0
35     */
36    protected static int $CHECKSUM = 0;
37
38    /**
39     * Char weighted array.
40     *
41     * @var string[]
42     * @since 1.0.0
43     */
44    protected static array $CODEARRAY = [];
45
46    /**
47     * Code start.
48     *
49     * @var string
50     * @since 1.0.0
51     */
52    protected static string $CODE_START = '';
53
54    /**
55     * Code end.
56     *
57     * @var string
58     * @since 1.0.0
59     */
60    protected static string $CODE_END = '';
61
62    /**
63     * Show text below barcode.
64     *
65     * @var bool
66     * @since 1.0.0
67     */
68    protected bool $showText = true;
69
70    /**
71     * {@inheritdoc}
72     */
73    public function get() : mixed
74    {
75        $codeString = static::$CODE_START . $this->generateCodeString() . static::$CODE_END;
76
77        return $this->createImage($codeString);
78    }
79
80    /**
81     * Validate the barcode string
82     *
83     * @param string $barcode Barcode string
84     *
85     * @return bool Returns true if the string is valid for the specific code implementetion otherwise false is returned
86     *
87     * @since 1.0.0
88     */
89    public static function isValidString(string $barcode) : bool
90    {
91        $length = \strlen($barcode);
92
93        for ($i = 0; $i < $length; ++$i) {
94            if (!isset(static::$CODEARRAY[$barcode[$i]]) && !\in_array($barcode[$i], static::$CODEARRAY)) {
95                return false;
96            }
97        }
98
99        return true;
100    }
101
102    /**
103     * Generate weighted code string
104     *
105     * @return string Returns the code string generated from the human readable content
106     *
107     * @since 1.0.0
108     */
109    protected function generateCodeString() : string
110    {
111        if ($this->codestring === '') {
112            $keys     = \array_keys(static::$CODEARRAY);
113            $values   = \array_flip($keys);
114            $length   = \strlen($this->content);
115            $checksum = static::$CHECKSUM;
116
117            for ($pos = 1; $pos <= $length; ++$pos) {
118                $activeKey         = \substr($this->content, ($pos - 1), 1);
119                $this->codestring .= static::$CODEARRAY[$activeKey];
120                $checksum         += $values[$activeKey] * $pos;
121            }
122
123            $this->codestring .= static::$CODEARRAY[$keys[($checksum - ((int) ($checksum / 103) * 103))]];
124        }
125
126        return $this->codestring;
127    }
128
129    /**
130     * Create barcode image
131     *
132     * @param string $codeString Code string to render
133     *
134     * @return \GdImage
135     *
136     * @throws \Exception
137     *
138     * @since 1.0.0
139     */
140    protected function createImage(string $codeString) : mixed
141    {
142        $dimensions = $this->calculateDimensions($codeString);
143        $image      = \imagecreate($dimensions['width'], $dimensions['height']);
144
145        if ($image === false) {
146            throw new \Exception(); // @codeCoverageIgnore
147        }
148
149        $black = \imagecolorallocate($image, 0, 0, 0);
150        $white = \imagecolorallocate($image, 255, 255, 255);
151
152        if ($white === false || $black === false) {
153            throw new \Exception(); // @codeCoverageIgnore
154        }
155
156        \imagefill($image, 0, 0, $white);
157
158        $location = 0;
159        $length   = \strlen($codeString);
160
161        for ($position = 1; $position <= $length; ++$position) {
162            $cur_size = $location + (int) (\substr($codeString, ($position - 1), 1));
163
164            if ($this->orientation === OrientationType::HORIZONTAL) {
165                \imagefilledrectangle(
166                    $image,
167                    $location + $this->margin,
168                    0 + $this->margin,
169                    $cur_size + $this->margin,
170                    $dimensions['height'] - $this->margin - 1,
171                    ($position % 2 === 0 ? $white : $black)
172                );
173            } else {
174                \imagefilledrectangle(
175                    $image,
176                    0 + $this->margin,
177                    $location + $this->margin,
178                    $dimensions['width'] - $this->margin - 1,
179                    $cur_size + $this->margin,
180                    ($position % 2 === 0 ? $white : $black)
181                );
182            }
183
184            $location = $cur_size;
185        }
186
187        return $image;
188    }
189
190    /**
191     * Calculate the code length for image dimensions
192     *
193     * @param string $codeString Code string to render
194     *
195     * @return int Length of the code
196     *
197     * @since 1.0.0
198     */
199    private function calculateCodeLength(string $codeString) : int
200    {
201        $codeLength = 0;
202        $length     = \strlen($codeString);
203
204        for ($i = 1; $i <= $length; ++$i) {
205            $codeLength += (int) (\substr($codeString, ($i - 1), 1));
206        }
207
208        return $codeLength;
209    }
210
211    /**
212     * Calculate the code dimensions
213     *
214     * @param string $codeString Code string to render
215     *
216     * @return array<string, int>
217     *
218     * @since 1.0.0
219     */
220    private function calculateDimensions(string $codeString) : array
221    {
222        $codeLength = $this->calculateCodeLength($codeString);
223        $dimensions = ['width' => 0, 'height' => 0];
224
225        if ($this->orientation === OrientationType::HORIZONTAL) {
226            $dimensions['width']  = $codeLength + $this->margin * 2 + 1;
227            $dimensions['height'] = $this->dimension['height'];
228        } else {
229            $dimensions['width']  = $this->dimension['width'];
230            $dimensions['height'] = $codeLength + $this->margin * 2 + 1;
231        }
232
233        return $dimensions;
234    }
235}