Completed
Push — master ( 853db6...0f61ee )
by Roberto
11:06
created

DefaultPrinter::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 7
ccs 1
cts 1
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Posprint\Printers;
4
5
/*
6
 * Default class for POS thermal printers.
7
 * 
8
 * From this class all other are extended.
9
 * In the child classes should be included all the commands that are different
10
 * from those in this class, especially those specific to particular brand and 
11
 * model of printer
12
 * 
13
 * NOTE: It was built around the commands of the Epson TM-T20,
14
 * so in theory the Epson class will be almost empty just extending this class.
15
 * 
16
 * CodePage default WINDOWS-1250
17
 * CountyPage default LATIN
18
 * 
19
 * @category   NFePHP
20
 * @package    Posprint
21
 * @copyright  Copyright (c) 2016
22
 * @license    http://www.gnu.org/licenses/lesser.html LGPL v3
23
 * @author     Roberto L. Machado <linux.rlm at gmail dot com>
24
 * @link       http://github.com/nfephp-org/posprint for the canonical source repository
25
 */
26
27
use Posprint\Connectors\ConnectorInterface;
28
use Posprint\Connectors\Buffer;
29
use Posprint\Graphics\Graphics;
30
use RuntimeException;
31
use InvalidArgumentException;
32
33
abstract class DefaultPrinter implements PrinterInterface
34
{
35
    //set standards
36
    const NUL = "\x0"; //Nulo
37
    const EOT = "\x4"; //EOT fim da transmissão
38
    const ENQ = "\x5"; //ENQ colocar na fila Pedido de status 1
39
    const HT = "\x9"; //tabulação horizontal
40
    const VT = "\xb"; //tabulação vertical
41
    const LF = "\x0a"; //Inicia a impressão e avança uma linha
42
    const FF = "\x0c"; //avança pagina
43
    const CR = "\x0d"; //retorno de carro
44
    const DLE = "\x10"; //Data Link Escape
45
    const CAN = "\x18"; //CAN Cancela linha enviada
46
    const BEL = "\x07"; //BEL sinal sonoro
47
    const ESC = "\x1b"; //escape
48
    const FS = "\x1c"; //FS
49
    const GS = "\x1d"; //GS
50
    const SO = "\x0e"; //SO Inicia modo expandido
51
    const DC1 = "\x11"; //DC1 Inicia modo enfatizado
52
    const DC2 = "\x12"; //DC2 Cancela modo condensado
53
    const DC3 = "\x13"; //DC3 Cancela modo enfatizado
54
    const DC4 = "\x14"; //DC4 Controle de dispositivo 4 Inicia modo normal
55
    const SI = "\x0f"; //Seleciona modo condensado
56
    const EM = "\x19"; //Avança 4 linhas
57
    const DEL = "\x7f"; //Cancela último caracter
58
    const SYN = "\x16"; //Sincronismo
59
    const NOTRANS = false; //not translate characters codepage
60
    const TRANS = true; //perform a character convertion to codepage
61
62
    //Cut types 
63
    const CUT_FULL = 65;
64
    const CUT_PARTIAL = 66;
65
    
66
    //Image sizing options
67
    const IMG_DEFAULT = 0;
68
    const IMG_DOUBLE_WIDTH = 1;
69
    const IMG_DOUBLE_HEIGHT = 2;
70
71
    //1D barcode types
72
    const UPC_A = 'A';
73
    const UPC_E = 'B';
74
    const EAN13 = 'C';
75
    const EAN8 = 'D';
76
    const CODE39 = 'E';
77
    const ITF = 'F';
78
    const CODABAR = 'G';
79
    const CODE93 = 'H';
80
    const CODE128 = 'I';
81
    const GS1_128 = 'J';
82
    const GS1_DataBar_Omnidirectional = 'K';
83
    const GS1_DataBar_Truncated = 'L';
84
    const GS1_DataBar_Limited = 'M';
85
    const GS1_DataBar_Expanded = 'N';
86
87
    /**
88
     * List all available region pages.
89
     *
90
     * @var array
91
     */
92
    protected $aRegion = array(
93
        'USA',
94
        'FRANCE',
95
        'GERMANY',
96
        'UK',
97
        'DENMARK',
98
        'SWEDEN',
99
        'ITALY',
100
        'SPAIN',
101
        'JAPAN',
102
        'NORWAY',
103
        'DENMARK2',
104
        'SPAIN2',
105
        'LATIN',
106
        'KOREA',
107
        'SLOVENIA',
108
        'CHINA',
109
        'VIETNAM',
110
        'ARABIA',
111
    );
112
113
    /**
114
     * List all available code pages.
115
     *
116
     * @var array
117
     */
118
    protected $aCodePage = array(
119
        'CP437' => array('conv' => '437', 'table' => '0', 'desc' => 'PC437: USA, Standard Europe'),
120
        'CP850' => array('conv' => '850', 'table' => '2', 'desc' => 'PC850: Multilingual'),
121
        'CP860' => array('conv' => '860', 'table' => '3', 'desc' => 'PC860: Portuguese'),
122
        'CP863' => array('conv' => '863', 'table' => '4', 'desc' => 'PC863: Canadian-French'),
123
        'CP865' => array('conv' => '865', 'table' => '5', 'desc' => 'PC865: Nordic'),
124
        'CP851' => array('conv' => '851', 'table' => '11', 'desc' => 'PC851: Greek'),
125
        'CP853' => array('conv' => '853', 'table' => '12', 'desc' => 'PC853: Turkish'),
126
        'CP857' => array('conv' => '857', 'table' => '13', 'desc' => 'PC857: Turkish'),
127
        'CP737' => array('conv' => '737', 'table' => '14', 'desc' => 'PC737: Greek'),
128
        'ISO8859-7' => array('conv' => 'ISO8859-7', 'table' => '15', 'desc' => 'ISO8859-7: Greek'),
129
        'CP866' => array('conv' => '866', 'table' => '17', 'desc' => 'PC866: Cyrillic #2'),
130
        'CP852' => array('conv' => '852', 'table' => '18', 'desc' => 'PC852: Latin2'),
131
        'CP858' => array('conv' => '858', 'table' => '19', 'desc' => 'PC858: Euro'),
132
        'CP720' => array('conv' => '720', 'table' => '32', 'desc' => 'PC720: Arabic'),
133
        'CP855' => array('conv' => '855', 'table' => '34', 'desc' => 'PC855: Cyrillic'),
134
        'CP861' => array('conv' => '861', 'table' => '35', 'desc' => 'PC861: Icelandic'),
135
        'CP862' => array('conv' => '862', 'table' => '36', 'desc' => 'PC862: Hebrew'),
136
        'CP864' => array('conv' => '864', 'table' => '37', 'desc' => 'PC864: Arabic'),
137
        'CP869' => array('conv' => '869', 'table' => '38', 'desc' => 'PC869: Greek'),
138
        'ISO8859-2' => array('conv' => 'ISO8859-2', 'table' => '39', 'desc' => 'ISO8859-2: Latin2'),
139
        'ISO8859-15' => array('conv' => 'ISO8859-15', 'table' => '40', 'desc' => 'ISO8859-15: Latin9'),
140
        'WINDOWS-1250' => array('conv' => 'WINDOWS-1250', 'table' => '45', 'desc' => 'WPC1250: Latin2'),
141
        'WINDOWS-1251' => array('conv' => 'WINDOWS-1251', 'table' => '46', 'desc' => 'WPC1251: Cyrillic'),
142
        'WINDOWS-1252' => array('conv' => 'WINDOWS-1252', 'table' => '47', 'desc' => 'WPC1253: Greek'),
143
        'WINDOWS-1254' => array('conv' => 'WINDOWS-1254', 'table' => '48', 'desc' => 'WPC1254: Turkish'),
144
        'WINDOWS-1255' => array('conv' => 'WINDOWS-1255', 'table' => '49', 'desc' => 'WPC1255: Hebrew'),
145
        'WINDOWS-1256' => array('conv' => 'WINDOWS-1256', 'table' => '50', 'desc' => 'WPC1256: Arabic'),
146
        'WINDOWS-1257' => array('conv' => 'WINDOWS-1257', 'table' => '51', 'desc' => 'WPC1257: Baltic Rim'),
147
        'WINDOWS-1258' => array('conv' => 'WINDOWS-1258', 'table' => '52', 'desc' => 'WPC1258: Vietnamese'),
148
    );
149
    
150
    /**
151
     * Seleted code page
152
     * Defined in printer class.
153
     *
154
     * @var string
155
     */
156
    protected $codepage = 'CP437';
157
    /**
158
     * Number of codpage in printer memory.
159
     *
160
     * @var int
161
     */
162
    protected $charsetTableNum = 0;
163
    /**
164
     * Selected Region character page
165
     * Defined in printer class.
166
     *
167
     * @var string
168
     */
169
    protected $region = 'LATIN';
170
    /**
171
     * List all avaiable fonts
172
     * @var array
173
     */
174
    protected $aFont = array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 97 => 'SA', 98 => 'SB');
