├── LICENSE.md
├── composer.json
├── config
└── barcode.php
└── src
├── AbstractGenerator.php
├── Barcode.php
├── BarcodeBar.php
├── BarcodeManager.php
├── BarcodeServiceProvider.php
├── Contracts
├── Factory.php
└── ImageType.php
├── Drivers
├── DynamicHTML.php
├── HTML.php
├── JPG.php
├── PNG.php
└── SVG.php
├── Enums
├── BarcodeType.php
└── Type.php
├── Exceptions
├── BarcodeException.php
├── InvalidCharacterException.php
├── InvalidCheckDigitException.php
├── InvalidFormatException.php
├── InvalidLengthException.php
└── UnknownTypeException.php
├── Facades
└── Barcode.php
├── Helpers
├── BarcodeHelper.php
└── BinarySequenceConverter.php
└── Types
├── TypeCodabar.php
├── TypeCode11.php
├── TypeCode128.php
├── TypeCode128A.php
├── TypeCode128B.php
├── TypeCode128C.php
├── TypeCode32.php
├── TypeCode39.php
├── TypeCode39Checksum.php
├── TypeCode39Extended.php
├── TypeCode39ExtendedChecksum.php
├── TypeCode93.php
├── TypeEan13.php
├── TypeEan8.php
├── TypeEanUpcBase.php
├── TypeIntelligentMailBarcode.php
├── TypeInterface.php
├── TypeInterleaved25.php
├── TypeInterleaved25Checksum.php
├── TypeKix.php
├── TypeMsi.php
├── TypeMsiChecksum.php
├── TypePharmacode.php
├── TypePharmacodeTwoCode.php
├── TypePlanet.php
├── TypePostnet.php
├── TypeRms4cc.php
├── TypeStandard2of5.php
├── TypeStandard2of5Checksum.php
├── TypeUpcA.php
├── TypeUpcE.php
├── TypeUpcExtension2.php
└── TypeUpcExtension5.php
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) AgeekDev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ageekdev/laravel-barcode",
3 | "description": "laravel barcode generator",
4 | "keywords": [
5 | "ageekdev",
6 | "laravel",
7 | "barcode"
8 | ],
9 | "homepage": "https://github.com/ageekdev/laravel-barcode",
10 | "license": "MIT",
11 | "authors": [
12 | {
13 | "name": "Tint Naing Win",
14 | "email": "amigo.k8@gmail.com",
15 | "role": "Developer"
16 | }
17 | ],
18 | "require": {
19 | "php": "^8.1",
20 | "ext-bcmath": "*",
21 | "illuminate/contracts": "^9.0|^10.0|^11.0|^12.0",
22 | "spatie/color": "^1.5"
23 | },
24 | "require-dev": {
25 | "laravel/pint": "^1.5",
26 | "larastan/larastan": "^2.0|^3.0",
27 | "orchestra/testbench": "^7.31|^8.11|^9.0|^10.0",
28 | "pestphp/pest": "^1.21|^2.0|^3.0",
29 | "pestphp/pest-plugin-laravel": "^1.4|^2.0|^3.0",
30 | "phpstan/extension-installer": "^1.1",
31 | "phpstan/phpstan-deprecation-rules": "^1.0|^2.0",
32 | "phpstan/phpstan-phpunit": "^1.0|^2.0",
33 | "roave/security-advisories": "dev-latest"
34 | },
35 | "autoload": {
36 | "psr-4": {
37 | "AgeekDev\\Barcode\\": "src"
38 | }
39 | },
40 | "autoload-dev": {
41 | "psr-4": {
42 | "AgeekDev\\Barcode\\Tests\\": "tests"
43 | }
44 | },
45 | "suggest": {
46 | "ext-gd": "For JPG and PNG generators, GD or Imagick is required",
47 | "ext-imagick": "For JPG and PNG generators, GD or Imagick is required"
48 | },
49 | "scripts": {
50 | "analyse": "vendor/bin/phpstan analyse",
51 | "test": "vendor/bin/pest",
52 | "test-coverage": "vendor/bin/pest --coverage",
53 | "format": "vendor/bin/pint"
54 | },
55 | "config": {
56 | "sort-packages": true,
57 | "allow-plugins": {
58 | "pestphp/pest-plugin": true,
59 | "phpstan/extension-installer": true
60 | }
61 | },
62 | "extra": {
63 | "laravel": {
64 | "providers": [
65 | "AgeekDev\\Barcode\\BarcodeServiceProvider"
66 | ],
67 | "aliases": {
68 | "Barcode": "AgeekDev\\Barcode\\Facades\\Barcode"
69 | }
70 | }
71 | },
72 | "minimum-stability": "dev",
73 | "prefer-stable": true
74 | }
75 |
--------------------------------------------------------------------------------
/config/barcode.php:
--------------------------------------------------------------------------------
1 | env('BARCODE_DRIVER', 'png'),
17 |
18 | /*
19 | |----------------------------------------------------------------------------------------------
20 | | Accepted Barcode Types
21 | |----------------------------------------------------------------------------------------------
22 | | Supported: TYPE_CODE_32, TYPE_CODE_39, TYPE_CODE_39_CHECKSUM, TYPE_CODE_39E,
23 | | TYPE_CODE_39E_CHECKSUM, TYPE_CODE_93, TYPE_STANDARD_2_5, TYPE_STANDARD_2_5_CHECKSUM,
24 | | TYPE_INTERLEAVED_2_5, TYPE_INTERLEAVED_2_5_CHECKSUM, TYPE_CODE_128, TYPE_CODE_128_A,
25 | | TYPE_CODE_128_B, TYPE_CODE_128_C, TYPE_EAN_2, TYPE_EAN_5, TYPE_EAN_8, TYPE_EAN_13,
26 | | TYPE_UPC_A, TYPE_UPC_E, TYPE_MSI, TYPE_MSI_CHECKSUM, TYPE_POSTNET, TYPE_PLANET, TYPE_RMS4CC,
27 | | TYPE_KIX, TYPE_IMB, TYPE_CODABAR, TYPE_CODE_11, TYPE_PHARMA_CODE, TYPE_PHARMA_CODE_TWO_TRACKS
28 | |
29 | */
30 | 'type' => \AgeekDev\Barcode\Enums\BarcodeType::CODE_128,
31 |
32 | /*
33 | * Foreground color of the barcode
34 | */
35 | 'foreground_color' => '#000000',
36 |
37 | /*
38 | * width factor of barcode
39 | */
40 | 'width_factor' => 2,
41 |
42 | /*
43 | * Height of image barcode
44 | */
45 | 'height' => 30,
46 |
47 | ];
48 |
--------------------------------------------------------------------------------
/src/AbstractGenerator.php:
--------------------------------------------------------------------------------
1 | foregroundColor = config('barcode.foreground_color');
26 | $this->widthFactor = config('barcode.width_factor');
27 | $this->height = config('barcode.height');
28 | $this->type = config('barcode.type');
29 | }
30 |
31 | protected function getBarcodeData(string $code, BarcodeType|Type $type): Barcode
32 | {
33 | return $this->createDataBuilderForType($type)->getBarcodeData($code);
34 | }
35 |
36 | protected function createDataBuilderForType(BarcodeType|Type $type): TypeInterface
37 | {
38 | return $type->class();
39 | }
40 |
41 | public function type(BarcodeType|Type $type): static
42 | {
43 | $this->type = $type;
44 |
45 | return $this;
46 | }
47 |
48 | public function foregroundColor(string $foregroundColor): static
49 | {
50 | $this->foregroundColor = $foregroundColor;
51 |
52 | return $this;
53 | }
54 |
55 | public function height(int $height): static
56 | {
57 | $this->height = $height;
58 |
59 | return $this;
60 | }
61 |
62 | public function widthFactor(int $widthFactor): static
63 | {
64 | $this->widthFactor = $widthFactor;
65 |
66 | return $this;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Barcode.php:
--------------------------------------------------------------------------------
1 | barcode = $barcode;
18 | }
19 |
20 | /**
21 | * Add bar.
22 | */
23 | public function addBar(BarcodeBar $bar): void
24 | {
25 | $this->bars[] = $bar;
26 | $this->width += $bar->getWidth();
27 | $this->height = max($this->height, $bar->getHeight());
28 | }
29 |
30 | /**
31 | * Get the barcode.
32 | */
33 | public function getBarcode(): string
34 | {
35 | return $this->barcode;
36 | }
37 |
38 | /**
39 | * Get the width.
40 | */
41 | public function getWidth(): int
42 | {
43 | return $this->width;
44 | }
45 |
46 | /**
47 | * Get the height.
48 | */
49 | public function getHeight(): int
50 | {
51 | return $this->height;
52 | }
53 |
54 | /**
55 | * Get the bars.
56 | */
57 | public function getBars(): array
58 | {
59 | return $this->bars;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/BarcodeBar.php:
--------------------------------------------------------------------------------
1 | width = $width;
22 | $this->height = $height;
23 | $this->positionVertical = $positionVertical;
24 | $this->type = $drawBar ? self::TYPE_BAR : self::TYPE_SPACING;
25 | }
26 |
27 | /**
28 | * Get the width.
29 | */
30 | public function getWidth(): int
31 | {
32 | return $this->width;
33 | }
34 |
35 | /**
36 | * Get the height.
37 | */
38 | public function getHeight(): int
39 | {
40 | return $this->height;
41 | }
42 |
43 | /**
44 | * Get position vertical.
45 | */
46 | public function getPositionVertical(): int
47 | {
48 | return $this->positionVertical;
49 | }
50 |
51 | /**
52 | * Bar or not.
53 | */
54 | public function isBar(): bool
55 | {
56 | return $this->type === self::TYPE_BAR;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/BarcodeManager.php:
--------------------------------------------------------------------------------
1 | container = $container;
53 | $this->config = $container->make('config');
54 | }
55 |
56 | /**
57 | * Get a image type instance.
58 | */
59 | public function imageType(?string $name = null): ImageType
60 | {
61 | $name = $name ?: $this->getDefaultDriver();
62 |
63 | // If the given driver has not been created before, we will create the instances
64 | // here and cache it, so we can return it next time very quickly. If there is
65 | // already a driver created by this name, we'll just return that instance.
66 | if (! isset($this->imageTypes[$name])) {
67 | $this->imageTypes[$name] = $this->createDriver($name);
68 | }
69 |
70 | return $this->imageTypes[$name];
71 | }
72 |
73 | /**
74 | * Create a new driver instance.
75 | *
76 | * @throws InvalidArgumentException
77 | */
78 | protected function createDriver(string $driver): ImageType
79 | {
80 | // First, we will determine if a custom driver creator exists for the given driver and
81 | // if it does not we will check for a creator method for the driver. Custom creator
82 | // callbacks allow developers to build their own "drivers" easily using Closures.
83 | if (isset($this->customCreators[$driver])) {
84 | return $this->callCustomCreator($driver);
85 | }
86 |
87 | $method = 'create'.Str::studly($driver).'Driver';
88 |
89 | if (method_exists($this, $method)) {
90 | return $this->$method();
91 | }
92 |
93 | throw new InvalidArgumentException("ImageType [$driver] not supported.");
94 | }
95 |
96 | /**
97 | * Call a custom driver creator.
98 | */
99 | protected function callCustomCreator(string $driver): ImageType
100 | {
101 | return $this->customCreators[$driver]($this->container);
102 | }
103 |
104 | /**
105 | * Create an HTML instance.
106 | */
107 | public function createHtmlDriver(): ImageType
108 | {
109 | return new HTML;
110 | }
111 |
112 | /**
113 | * Create an DynamicHTML instance.
114 | */
115 | public function createDynamicHtmlDriver(): ImageType
116 | {
117 | return new DynamicHTML;
118 | }
119 |
120 | /**
121 | * Create an JPG instance.
122 | */
123 | public function createJpgDriver(): ImageType
124 | {
125 | return new JPG;
126 | }
127 |
128 | /**
129 | * Create an PNG instance.
130 | */
131 | public function createPngDriver(): ImageType
132 | {
133 | return new PNG;
134 | }
135 |
136 | /**
137 | * Create an SVG instance.
138 | */
139 | public function createSvgDriver(): ImageType
140 | {
141 | return new SVG;
142 | }
143 |
144 | /**
145 | * Generate Barcode.
146 | */
147 | public function generate(string $text): string
148 | {
149 | return $this->imageType()->generate($text);
150 | }
151 |
152 | /**
153 | * Set the barcode type.
154 | */
155 | public function type(BarcodeType|Type $type): ImageType
156 | {
157 | return $this->imageType()->type($type);
158 | }
159 |
160 | /**
161 | * Set the barcode foreground color.
162 | */
163 | public function foregroundColor(string $foregroundColor): ImageType
164 | {
165 | return $this->imageType()->foregroundColor($foregroundColor);
166 | }
167 |
168 | /**
169 | * Set the barcode height.
170 | */
171 | public function height(int $height): ImageType
172 | {
173 | return $this->imageType()->height($height);
174 | }
175 |
176 | /**
177 | * Set the barcode width factor.
178 | */
179 | public function widthFactor(int $widthFactor): ImageType
180 | {
181 | return $this->imageType()->widthFactor($widthFactor);
182 | }
183 |
184 | /**
185 | * Force the use of Imagick image extension
186 | *
187 | * @throws BarcodeException
188 | */
189 | public function useImagick(): ImageType
190 | {
191 | if (method_exists($this->imageType(), 'useImagick')) {
192 | if (! extension_loaded('imagick')) {
193 | throw new BarcodeException('The imagick is not installed!');
194 | }
195 |
196 | return $this->imageType()->useImagick();
197 | }
198 |
199 | throw new BarcodeException('This image type does not support useImagick function.');
200 | }
201 |
202 | /**
203 | * Force the use of the GD image library
204 | *
205 | * @throws BarcodeException
206 | */
207 | public function useGd(): ImageType
208 | {
209 | if (method_exists($this->imageType(), 'useGd')) {
210 | if (! function_exists('imagecreate')) {
211 | throw new BarcodeException('The GD is not installed!');
212 | }
213 |
214 | return $this->imageType()->useGd();
215 | }
216 |
217 | throw new BarcodeException('This image type does not support useGd function.');
218 | }
219 |
220 | /**
221 | * Get the default driver name.
222 | */
223 | public function getDefaultDriver(): string
224 | {
225 | return $this->config->get('barcode.image_type', 'png');
226 | }
227 |
228 | /**
229 | * Register a custom driver creator Closure.
230 | */
231 | public function extend(string $imageType, Closure $callback): self
232 | {
233 | $this->customCreators[$imageType] = $callback;
234 |
235 | return $this;
236 | }
237 |
238 | /**
239 | * Get the container instance used by the manager.
240 | */
241 | public function getContainer(): Container
242 | {
243 | return $this->container;
244 | }
245 |
246 | /**
247 | * Set the container instance used by the manager.
248 | */
249 | public function setContainer(Container $container): self
250 | {
251 | $this->container = $container;
252 |
253 | return $this;
254 | }
255 |
256 | /**
257 | * Unset the given disk instances.
258 | */
259 | public function forgetImageType(array|string $imageType): self
260 | {
261 | foreach ((array) $imageType as $imageTypeName) {
262 | unset($this->imageTypes[$imageTypeName]);
263 | }
264 |
265 | return $this;
266 | }
267 |
268 | /**
269 | * Dynamically call the default driver instance.
270 | *
271 | * @return mixed
272 | */
273 | public function __call(string $method, array $parameters)
274 | {
275 | return $this->imageType()->$method(...$parameters);
276 | }
277 | }
278 |
--------------------------------------------------------------------------------
/src/BarcodeServiceProvider.php:
--------------------------------------------------------------------------------
1 | mergeConfigFrom(__DIR__.'/../config/barcode.php', 'barcode');
15 |
16 | $this->app->bind('laravel-barcode', function ($app) {
17 | return new BarcodeManager($app);
18 | });
19 | }
20 |
21 | public function boot(): void
22 | {
23 | $this->publishes([
24 | __DIR__.'/../config/barcode.php' => config_path('barcode.php'),
25 | ], 'laravel-barcode-config');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Contracts/Factory.php:
--------------------------------------------------------------------------------
1 | getBarcodeData($text, $this->type);
21 |
22 | $html = '
'.PHP_EOL;
23 |
24 | $positionHorizontal = 0;
25 | /** @var BarcodeBar $bar */
26 | foreach ($barcodeData->getBars() as $bar) {
27 | $barWidth = $bar->getWidth() / $barcodeData->getWidth() * 100;
28 | $barHeight = round(($bar->getHeight() / $barcodeData->getHeight() * 100), 3);
29 |
30 | if ($barWidth > 0 && $bar->isBar()) {
31 | $positionVertical = round(($bar->getPositionVertical() / $barcodeData->getHeight() * 100), 3);
32 |
33 | // draw a vertical bar
34 | $html .= '
'.PHP_EOL;
35 | }
36 |
37 | $positionHorizontal += $barWidth;
38 | }
39 |
40 | $html .= '
'.PHP_EOL;
41 |
42 | return $html;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Drivers/HTML.php:
--------------------------------------------------------------------------------
1 | getBarcodeData($text, $this->type);
17 |
18 | $html = ''.PHP_EOL;
19 |
20 | $positionHorizontal = 0;
21 | /** @var BarcodeBar $bar */
22 | foreach ($barcodeData->getBars() as $bar) {
23 | $barWidth = round(($bar->getWidth() * $this->widthFactor), 3);
24 | $barHeight = round(($bar->getHeight() * $this->height / $barcodeData->getHeight()), 3);
25 |
26 | if ($barWidth > 0 && $bar->isBar()) {
27 | $positionVertical = round(($bar->getPositionVertical() * $this->height / $barcodeData->getHeight()), 3);
28 |
29 | $html .= '
'.PHP_EOL;
30 | }
31 |
32 | $positionHorizontal += $barWidth;
33 | }
34 |
35 | $html .= '
'.PHP_EOL;
36 |
37 | return $html;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Drivers/JPG.php:
--------------------------------------------------------------------------------
1 | newImage($width, $height, 'white', 'JPG');
13 |
14 | return $image;
15 | }
16 |
17 | protected function generateGdImage($image): void
18 | {
19 | imagejpeg($image);
20 | imagedestroy($image);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Drivers/PNG.php:
--------------------------------------------------------------------------------
1 | useImagick = true;
27 | } elseif (function_exists('imagecreate')) {
28 | $this->useImagick = false;
29 | } else {
30 | throw new BarcodeException('Neither gd-lib or imagick are installed!');
31 | }
32 | }
33 |
34 | /**
35 | * Force the use of Imagick image extension.
36 | */
37 | public function useImagick(): self
38 | {
39 | $this->useImagick = true;
40 |
41 | return $this;
42 | }
43 |
44 | /**
45 | * Force the use of the GD image library.
46 | */
47 | public function useGd(): self
48 | {
49 | $this->useImagick = false;
50 |
51 | return $this;
52 | }
53 |
54 | /**
55 | * @param string $text code to print
56 | *
57 | * @throws \ImagickDrawException
58 | * @throws \ImagickException
59 | * @throws \ImagickPixelException
60 | */
61 | public function generate(string $text): string
62 | {
63 | $barcodeData = $this->getBarcodeData($text, $this->type);
64 | $width = round($barcodeData->getWidth() * $this->widthFactor);
65 |
66 | $foregroundColor = $this->getForegroundColor();
67 |
68 | if ($this->useImagick) {
69 | $imagickBarsShape = new imagickdraw;
70 | $imagickBarsShape->setFillColor(new imagickpixel('rgb('.implode(',', $foregroundColor).')'));
71 | } else {
72 | $image = $this->createGdImageObject($width, $this->height);
73 | $gdForegroundColor = imagecolorallocate($image, $foregroundColor[0], $foregroundColor[1], $foregroundColor[2]);
74 | }
75 |
76 | // print bars
77 | $positionHorizontal = 0;
78 | /** @var BarcodeBar $bar */
79 | foreach ($barcodeData->getBars() as $bar) {
80 | $barWidth = round(($bar->getWidth() * $this->widthFactor), 3);
81 |
82 | if ($barWidth > 0 && $bar->isBar()) {
83 | $y = round(($bar->getPositionVertical() * $this->height / $barcodeData->getHeight()), 3);
84 | $barHeight = round(($bar->getHeight() * $this->height / $barcodeData->getHeight()), 3);
85 |
86 | // draw a vertical bar
87 | if ($this->useImagick) {
88 | $imagickBarsShape->rectangle($positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight));
89 | } else {
90 | imagefilledrectangle($image, $positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight), $gdForegroundColor);
91 | }
92 | }
93 | $positionHorizontal += $barWidth;
94 | }
95 |
96 | if ($this->useImagick) {
97 | $image = $this->createImagickImageObject($width, $this->height);
98 | $image->drawImage($imagickBarsShape);
99 |
100 | return $image->getImageBlob();
101 | }
102 |
103 | ob_start();
104 | $this->generateGdImage($image);
105 |
106 | return ob_get_clean();
107 | }
108 |
109 | public function getForegroundColor(): string|array
110 | {
111 | $color = Hex::fromString($this->foregroundColor)->toRgba();
112 |
113 | return [$color->red(), $color->blue(), $color->green()];
114 | }
115 |
116 | protected function createGdImageObject(int $width, int $height)
117 | {
118 | $image = imagecreate($width, $height);
119 | $colorBackground = imagecolorallocate($image, 255, 255, 255);
120 | imagecolortransparent($image, $colorBackground);
121 |
122 | return $image;
123 | }
124 |
125 | /**
126 | * @throws \ImagickException
127 | */
128 | protected function createImagickImageObject(int $width, int $height): Imagick
129 | {
130 | $image = new Imagick;
131 | $image->newImage($width, $height, 'none', 'PNG');
132 |
133 | return $image;
134 | }
135 |
136 | protected function generateGdImage($image): void
137 | {
138 | imagepng($image);
139 | imagedestroy($image);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/Drivers/SVG.php:
--------------------------------------------------------------------------------
1 | getBarcodeData($text, $this->type);
18 |
19 | // replace table for special characters
20 | $repstr = ["\0" => '', '&' => '&', '<' => '<', '>' => '>'];
21 |
22 | $width = round(($barcodeData->getWidth() * $this->widthFactor), 3);
23 |
24 | $svg = ''.PHP_EOL;
25 | $svg .= ''.PHP_EOL;
26 | $svg .= ''.PHP_EOL;
27 | $svg .= "\t".''.strtr($barcodeData->getBarcode(), $repstr).' '.PHP_EOL;
28 | $svg .= "\t".''.PHP_EOL;
29 |
30 | // print bars
31 | $positionHorizontal = 0;
32 | /** @var BarcodeBar $bar */
33 | foreach ($barcodeData->getBars() as $bar) {
34 | $barWidth = round(($bar->getWidth() * $this->widthFactor), 3);
35 | $barHeight = round(($bar->getHeight() * $this->height / $barcodeData->getHeight()), 3);
36 |
37 | if ($bar->isBar() && $barWidth > 0) {
38 | $positionVertical = round(($bar->getPositionVertical() * $this->height / $barcodeData->getHeight()), 3);
39 | // draw a vertical bar
40 | $svg .= "\t\t".' '.PHP_EOL;
41 | }
42 |
43 | $positionHorizontal += $barWidth;
44 | }
45 | $svg .= "\t ".PHP_EOL;
46 | $svg .= ' '.PHP_EOL;
47 |
48 | return $svg;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Enums/BarcodeType.php:
--------------------------------------------------------------------------------
1 | new TypeCode32,
106 |
107 | self::CODE_39 => new TypeCode39,
108 |
109 | self::CODE_39_CHECKSUM => new TypeCode39Checksum,
110 |
111 | self::CODE_39E => new TypeCode39Extended,
112 |
113 | self::CODE_39E_CHECKSUM => new TypeCode39ExtendedChecksum,
114 |
115 | self::CODE_93 => new TypeCode93,
116 |
117 | self::STANDARD_2_5 => new TypeStandard2of5,
118 |
119 | self::STANDARD_2_5_CHECKSUM => new TypeStandard2of5Checksum,
120 |
121 | self::INTERLEAVED_2_5 => new TypeInterleaved25,
122 |
123 | self::INTERLEAVED_2_5_CHECKSUM => new TypeInterleaved25Checksum,
124 |
125 | self::CODE_128 => new TypeCode128,
126 |
127 | self::CODE_128_A => new TypeCode128A,
128 |
129 | self::CODE_128_B => new TypeCode128B,
130 |
131 | self::CODE_128_C => new TypeCode128C,
132 |
133 | self::EAN_2 => new TypeUpcExtension2,
134 |
135 | self::EAN_5 => new TypeUpcExtension5,
136 |
137 | self::EAN_8 => new TypeEan8,
138 |
139 | self::EAN_13 => new TypeEan13,
140 |
141 | self::UPC_A => new TypeUpcA,
142 |
143 | self::UPC_E => new TypeUpcE,
144 |
145 | self::MSI => new TypeMsi,
146 |
147 | self::MSI_CHECKSUM => new TypeMsiChecksum,
148 |
149 | self::POSTNET => new TypePostnet,
150 |
151 | self::PLANET => new TypePlanet,
152 |
153 | self::RMS4CC => new TypeRms4cc,
154 |
155 | self::KIX => new TypeKix,
156 |
157 | self::IMB => new TypeIntelligentMailBarcode,
158 |
159 | self::CODABAR => new TypeCodabar,
160 |
161 | self::CODE_11 => new TypeCode11,
162 |
163 | self::PHARMA_CODE => new TypePharmacode,
164 |
165 | self::PHARMA_CODE_TWO_TRACKS => new TypePharmacodeTwoCode,
166 | };
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/Enums/Type.php:
--------------------------------------------------------------------------------
1 | new TypeCode32,
109 |
110 | self::TYPE_CODE_39 => new TypeCode39,
111 |
112 | self::TYPE_CODE_39_CHECKSUM => new TypeCode39Checksum,
113 |
114 | self::TYPE_CODE_39E => new TypeCode39Extended,
115 |
116 | self::TYPE_CODE_39E_CHECKSUM => new TypeCode39ExtendedChecksum,
117 |
118 | self::TYPE_CODE_93 => new TypeCode93,
119 |
120 | self::TYPE_STANDARD_2_5 => new TypeStandard2of5,
121 |
122 | self::TYPE_STANDARD_2_5_CHECKSUM => new TypeStandard2of5Checksum,
123 |
124 | self::TYPE_INTERLEAVED_2_5 => new TypeInterleaved25,
125 |
126 | self::TYPE_INTERLEAVED_2_5_CHECKSUM => new TypeInterleaved25Checksum,
127 |
128 | self::TYPE_CODE_128 => new TypeCode128,
129 |
130 | self::TYPE_CODE_128_A => new TypeCode128A,
131 |
132 | self::TYPE_CODE_128_B => new TypeCode128B,
133 |
134 | self::TYPE_CODE_128_C => new TypeCode128C,
135 |
136 | self::TYPE_EAN_2 => new TypeUpcExtension2,
137 |
138 | self::TYPE_EAN_5 => new TypeUpcExtension5,
139 |
140 | self::TYPE_EAN_8 => new TypeEan8,
141 |
142 | self::TYPE_EAN_13 => new TypeEan13,
143 |
144 | self::TYPE_UPC_A => new TypeUpcA,
145 |
146 | self::TYPE_UPC_E => new TypeUpcE,
147 |
148 | self::TYPE_MSI => new TypeMsi,
149 |
150 | self::TYPE_MSI_CHECKSUM => new TypeMsiChecksum,
151 |
152 | self::TYPE_POSTNET => new TypePostnet,
153 |
154 | self::TYPE_PLANET => new TypePlanet,
155 |
156 | self::TYPE_RMS4CC => new TypeRms4cc,
157 |
158 | self::TYPE_KIX => new TypeKix,
159 |
160 | self::TYPE_IMB => new TypeIntelligentMailBarcode,
161 |
162 | self::TYPE_CODABAR => new TypeCodabar,
163 |
164 | self::TYPE_CODE_11 => new TypeCode11,
165 |
166 | self::TYPE_PHARMA_CODE => new TypePharmacode,
167 |
168 | self::TYPE_PHARMA_CODE_TWO_TRACKS => new TypePharmacodeTwoCode,
169 | };
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/Exceptions/BarcodeException.php:
--------------------------------------------------------------------------------
1 | 0) {
20 | $r = (10 - $r);
21 | }
22 |
23 | return $r;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Helpers/BinarySequenceConverter.php:
--------------------------------------------------------------------------------
1 | addBar(new BarcodeBar($barWidth, 1, $drawBar));
34 | $barWidth = 0;
35 | }
36 | }
37 |
38 | return $barcode;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Types/TypeCodabar.php:
--------------------------------------------------------------------------------
1 | '11111221',
18 | '1' => '11112211',
19 | '2' => '11121121',
20 | '3' => '22111111',
21 | '4' => '11211211',
22 | '5' => '21111211',
23 | '6' => '12111121',
24 | '7' => '12112111',
25 | '8' => '12211111',
26 | '9' => '21121111',
27 | '-' => '11122111',
28 | '$' => '11221111',
29 | ':' => '21112121',
30 | '/' => '21211121',
31 | '.' => '21212111',
32 | '+' => '11222221',
33 | 'A' => '11221211',
34 | 'B' => '12121121',
35 | 'C' => '11121221',
36 | 'D' => '11122211',
37 | ];
38 |
39 | /**
40 | * @throws InvalidCharacterException
41 | */
42 | public function getBarcodeData(string $code): Barcode
43 | {
44 | $barcode = new Barcode($code);
45 |
46 | $code = 'A'.strtoupper($code).'A';
47 |
48 | for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
49 | if (! isset($this->conversionTable[$code[$i]])) {
50 | throw new InvalidCharacterException('Char '.$code[$i].' is unsupported');
51 | }
52 |
53 | $seq = $this->conversionTable[$code[$i]];
54 | for ($j = 0; $j < 8; $j++) {
55 | if (($j % 2) === 0) {
56 | $drawBar = true;
57 | } else {
58 | $drawBar = false;
59 | }
60 | $barWidth = $seq[$j];
61 | $barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
62 | }
63 | }
64 |
65 | return $barcode;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Types/TypeCode11.php:
--------------------------------------------------------------------------------
1 | '111121',
18 | '1' => '211121',
19 | '2' => '121121',
20 | '3' => '221111',
21 | '4' => '112121',
22 | '5' => '212111',
23 | '6' => '122111',
24 | '7' => '111221',
25 | '8' => '211211',
26 | '9' => '211111',
27 | '-' => '112111',
28 | 'S' => '112211',
29 | ];
30 |
31 | /**
32 | * @throws InvalidCharacterException
33 | */
34 | public function getBarcodeData(string $code): Barcode
35 | {
36 | $barcode = new Barcode($code);
37 |
38 | $code .= $this->getCheckDigitC($code);
39 | $code .= $this->getCheckDigitK($code);
40 |
41 | $code = 'S'.$code.'S';
42 |
43 | for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
44 | if (! isset($this->conversionTable[$code[$i]])) {
45 | throw new InvalidCharacterException('Char '.$code[$i].' is unsupported');
46 | }
47 |
48 | $seq = $this->conversionTable[$code[$i]];
49 | for ($j = 0, $jMax = strlen($seq); $j < $jMax; $j++) {
50 | if (($j % 2) === 0) {
51 | $drawBar = true;
52 | } else {
53 | $drawBar = false;
54 | }
55 | $barWidth = $seq[$j];
56 |
57 | $barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
58 | }
59 | }
60 |
61 | return $barcode;
62 | }
63 |
64 | private function getCheckDigitC(string $code): string
65 | {
66 | $p = 1;
67 | $check = 0;
68 | for ($i = (strlen($code) - 1); $i >= 0; $i--) {
69 | $digit = $code[$i];
70 | if ($digit === '-') {
71 | $dval = 10;
72 | } else {
73 | $dval = (int) $digit;
74 | }
75 | $check += ($dval * $p);
76 | $p++;
77 | if ($p > 10) {
78 | $p = 1;
79 | }
80 | }
81 | $check %= 11;
82 | if ($check === 10) {
83 | $check = '-';
84 | }
85 |
86 | return $check;
87 | }
88 |
89 | private function getCheckDigitK(string $code): string
90 | {
91 | if (strlen($code) <= 10) {
92 | return '';
93 | }
94 |
95 | $p = 1;
96 | $check = 0;
97 | for ($i = (strlen($code) - 1); $i >= 0; $i--) {
98 | $digit = $code[$i];
99 | if ($digit === '-') {
100 | $dval = 10;
101 | } else {
102 | $dval = (int) $digit;
103 | }
104 | $check += ($dval * $p);
105 | $p++;
106 | if ($p > 9) {
107 | $p = 1;
108 | }
109 | }
110 | $check %= 11;
111 |
112 | return (string) $check;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/Types/TypeCode128.php:
--------------------------------------------------------------------------------
1 | ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
145 | $keys_a .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9);
146 | $keys_a .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19);
147 | $keys_a .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29);
148 | $keys_a .= chr(30).chr(31);
149 |
150 | // ASCII characters for code B (ASCII 32 - 127)
151 | $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
152 |
153 | // special codes
154 | $fnc_a = [241 => 102, 242 => 97, 243 => 96, 244 => 101];
155 | $fnc_b = [241 => 102, 242 => 97, 243 => 96, 244 => 100];
156 |
157 | // array of symbols
158 | $code_data = [];
159 |
160 | // length of the code
161 | $len = strlen($code);
162 |
163 | switch (strtoupper($this->type ?? '')) {
164 | case 'A':
165 | $startid = 103;
166 | for ($i = 0; $i < $len; $i++) {
167 | $char = $code[$i];
168 | $char_id = ord($char);
169 | if (($char_id <= 244) && ($char_id >= 241)) {
170 | $code_data[] = $fnc_a[$char_id];
171 | } elseif ($char_id <= 95) {
172 | $code_data[] = strpos($keys_a, $char);
173 | } else {
174 | throw new InvalidCharacterException('Char '.$char.' is unsupported');
175 | }
176 | }
177 | break;
178 |
179 | case 'B':
180 | $startid = 104;
181 | for ($i = 0; $i < $len; $i++) {
182 | $char = $code[$i];
183 | $char_id = ord($char);
184 | if (($char_id >= 241) && ($char_id <= 244)) {
185 | $code_data[] = $fnc_b[$char_id];
186 | } elseif (($char_id >= 32) && ($char_id <= 127)) {
187 | $code_data[] = strpos($keys_b, $char);
188 | } else {
189 | throw new InvalidCharacterException('Char '.$char.' is unsupported');
190 | }
191 | }
192 | break;
193 |
194 | case 'C':
195 | $startid = 105;
196 | if (ord($code[0]) === 241) {
197 | $code_data[] = 102;
198 | $code = substr($code, 1);
199 | $len--;
200 | }
201 | if (($len % 2) !== 0) {
202 | throw new InvalidLengthException('Length must be even');
203 | }
204 | for ($i = 0; $i < $len; $i += 2) {
205 | $chrnum = $code[$i].$code[$i + 1];
206 | if (preg_match('/(\d{2})/', $chrnum) > 0) {
207 | $code_data[] = (int) $chrnum;
208 | } else {
209 | throw new InvalidCharacterException;
210 | }
211 | }
212 | break;
213 |
214 | default:
215 | // split code into sequences
216 | $sequence = [];
217 | // get numeric sequences (if any)
218 | $numseq = [];
219 | preg_match_all('/(\d{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE);
220 |
221 | if (! empty($numseq[1])) {
222 | $end_offset = 0;
223 |
224 | foreach ($numseq[1] as $val) {
225 | $offset = $val[1];
226 |
227 | // numeric sequence
228 | $slen = strlen($val[0]);
229 | if (($slen % 2) != 0) {
230 | // the length must be even
231 | $offset++;
232 | $val[0] = substr($val[0], 1);
233 | }
234 |
235 | if ($offset > $end_offset) {
236 | // non numeric sequence
237 | $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset))));
238 | }
239 |
240 | // numeric sequence fallback
241 | $slen = strlen($val[0]);
242 | if (($slen % 2) != 0) {
243 | // the length must be even
244 | $slen--;
245 | }
246 | $sequence[] = ['C', substr($code, $offset, $slen), $slen];
247 | $end_offset = $offset + $slen;
248 | }
249 | if ($end_offset < $len) {
250 | $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset)));
251 | }
252 | } else {
253 | // text code (non C mode)
254 | $sequence = array_merge($sequence, $this->get128ABsequence($code));
255 | }
256 |
257 | $startid = 0;
258 | // process the sequence
259 | foreach ($sequence as $key => $seq) {
260 | switch ($seq[0]) {
261 | case 'A':
262 | if ($key === 0) {
263 | $startid = 103;
264 | } elseif ($sequence[($key - 1)][0] !== 'A') {
265 | if (($seq[2] === 1) && ($key > 0) && ($sequence[($key - 1)][0] === 'B') && (! isset($sequence[($key - 1)][3]))) {
266 | // single character shift
267 | $code_data[] = 98;
268 | // mark shift
269 | $sequence[$key][3] = true;
270 | } elseif (! isset($sequence[($key - 1)][3])) {
271 | $code_data[] = 101;
272 | }
273 | }
274 | for ($i = 0; $i < $seq[2]; $i++) {
275 | $char = $seq[1][$i];
276 | $char_id = ord($char);
277 | if (($char_id >= 241) && ($char_id <= 244)) {
278 | $code_data[] = $fnc_a[$char_id];
279 | } else {
280 | $code_data[] = strpos($keys_a, $char);
281 | }
282 | }
283 | break;
284 |
285 | case 'B':
286 | if ($key === 0) {
287 | $tmpchr = ord($seq[1][0]);
288 | if (($seq[2] === 1) && ($tmpchr >= 241) && ($tmpchr <= 244) && isset($sequence[($key + 1)]) && ($sequence[($key + 1)][0] !== 'B')) {
289 | switch ($sequence[($key + 1)][0]) {
290 | case 'A':
291 |
292 | $startid = 103;
293 | $sequence[$key][0] = 'A';
294 | $code_data[] = $fnc_a[$tmpchr];
295 | break;
296 |
297 | case 'C':
298 |
299 | $startid = 105;
300 | $sequence[$key][0] = 'C';
301 | $code_data[] = $fnc_a[$tmpchr];
302 | break;
303 | }
304 | break;
305 | }
306 |
307 | $startid = 104;
308 | } elseif ($sequence[($key - 1)][0] !== 'B') {
309 | if (($seq[2] === 1) && ($key > 0) && ($sequence[($key - 1)][0] === 'A') && (! isset($sequence[($key - 1)][3]))) {
310 | // single character shift
311 | $code_data[] = 98;
312 | // mark shift
313 | $sequence[$key][3] = true;
314 | } elseif (! isset($sequence[($key - 1)][3])) {
315 | $code_data[] = 100;
316 | }
317 | }
318 | for ($i = 0; $i < $seq[2]; $i++) {
319 | $char = $seq[1][$i];
320 | $char_id = ord($char);
321 | if (($char_id >= 241) && ($char_id <= 244)) {
322 | $code_data[] = $fnc_b[$char_id];
323 | } else {
324 | $code_data[] = strpos($keys_b, $char);
325 | }
326 | }
327 | break;
328 |
329 | case 'C':
330 | if ($key === 0) {
331 | $startid = 105;
332 | } elseif ($sequence[($key - 1)][0] !== 'C') {
333 | $code_data[] = 99;
334 | }
335 | for ($i = 0; $i < $seq[2]; $i += 2) {
336 | $chrnum = $seq[1][$i].$seq[1][$i + 1];
337 | $code_data[] = (int) $chrnum;
338 | }
339 | break;
340 | }
341 | }
342 | }
343 |
344 | // calculate check character
345 | $sum = $startid;
346 | foreach ($code_data as $key => $val) {
347 | $sum += ($val * ($key + 1));
348 | }
349 | // add check character
350 | $code_data[] = ($sum % 103);
351 | // add stop sequence
352 | $code_data[] = 106;
353 | $code_data[] = 107;
354 | // add start code at the beginning
355 | array_unshift($code_data, $startid);
356 |
357 | // build barcode array
358 | $barcode = new Barcode($code);
359 | foreach ($code_data as $val) {
360 | $seq = $this->conversionTable[$val];
361 | for ($j = 0; $j < 6; $j++) {
362 | if (($j % 2) === 0) {
363 | $t = true; // bar
364 | } else {
365 | $t = false; // space
366 | }
367 | $w = $seq[$j];
368 |
369 | $barcode->addBar(new BarcodeBar($w, 1, $t));
370 | }
371 | }
372 |
373 | return $barcode;
374 | }
375 |
376 | /**
377 | * Split text code in A/B sequence for 128 code
378 | *
379 | * @param $code (string) code to split.
380 | */
381 | protected function get128ABsequence(string $code): array
382 | {
383 | $len = strlen($code);
384 | $sequence = [];
385 | // get A sequences (if any)
386 | $numseq = [];
387 | preg_match_all('/([\x00-\x1f])/', $code, $numseq, PREG_OFFSET_CAPTURE);
388 | if (! empty($numseq[1])) {
389 | $end_offset = 0;
390 | foreach ($numseq[1] as $val) {
391 | $offset = $val[1];
392 | if ($offset > $end_offset) {
393 | // B sequence
394 | $sequence[] = [
395 | 'B',
396 | substr($code, $end_offset, ($offset - $end_offset)),
397 | ($offset - $end_offset),
398 | ];
399 | }
400 | // A sequence
401 | $slen = strlen($val[0]);
402 | $sequence[] = ['A', substr($code, $offset, $slen), $slen];
403 | $end_offset = $offset + $slen;
404 | }
405 | if ($end_offset < $len) {
406 | $sequence[] = ['B', substr($code, $end_offset), ($len - $end_offset)];
407 | }
408 | } else {
409 | // only B sequence
410 | $sequence[] = ['B', $code, $len];
411 | }
412 |
413 | return $sequence;
414 | }
415 | }
416 |
--------------------------------------------------------------------------------
/src/Types/TypeCode128A.php:
--------------------------------------------------------------------------------
1 | '0',
15 | '1' => '1',
16 | '2' => '2',
17 | '3' => '3',
18 | '4' => '4',
19 | '5' => '5',
20 | '6' => '6',
21 | '7' => '7',
22 | '8' => '8',
23 | '9' => '9',
24 | '10' => 'B',
25 | '11' => 'C',
26 | '12' => 'D',
27 | '13' => 'F',
28 | '14' => 'G',
29 | '15' => 'H',
30 | '16' => 'J',
31 | '17' => 'K',
32 | '18' => 'L',
33 | '19' => 'M',
34 | '20' => 'N',
35 | '21' => 'P',
36 | '22' => 'Q',
37 | '23' => 'R',
38 | '24' => 'S',
39 | '25' => 'T',
40 | '26' => 'U',
41 | '27' => 'V',
42 | '28' => 'W',
43 | '29' => 'X',
44 | '30' => 'Y',
45 | '31' => 'Z',
46 | ];
47 |
48 | public function getBarcodeData(string $code): Barcode
49 | {
50 | $code39 = '';
51 | $codeElab = $code;
52 |
53 | for ($e = 5; $e >= 0; $e--) {
54 | $code39 .= $this->conversionTable32[(int) ($codeElab / (32 ** $e))];
55 | $codeElab %= 32 ** $e;
56 | }
57 |
58 | return parent::getBarcodeData($code39);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Types/TypeCode39.php:
--------------------------------------------------------------------------------
1 | '111331311',
23 | '1' => '311311113',
24 | '2' => '113311113',
25 | '3' => '313311111',
26 | '4' => '111331113',
27 | '5' => '311331111',
28 | '6' => '113331111',
29 | '7' => '111311313',
30 | '8' => '311311311',
31 | '9' => '113311311',
32 | 'A' => '311113113',
33 | 'B' => '113113113',
34 | 'C' => '313113111',
35 | 'D' => '111133113',
36 | 'E' => '311133111',
37 | 'F' => '113133111',
38 | 'G' => '111113313',
39 | 'H' => '311113311',
40 | 'I' => '113113311',
41 | 'J' => '111133311',
42 | 'K' => '311111133',
43 | 'L' => '113111133',
44 | 'M' => '313111131',
45 | 'N' => '111131133',
46 | 'O' => '311131131',
47 | 'P' => '113131131',
48 | 'Q' => '111111333',
49 | 'R' => '311111331',
50 | 'S' => '113111331',
51 | 'T' => '111131331',
52 | 'U' => '331111113',
53 | 'V' => '133111113',
54 | 'W' => '333111111',
55 | 'X' => '131131113',
56 | 'Y' => '331131111',
57 | 'Z' => '133131111',
58 | '-' => '131111313',
59 | '.' => '331111311',
60 | ' ' => '133111311',
61 | '$' => '131313111',
62 | '/' => '131311131',
63 | '+' => '131113131',
64 | '%' => '111313131',
65 | '*' => '131131311',
66 | ];
67 |
68 | /**
69 | * @throws InvalidCharacterException
70 | * @throws InvalidLengthException
71 | */
72 | public function getBarcodeData(string $code): Barcode
73 | {
74 | if (trim($code) === '') {
75 | throw new InvalidLengthException('You should provide a barcode string.');
76 | }
77 |
78 | if ($this->extended) {
79 | // extended mode
80 | $code = $this->encode_code39_ext($code);
81 | }
82 |
83 | if ($this->checksum) {
84 | // checksum
85 | $code .= $this->checksum_code39($code);
86 | }
87 |
88 | // add start and stop codes
89 | $code = '*'.$code.'*';
90 |
91 | $barcode = new Barcode($code);
92 |
93 | for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
94 | $char = $code[$i];
95 | if (! isset($this->conversionTable[$char])) {
96 | throw new InvalidCharacterException('Char '.$char.' is unsupported');
97 | }
98 |
99 | for ($j = 0; $j < 9; $j++) {
100 | if (($j % 2) === 0) {
101 | $drawBar = true;
102 | } else {
103 | $drawBar = false;
104 | }
105 | $barWidth = $this->conversionTable[$char][$j];
106 | $barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
107 | }
108 |
109 | // inter character gap
110 | $barcode->addBar(new BarcodeBar(1, 1, false));
111 | }
112 |
113 | return $barcode;
114 | }
115 |
116 | /**
117 | * Encode a string to be used for CODE 39 Extended mode.
118 | *
119 | * @param string $code code to represent.
120 | *
121 | * @throws InvalidCharacterException
122 | */
123 | protected function encode_code39_ext(string $code): string
124 | {
125 | $encode = [
126 | chr(0) => '%U',
127 | chr(1) => '$A',
128 | chr(2) => '$B',
129 | chr(3) => '$C',
130 | chr(4) => '$D',
131 | chr(5) => '$E',
132 | chr(6) => '$F',
133 | chr(7) => '$G',
134 | chr(8) => '$H',
135 | chr(9) => '$I',
136 | chr(10) => '$J',
137 | chr(11) => '$K',
138 | chr(12) => '$L',
139 | chr(13) => '$M',
140 | chr(14) => '$N',
141 | chr(15) => '$O',
142 | chr(16) => '$P',
143 | chr(17) => '$Q',
144 | chr(18) => '$R',
145 | chr(19) => '$S',
146 | chr(20) => '$T',
147 | chr(21) => '$U',
148 | chr(22) => '$V',
149 | chr(23) => '$W',
150 | chr(24) => '$X',
151 | chr(25) => '$Y',
152 | chr(26) => '$Z',
153 | chr(27) => '%A',
154 | chr(28) => '%B',
155 | chr(29) => '%C',
156 | chr(30) => '%D',
157 | chr(31) => '%E',
158 | chr(32) => ' ',
159 | chr(33) => '/A',
160 | chr(34) => '/B',
161 | chr(35) => '/C',
162 | chr(36) => '/D',
163 | chr(37) => '/E',
164 | chr(38) => '/F',
165 | chr(39) => '/G',
166 | chr(40) => '/H',
167 | chr(41) => '/I',
168 | chr(42) => '/J',
169 | chr(43) => '/K',
170 | chr(44) => '/L',
171 | chr(45) => '-',
172 | chr(46) => '.',
173 | chr(47) => '/O',
174 | chr(48) => '0',
175 | chr(49) => '1',
176 | chr(50) => '2',
177 | chr(51) => '3',
178 | chr(52) => '4',
179 | chr(53) => '5',
180 | chr(54) => '6',
181 | chr(55) => '7',
182 | chr(56) => '8',
183 | chr(57) => '9',
184 | chr(58) => '/Z',
185 | chr(59) => '%F',
186 | chr(60) => '%G',
187 | chr(61) => '%H',
188 | chr(62) => '%I',
189 | chr(63) => '%J',
190 | chr(64) => '%V',
191 | chr(65) => 'A',
192 | chr(66) => 'B',
193 | chr(67) => 'C',
194 | chr(68) => 'D',
195 | chr(69) => 'E',
196 | chr(70) => 'F',
197 | chr(71) => 'G',
198 | chr(72) => 'H',
199 | chr(73) => 'I',
200 | chr(74) => 'J',
201 | chr(75) => 'K',
202 | chr(76) => 'L',
203 | chr(77) => 'M',
204 | chr(78) => 'N',
205 | chr(79) => 'O',
206 | chr(80) => 'P',
207 | chr(81) => 'Q',
208 | chr(82) => 'R',
209 | chr(83) => 'S',
210 | chr(84) => 'T',
211 | chr(85) => 'U',
212 | chr(86) => 'V',
213 | chr(87) => 'W',
214 | chr(88) => 'X',
215 | chr(89) => 'Y',
216 | chr(90) => 'Z',
217 | chr(91) => '%K',
218 | chr(92) => '%L',
219 | chr(93) => '%M',
220 | chr(94) => '%N',
221 | chr(95) => '%O',
222 | chr(96) => '%W',
223 | chr(97) => '+A',
224 | chr(98) => '+B',
225 | chr(99) => '+C',
226 | chr(100) => '+D',
227 | chr(101) => '+E',
228 | chr(102) => '+F',
229 | chr(103) => '+G',
230 | chr(104) => '+H',
231 | chr(105) => '+I',
232 | chr(106) => '+J',
233 | chr(107) => '+K',
234 | chr(108) => '+L',
235 | chr(109) => '+M',
236 | chr(110) => '+N',
237 | chr(111) => '+O',
238 | chr(112) => '+P',
239 | chr(113) => '+Q',
240 | chr(114) => '+R',
241 | chr(115) => '+S',
242 | chr(116) => '+T',
243 | chr(117) => '+U',
244 | chr(118) => '+V',
245 | chr(119) => '+W',
246 | chr(120) => '+X',
247 | chr(121) => '+Y',
248 | chr(122) => '+Z',
249 | chr(123) => '%P',
250 | chr(124) => '%Q',
251 | chr(125) => '%R',
252 | chr(126) => '%S',
253 | chr(127) => '%T',
254 | ];
255 |
256 | $code_ext = '';
257 | for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
258 | if (ord($code[$i]) > 127) {
259 | throw new InvalidCharacterException('Only supports till char 127');
260 | }
261 |
262 | $code_ext .= $encode[$code[$i]];
263 | }
264 |
265 | return $code_ext;
266 | }
267 |
268 | /**
269 | * Calculate CODE 39 checksum (modulo 43).
270 | *
271 | * @param string $code code to represent.
272 | */
273 | protected function checksum_code39(string $code): string
274 | {
275 | $chars = [
276 | '0',
277 | '1',
278 | '2',
279 | '3',
280 | '4',
281 | '5',
282 | '6',
283 | '7',
284 | '8',
285 | '9',
286 | 'A',
287 | 'B',
288 | 'C',
289 | 'D',
290 | 'E',
291 | 'F',
292 | 'G',
293 | 'H',
294 | 'I',
295 | 'J',
296 | 'K',
297 | 'L',
298 | 'M',
299 | 'N',
300 | 'O',
301 | 'P',
302 | 'Q',
303 | 'R',
304 | 'S',
305 | 'T',
306 | 'U',
307 | 'V',
308 | 'W',
309 | 'X',
310 | 'Y',
311 | 'Z',
312 | '-',
313 | '.',
314 | ' ',
315 | '$',
316 | '/',
317 | '+',
318 | '%',
319 | ];
320 |
321 | $sum = 0;
322 | for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
323 | $k = array_keys($chars, $code[$i]);
324 | $sum += $k[0];
325 | }
326 | $j = ($sum % 43);
327 |
328 | return $chars[$j];
329 | }
330 | }
331 |
--------------------------------------------------------------------------------
/src/Types/TypeCode39Checksum.php:
--------------------------------------------------------------------------------
1 | '131112', // 0
20 | 49 => '111213', // 1
21 | 50 => '111312', // 2
22 | 51 => '111411', // 3
23 | 52 => '121113', // 4
24 | 53 => '121212', // 5
25 | 54 => '121311', // 6
26 | 55 => '111114', // 7
27 | 56 => '131211', // 8
28 | 57 => '141111', // 9
29 | 65 => '211113', // A
30 | 66 => '211212', // B
31 | 67 => '211311', // C
32 | 68 => '221112', // D
33 | 69 => '221211', // E
34 | 70 => '231111', // F
35 | 71 => '112113', // G
36 | 72 => '112212', // H
37 | 73 => '112311', // I
38 | 74 => '122112', // J
39 | 75 => '132111', // K
40 | 76 => '111123', // L
41 | 77 => '111222', // M
42 | 78 => '111321', // N
43 | 79 => '121122', // O
44 | 80 => '131121', // P
45 | 81 => '212112', // Q
46 | 82 => '212211', // R
47 | 83 => '211122', // S
48 | 84 => '211221', // T
49 | 85 => '221121', // U
50 | 86 => '222111', // V
51 | 87 => '112122', // W
52 | 88 => '112221', // X
53 | 89 => '122121', // Y
54 | 90 => '123111', // Z
55 | 45 => '121131', // -
56 | 46 => '311112', // .
57 | 32 => '311211', //
58 | 36 => '321111', // $
59 | 47 => '112131', // /
60 | 43 => '113121', // +
61 | 37 => '211131', // %
62 | 97 => '121221', // ($)
63 | 98 => '312111', // (%)
64 | 99 => '311121', // (/)
65 | 100 => '122211', // (+)
66 | 42 => '111141', // start-stop
67 | ];
68 |
69 | /**
70 | * @throws InvalidCharacterException
71 | */
72 | public function getBarcodeData(string $code): Barcode
73 | {
74 | $encode = [
75 | chr(0) => 'bU',
76 | chr(1) => 'aA',
77 | chr(2) => 'aB',
78 | chr(3) => 'aC',
79 | chr(4) => 'aD',
80 | chr(5) => 'aE',
81 | chr(6) => 'aF',
82 | chr(7) => 'aG',
83 | chr(8) => 'aH',
84 | chr(9) => 'aI',
85 | chr(10) => 'aJ',
86 | chr(11) => 'aK',
87 | chr(12) => 'aL',
88 | chr(13) => 'aM',
89 | chr(14) => 'aN',
90 | chr(15) => 'aO',
91 | chr(16) => 'aP',
92 | chr(17) => 'aQ',
93 | chr(18) => 'aR',
94 | chr(19) => 'aS',
95 | chr(20) => 'aT',
96 | chr(21) => 'aU',
97 | chr(22) => 'aV',
98 | chr(23) => 'aW',
99 | chr(24) => 'aX',
100 | chr(25) => 'aY',
101 | chr(26) => 'aZ',
102 | chr(27) => 'bA',
103 | chr(28) => 'bB',
104 | chr(29) => 'bC',
105 | chr(30) => 'bD',
106 | chr(31) => 'bE',
107 | chr(32) => ' ',
108 | chr(33) => 'cA',
109 | chr(34) => 'cB',
110 | chr(35) => 'cC',
111 | chr(36) => '$',
112 | chr(37) => '%',
113 | chr(38) => 'cF',
114 | chr(39) => 'cG',
115 | chr(40) => 'cH',
116 | chr(41) => 'cI',
117 | chr(42) => 'cJ',
118 | chr(43) => '+',
119 | chr(44) => 'cL',
120 | chr(45) => '-',
121 | chr(46) => '.',
122 | chr(47) => '/',
123 | chr(48) => '0',
124 | chr(49) => '1',
125 | chr(50) => '2',
126 | chr(51) => '3',
127 | chr(52) => '4',
128 | chr(53) => '5',
129 | chr(54) => '6',
130 | chr(55) => '7',
131 | chr(56) => '8',
132 | chr(57) => '9',
133 | chr(58) => 'cZ',
134 | chr(59) => 'bF',
135 | chr(60) => 'bG',
136 | chr(61) => 'bH',
137 | chr(62) => 'bI',
138 | chr(63) => 'bJ',
139 | chr(64) => 'bV',
140 | chr(65) => 'A',
141 | chr(66) => 'B',
142 | chr(67) => 'C',
143 | chr(68) => 'D',
144 | chr(69) => 'E',
145 | chr(70) => 'F',
146 | chr(71) => 'G',
147 | chr(72) => 'H',
148 | chr(73) => 'I',
149 | chr(74) => 'J',
150 | chr(75) => 'K',
151 | chr(76) => 'L',
152 | chr(77) => 'M',
153 | chr(78) => 'N',
154 | chr(79) => 'O',
155 | chr(80) => 'P',
156 | chr(81) => 'Q',
157 | chr(82) => 'R',
158 | chr(83) => 'S',
159 | chr(84) => 'T',
160 | chr(85) => 'U',
161 | chr(86) => 'V',
162 | chr(87) => 'W',
163 | chr(88) => 'X',
164 | chr(89) => 'Y',
165 | chr(90) => 'Z',
166 | chr(91) => 'bK',
167 | chr(92) => 'bL',
168 | chr(93) => 'bM',
169 | chr(94) => 'bN',
170 | chr(95) => 'bO',
171 | chr(96) => 'bW',
172 | chr(97) => 'dA',
173 | chr(98) => 'dB',
174 | chr(99) => 'dC',
175 | chr(100) => 'dD',
176 | chr(101) => 'dE',
177 | chr(102) => 'dF',
178 | chr(103) => 'dG',
179 | chr(104) => 'dH',
180 | chr(105) => 'dI',
181 | chr(106) => 'dJ',
182 | chr(107) => 'dK',
183 | chr(108) => 'dL',
184 | chr(109) => 'dM',
185 | chr(110) => 'dN',
186 | chr(111) => 'dO',
187 | chr(112) => 'dP',
188 | chr(113) => 'dQ',
189 | chr(114) => 'dR',
190 | chr(115) => 'dS',
191 | chr(116) => 'dT',
192 | chr(117) => 'dU',
193 | chr(118) => 'dV',
194 | chr(119) => 'dW',
195 | chr(120) => 'dX',
196 | chr(121) => 'dY',
197 | chr(122) => 'dZ',
198 | chr(123) => 'bP',
199 | chr(124) => 'bQ',
200 | chr(125) => 'bR',
201 | chr(126) => 'bS',
202 | chr(127) => 'bT',
203 | ];
204 |
205 | $code_ext = '';
206 | $clen = strlen($code);
207 | for ($i = 0; $i < $clen; $i++) {
208 | if (ord($code[$i]) > 127) {
209 | throw new InvalidCharacterException('Only supports till char 127');
210 | }
211 | $code_ext .= $encode[$code[$i]];
212 | }
213 |
214 | // checksum
215 | $code_ext .= $this->checksum_code93($code_ext);
216 |
217 | // add start and stop codes
218 | $code = '*'.$code_ext.'*';
219 |
220 | $barcode = new Barcode($code);
221 |
222 | for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
223 | $char = ord($code[$i]);
224 | if (! isset($this->conversionTable[$char])) {
225 | throw new InvalidCharacterException('Char '.$char.' is unsupported');
226 | }
227 |
228 | for ($j = 0; $j < 6; $j++) {
229 | if (($j % 2) === 0) {
230 | $drawBar = true;
231 | } else {
232 | $drawBar = false;
233 | }
234 | $barWidth = $this->conversionTable[$char][$j];
235 |
236 | $barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
237 | }
238 | }
239 |
240 | $barcode->addBar(new BarcodeBar(1, 1, true));
241 |
242 | return $barcode;
243 | }
244 |
245 | /**
246 | * Calculate CODE 93 checksum (modulo 47).
247 | *
248 | * @param $code (string) code to represent.
249 | */
250 | protected function checksum_code93(string $code): string
251 | {
252 | $chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', 'a', 'b', 'c', 'd'];
253 |
254 | // calculate check digit C
255 | $len = strlen($code);
256 | $p = 1;
257 | $check = 0;
258 | for ($i = ($len - 1); $i >= 0; $i--) {
259 | $k = array_keys($chars, $code[$i]);
260 | $check += ($k[0] * $p);
261 | $p++;
262 | if ($p > 20) {
263 | $p = 1;
264 | }
265 | }
266 | $check %= 47;
267 | $c = $chars[$check];
268 | $code .= $c;
269 |
270 | // calculate check digit K
271 | $p = 1;
272 | $check = 0;
273 | for ($i = $len; $i >= 0; $i--) {
274 | $k = array_keys($chars, $code[$i]);
275 | $check += ($k[0] * $p);
276 | $p++;
277 | if ($p > 15) {
278 | $p = 1;
279 | }
280 | }
281 | $check %= 47;
282 | $k = $chars[$check];
283 |
284 | return $c.$k;
285 | }
286 | }
287 |
--------------------------------------------------------------------------------
/src/Types/TypeEan13.php:
--------------------------------------------------------------------------------
1 | length;
41 |
42 | $dataLength = $length - 1;
43 |
44 | // Add zero padding in front
45 | $code = str_pad($code, $dataLength, '0', STR_PAD_LEFT);
46 |
47 | $checksumDigit = $this->calculateChecksumDigit($code);
48 |
49 | if (strlen($code) === $dataLength) {
50 | $code .= $checksumDigit;
51 | } elseif ($checksumDigit !== (int) $code[$dataLength]) {
52 | // If length of given barcode is same as final length, barcode is including checksum
53 | // Make sure that checksum is the same as we calculated
54 | throw new InvalidCheckDigitException;
55 | }
56 |
57 | if ($this->upca || $this->upce) {
58 | $code = '0'.$code;
59 | $length++;
60 | }
61 |
62 | if ($this->upce) {
63 | // convert UPC-A to UPC-E
64 | $tmp = substr($code, 4, 3);
65 | if (($tmp === '000') || ($tmp === '100') || ($tmp === '200')) {
66 | // manufacturer code ends in 000, 100, or 200
67 | $upce_code = substr($code, 2, 2).substr($code, 9, 3).$code[4];
68 | } else {
69 | $tmp = substr($code, 5, 2);
70 | if ($tmp === '00') {
71 | // manufacturer code ends in 00
72 | $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
73 | } else {
74 | $tmp = $code[6];
75 | if ($tmp === '0') {
76 | // manufacturer code ends in 0
77 | $upce_code = substr($code, 2, 4).$code[11].'4';
78 | } else {
79 | // manufacturer code does not end in zero
80 | $upce_code = substr($code, 2, 5).$code[11];
81 | }
82 | }
83 | }
84 | }
85 |
86 | // Convert digits to bars
87 | $codes = [
88 | 'A' => [ // left odd parity
89 | '0' => '0001101',
90 | '1' => '0011001',
91 | '2' => '0010011',
92 | '3' => '0111101',
93 | '4' => '0100011',
94 | '5' => '0110001',
95 | '6' => '0101111',
96 | '7' => '0111011',
97 | '8' => '0110111',
98 | '9' => '0001011',
99 | ],
100 | 'B' => [ // left even parity
101 | '0' => '0100111',
102 | '1' => '0110011',
103 | '2' => '0011011',
104 | '3' => '0100001',
105 | '4' => '0011101',
106 | '5' => '0111001',
107 | '6' => '0000101',
108 | '7' => '0010001',
109 | '8' => '0001001',
110 | '9' => '0010111',
111 | ],
112 | 'C' => [ // right
113 | '0' => '1110010',
114 | '1' => '1100110',
115 | '2' => '1101100',
116 | '3' => '1000010',
117 | '4' => '1011100',
118 | '5' => '1001110',
119 | '6' => '1010000',
120 | '7' => '1000100',
121 | '8' => '1001000',
122 | '9' => '1110100',
123 | ],
124 | ];
125 |
126 | $parities = [
127 | '0' => ['A', 'A', 'A', 'A', 'A', 'A'],
128 | '1' => ['A', 'A', 'B', 'A', 'B', 'B'],
129 | '2' => ['A', 'A', 'B', 'B', 'A', 'B'],
130 | '3' => ['A', 'A', 'B', 'B', 'B', 'A'],
131 | '4' => ['A', 'B', 'A', 'A', 'B', 'B'],
132 | '5' => ['A', 'B', 'B', 'A', 'A', 'B'],
133 | '6' => ['A', 'B', 'B', 'B', 'A', 'A'],
134 | '7' => ['A', 'B', 'A', 'B', 'A', 'B'],
135 | '8' => ['A', 'B', 'A', 'B', 'B', 'A'],
136 | '9' => ['A', 'B', 'B', 'A', 'B', 'A'],
137 | ];
138 |
139 | $upce_parities = [
140 | [
141 | '0' => ['B', 'B', 'B', 'A', 'A', 'A'],
142 | '1' => ['B', 'B', 'A', 'B', 'A', 'A'],
143 | '2' => ['B', 'B', 'A', 'A', 'B', 'A'],
144 | '3' => ['B', 'B', 'A', 'A', 'A', 'B'],
145 | '4' => ['B', 'A', 'B', 'B', 'A', 'A'],
146 | '5' => ['B', 'A', 'A', 'B', 'B', 'A'],
147 | '6' => ['B', 'A', 'A', 'A', 'B', 'B'],
148 | '7' => ['B', 'A', 'B', 'A', 'B', 'A'],
149 | '8' => ['B', 'A', 'B', 'A', 'A', 'B'],
150 | '9' => ['B', 'A', 'A', 'B', 'A', 'B'],
151 | ],
152 | [
153 | '0' => ['A', 'A', 'A', 'B', 'B', 'B'],
154 | '1' => ['A', 'A', 'B', 'A', 'B', 'B'],
155 | '2' => ['A', 'A', 'B', 'B', 'A', 'B'],
156 | '3' => ['A', 'A', 'B', 'B', 'B', 'A'],
157 | '4' => ['A', 'B', 'A', 'A', 'B', 'B'],
158 | '5' => ['A', 'B', 'B', 'A', 'A', 'B'],
159 | '6' => ['A', 'B', 'B', 'B', 'A', 'A'],
160 | '7' => ['A', 'B', 'A', 'B', 'A', 'B'],
161 | '8' => ['A', 'B', 'A', 'B', 'B', 'A'],
162 | '9' => ['A', 'B', 'B', 'A', 'B', 'A'],
163 | ],
164 | ];
165 |
166 | $seq = '101'; // left guard bar
167 | if ($this->upce) {
168 | $barcode = new Barcode($upce_code);
169 | $p = $upce_parities[$code[1]][$checksumDigit];
170 | for ($i = 0; $i < 6; $i++) {
171 | $seq .= $codes[$p[$i]][$upce_code[$i]];
172 | }
173 | $seq .= '010101'; // right guard bar
174 | } else {
175 | $barcode = new Barcode($code);
176 | $half_len = (int) ceil($length / 2);
177 | if ($length === 8) {
178 | for ($i = 0; $i < $half_len; $i++) {
179 | $seq .= $codes['A'][$code[$i]];
180 | }
181 | } else {
182 | $p = $parities[$code[0]];
183 | for ($i = 1; $i < $half_len; $i++) {
184 | $seq .= $codes[$p[$i - 1]][$code[$i]];
185 | }
186 | }
187 | $seq .= '01010'; // center guard bar
188 | for ($i = $half_len; $i < $length; $i++) {
189 | if (! isset($codes['C'][$code[$i]])) {
190 | throw new InvalidCharacterException('Char '.$code[$i].' not allowed');
191 | }
192 | $seq .= $codes['C'][$code[$i]];
193 | }
194 | $seq .= '101'; // right guard bar
195 | }
196 |
197 | return BinarySequenceConverter::generate($seq, $barcode);
198 | }
199 |
200 | protected function calculateChecksumDigit(string $code): int
201 | {
202 | // calculate check digit
203 | $sum_a = 0;
204 | for ($i = 1; $i < $this->length - 1; $i += 2) {
205 | $sum_a += (int) $code[$i];
206 | }
207 | if ($this->length > 12) {
208 | $sum_a *= 3;
209 | }
210 | $sum_b = 0;
211 | for ($i = 0; $i < $this->length - 1; $i += 2) {
212 | $sum_b += (int) $code[$i];
213 | }
214 | if ($this->length < 13) {
215 | $sum_b *= 3;
216 | }
217 | $checksumDigit = ($sum_a + $sum_b) % 10;
218 | if ($checksumDigit > 0) {
219 | $checksumDigit = (10 - $checksumDigit);
220 | }
221 |
222 | return $checksumDigit;
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/src/Types/TypeIntelligentMailBarcode.php:
--------------------------------------------------------------------------------
1 | The Barcode Identifier shall be assigned by USPS to encode the
14 | * presort identification that is currently printed in human-readable form on the optional endorsement line (OEL)
15 | * as well as for future USPS use. This shall be two digits, with the second digit in the range of 0–4. The
16 | * allowable encoding ranges shall be 00–04, 10–14, 20–24, 30–34, 40–44, 50–54, 60–64, 70–74, 80–84, and
17 | * 90–94. The Service Type Identifier shall be assigned by USPS for any combination of services requested
18 | * on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php–999.
19 | * Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each
20 | * service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier
21 | * values. The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digits number
22 | * that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000-
23 | * 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999. The
24 | * Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The
25 | * allowable encoding range shall be 000000000–999999999 when used with a 6 digit Mailer ID and 000000-999999 when
26 | * used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the
27 | * mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be
28 | * 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000–99999, 000000000–999999999,
29 | * and 00000000000–99999999999.
30 | *
31 | * code to print, separate the ZIP (routing code) from the rest using a minus char '-'
32 | * (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
33 | */
34 |
35 | class TypeIntelligentMailBarcode implements TypeInterface
36 | {
37 | /**
38 | * @throws BarcodeException
39 | */
40 | public function getBarcodeData(string $code): Barcode
41 | {
42 | $asc_chr = [
43 | 4,
44 | 0,
45 | 2,
46 | 6,
47 | 3,
48 | 5,
49 | 1,
50 | 9,
51 | 8,
52 | 7,
53 | 1,
54 | 2,
55 | 0,
56 | 6,
57 | 4,
58 | 8,
59 | 2,
60 | 9,
61 | 5,
62 | 3,
63 | 0,
64 | 1,
65 | 3,
66 | 7,
67 | 4,
68 | 6,
69 | 8,
70 | 9,
71 | 2,
72 | 0,
73 | 5,
74 | 1,
75 | 9,
76 | 4,
77 | 3,
78 | 8,
79 | 6,
80 | 7,
81 | 1,
82 | 2,
83 | 4,
84 | 3,
85 | 9,
86 | 5,
87 | 7,
88 | 8,
89 | 3,
90 | 0,
91 | 2,
92 | 1,
93 | 4,
94 | 0,
95 | 9,
96 | 1,
97 | 7,
98 | 0,
99 | 2,
100 | 4,
101 | 6,
102 | 3,
103 | 7,
104 | 1,
105 | 9,
106 | 5,
107 | 8,
108 | ];
109 | $dsc_chr = [
110 | 7,
111 | 1,
112 | 9,
113 | 5,
114 | 8,
115 | 0,
116 | 2,
117 | 4,
118 | 6,
119 | 3,
120 | 5,
121 | 8,
122 | 9,
123 | 7,
124 | 3,
125 | 0,
126 | 6,
127 | 1,
128 | 7,
129 | 4,
130 | 6,
131 | 8,
132 | 9,
133 | 2,
134 | 5,
135 | 1,
136 | 7,
137 | 5,
138 | 4,
139 | 3,
140 | 8,
141 | 7,
142 | 6,
143 | 0,
144 | 2,
145 | 5,
146 | 4,
147 | 9,
148 | 3,
149 | 0,
150 | 1,
151 | 6,
152 | 8,
153 | 2,
154 | 0,
155 | 4,
156 | 5,
157 | 9,
158 | 6,
159 | 7,
160 | 5,
161 | 2,
162 | 6,
163 | 3,
164 | 8,
165 | 5,
166 | 1,
167 | 9,
168 | 8,
169 | 7,
170 | 4,
171 | 0,
172 | 2,
173 | 6,
174 | 3,
175 | ];
176 | $asc_pos = [
177 | 3,
178 | 0,
179 | 8,
180 | 11,
181 | 1,
182 | 12,
183 | 8,
184 | 11,
185 | 10,
186 | 6,
187 | 4,
188 | 12,
189 | 2,
190 | 7,
191 | 9,
192 | 6,
193 | 7,
194 | 9,
195 | 2,
196 | 8,
197 | 4,
198 | 0,
199 | 12,
200 | 7,
201 | 10,
202 | 9,
203 | 0,
204 | 7,
205 | 10,
206 | 5,
207 | 7,
208 | 9,
209 | 6,
210 | 8,
211 | 2,
212 | 12,
213 | 1,
214 | 4,
215 | 2,
216 | 0,
217 | 1,
218 | 5,
219 | 4,
220 | 6,
221 | 12,
222 | 1,
223 | 0,
224 | 9,
225 | 4,
226 | 7,
227 | 5,
228 | 10,
229 | 2,
230 | 6,
231 | 9,
232 | 11,
233 | 2,
234 | 12,
235 | 6,
236 | 7,
237 | 5,
238 | 11,
239 | 0,
240 | 3,
241 | 2,
242 | ];
243 | $dsc_pos = [
244 | 2,
245 | 10,
246 | 12,
247 | 5,
248 | 9,
249 | 1,
250 | 5,
251 | 4,
252 | 3,
253 | 9,
254 | 11,
255 | 5,
256 | 10,
257 | 1,
258 | 6,
259 | 3,
260 | 4,
261 | 1,
262 | 10,
263 | 0,
264 | 2,
265 | 11,
266 | 8,
267 | 6,
268 | 1,
269 | 12,
270 | 3,
271 | 8,
272 | 6,
273 | 4,
274 | 4,
275 | 11,
276 | 0,
277 | 6,
278 | 1,
279 | 9,
280 | 11,
281 | 5,
282 | 3,
283 | 7,
284 | 3,
285 | 10,
286 | 7,
287 | 11,
288 | 8,
289 | 2,
290 | 10,
291 | 3,
292 | 5,
293 | 8,
294 | 0,
295 | 3,
296 | 12,
297 | 11,
298 | 8,
299 | 4,
300 | 5,
301 | 1,
302 | 3,
303 | 0,
304 | 7,
305 | 12,
306 | 9,
307 | 8,
308 | 10,
309 | ];
310 | $code_arr = explode('-', $code);
311 | $tracking_number = $code_arr[0];
312 | $routing_code = $code_arr[1] ?? '';
313 | // Conversion of Routing Code
314 | $binary_code = match (strlen($routing_code)) {
315 | 0 => 0,
316 | 5 => bcadd($routing_code, '1'),
317 | 9 => bcadd($routing_code, '100001'),
318 | 11 => bcadd($routing_code, '1000100001'),
319 | default => throw new BarcodeException('Routing code unknown'),
320 | };
321 |
322 | $binary_code = bcmul($binary_code, 10);
323 | $binary_code = bcadd($binary_code, $tracking_number[0]);
324 | $binary_code = bcmul($binary_code, 5);
325 | $binary_code = bcadd($binary_code, $tracking_number[1]);
326 | $binary_code .= substr($tracking_number, 2, 18);
327 |
328 | // convert to hexadecimal
329 | $binary_code = $this->dec_to_hex($binary_code);
330 |
331 | // pad to get 13 bytes
332 | $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
333 |
334 | // convert string to array of bytes
335 | $binary_code_arr = chunk_split($binary_code, 2, "\r");
336 | $binary_code_arr = substr($binary_code_arr, 0, -1);
337 | $binary_code_arr = explode("\r", $binary_code_arr);
338 |
339 | // calculate frame check sequence
340 | $fcs = $this->imb_crc11fcs($binary_code_arr);
341 |
342 | // exclude first 2 bits from first byte
343 | $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
344 | $binary_code_102bit = $first_byte.substr($binary_code, 2);
345 |
346 | // convert binary data to codewords
347 | $codewords = [];
348 | $data = $this->hex_to_dec($binary_code_102bit);
349 | $codewords[0] = bcmod($data, 636) * 2;
350 | $data = bcdiv($data, 636);
351 | for ($i = 1; $i < 9; $i++) {
352 | $codewords[$i] = bcmod($data, 1365);
353 | $data = bcdiv($data, 1365);
354 | }
355 | $codewords[9] = $data;
356 | if (($fcs >> 10) === 1) {
357 | $codewords[9] += 659;
358 | }
359 |
360 | // generate lookup tables
361 | $table2of13 = $this->imb_tables(2, 78);
362 | $table5of13 = $this->imb_tables(5, 1287);
363 |
364 | // convert codewords to characters
365 | $characters = [];
366 | $bitmask = 512;
367 | foreach ($codewords as $val) {
368 | if ($val <= 1286) {
369 | $chrcode = $table5of13[$val];
370 | } else {
371 | $chrcode = $table2of13[($val - 1287)];
372 | }
373 | if (($fcs & $bitmask) > 0) {
374 | // bitwise invert
375 | $chrcode = ((~$chrcode) & 8191);
376 | }
377 | $characters[] = $chrcode;
378 | $bitmask /= 2;
379 | }
380 | $characters = array_reverse($characters);
381 |
382 | // build bars
383 | $barcode = new Barcode($code);
384 | for ($i = 0; $i < 65; $i++) {
385 | $asc = (($characters[$asc_chr[$i]] & (2 ** $asc_pos[$i])) > 0);
386 | $dsc = (($characters[$dsc_chr[$i]] & (2 ** $dsc_pos[$i])) > 0);
387 | if ($asc && $dsc) {
388 | // full bar (F)
389 | $p = 0;
390 | $h = 3;
391 | } elseif ($asc) {
392 | // ascender (A)
393 | $p = 0;
394 | $h = 2;
395 | } elseif ($dsc) {
396 | // descender (D)
397 | $p = 1;
398 | $h = 2;
399 | } else {
400 | // tracker (T)
401 | $p = 1;
402 | $h = 1;
403 | }
404 | $barcode->addBar(new BarcodeBar(1, $h, true, $p));
405 | if ($i < 64) {
406 | $barcode->addBar(new BarcodeBar(1, 2, false, 0));
407 | }
408 | }
409 |
410 | return $barcode;
411 | }
412 |
413 | /**
414 | * Convert large integer number to hexadecimal representation.
415 | * (requires PHP bcmath extension)
416 | *
417 | * @param $number (string) number to convert specified as a string
418 | */
419 | protected function dec_to_hex(string $number): string
420 | {
421 | if ($number === '0') {
422 | return '00';
423 | }
424 |
425 | $hex = [];
426 |
427 | while ($number > 0) {
428 | $hex[] = strtoupper(dechex(bcmod($number, '16')));
429 | $number = bcdiv($number, '16');
430 | }
431 | $hex = array_reverse($hex);
432 |
433 | return implode($hex);
434 | }
435 |
436 | /**
437 | * Intelligent Mail Barcode calculation of Frame Check Sequence
438 | *
439 | * @param $code_arr array of hexadecimal values (13 bytes holding 102 bits right justified).
440 | * @return int 11 bit Frame Check Sequence as integer (decimal base)
441 | */
442 | protected function imb_crc11fcs(array $code_arr): int
443 | {
444 | $genpoly = 0x0F35; // generator polynomial
445 | $fcs = 0x07FF; // Frame Check Sequence
446 | // do most significant byte skipping the 2 most significant bits
447 | $data = hexdec($code_arr[0]) << 5;
448 | for ($bit = 2; $bit < 8; $bit++) {
449 | if (($fcs ^ $data) & 0x400) {
450 | $fcs = ($fcs << 1) ^ $genpoly;
451 | } else {
452 | $fcs <<= 1;
453 | }
454 | $fcs &= 0x7FF;
455 | $data <<= 1;
456 | }
457 | // do rest of bytes
458 | for ($byte = 1; $byte < 13; $byte++) {
459 | $data = hexdec($code_arr[$byte]) << 3;
460 | for ($bit = 0; $bit < 8; $bit++) {
461 | if (($fcs ^ $data) & 0x400) {
462 | $fcs = ($fcs << 1) ^ $genpoly;
463 | } else {
464 | $fcs <<= 1;
465 | }
466 | $fcs &= 0x7FF;
467 | $data <<= 1;
468 | }
469 | }
470 |
471 | return $fcs;
472 | }
473 |
474 | /**
475 | * Convert large hexadecimal number to decimal representation (string).
476 | * (requires PHP bcmath extension)
477 | *
478 | * @param $hex (string) hexadecimal number to convert specified as a string
479 | * @return int|string hexadecimal representation
480 | */
481 | protected function hex_to_dec(string $hex): int|string
482 | {
483 | $dec = 0;
484 | $bitval = 1;
485 | $len = strlen($hex);
486 | for ($pos = ($len - 1); $pos >= 0; $pos--) {
487 | $dec = bcadd($dec, bcmul(hexdec($hex[$pos]), $bitval));
488 | $bitval = bcmul($bitval, 16);
489 | }
490 |
491 | return $dec;
492 | }
493 |
494 | /**
495 | * generate Nof13 tables used for Intelligent Mail Barcode
496 | *
497 | * @param $n (int) is the type of table: 2 for 2of13 table, 5 for 5of13table
498 | * @param $size (int) size of table (78 for n=2 and 1287 for n=5)
499 | */
500 | protected function imb_tables(int $n, int $size): array
501 | {
502 | $table = [];
503 | $lli = 0; // LUT lower index
504 | $lui = $size - 1; // LUT upper index
505 | for ($count = 0; $count < 8192; $count++) {
506 | $bit_count = 0;
507 | for ($bit_index = 0; $bit_index < 13; $bit_index++) {
508 | $bit_count += (int) (($count & (1 << $bit_index)) !== 0);
509 | }
510 | // if we don't have the right number of bits on, go on to the next value
511 | if ($bit_count === $n) {
512 | $reverse = ($this->imb_reverse_us($count) >> 3);
513 | // if the reverse is less than count, we have already visited this pair before
514 | if ($reverse >= $count) {
515 | // If count is symmetric, place it at the first free slot from the end of the list.
516 | // Otherwise, place it at the first free slot from the beginning of the list && place $reverse ath the next free slot from the beginning of the list
517 | if ($reverse === $count) {
518 | $table[$lui] = $count;
519 | $lui--;
520 | } else {
521 | $table[$lli] = $count;
522 | $lli++;
523 | $table[$lli] = $reverse;
524 | $lli++;
525 | }
526 | }
527 | }
528 | }
529 |
530 | return $table;
531 | }
532 |
533 | /**
534 | * Reverse unsigned short value
535 | *
536 | * @param $num (int) value to reverse
537 | */
538 | protected function imb_reverse_us(int $num): int
539 | {
540 | $rev = 0;
541 | for ($i = 0; $i < 16; $i++) {
542 | $rev <<= 1;
543 | $rev |= ($num & 1);
544 | $num >>= 1;
545 | }
546 |
547 | return $rev;
548 | }
549 | }
550 |
--------------------------------------------------------------------------------
/src/Types/TypeInterface.php:
--------------------------------------------------------------------------------
1 | getChecksum($code);
38 |
39 | if ((strlen($code) % 2) != 0) {
40 | // add leading zero if code-length is odd
41 | $code = '0'.$code;
42 | }
43 | // add start and stop codes
44 | $code = 'AA'.strtolower($code).'ZA';
45 |
46 | $barcode = new Barcode($code);
47 | for ($i = 0, $iMax = strlen($code); $i < $iMax; $i = ($i + 2)) {
48 | $char_bar = $code[$i];
49 | $char_space = $code[$i + 1];
50 | if (! isset($chr[$char_bar], $chr[$char_space])) {
51 | throw new InvalidCharacterException;
52 | }
53 |
54 | // create a bar-space sequence
55 | $seq = '';
56 | $chrlen = strlen($chr[$char_bar]);
57 | for ($s = 0; $s < $chrlen; $s++) {
58 | $seq .= $chr[$char_bar][$s].$chr[$char_space][$s];
59 | }
60 |
61 | for ($j = 0, $jMax = strlen($seq); $j < $jMax; $j++) {
62 | if (($j % 2) === 0) {
63 | $t = true; // bar
64 | } else {
65 | $t = false; // space
66 | }
67 | $w = $seq[$j];
68 | $barcode->addBar(new BarcodeBar($w, 1, $t));
69 | }
70 | }
71 |
72 | return $barcode;
73 | }
74 |
75 | protected function getChecksum(string $code): string
76 | {
77 | return (string) BarcodeHelper::getChecksum($code);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Types/TypeKix.php:
--------------------------------------------------------------------------------
1 | checksum) {
44 | // add checksum
45 | $clen = strlen($code);
46 | $p = 2;
47 | $check = 0;
48 | for ($i = ($clen - 1); $i >= 0; $i--) {
49 | $check += (hexdec($code[$i]) * $p);
50 | $p++;
51 | if ($p > 7) {
52 | $p = 2;
53 | }
54 | }
55 | $check %= 11;
56 | if ($check > 0) {
57 | $check = 11 - $check;
58 | }
59 | $code .= $check;
60 | }
61 | $seq = '110'; // left guard
62 | $clen = strlen($code);
63 | for ($i = 0; $i < $clen; $i++) {
64 | $digit = $code[$i];
65 | if (! isset($chr[$digit])) {
66 | throw new InvalidCharacterException('Char '.$digit.' is unsupported');
67 | }
68 | $seq .= $chr[$digit];
69 | }
70 | $seq .= '1001'; // right guard
71 |
72 | return BinarySequenceConverter::convert($code, $seq);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Types/TypePharmacode.php:
--------------------------------------------------------------------------------
1 | 0) {
21 | if (($code % 2) === 0) {
22 | $seq .= '11100';
23 | $code -= 2;
24 | } else {
25 | $seq .= '100';
26 | $code--;
27 | }
28 | $code /= 2;
29 | }
30 |
31 | $seq = substr($seq, 0, -2);
32 | $seq = strrev($seq);
33 |
34 | return BinarySequenceConverter::convert($code, $seq);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Types/TypePharmacodeTwoCode.php:
--------------------------------------------------------------------------------
1 | addBar(new BarcodeBar(1, $h, 1, $p));
71 | if ($i < (strlen($seq) - 1)) {
72 | $barcode->addBar(new BarcodeBar(1, 2, 0, 0));
73 | }
74 | }
75 |
76 | return $barcode;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Types/TypePlanet.php:
--------------------------------------------------------------------------------
1 | [1, 1, 2, 2, 2],
18 | 1 => [2, 2, 2, 1, 1],
19 | 2 => [2, 2, 1, 2, 1],
20 | 3 => [2, 2, 1, 1, 2],
21 | 4 => [2, 1, 2, 2, 1],
22 | 5 => [2, 1, 2, 1, 2],
23 | 6 => [2, 1, 1, 2, 2],
24 | 7 => [1, 2, 2, 2, 1],
25 | 8 => [1, 2, 2, 1, 2],
26 | 9 => [1, 2, 1, 2, 2],
27 | ];
28 | }
29 |
--------------------------------------------------------------------------------
/src/Types/TypePostnet.php:
--------------------------------------------------------------------------------
1 | [2, 2, 1, 1, 1],
21 | 1 => [1, 1, 1, 2, 2],
22 | 2 => [1, 1, 2, 1, 2],
23 | 3 => [1, 1, 2, 2, 1],
24 | 4 => [1, 2, 1, 1, 2],
25 | 5 => [1, 2, 1, 2, 1],
26 | 6 => [1, 2, 2, 1, 1],
27 | 7 => [2, 1, 1, 1, 2],
28 | 8 => [2, 1, 1, 2, 1],
29 | 9 => [2, 1, 2, 1, 1],
30 | ];
31 |
32 | public function getBarcodeData(string $code): Barcode
33 | {
34 | $code = str_replace(['-', ' '], '', $code);
35 | $len = strlen($code);
36 |
37 | $barcode = new Barcode($code);
38 |
39 | // calculate checksum
40 | $sum = 0;
41 | for ($i = 0; $i < $len; $i++) {
42 | $sum += (int) $code[$i];
43 | }
44 | $chkd = ($sum % 10);
45 | if ($chkd > 0) {
46 | $chkd = (10 - $chkd);
47 | }
48 | $code .= $chkd;
49 | $len = strlen($code);
50 |
51 | // start bar
52 | $barcode->addBar(new BarcodeBar(1, 2, 1));
53 | $barcode->addBar(new BarcodeBar(1, 2, 0));
54 |
55 | for ($i = 0; $i < $len; $i++) {
56 | for ($j = 0; $j < 5; $j++) {
57 | $h = $this->barlen[$code[$i]][$j];
58 | $p = floor(1 / $h);
59 | $barcode->addBar(new BarcodeBar(1, $h, 1, $p));
60 | $barcode->addBar(new BarcodeBar(1, 2, 0));
61 | }
62 | }
63 |
64 | // end bar
65 | $barcode->addBar(new BarcodeBar(1, 2, 1));
66 |
67 | return $barcode;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Types/TypeRms4cc.php:
--------------------------------------------------------------------------------
1 | [3, 3, 2, 2],
29 | '1' => [3, 4, 1, 2],
30 | '2' => [3, 4, 2, 1],
31 | '3' => [4, 3, 1, 2],
32 | '4' => [4, 3, 2, 1],
33 | '5' => [4, 4, 1, 1],
34 | '6' => [3, 1, 4, 2],
35 | '7' => [3, 2, 3, 2],
36 | '8' => [3, 2, 4, 1],
37 | '9' => [4, 1, 3, 2],
38 | 'A' => [4, 1, 4, 1],
39 | 'B' => [4, 2, 3, 1],
40 | 'C' => [3, 1, 2, 4],
41 | 'D' => [3, 2, 1, 4],
42 | 'E' => [3, 2, 2, 3],
43 | 'F' => [4, 1, 1, 4],
44 | 'G' => [4, 1, 2, 3],
45 | 'H' => [4, 2, 1, 3],
46 | 'I' => [1, 3, 4, 2],
47 | 'J' => [1, 4, 3, 2],
48 | 'K' => [1, 4, 4, 1],
49 | 'L' => [2, 3, 3, 2],
50 | 'M' => [2, 3, 4, 1],
51 | 'N' => [2, 4, 3, 1],
52 | 'O' => [1, 3, 2, 4],
53 | 'P' => [1, 4, 1, 4],
54 | 'Q' => [1, 4, 2, 3],
55 | 'R' => [2, 3, 1, 4],
56 | 'S' => [2, 3, 2, 3],
57 | 'T' => [2, 4, 1, 3],
58 | 'U' => [1, 1, 4, 4],
59 | 'V' => [1, 2, 3, 4],
60 | 'W' => [1, 2, 4, 3],
61 | 'X' => [2, 1, 3, 4],
62 | 'Y' => [2, 1, 4, 3],
63 | 'Z' => [2, 2, 3, 3],
64 | ];
65 |
66 | $code = strtoupper($code);
67 | $len = strlen($code);
68 |
69 | $barcode = new Barcode($code);
70 |
71 | if (! $this->kix) {
72 | // table for checksum calculation (row,col)
73 | $checktable = [
74 | '0' => [1, 1],
75 | '1' => [1, 2],
76 | '2' => [1, 3],
77 | '3' => [1, 4],
78 | '4' => [1, 5],
79 | '5' => [1, 0],
80 | '6' => [2, 1],
81 | '7' => [2, 2],
82 | '8' => [2, 3],
83 | '9' => [2, 4],
84 | 'A' => [2, 5],
85 | 'B' => [2, 0],
86 | 'C' => [3, 1],
87 | 'D' => [3, 2],
88 | 'E' => [3, 3],
89 | 'F' => [3, 4],
90 | 'G' => [3, 5],
91 | 'H' => [3, 0],
92 | 'I' => [4, 1],
93 | 'J' => [4, 2],
94 | 'K' => [4, 3],
95 | 'L' => [4, 4],
96 | 'M' => [4, 5],
97 | 'N' => [4, 0],
98 | 'O' => [5, 1],
99 | 'P' => [5, 2],
100 | 'Q' => [5, 3],
101 | 'R' => [5, 4],
102 | 'S' => [5, 5],
103 | 'T' => [5, 0],
104 | 'U' => [0, 1],
105 | 'V' => [0, 2],
106 | 'W' => [0, 3],
107 | 'X' => [0, 4],
108 | 'Y' => [0, 5],
109 | 'Z' => [0, 0],
110 | ];
111 |
112 | $row = 0;
113 | $col = 0;
114 | for ($i = 0; $i < $len; $i++) {
115 | $row += $checktable[$code[$i]][0];
116 | $col += $checktable[$code[$i]][1];
117 | }
118 | $row %= 6;
119 | $col %= 6;
120 | $chk = array_keys($checktable, [$row, $col]);
121 | $code .= $chk[0];
122 | $len++;
123 |
124 | // start bar
125 | $barcode->addBar(new BarcodeBar(1, 2, 1));
126 | $barcode->addBar(new BarcodeBar(1, 2, 0));
127 | }
128 |
129 | for ($i = 0; $i < $len; $i++) {
130 | for ($j = 0; $j < 4; $j++) {
131 | switch ($barmode[$code[$i]][$j]) {
132 | case 1:
133 | $p = 0;
134 | $h = 2;
135 | break;
136 |
137 | case 2:
138 | $p = 0;
139 | $h = 3;
140 | break;
141 |
142 | case 3:
143 | $p = 1;
144 | $h = 1;
145 | break;
146 |
147 | case 4:
148 | $p = 1;
149 | $h = 2;
150 | break;
151 | }
152 |
153 | $barcode->addBar(new BarcodeBar(1, $h, 1, $p));
154 | $barcode->addBar(new BarcodeBar(1, 2, 0));
155 | }
156 | }
157 |
158 | if (! $this->kix) {
159 | // stop bar
160 | $barcode->addBar(new BarcodeBar(1, 3, 1));
161 | }
162 |
163 | return $barcode;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/Types/TypeStandard2of5.php:
--------------------------------------------------------------------------------
1 | checksum) {
36 | // add checksum
37 | $code .= $this->checksum_s25($code);
38 | }
39 | $seq = '11011010';
40 |
41 | for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
42 | $digit = $code[$i];
43 | if (! isset($chr[$digit])) {
44 | throw new InvalidCharacterException('Char '.$digit.' is unsupported');
45 | }
46 | $seq .= $chr[$digit];
47 | }
48 | $seq .= '1101011';
49 |
50 | return BinarySequenceConverter::convert($code, $seq);
51 | }
52 |
53 | /**
54 | * Checksum for standard 2 of 5 barcodes.
55 | *
56 | * @param $code (string) code to process.
57 | * @return int checksum.
58 | */
59 | protected function checksum_s25(string $code): int
60 | {
61 | return BarcodeHelper::getChecksum($code);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Types/TypeStandard2of5Checksum.php:
--------------------------------------------------------------------------------
1 | length;
25 |
26 | // Padding
27 | $code = str_pad($code, $len, '0', STR_PAD_LEFT);
28 |
29 | // calculate check digit
30 | if ($len === 2) {
31 | $r = (int) $code % 4;
32 | } elseif ($len === 5) {
33 | $r = (3 * ((int) $code[0] + (int) $code[2] + (int) $code[4])) + (9 * ((int) $code[1] + (int) $code[3]));
34 | $r %= 10;
35 | } else {
36 | throw new InvalidCheckDigitException;
37 | }
38 |
39 | // Convert digits to bars
40 | $codes = [
41 | 'A' => [ // left odd parity
42 | '0' => '0001101',
43 | '1' => '0011001',
44 | '2' => '0010011',
45 | '3' => '0111101',
46 | '4' => '0100011',
47 | '5' => '0110001',
48 | '6' => '0101111',
49 | '7' => '0111011',
50 | '8' => '0110111',
51 | '9' => '0001011',
52 | ],
53 | 'B' => [ // left even parity
54 | '0' => '0100111',
55 | '1' => '0110011',
56 | '2' => '0011011',
57 | '3' => '0100001',
58 | '4' => '0011101',
59 | '5' => '0111001',
60 | '6' => '0000101',
61 | '7' => '0010001',
62 | '8' => '0001001',
63 | '9' => '0010111',
64 | ],
65 | ];
66 |
67 | $parities = [
68 | 2 => [
69 | '0' => ['A', 'A'],
70 | '1' => ['A', 'B'],
71 | '2' => ['B', 'A'],
72 | '3' => ['B', 'B'],
73 | ],
74 | 5 => [
75 | '0' => ['B', 'B', 'A', 'A', 'A'],
76 | '1' => ['B', 'A', 'B', 'A', 'A'],
77 | '2' => ['B', 'A', 'A', 'B', 'A'],
78 | '3' => ['B', 'A', 'A', 'A', 'B'],
79 | '4' => ['A', 'B', 'B', 'A', 'A'],
80 | '5' => ['A', 'A', 'B', 'B', 'A'],
81 | '6' => ['A', 'A', 'A', 'B', 'B'],
82 | '7' => ['A', 'B', 'A', 'B', 'A'],
83 | '8' => ['A', 'B', 'A', 'A', 'B'],
84 | '9' => ['A', 'A', 'B', 'A', 'B'],
85 | ],
86 | ];
87 |
88 | $p = $parities[$len][$r];
89 | $seq = '1011'; // left guard bar
90 | $seq .= $codes[$p[0]][$code[0]];
91 | for ($i = 1; $i < $len; $i++) {
92 | $seq .= '01'; // separator
93 | $seq .= $codes[$p[$i]][$code[$i]];
94 | }
95 |
96 | return BinarySequenceConverter::convert($code, $seq);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Types/TypeUpcExtension5.php:
--------------------------------------------------------------------------------
1 |