Completed
Pull Request — master (#23)
by John
06:52
created

BarcodeRenderer::render()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1.0568

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 20
ccs 8
cts 13
cp 0.6153
rs 9.4285
cc 1
eloc 12
nc 1
nop 0
crap 1.0568
1
<?php
2
3
namespace Graze\CiffRenderer\Field\Renderer;
4
5
use Graze\CiffRenderer\Field\Renderer\FixedTextRenderer;
6
use Graze\CiffRenderer\Field\Renderer\Font\FontFace;
7
8
class BarcodeRenderer extends FixedTextRenderer
9
{
10
    const FONT_SIZE_MULTIPLIER = 6.2;
11
12
    /**
13
     * @return string
14
     */
15
    public function getFontFace()
16
    {
17
        return FontFace::FACE_BARCODE;
18
    }
19
20
    /**
21
     * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
22
     */
23
    protected function getFontSize()
24
    {
25
        return parent::getFontSize() * self::FONT_SIZE_MULTIPLIER;
26
    }
27
28
    /**
29
     * @return Intervention/Image/Image
0 ignored issues
show
Documentation introduced by
The doc-type Intervention/Image/Image could not be parsed: Unknown type name "Intervention/Image/Image" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
30
     */
31 1
    public function render()
32
    {
33 1
        $canvas = $this->getImageManager()->canvas($this->getWidth(), $this->getHeight(), '#000');
34
35 1
        $fontResolver = $this->getFontResolver();
36
37 1
        $fontPath = $fontResolver($this->getFontFace());
38
39 1
        $fontCallback = function ($font) use ($fontPath) {
40
            $font->file($fontPath);
41
            $font->size($this->getFontSize());
42
            $font->color('#fff');
43
            $font->align('center');
44
            $font->valign('middle');
45 1
        };
46
47 1
        $canvas->text($this->getBarcode(), $this->getWidth() / 2, $this->getHeight(), $fontCallback);
48
49 1
        return $canvas;
50
    }
51
52
    /**
53
     * Only EAN13 currently supported.
54
     *
55
     * @return string
56
     */
57
    private function getBarcode()
58
    {
59
        $barcode = $this->getText();
60
61
        // add up each digit in the barcode - odd digits counting
62
        // from the right are tripled before being added
63
        $sum = 0;
64
        $triple = true;
65
        for($i = strlen($barcode)-1; $i >= 0; $i--) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FOR keyword; 0 found
Loading history...
66
            $sum += ($triple ? 3 : 1) * $barcode[$i];
67
            $triple = !$triple;
68
        }
69
70
        //check digit is the inverse remainder after / by 10
71
        //e.g. 4 becomes 6, 8 becomes 2 etc...
72
        $remainder = $sum % 10;
73
74
        if ($remainder > 0) {
75
            $remainder = 10 - $remainder;
76
        }
77
78
        return $this->convertToFontCode($barcode . $remainder);
79
    }
80
81
    /**
82
     * @param string $barcode
83
     * @return string
84
     */
85
    private function convertToFontCode($barcode)
86
    {
87
        /**
88
         * The barcode is split into the following sections:
89
         *  First digit
90
         *  First group of 6 digits (2nd-7th)
91
         *  Last group of 6 digits (8th-13th)
92
         *      e.g.        1234567890128
93
         *      becomes     1   234567  890128
94
         *
95
         * The font converts the first digit to a char between q-z
96
         *
97
         * The first group of digits are converted to chars starting at either A or Q,
98
         * the first digit affects the format of the first group as follows:
99
         *  1st digit     First group format
100
         *      0           AAAAAA
101
         *      1           AAQAQQ
102
         *      2           AAQQAQ
103
         *      3           AAQQQA
104
         *      4           AQAAQQ
105
         *      5           AQQAAQ
106
         *      6           AQQQAA
107
         *      7           AQAQAQ
108
         *      8           AQAQQA
109
         *      9           AQQAQA
110
         *
111
         * The last group of digits remain unchanged
112
         *
113
         * The actual format used by the font is:
114
         *       firstDigit  {{{{{|  firstGroup  {|{  secondGroup  |
115
         */
116
117
        // convert first digit
118
        $firstDigit = (int)substr($barcode, 0, 1);
119
        $firstDigitChar = chr(113 + $firstDigit);
120
121
        // convert first group
122
        $firstGroup = '';
123
        $firstGroupFormats = array(
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
124
            'AAAAAA',
125
            'AAQAQQ',
126
            'AAQQAQ',
127
            'AAQQQA',
128
            'AQAAQQ',
129
            'AQQAAQ',
130
            'AQQQAA',
131
            'AQAQAQ',
132
            'AQAQQA',
133
            'AQQAQA'
134
        );
135
        $firstGroupFormat = $firstGroupFormats[$firstDigit];
136
        for($i = 1; $i <= 6; $i++) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FOR keyword; 0 found
Loading history...
137
            $digit = (int)substr($barcode, $i, 1);
138
            $startingChar = substr($firstGroupFormat, $i - 1, 1);
139
            $firstGroup .= chr(ord($startingChar) + $digit);
140
        }
141
142
        // extract second group
143
        $secondGroup = substr($barcode, 7);
144
145
        // combine the barcode with the special chars used by the font
146
        return $firstDigitChar.'{{{{{|'.$firstGroup.'{|{'.$secondGroup.'|';
147
    }
148
}
149