175
    /**
176
     * Selected internal font.
177
     *
178
     * @var string
179
     */
180
    protected $font = 'A';           
181
    /**
182
     * Resolution in dpi.
183
     *
184
     * @var int
185
     */
186
    public $dpi = 203; //dots per inch
187
    /**
188
     * Resolution in dpmm.
189
     *
190
     * @var int
191
     */
192
    public $dpmm = 8; //dots per mm
193
    /**
194
     * Maximum width paper.
195
     *
196
     * @var int
197
     */
198
    public $widthMaxmm = 80;//mm
199
    /**
200
     * Selected Width paper.
201
     *
202
     * @var int
203
     */
204
    public $widthPaper = 80;//mm
205
    /**
206
     * Maximum width for printed area.
207
     *
208
     * @var int
209
     */
210
    public $widthPrint = 72;//mm
211
    /**
212
     * Maximum width for printed area in dots.
213
     *
214
     * @var int
215
     */
216
    public $widthMaxdots = 576;//dots
217
    /**
218
     * Maximum number of characters per line.
219
     *
220
     * @var int
221
     */
222
    public $maxchars = 48;//max characters per line
223
224
    //protected property standards
225
    /**
226
     * Connector to printer.
227
     *
228
     * @var ConnectosInterface
229
     */
230
    protected $connector = null;
231
    /**
232
     * Seleted printer mode.
233
     *
234
     * @var string
235
     */
236
    protected $printerMode = 'normal';
237
    /**
238
     * Selected bold mode.
239
     *
240
     * @var bool
241
     */
242
    protected $boldMode = false;
243
    /**
244
     * Selected reverse colors mode.
245
     *
246
     * @var bool
247
     */
248
    protected $reverseColors = false;
249
    /**
250
     * Selected under lined mode.
251
     * 
252
     * @var bool
253
     */
254
    protected $underlineMode = false;
255
    /**
256
     * Selected rotate 90 degrees mode
257
     * @var bool
258
     */
259
    protected $rotateMode = false;
260
    /**
261
     * Buffer class.
262
     *
263
     * @var Connectors\Buffer
264
     */
265
    protected $buffer = null;
266
267 24
    /**
268
     * Class constructor
269 24
     * Instantiates the data buffer.
270
     *
271
     * @param ConnectorInterface $conn
272 24
     */
273 24
    public function __construct(ConnectorInterface $conn = null)
274
    {
275
        if (!is_null($conn)) {
276
            $this->connector = $conn;
0 ignored issues
show
Documentation Bug introduced by
It seems like $conn of type object<Posprint\Connectors\ConnectorInterface> is incompatible with the declared type object<Posprint\Printers\ConnectosInterface> of property $connector.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
277
        }
278
        $this->buffer = new Buffer();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Posprint\Connectors\Buffer() of type object<Posprint\Connectors\Buffer> is incompatible with the declared type object<Posprint\Printers\Connectors\Buffer> of property $buffer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
279
    }
280
281
    /**
282
     * Returns a default region for codepage
283
     * if param $region is null will return actual default region from class
284
     * if param $region is 'all' will return a array with all avaiable regions
285 2
     * if param $region is a string will set the region parameter of class and returns it.
286
     * NOTE: This command do not set the printer, only class parameters
287 2
     * 
288 2
     * @param string $region
289 2
     * @return string|array
290 1
     */
291
    public function defaultRegionPage($region = null)
292 2
    {
293 2
        if (!is_null($region)) {
294 2
            $region = strtoupper(trim($region));
295 2
            if ($region == 'ALL') {
296 2
                return $this->aRegion;
297 2
            }
298
            $reg = array_search($region, $this->aRegion, true);
299
            if ($reg !== false) {
300
                $this->region = $region;
301
            }
302
        }
303
        return $this->region;
304
    }
305
306
    /**
307
     * Returns a default codepage
308
     * if param $codepage is null will return actual default codepage from class
309
     * if param $codepage is 'all' will return a array with all avaiable codepages
310 21
     * if param $codepage is a string will set the codepage parameter of class and returns it.
311
     * NOTE: This command do not set the printer, only class parameters
312 21
     * 
313 21
     * @param string $codepage
314 21
     * @return string|array
315 1
     */
316
    public function defaultCodePage($codepage = null)
317 21
    {
318 3
        if (!is_null($codepage)) {
319 3
            $codepage = strtoupper(trim($codepage));
320 3
            if ($codepage == 'ALL') {
321 3
                return array_keys($this->aCodePage);
322 21
            }
323 21
            if (array_key_exists($codepage, $this->aCodePage)) {
324
                $this->codepage = $codepage;
325
                $table = $this->aCodePage[$codepage];
326
                $this->charsetTableNum = $table['table'];
327
            }
328
        }
329
        return $this->codepage;
330
    }
331 2
332
    /**
333 2
     * Set a codepage table in printer.
334 2
     *
335 2
     * @param string $codepage
336
     */
337
    public function setCodePage($codepage = null)
338
    {
339
        $codepage = $this->defaultCodePage($codepage);
0 ignored issues
show
Unused Code introduced by
$codepage is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
340
        $this->buffer->write(self::ESC.'t'.chr($this->charsetTableNum));
341
    }
342
343 1
    /**
344
     * Set a region page.
345 1
     * The numeric key of array $this->aRegion is the command parameter.
346 1
     *
347 1
     * @param string $region
348 1
     */
349
    public function setRegionPage($region = null)
350
    {
351
        $region = $this->defaultRegionPage($region);
352
        $mode = array_keys($this->aRegion, $region, true);
353
        $this->buffer->write(self::ESC.'R'.chr($mode[0]));
354
    }
355
    
356
    /**
357
     * Returns the default printer font 
358
     * A - Font A (12 x 24)
359
     * B - Font B (9 x 17)
360
     * C - Font C
361
     * D - Font D
362
     * E - Font E
363
     * Special A
364
     * Special B
365
     * Default Font A.
366
     * if param $font is null will return actual default font from class
367
     * if param $font is 'all' will return a array with all avaiable printer fonts
368 2
     * if param $font is a string will set the font parameter of class and returns it.
369
     * NOTE: This command do not set the printer, only class parameters
370 2
     * 
371 2
     * @param string $font
372 2
     * @return array|string
373
     */
374
    public function defaultFont($font = null)
375
    {
376
        if (!is_null($font)) {
377 2
            $font = strtoupper(trim($font));
378 2
            if ($font == 'ALL') {
379 2
                //return array
380 2
                return $this->aFont;
381 2
            }
382 2
            //set $this->font
383 2
            $fonts = array_flip($this->aFont);
384 2
            $keys = array_keys($fonts);
385
            $reg = array_search($font, $keys, true);
386
            if ($reg !== false) {
387
                $this->font = $font;
388
            }
389
        }
390
        return $this->font;
391
    }
392 1
    
393
    /**
394 1
     * Set a printer font 
395 1
     * If send a valid font name will set the printer otherelse a default font is selected
396 1
     * @param string $font
397 1
     */
398
    public function setFont($font = null)
399
    {
400
        $font = $this->defaultFont($font);
401
        $mode = array_keys($this->aFont, $font, true);
402 1
        $this->buffer->write(self::ESC.'M'.chr($mode[0]));
403
    }
404 1
405 1
    /**
406 1
     * Set emphasys mode on or off.
407 1
     */
408 1
    public function setBold()
409 1
    {
410
        if ($this->boldMode) {
411 1
            $this->boldMode = false;
412 1
            $mode = 0;
413
        } else {
414
            $this->boldMode = true;
415
            $mode = 1;
416
        }
417 1
        $this->buffer->write(self::ESC . 'E' . chr($mode));
418
    }
419 1
420 1
    /**
421 1
     * Set underline mode on or off.
422 1
     */
423 1
    public function setUnderlined()
424 1
    {
425
        if ($this->underlineMode) {
426 1
            $this->underlineMode = false;
427 1
            $mode = 0;
428
        } else {
429
            $this->underlineMode = true;
430
            $mode = 1;
431
        }
432
        $this->buffer->write(self::ESC . '-' . chr($mode));
433
    }
434
    
435 1
    /**
436
     * Set italic mode on or off
437 1
     * 
438
     * @return bool
439
     */
440 1
    public function setItalic()
441
    {
442 1
        return true;
443 1
    }
444 1
    
445 1
    /**
446
     * Aligns all data in one line to the selected layout in standard mode.
447
     * L - left  C - center  R - rigth
448 1
     * 
449 1
     * @param string $align 
450 1
     */
451 1
    public function setAlign($align = null)
452 1
    {
453
        if (is_null($align)) {
454
            $align = 'L';
455
        }
456
        $value = strtoupper($align);
457
        switch ($value) {
458 1
            case 'C':
459
               $mode = 1;
460 1
               break;
461 1
            case 'R':
462 1
               $mode = 2;
463 1
               break;
464 1
            default:
465 1
                $mode = 0;
466
        }
467 1
        $this->buffer->write(self::ESC . 'a' . chr($mode));
468 1
    }
469
    
470
    /**
471
     * Turns white/black reverse print On or Off for characters.
472
     * n = odd: On, n = even: Off.
473
     */
474 1
    public function setReverseColors()
475
    {
476 1
        if ($this->reverseColors) {
477
            $this->reverseColors = false;
478 1
            $mode = 0;
479 1
        } else {
480 1
            $this->reverseColors = true;
481 1
            $mode = 1;
482 1
        }
483 1
        $this->buffer->write(self::GS.'B'.chr($mode));
484 1
    }
485 1
    
486 1
    /**
487 1
     * Set expanded mode.
488 1
     * @param int $size multiplies normal size 1 - 8 
489 1
     */
490
    public function setExpanded($size = null)
491
    {
492
        $size = self::validateInteger($size, 1, 8, 1);
493
        $aSize = [
494
            [0, 0],
495
            [16, 1],
496
            [32, 2],
497
            [48, 3],
498
            [64, 4],
499
            [80, 5],
500
            [96, 6],
501
            [112, 7]
502
        ];
503
        $mode = $aSize[$size-1][0] + $aSize[$size-1][1];
504
        $this->buffer->write(self::ESC.'!'.chr($mode));
505
    }
506
507
    /**
508
     * Set condensed mode.
509 1
     */
510
    public function setCondensed()
511 1
    {
512 1
        $this->setExpanded(1);
513 1
        $this->setFont('B');
514 1
    }
515 1
    
516 1
517
    /**
518 1
     * Set the printer mode.
519 1
     */
520
    abstract public function setPrintMode($mode = null);
521
522
    /**
523
     * Set rotate 90 degrees.
524
     */
525
    public function setRotate90()
526 20
    {
527
        if ($this->rotateMode) {
528 20
            $this->rotateMode = false;
529 20
            $mode = 0;
530 20
        } else {
531 20
            $this->rotateMode = true;
532 20
            $mode = 1;
533 20
        }
534 20
        $this->buffer->write(self::ESC.'V'.chr($mode));
535 20
    }
536
    
537
    /**
538
     * initialize printer
539
     * Clears the data in the print buffer and resets the printer modes to 
540
     * the modes that were in effect when the power was turned on.
541
     */
542
    public function initialize()
543
    {
544 1
        $this->buffer->write(self::ESC.'@');
545
        $this->rotateMode = false;
546 1
        $this->defaultCodePage('CP470');
547 1
        $this->underlineMode = false;
548 1
        $this->boldMode = false;
549
        $this->printerMode = 'normal';
550
        $this->font = 'A';
551
    }
552
    
553
    /**
554
     * Send message or command to buffer
555
     * when sending commands is not required to convert characters,
556
     * so the variable may translate by false.
557
     * 
558 1
     * @param string $text
559
     */
560 1
    public function text($text = '')
561 1
    {
562 1
        $text = $this->translate($text);
563 1
        $this->buffer->write($text);
564
    }
565
566
    /**
567
     * Set horizontal and vertical motion units
568
     * $horizontal => character spacing 1/x"
569
     * $vertical => line spacing 1/y".
570
     *
571 1
     * @param int $horizontal
572
     * @param int $vertical
573 1
     */
574 1
    public function setSpacing($horizontal = 30, $vertical = 30)
575 1
    {
576
        $horizontal = self::validateInteger($horizontal, 0, 255, 30);
577
        $vertical = self::validateInteger($vertical, 0, 255, 30);
578
        $this->buffer->write(self::GS.'P'.chr($horizontal).chr($vertical));
579
    }
580
581
    /**
582
     * Set right-side character spacing
583
     * 0 ≤ n ≤ 255 => 1/x".
584
     * 
585
     * @param int $value
586 1
     */
587
    public function setCharSpacing($value = 3)
588 1
    {
589 1
        $value = self::validateInteger($value, 0, 255, 0);
590 1
        $this->buffer->write(self::ESC.' '.chr($value));
591 1
    }
592 1
593
    /**
594 1
     * Line spacing
595
     * The default is set to zero and 30/180 "
596 1
     * any different number of zero will generate multiples of.
597
     * n  1/180-inch vertical motion
598
     * normal paragraph 30/180" => 4.23 mm
599 1
     * 
600 1
     * @param int $paragraph
0 ignored issues
show
Bug introduced by
There is no parameter named $paragraph. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
601
     */
602
    public function setParagraph($value = 0)
603
    {  
604
        $value = self::validateInteger($value, 0, 255, 0);
605
        $paragraph = ceil($value);
606
        if ($paragraph == 0) {
607
            $this->buffer->write(self::ESC.'2');
608 1
            return;
609
        }
610 1
        if ($paragraph < 25) {
611 1
            $paragraph = 25;
612 1
        } elseif ($paragraph > 255) {
613 1
            $paragraph = 255;
614
        }
615 1
        $this->buffer->write(self::ESC.'3'.chr($paragraph));
616 1
    }
617
618
    /**
619
     * Prints data and feeds paper n lines
620
     * ESC d n Prints data and feeds paper n lines.
621
     *
622
     * @param type $lines
623
     */
624 1
    public function lineFeed($lines = 1)
625
    {
626 1
        $lines = self::validateInteger($lines, 0, 255, 1);
627 1
        if ($lines == 1) {
628 1
            $this->buffer->write(self::LF);
629
            return;
630
        }
631
        $this->buffer->write(self::ESC.'d'.chr($lines));
632
    }
633
634
    /**
635
     * Prints data and feeds paper n dots
636
     * ESC J n Prints data and feeds paper n dots.
637
     *
638 1
     * @param int $dots
639
     */
640 1
    public function dotFeed($dots = 1)
641 1
    {
642 1
        $dots = self::validateInteger($dots, 0, 80, 0);
643 1
        $this->buffer->write(self::ESC.'J'.chr($dots));
644 1
    }
645
646
    /**
647
     * Generate a pulse, for opening a cash drawer if one is connected.
648
     * The default settings should open an Epson drawer.
649
     *
650
     * @param int $pin    0 or 1, for pin 2 or pin 5 kick-out connector respectively.
651
     * @param int $on_ms  pulse ON time, in milliseconds.
652 1
     * @param int $off_ms pulse OFF time, in milliseconds.
653
     */
654 1
    public function pulse($pin = 0, $on_ms = 120, $off_ms = 240)
655 1
    {
656 1
        $pin = self::validateInteger($pin, 0, 1, 0);
657 1
        $on_ms = self::validateInteger($on_ms, 1, 511, 120);
658 1
        $off_ms = self::validateInteger($off_ms, 1, 511, 240);
659
        $this->buffer->write(self::ESC.'p'.chr($pin + 48).chr($on_ms / 2).chr($off_ms / 2));
660 1
    }
661 1
662
    /**
663
     * Cut the paper.
664
     *
665
     * @param int $mode  FULL or PARTIAL. If not specified, FULL will be used. 
666
     * @param int $lines Number of lines to feed after cut
667
     */
668
    public function cut($mode = 'PARTIAL', $lines = 3)
669
    {
670
        $lines = self::validateInteger($lines, 1, 10, 3);
671
        if ($mode == 'FULL') {
672
            $mode = self::CUT_FULL;
673
        } else {
674
            $mode = self::CUT_PARTIAL;
675
        }
676
        $this->buffer->write(self::GS.'V'.chr($mode).chr($lines));
677
    }
678
679
    /**
680
     * Implements barcodes 1D
681
     * GS k m n d1...dn
682
     * Prints bar code. n specifies the data length.
683
     *   m    bar code system             number of d (=k)
684
     *  "A"     UPC-A                       11 or 12
685
     *  "B"     UPC-E                       6, 7, 8, 11 or 12
686
     *  "C"     JAN13 / EAN13               12 or 13
687
     *  "D"     JAN8 / EAN8                 7 or 8
688
     *  "E"     CODE39                      1 or more
689
     *  "F"     ITF                         even
690
     *  "G"     CODABAR (NW-7)              2 or more
691
     *  "H"     CODE93                      1–255
692
     *  "I"     CODE128                     2–255    
693
     *  "J"     GS1-128                     2–255    
694
     *  "K"     GS1 DataBar Omnidirectional 13
695
     *  "L"     GS1 DataBar Truncated       13
696
     *  "M"     GS1 DataBar Limited         13
697
     *  "N"     GS1 DataBar Expanded        2–255.
698
     * 
699
     *  GS h n Sets bar code height to n dots.
700
     *  GS w n Sets bar width of bar code. n = 2–6 (thin–thick)
701 1
     *  GS H n Selects print position of HRI characters.
702
     *           n = 0, "0": Not printed
703
     *           n = 1, "1": Above the bar code
704
     *           n = 2, "2": Below the bar code
705
     *           n = 3, "3": Both above and below the bar code
706
     *  GS f n Selects font for the HRI characters.
707
     *           n = 0, "0": Font A,
708
     *           n = 1, "1": Font B
709
     *
710 1
     * @param int    $type        Default CODE128
711
     * @param int    $height
712
     * @param int    $lineWidth
713 1
     * @param string $txtPosition
714
     * @param string $txtFont
715
     * @param string $data
716 1
     */
717
    public function barcode(
718
        $type = self::CODE128,
719 1
        $height = 162,
720
        $lineWidth = 2,
721 1
        $txtPosition = 'none',
722 1
        $txtFont = '',
723 1
        $data = '123456'
724 1
    ) {
725
        switch ($txtPosition) {
726
            case 'Above':
727 1
                $tPos = 1;
728 1
                break;
729
            case 'Below':
730
                $tPos = 2;
731 1
                break;
732 1
            case 'Both':
733 1
                $tPos = 3;
734
                break;
735 1
            default:
736
                //none
737 1
                $tPos = 0;
738
        }
739 1
        $font = 0;
740
        if ($txtFont === 'B') {
741 1
            $font = 1;
742
        }
743 1
        $id = 0;
744 1
        if (self::validateBarcodeData($type, $id, $data) === false) {
745
            return false;
746
        }
747
        $height = self::validateInteger($height, 1, 255, 4);
748
        $lineWidth = self::validateInteger($lineWidth, 1, 6, 2);
749
        $nlen = strlen($data);
750
        //set barcode height
751
        $this->buffer->write(self::GS.'h'.chr($height));
752
        //set barcode bar width
753 1
        $this->buffer->write(self::GS.'w'.chr($lineWidth));
754
        //Selects print position of HRI characters.
755
        $this->buffer->write(self::GS.'H'.chr($tPos));
756 1
        //Selects font for the HRI characters.
757 1
        $this->buffer->write(self::GS.'f'.chr($font));
758
        //Print barcode
759
        $this->buffer->write(self::GS.'k'.chr($id).chr($nlen).$data);
760 1
    }
761
    
762 1
    /**
763
     * Imprime o QR Code
764 1
     * @param string $data Dados a serem inseridos no QRCode
765
     * @param string $level Nivel de correção L,M,Q ou H
766 1
     * @param int $modelo modelo de QRCode 1, 2 ou 0 Micro
767
     * @param int $wmod largura da barra 3 ~ 16
768
     */
769 1
    public function barcodeQRCode($data = '', $level = 'L', $modelo = 2, $wmod = 4)
770 1
    {
771 1
        //set model of QRCode
772
        $n1 = 50;
773
        if ($modelo == 1) {
774
            $n1 = 49;
775
        }
776
        $this->buffer->write(self::GS."(k".chr(4).chr(0).chr(49).chr(65).chr($n1).chr(0));
777
        //set module bar width
778
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(67).chr($wmod));
779
        //set error correction level
780
        $level = strtoupper($level);
781 1
        switch ($level) {
782
            case 'L':
783 1
                $n = 48;
784 1
                break;
785 1
            case 'M':
786 1
                $n = 49;
787
                break;
788 1
            case 'Q':
789 1
                $n = 50;
790
                break;
791
            case 'H':
792
                $n = 51;
793
                break;
794
            default:
795
                $n = 49;
796
        }
797
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(69).chr($n));
798
        //set data for QR Code assuming print only alphanumeric data
799
        $len = strlen($data) + 3;
800
        $pH = ($len / 256);
801
        $pL = $len % 256;
802
        $this->buffer->write(self::GS."(k".chr($pL).chr($pH).chr(49).chr(80).chr(48).$data);
803
        //Print QR Code
804
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(81).chr(48));
805 20
    }
806
807
    /**
808 20
     * Close and clean buffer
809
     * All data will be lost.
810
     */
811
    public function close()
812 20
    {
813
        $this->buffer->close();
814 19
    }
815 19
816 1
    /**
817
     * Return all data buffer.
818
     *
819
     * @param string $type specifies the return format
820 1
     */
821
    public function getBuffer($type = '')
822
    {
823
        switch ($type) {
824 1
            case 'binA':
825
                //returns a binary array of buffer
826
                $resp = $this->buffer->getDataBinary(true);
827
                break;
828 1
            case 'binS':
829
                //returns a binary string of buffer
830
                $resp = $this->buffer->getDataBinary(false);
831
                break;
832
            case 'b64A':
833 1
                //returns a base64 encoded array of buffer
834
                $resp = $this->buffer->getDataBase64(true);
835
                break;
836 1
            case 'b64S':
837 1
                //returns a base64 encoded string of buffer
838 20
                $resp = $this->buffer->getDataBase64(false);
839
                break;
840
            case 'json':
841
                //returns a json encoded of array buffer
842
                $resp = $this->buffer->getDataJson();
843
                break;
844
            case 'readA':
845
                //returns a human readable format of array buffer
846
                //only for debug reasons
847
                $resp = $this->buffer->getDataReadable(true);
848
                break;
849
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
850
                //returns a human readable format of string buffer
851
                //only for debug reasons
852
                $resp = $this->buffer->getDataReadable(false);
853
        }
854
        return $resp;
855
    }
856
857
    /**
858
     * Send commands from buffer to connector printer.
859
     */
860
    public function send(ConnectorInterface $conn = null)
861
    {
862
        if (!is_null($conn)) {
863
            $this->connector = $conn;
0 ignored issues
show
Documentation Bug introduced by
It seems like $conn of type object<Posprint\Connectors\ConnectorInterface> is incompatible with the declared type object<Posprint\Printers\ConnectosInterface> of property $connector.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
864
        }
865
        if (is_null($this->connector)) {
866 1
            return $this->getBuffer();
867
        }
868
        $aCmds = $this->getBuffer('binA');
869 1
        foreach ($aCmds as $cmd) {
870 1
            $this->connector->write($cmd);
871 1
        }
872 1
    }
873 1
874 1
    /**
875 1
     * Checks whether the barcode data is compatible with the chosen model
876 1
     * 
877 1
     * @param string $type
878 1
     * @param int    $id
879 1
     * @param string $data
880 1
     * @return string 
881 1
     */
882 1
    protected static function validateBarcodeData($type, &$id, &$data)
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
883 1
    {
884 1
        $aTypes = [
885
            'A' => ['id' => 65, 'desc' => 'UPC-A', 'len' => '11;12', 'type' => 'N'],
886
            'B' => ['id' => 66, 'desc' => 'UPC-E', 'len' => '6;7;8;11;12', 'type' => 'N'],
887 1
            'C' => ['id' => 67, 'desc' => 'EAN13', 'len' => '12;13', 'type' => 'N'],
888 1
            'D' => ['id' => 68, 'desc' => 'EAN8', 'len' => '7;8', 'type' => 'N'],
889 1
            'E' => ['id' => 69, 'desc' => 'CODE39', 'len' => '1-', 'type' => 'C'],
890 1
            'F' => ['id' => 70, 'desc' => 'ITF (i25)', 'len' => '1-even ', 'type' => 'N'],
891
            'G' => ['id' => 71, 'desc' => 'CODABAR', 'len' => '2-more', 'type' => 'C'],
892
            'H' => ['id' => 72, 'desc' => 'CODE93', 'len' => '1-255', 'type' => 'C'],
893
            'I' => ['id' => 73, 'desc' => 'CODE128', 'len' => '2-255', 'type' => 'C'],
894
            'J' => ['id' => 74, 'desc' => 'GS1-128', 'len' => '2-255', 'type' => 'C'],
895
            'K' => ['id' => 75, 'desc' => 'GS1 DataBar Omnidirectional', 'len' => '13', 'type' => 'N'],
896 1
            'L' => ['id' => 76, 'desc' => 'GS1 DataBar Truncated', 'len' => '13', 'type' => 'N'],
897
            'M' => ['id' => 77, 'desc' => 'GS1 DataBar Limited', 'len' => '13', 'type' => 'N'],
898
            'N' => ['id' => 78, 'desc' => 'GS1 DataBar Expanded', 'len' => '2-255', 'type' => 'C'],
899
        ];
900
        if (!array_key_exists($type, $aTypes)) {
901
            return false;
902
        }
903
        $bar = $aTypes[$type];
904
        $id = $bar['id'];
905
        $len = $bar['len'];
0 ignored issues
show
Unused Code introduced by
$len is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
906
        $dtype = $bar['type'];
0 ignored issues
show
Unused Code introduced by
$dtype is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
907
        //check data type if N only numeric is acceptable and all others chars must be removed
908
        //and if then field stay is empty, this is must be completed to an acceptable standard value
909
        
910
        //check for length of data, if the field length is different from the 
911
        //acceptable values, it must be adjusted by removing or adding characters
912
        return true;
913
    }
914
915
    /**
916
     * Insert a image.
917
     *
918
     * @param string $filename Path to image file
919
     * @param float  $width
920
     * @param float  $height
921
     * @param int    $size 0-normal 1-Double Width 2-Double Heigth 
922
     * @throws RuntimeException
923
     */
924
    public function putImage($filename = '', $width = null, $height = null, $size = 0)
925
    {
926
        try {
927
            $img = new Graphics($filename, $width, $height);
928
        } catch (RuntimeException $e) {
929
            throw new RuntimeException($e->getMessage());
930
        } catch (InvalidArgumentException $e) {
931
            throw new RuntimeException($e->getMessage());
932
        }
933
        $size = self::validateInteger($size, 0, 3, 0);
934
        $imgHeader = self::dataHeader(array($img->getWidth(), $img->getHeight()), true);
935
        $tone = '0';
936
        $colors = '1';
937
        $xm = (($size & self::IMG_DOUBLE_WIDTH) == self::IMG_DOUBLE_WIDTH) ? chr(2) : chr(1);
938
        $ym = (($size & self::IMG_DOUBLE_HEIGHT) == self::IMG_DOUBLE_HEIGHT) ? chr(2) : chr(1);
939
        $header = $tone.$xm.$ym.$colors.$imgHeader;
940
        $this->sendGraphicsData('0', 'p', $header.$img->getRasterImage());
941
        $this->sendGraphicsData('0', '2');
942
    }
943
944
    /**
945
     * Wrapper for GS ( L, to calculate and send correct data length.
946
     *
947
     * @param string $m    Modifier/variant for function. Usually '0'.
948
     * @param string $fn   Function number to use, as character.
949
     * @param string $data Data to send.
950
     */
951
    protected function sendGraphicsData($m, $fn, $data = '')
952
    {
953
        $header = $this->intLowHigh(strlen($data) + 2, 2);
954
        $this->buffer->write(self::GS.'(L'.$header.$m.$fn.$data);
955
    }
956
957
    /**
958
     * Generate two characters for a number: 
959
     * In lower and higher parts, or more parts as needed.
960
     *
961
     * @param int $int    Input number
0 ignored issues
show
Bug introduced by
There is no parameter named $int. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
962
     * @param int $length The number of bytes to output (1 - 4).
963
     */
964
    protected static function intLowHigh($input, $length)
965
    {
966
        $maxInput = (256 << ($length * 8) - 1);
0 ignored issues
show
Unused Code introduced by
$maxInput is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
967
        $outp = '';
968
        for ($i = 0; $i < $length; ++$i) {
969
            $outp .= chr($input % 256);
970
            $input = (int) ($input / 256);
971
        }
972
        return $outp;
973
    }
974
975
    /**
976
     * Convert widths and heights to characters.
977
     * Used before sending graphics to set the size.
978
     *
979
     * @param array $inputs
980
     * @param bool  $long   True to use 4 bytes, false to use 2
981
     * @return string
982
     */
983
    protected static function dataHeader(array $inputs, $long = true)
984
    {
985
        $outp = array();
986
        foreach ($inputs as $input) {
987
            if ($long) {
988
                $outp[] = self::intLowHigh($input, 2);
989
            } else {
990
                $input = self::validateInteger($input, 0, 255, 0);
991
                $outp[] = chr($input);
992
            }
993
        }
994
        return implode('', $outp);
995
    }
996
997
    /**
998
     * Verify if the argument given is not a boolean.
999
     * 
1000
     * @param bool   $test   the input to test
1001
     * @param bool    $default the default value
1002 9
     * @return bool 
1003
     */
1004 9
    protected static function validateBoolean($test, $default)
1005 1
    {
1006
        if (!($test === true || $test === false)) {
1007 9
            return $default;
1008
        }
1009
        return $test;
1010
    }
1011
1012
    /**
1013
     * Verify if the argument given is not an integer within the specified range.
1014
     * will return default instead
1015
     * 
1016
     * @param int    $test    the input to test
1017
     * @param int    $min     the minimum allowable value (inclusive)
1018
     * @param int    $max     the maximum allowable value (inclusive)
1019
     * @param int    $default the default value
1020
     * @return int
1021
     */
1022
    protected static function validateInteger($test, $min, $max, $default)
1023
    {
1024
        if (!is_integer($test) || $test < $min || $test > $max) {
1025
            return $default;
1026
        }
1027
        return $test;
1028
    }
1029
1030
    /**
1031
     * Verify if the argument given can't be cast to a string.
1032 1
     *
1033
     * @param string $test    the input to test
1034 1
     * @param string $default the default value
1035 1
     * @return string
1036 1
     */
1037 1
    protected static function validateString($test, $default)
1038 1
    {
1039 1
        if (is_object($test) && !method_exists($test, '__toString')) {
1040 1
            return $default;
1041 1
        }
1042
        return $test;
1043
    }
1044
    
1045
    /**
1046
     * Translate the text from UTF-8 for the specified codepage
1047
     * this translation uses "iconv" and admits texts ONLY in UTF-8.
1048
     *
1049
     * @param string $text
1050
     * @return string
1051
     */
1052
    protected function translate($text = '')
1053
    {
1054
        $indCode = $this->defaultCodePage();
1055
        if (!empty($indCode)) {
1056
            $codep = $this->aCodePage[$indCode];
1057
            if (!empty($codep)) {
1058
                $text = iconv('UTF-8', $codep['conv'], $text);
1059
            }
1060
        }
1061
        return $text;
1062
    }
1063
}
1064