├── .coveralls.yml
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── CONTRIBUTORS.md
├── LICENSE.md
├── README.md
├── composer.json
├── composer.lock
├── doc
├── FAQ.md
├── Makefile
└── escpos.doxyfile
├── example
├── README.md
├── barcode.php
├── bit-image.php
├── character-encodings-with-images.php
├── character-encodings.php
├── character-tables.php
├── customer-display.php
├── demo.php
├── graphics.php
├── interface
│ ├── README.md
│ ├── cups.php
│ ├── ethernet.php
│ ├── linux-usb.php
│ ├── smb.php
│ ├── windows-lpt.php
│ └── windows-usb.php
├── margins-and-spacing.php
├── pdf417-code.php
├── print-from-html.php
├── print-from-pdf.php
├── qr-code.php
├── rawbt-receipt.html
├── rawbt-receipt.php
├── receipt-with-logo.php
├── resources
│ ├── character-encoding-test-strings.inc
│ ├── document.html
│ ├── document.odt
│ ├── document.pdf
│ ├── document.z
│ ├── escpos-php-small.png
│ ├── escpos-php.png
│ ├── rawbtlogo.png
│ ├── tulips.png
│ └── tux.png
├── specific
│ ├── 123-code128-barcode.php
│ ├── 141-custom-command.php
│ ├── 148-data-uri.php
│ ├── 235-get-data.php
│ ├── 29-latvian-star-tup592.php
│ ├── 32-german-tm-t20-ii-custom-command.php
│ ├── 33-spanish-seypos-prp-300.php
│ ├── 37-chinese.php
│ ├── 39-currency-symbols.php
│ ├── 44-pound-symbol-star-tsp650.php
│ ├── 50-P-822D-greek.php
│ ├── 54-gfx-sidebyside.php
│ ├── 6-arabic-epos-tep-220m.php
│ ├── 62-greek-symbol-swap.php
│ ├── 68-redblack.php
│ ├── 97-dithering.php
│ └── README.md
├── text-size.php
├── unifont-print-buffer.php
└── upside-down.php
├── phpunit.xml
├── src
└── Mike42
│ └── Escpos
│ ├── CapabilityProfile.php
│ ├── CodePage.php
│ ├── Devices
│ └── AuresCustomerDisplay.php
│ ├── EscposImage.php
│ ├── Experimental
│ └── Unifont
│ │ ├── ColumnFormatGlyph.php
│ │ ├── ColumnFormatGlyphFactory.php
│ │ ├── FontMap.php
│ │ ├── UnifontGlyphFactory.php
│ │ └── UnifontPrintBuffer.php
│ ├── GdEscposImage.php
│ ├── ImagickEscposImage.php
│ ├── NativeEscposImage.php
│ ├── PrintBuffers
│ ├── EscposPrintBuffer.php
│ ├── ImagePrintBuffer.php
│ ├── PrintBuffer.php
│ └── cache
│ │ ├── Characters-OCD-300.ser.z
│ │ ├── Characters-default.ser.z
│ │ └── Characters-simple.ser.z
│ ├── PrintConnectors
│ ├── CupsPrintConnector.php
│ ├── DummyPrintConnector.php
│ ├── FilePrintConnector.php
│ ├── MultiplePrintConnector.php
│ ├── NetworkPrintConnector.php
│ ├── PrintConnector.php
│ ├── RawbtPrintConnector.php
│ ├── UriPrintConnector.php
│ └── WindowsPrintConnector.php
│ ├── Printer.php
│ └── resources
│ └── capabilities.json
└── test
├── bootstrap.php
├── integration
├── ExampleTest.php
└── resources
│ └── output
│ ├── barcode.bin
│ ├── bit-image.bin
│ ├── character-encodings.bin
│ ├── character-tables.bin
│ ├── demo.bin
│ ├── graphics.bin
│ ├── margins-and-spacing.bin
│ ├── pdf417-code.bin
│ ├── qr-code.bin
│ ├── receipt-with-logo.bin
│ ├── text-size.bin
│ └── unifont-print-buffer.bin
└── unit
├── AuresCustomerDisplayTest.php
├── CapabilityProfileTest.php
├── CodePageTest.php
├── CupsPrintConnectorTest.php
├── EscposImageTest.php
├── EscposPrintBufferTest.php
├── EscposTest.php
├── Experimental
└── Unifont
│ └── UnifontPrintBufferTest.php
├── FilePrintConnectorTest.php
├── GdEscposImageTest.php
├── ImagickEscposImageTest.php
├── MultiplePrintConnectorTest.php
├── NativeEscposImageTest.php
├── UriPrintConnectorTest.php
├── WindowsPrintConnectorTest.php
└── resources
├── black_transparent.gif
├── black_transparent.png
├── black_white.bmp
├── black_white.gif
├── black_white.jpg
├── black_white.png
├── black_white_tall.png
├── canvas_black.bmp
├── canvas_black.gif
├── canvas_black.jpg
├── canvas_black.png
├── canvas_white.bmp
├── canvas_white.gif
├── canvas_white.jpg
├── canvas_white.png
├── demo.php
└── doc.pdf
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service_name: travis-ci
2 | coverage_clover: build/logs/clover.xml
3 | json_path: build/logs/coveralls-upload.json
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Eclipse files
2 | .settings/*
3 | .project
4 | .buildpath
5 |
6 | # doxygen files
7 | doc/html
8 | doc/latex
9 | doc/doxygen_sqlite3.db
10 |
11 | # composer files
12 | vendor/
13 |
14 | # other build files
15 | build/*
16 | *.phar
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dist: xenial
3 | sudo: required
4 |
5 | language: php
6 |
7 | php:
8 | - '7.3'
9 | - '7.4'
10 | - '8.0'
11 | - nightly
12 |
13 | matrix:
14 | allow_failures:
15 | - php: nightly
16 |
17 | before_install:
18 | - sudo apt-get -qq update
19 | - sudo apt-get install -y imagemagick ghostscript unifont
20 |
21 | install:
22 | - composer install
23 |
24 | before_script:
25 | # Install 'imagick' plugin
26 | - bash -c 'if [[ $TRAVIS_PHP_VERSION != 8* ]] && [[ $TRAVIS_PHP_VERSION != "nightly" ]] ; then printf "\n" | pecl install imagick; fi'
27 | # Directory for coverage report
28 | - mkdir -p build/logs/
29 |
30 | script:
31 | # Check code style
32 | - php vendor/bin/phpcs --standard=psr2 src/ -n
33 | # Run tests
34 | - php vendor/bin/phpunit --coverage-clover build/logs/clover.xml
35 |
36 | after_success:
37 | # Upload coverage statistics to coveralls service after test
38 | - wget -c -nc https://github.com/satooshi/php-coveralls/releases/download/v1.0.1/coveralls.phar
39 | - php coveralls.phar -v
40 | ...
41 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | This project is open to many different types of contribution. You can help with improving the documentation and examples, sharing your insights on the issue tracker, adding fixes to the code, providing test cases, or just [writing about your hardware setup that you use](https://github.com/mike42/escpos-php/issues/new).
4 |
5 | ## Issue tracker
6 |
7 | Open issues of all sorts are tracked on the [issue tracker](https://github.com/mike42/escpos-php/issues). Please check [the FAQ](https://github.com/mike42/escpos-php/blob/development/doc/FAQ.md) before you post, and practice good [bug tracker etiquette](https://bugzilla.mozilla.org/page.cgi?id=etiquette.html) to keep it running smoothly.
8 |
9 | Issues are [loosely categorised](https://github.com/mike42/escpos-php/labels), and will stay open while there is still something that can be resolved.
10 |
11 | Anybody may add to the discussion on the bug tracker. Just be sure to add new questions as separate issues, and to avoid commenting on closed issues.
12 |
13 | ## Submitting changes
14 |
15 | Code changes may be submitted as a "[pull request](https://help.github.com/articles/about-pull-requests/)" at [mike42/escpos-php](https://github.com/mike42/escpos-php). The description should include some information about how the change improves the library.
16 |
17 | The project is MIT-licensed (see [LICENSE.md](https://github.com/mike42/escpos-php/blob/development/LICENSE.md) for details). You are not required to assign copyright in order to submit changes, but you do need to agree for your code to be distributed under this license in order for it to be accepted.
18 |
19 | ### Documentation changes
20 |
21 | The official documentaton is also located in the main repository, under the [doc/](https://github.com/mike42/escpos-php/tree/development/doc) folder.
22 |
23 | You are welcome to post any suggested improvements as pull requests.
24 |
25 | ### Release process
26 |
27 | Once a pull request is accepted, it usually appears in a release a few days later.
28 |
29 | Branches:
30 |
31 | - "development" is the most recent code, possibly containing unreleased fixes
32 | - "master" contains the most recently released code (old versions are not maintained).
33 |
34 | The release process for your changes is:
35 |
36 | - Changes are submitted via pull request to the shared "development" branch.
37 | - A new release is staged on the "master" branch via another pull request, and then tagged.
38 |
39 | ## Code style
40 |
41 | This project uses the [PSR-2 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) for all PHP source code.
42 |
43 | ## Testing and CI
44 |
45 | The tests are executed on [Travis CI](https://travis-ci.org/mike42/escpos-php) over PHP 5.4, 5.5, 5.6, 7.0, 7.1 and 7.2, plus the latest LTS version of HHVM, 3.21. Older versions of PHP are not supported in current releases.
46 |
47 | For development, it's suggested that you load `imagick`, `gd` and `Xdebug` PHP exensions, and install `composer`.
48 |
49 | Fetch a copy of this code and load dependencies with composer:
50 |
51 | git clone https://github.com/mike42/escpos-php
52 | cd escpos-php/
53 | composer install
54 |
55 | Execute unit tests via `phpunit`:
56 |
57 | php vendor/bin/phpunit --coverage-text
58 |
59 | Code style can be checked via [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer):
60 |
61 | php vendor/bin/phpcs --standard=psr2 src/ -n
62 |
63 | The developer docs are built with [doxygen](https://github.com/doxygen/doxygen). Re-build them to check for documentation warnings:
64 |
65 | make -C doc clean && make -C doc
66 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | # escpos-php contributors
2 |
3 | This file contains a list of people who have made contributions of
4 | code which appear in the public repository of escpos-php.
5 |
6 | Main repository: [mike42/escpos-php](https://github.com/mike42/escpos-php) ([online contributor list](https://github.com/mike42/escpos-php/graphs/contributors))
7 |
8 | - [Michael Billington](https://github.com/mike42)
9 | - [Alif Maulana El Fattah Nataly](https://github.com/alif25r)
10 | - [Mareks Sudniks](https://github.com/marech)
11 | - [matiasgaston](https://github.com/matiasgaston)
12 | - [Mike Stivala](https://github.com/brndwgn)
13 | - [Nicholas Long](https://github.com/longsview)
14 | - [Evandro Araújo](https://github.com/evsar3)
15 |
16 | Via fork: [wdoyle/EpsonESCPOS-PHP](https://github.com/wdoyle/EpsonESCPOS-PHP):
17 |
18 | - [Warren Doyle](https://github.com/wdoyle)
19 |
20 | Via fork: [ronisaha/php-esc-pos](https://github.com/ronisaha/php-esc-pos):
21 |
22 | - [Roni Saha](https://github.com/ronisaha)
23 | - [Gergely Radics](https://github.com/Gerifield)
24 | - [vharo](https://github.com/vharo)
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2014-2016 Michael Billington, incorporating modifications by others.
4 | See CONTRIBUTORS.md for a full list.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "mike42/escpos-php",
3 | "type" : "library",
4 | "description" : "PHP receipt printer library for use with ESC/POS-compatible thermal and impact printers",
5 | "homepage" : "https://github.com/mike42/escpos-php",
6 | "keywords" : [
7 | "barcode",
8 | "epson",
9 | "receipt-printer",
10 | "printer",
11 | "escpos"
12 | ],
13 | "license" : "MIT",
14 | "authors" : [{
15 | "name" : "Michael Billington",
16 | "email" : "michael.billington@gmail.com"
17 | }
18 | ],
19 | "config": {
20 | "platform": {
21 | "php": "7.3.0"
22 | }
23 | },
24 | "require" : {
25 | "php" : ">=7.3.0",
26 | "ext-json": "*",
27 | "ext-intl": "*",
28 | "ext-zlib": "*",
29 | "mike42/gfx-php" : "^0.6"
30 | },
31 | "suggest" : {
32 | "ext-imagick" : "Will be used for image printing if present. Required for PDF printing or use of custom fonts.",
33 | "ext-gd" : "Used for image printing if present."
34 | },
35 | "require-dev" : {
36 | "phpunit/phpunit" : "^9",
37 | "squizlabs/php_codesniffer" : "^3.3"
38 | },
39 | "autoload" : {
40 | "psr-4" : {
41 | "Mike42\\" : "src/Mike42"
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/doc/FAQ.md:
--------------------------------------------------------------------------------
1 | # Frequently Asked Questions (FAQ)
2 |
3 | ## Can I print to File Format X with this?
4 |
5 | If you are trying to generate XPS, PDF or DOCX or HTML files from PHP, then you are most likely in the wrong place.
6 |
7 | The purpose of this driver it to generate binary ESC/POS code, which is understood by many embedded thermal receipt and impact printers.
8 |
9 | ## I have Printer X. Can I use this driver?
10 |
11 | If the printer understands ESC/POS, and you know how to get raw binary data to it, then yes. Otherwise, no.
12 |
13 | The [list of printers that are known to work](https://github.com/mike42/escpos-php/blob/development/README.md#printers) is crowd-sourced. We appreciate it when developers try out the driver, then [file information on the bug tracker](https://github.com/mike42/escpos-php/issues/new) with some information about which features worked on their model of printer.
14 |
15 | To see how well your printer works, first check that it supports ESC/POS, then begin by attempting to send the text "Hello World" to your printer on the command-line, from the computer that will run PHP.
16 |
17 | Once you solve this, [try to do the same from PHP](https://github.com/mike42/escpos-php/blob/development/README.md#basic-usage) using the default profile. Further details are in the [README](https://github.com/mike42/escpos-php/blob/development/README.md) file.
18 |
19 | ## Can you add support for Printer X?
20 |
21 | Features vary between printers, so we collaborate on an ESC/POS printer compatibility database to collect known differences: [receipt-print-hq/escpos-printer-db](https://github.com/receipt-print-hq/escpos-printer-db).
22 |
23 | If you encounter garbage output when you try to print images or special characters, then please submit a test page and a link to vendor documentation to the `escpos-printer-db` project, so that support can be improved for future versions.
24 |
25 | ## I have a printer that does not understand ESC/POS. Can I use this driver?
26 |
27 | No. The purpose of this driver it to generate binary ESC/POS code. If your printer doesn't understand that, then this code wont be much use to you.
28 |
29 | Some printers do have an emulation mode for ESC/POS. The vendor docs will tell if this is the case, and how to enable it.
30 |
31 | ## Why do I get this error when I try to print?
32 |
33 | Start by testing that you can send text to your printer outside of escpos-php. The examples linked to in the README are commented with some commands to get you started.
34 |
35 | Generally, initial setup problems seem to have one of these causes:
36 |
37 | 1. You are writing to the wrong place. Writing to `LPT1` does not output to parallel port on Linux, and `/dev/ttyS0` is not a serial printer on Windows.
38 | 2. The printer has not been set up to accept printing the way you expect. This means permissions on Linux, network printers being configured, and shared printers having user accounts and firewalls set up correctly on the print server.
39 | 3. Your printer actually doesn't work (rare but possible).
40 |
41 | To be clear, these are not escpos-php issues: No amount of PHP code can set up your printer for you. Instead, the driver relies on developers determining how their setup is going to work before using a connector to transport data to their printer.
42 |
43 | Once you have a working command to send text to your printer (from the PHP server), you are ready to use escpos-php. You can try to use a PrintConnector now, based on your operating system and printer interface. A table is located in the README to help you select the right one.
44 |
45 | The connectors are-
46 |
47 | - `FilePrintConnector` and `NetworkPrintConnector` directly use files or network sockets.
48 | - `WindowsPrintConnector` and `CupsPrintConnector` tie in with Windows and Unix system printing.
49 | - `DummyPrintConnector` does not connect to a real printer, and can be used to save ESC/POS receipts to a database, for example.
50 |
51 | At this point, you might find that the way you would like to print is not supported by escpos-php. You can post your printing command as a feature request on the issue tracker.
52 |
53 | Lastly, you may run in to the final common trap:
54 |
55 | 4. Your PHP is not running with the same sort of permissions as your login account. Again, no amount of PHP code can fix this. For example, on LAMP, your `www-data` user needs to be in the `lp` group, while on WAMP, `Local Service` account may run in to problems. SELinux and firewalls are also worth a look.
56 |
57 | When printing fails, you can expect a PHP Exception that explains what went wrong. They are all clues:
58 |
59 | - `Warning: copy(\\pc\printer): failed to open stream: Permission denied`
60 | - `/dev/usb/lp0: Permission denied`
61 | - `User name or password is incorrect`
62 |
63 | Ensure that while you are developing, you configure PHP to show error messages, so that you can see these problems.
64 |
65 | Please file a bug if you think that there is a specific situation which escpos-php could provide better error messages for.
66 |
67 | ## Can I print over the network?
68 |
69 | Certainly, as long as your printer is available over the network.
70 |
71 | - `NetworkPrintConnector` will speak directly to an Ethernet-connected printer on port 9100.
72 |
73 | For USB or Serial printers, you need to install the printer on a computer and then share it, so that it becomes network-accessible.
74 |
75 | - `WindowsPrintConnector` will connect to Windows shared printers from Windows or Linux (Linux users will need Samba).
76 | - `CupsPrintConnector` will connect to CUPS-shared printers from Linux or Mac.
77 |
78 | Always start by testing your shared printer setup outside of escpos-php. The examples linked to in the README are commented with some example commands to get you started. Typically, networks, firewalls and permissions need to be set up.
79 |
80 | Once you have a working command to send text to your printer (from the PHP server), you are ready to use escpos-php.
81 |
82 | If you have any issues at this stage, please ask on the issue tracker, and include the commands that you used to verify your setup.
83 |
84 | ## Can I print from my server on the Internet?
85 |
86 | Since PHP is a server-side language, escpos-php is a server-side print library. The driver is able to transport data between a server and a printer in a few different ways, all of them server-side. For example, you may print to a USB printer *connected to the server running PHP*, or an Ethernet printer *on a network accessible to the server*.
87 |
88 | Many developers dream of having an application that is hosted on the public Internet, with POS terminals accessing it, and printing via a web browser. Because the webserver cannot see the printer in this sort of setup, a server-side print driver is not much use.
89 |
90 | Because of this, there are no cut-and-paste recipes available, but here are two top-level approaches you could take:
91 |
92 | 1. Architect your application so that the server can see your printer
93 | 2. Use an application which runs client-side to deliver print data instead
94 |
95 | ### Option 1: Allow the server to print
96 |
97 | Server-side printing is viable if the server can get to the printer. Here are some ways it could work:
98 |
99 | - Run your server on the LAN instead, and read the section above about printing over the network
100 | - Set up a VPN so that your cloud-hosted server can also access the LAN
101 | - Expose the printer via some other secure tunnel to the server, via SSH or TLS
102 |
103 | Please do your own research to determine how these may apply to your setup- the escpos-php issue tracker is not a place where you should be requesting network support.
104 |
105 | ### Option 2: Use client software to print
106 |
107 | If you aren't able to set up some network infrastructure to implement the above, then you cannot use a server-side print driver.
108 |
109 | Here are some browser-based printing tools which you may like to consider instead.
110 |
111 | - Use system printing with a vendor driver, and some good `@media print` CSS
112 | - [Chrome Raw Print](https://github.com/receipt-print-hq/chrome-raw-print) app
113 | - [qz](https://qz.io/)
114 | - [ePOS-Device SDK for JavaScript](https://reference.epson-biz.com/modules/ref_epos_device_js_en/index.php?content_id=139). Requires network interface card that supports ePOS (UB-E04/R04)
115 |
116 | Please direct queries about client-side printing products to the appropriate project.
117 |
118 | ## Why is image printing slow?
119 |
120 | Three things tend to slow down the image processing:
121 |
122 | 1. Slow PHP code
123 | 2. Data link
124 | 3. The printer itself
125 |
126 | First, ensure you have the Imagick plugin loaded. The driver will avoid a slower image processing implementation once you've got it.
127 |
128 | Next, connect over a faster interface. Serial printers have a low bit-rate, and the printer spends a lot of time waiting for data. If you have USB or Ethernet, then use it (note: storing graphics to the printer memory is not currently implemented).
129 |
130 | Lastly, the printer will go faster if you use less pixels. Since images are two-dimensional, scaling down by 50% removes 75% of the pixels. The driver can then print at a half the density, so that your lower resolution image appears the same size when printed.
131 |
132 | ## How can I get the status of the printer?
133 |
134 | This feature is not implemented, but a solution for some Epson printers is planned.
135 |
136 | Only `FilePrintConnector` or `NetworkPrintConnector` will support reading from the printer, ensure that you migrate to those if you would like these features.
137 |
138 | ## How do I produce this complex layout?
139 |
140 | ESC/POS "page mode" is not currently supported, which would allow some printers to render some more complex layouts natively
141 |
142 | Since the output is raster anyway, it is suggested that you render your output to an image and print that instead. The driver supports PDF printing via Imagick, and an example that uses `wkhtmltoimage` is available in the repository.
143 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | html: escpos.doxyfile
2 | # Compile
3 | doxygen escpos.doxyfile
4 | # Filter out warnings on README.md- doxygen cannot handle image links that
5 | # are used there: [](https://example.com/image)
6 | sed -i '/README.md\:/d' warnings.log
7 | # Show warnings log
8 | cat warnings.log
9 | # Return failure if there were any doc warnings
10 | [ ! -s warnings.log ]
11 |
12 | latex: html
13 | # Do nothing
14 |
15 | xml: html
16 | xsltproc xml/combine.xslt xml/index.xml > all.xml
17 |
18 | clean:
19 | rm --preserve-root -Rf html latex xml doxygen_sqlite3.db all.xml warnings.log
20 |
21 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | Examples
2 | --------
3 |
4 | This folder contains a collectoion of feature examples.
5 | Generally, demo.php is the fastest way to find out which features your
6 | printer supports.
7 |
8 | ## Subfolders
9 | - `interface/` - contains examples for output interfaces: eg, parallel, serial, USB, network, file-based.
10 | - `specific/` - examples made in response to issues & questions. These cover specific languages, printers and interfaces, so hit narrower use cases.
11 |
12 | ## List of examples
13 |
14 | Each example prints to standard output, so either edit the print connector, or redirect the output to your printer to see it in action. They are designed for developers: open them in a text editor before you run them!
15 |
16 | - `bit-image.php` - Prints a images to the printer using the older "bit image" commands.
17 | - `demo.php` - Demonstrates output using a large subset of availale features.
18 | - `qr-code.php` - Prints QR codes, if your printer supports it.
19 | - `character-encodings.php` - Shows available character encodings. Change from the DefaultCapabilityProfile to get more useful output for your specific printer.
20 | - `graphics.php` - The same output as `bit-image.php`, printed with the newer graphics commands (not supported on many non-Epson printers)
21 | - `receipt-with-logo.php` - A simple receipt containing a logo and basic formating.
22 | - `character-encodings-with-images.php` - The same as `character-encodings.php`, but also prints each string using an `ImagePrintBuffer`, showing compatibility gaps.
23 | - `print-from-html.php` - Runs `wkhtmltoimage` to convert HTML to an image, and then prints the image. (This is very slow)
24 | - `character-tables.php` - Prints a compact character code table for each available character set. Used to debug incorrect output from `character-encodings.php`.
25 | - `print-from-pdf.php` - Loads a PDF and prints each page in a few different ways (very slow as well)
26 | - `rawbt-receipt` (.php & .html) - Demonstration of Back and Front for integration between the site and the Android application “RawBT - Printer Driver for Android”
27 |
--------------------------------------------------------------------------------
/example/barcode.php:
--------------------------------------------------------------------------------
1 | selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_DOUBLE_WIDTH);
11 | $printer->text("Height and bar width\n");
12 | $printer->selectPrintMode();
13 | $heights = array(1, 2, 4, 8, 16, 32);
14 | $widths = array(1, 2, 3, 4, 5, 6, 7, 8);
15 | $printer -> text("Default look\n");
16 | $printer->barcode("ABC", Printer::BARCODE_CODE39);
17 |
18 | foreach($heights as $height) {
19 | $printer -> text("\nHeight $height\n");
20 | $printer->setBarcodeHeight($height);
21 | $printer->barcode("ABC", Printer::BARCODE_CODE39);
22 | }
23 | foreach($widths as $width) {
24 | $printer -> text("\nWidth $width\n");
25 | $printer->setBarcodeWidth($width);
26 | $printer->barcode("ABC", Printer::BARCODE_CODE39);
27 | }
28 | $printer->feed();
29 | // Set to something sensible for the rest of the examples
30 | $printer->setBarcodeHeight(40);
31 | $printer->setBarcodeWidth(2);
32 |
33 | /* Text position */
34 | $printer->selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_DOUBLE_WIDTH);
35 | $printer->text("Text position\n");
36 | $printer->selectPrintMode();
37 | $hri = array (
38 | Printer::BARCODE_TEXT_NONE => "No text",
39 | Printer::BARCODE_TEXT_ABOVE => "Above",
40 | Printer::BARCODE_TEXT_BELOW => "Below",
41 | Printer::BARCODE_TEXT_ABOVE | Printer::BARCODE_TEXT_BELOW => "Both"
42 | );
43 | foreach ($hri as $position => $caption) {
44 | $printer->text($caption . "\n");
45 | $printer->setBarcodeTextPosition($position);
46 | $printer->barcode("012345678901", Printer::BARCODE_JAN13);
47 | $printer->feed();
48 | }
49 |
50 | /* Barcode types */
51 | $standards = array (
52 | Printer::BARCODE_UPCA => array (
53 | "title" => "UPC-A",
54 | "caption" => "Fixed-length numeric product barcodes.",
55 | "example" => array (
56 | array (
57 | "caption" => "12 char numeric including (wrong) check digit.",
58 | "content" => "012345678901"
59 | ),
60 | array (
61 | "caption" => "Send 11 chars to add check digit automatically.",
62 | "content" => "01234567890"
63 | )
64 | )
65 | ),
66 | Printer::BARCODE_UPCE => array (
67 | "title" => "UPC-E",
68 | "caption" => "Fixed-length numeric compact product barcodes.",
69 | "example" => array (
70 | array (
71 | "caption" => "6 char numeric - auto check digit & NSC",
72 | "content" => "123456"
73 | ),
74 | array (
75 | "caption" => "7 char numeric - auto check digit",
76 | "content" => "0123456"
77 | ),
78 | array (
79 | "caption" => "8 char numeric",
80 | "content" => "01234567"
81 | ),
82 | array (
83 | "caption" => "11 char numeric - auto check digit",
84 | "content" => "01234567890"
85 | ),
86 | array (
87 | "caption" => "12 char numeric including (wrong) check digit",
88 | "content" => "012345678901"
89 | )
90 | )
91 | ),
92 | Printer::BARCODE_JAN13 => array (
93 | "title" => "JAN13/EAN13",
94 | "caption" => "Fixed-length numeric barcodes.",
95 | "example" => array (
96 | array (
97 | "caption" => "12 char numeric - auto check digit",
98 | "content" => "012345678901"
99 | ),
100 | array (
101 | "caption" => "13 char numeric including (wrong) check digit",
102 | "content" => "0123456789012"
103 | )
104 | )
105 | ),
106 | Printer::BARCODE_JAN8 => array (
107 | "title" => "JAN8/EAN8",
108 | "caption" => "Fixed-length numeric barcodes.",
109 | "example" => array (
110 | array (
111 | "caption" => "7 char numeric - auto check digit",
112 | "content" => "0123456"
113 | ),
114 | array (
115 | "caption" => "8 char numeric including (wrong) check digit",
116 | "content" => "01234567"
117 | )
118 | )
119 | ),
120 | Printer::BARCODE_CODE39 => array (
121 | "title" => "Code39",
122 | "caption" => "Variable length alphanumeric w/ some special chars.",
123 | "example" => array (
124 | array (
125 | "caption" => "Text, numbers, spaces",
126 | "content" => "ABC 012"
127 | ),
128 | array (
129 | "caption" => "Special characters",
130 | "content" => "$%+-./"
131 | ),
132 | array (
133 | "caption" => "Extra char (*) Used as start/stop",
134 | "content" => "*TEXT*"
135 | )
136 | )
137 | ),
138 | Printer::BARCODE_ITF => array (
139 | "title" => "ITF",
140 | "caption" => "Variable length numeric w/even number of digits,\nas they are encoded in pairs.",
141 | "example" => array (
142 | array (
143 | "caption" => "Numeric- even number of digits",
144 | "content" => "0123456789"
145 | )
146 | )
147 | ),
148 | Printer::BARCODE_CODABAR => array (
149 | "title" => "Codabar",
150 | "caption" => "Varaible length numeric with some allowable\nextra characters. ABCD/abcd must be used as\nstart/stop characters (one at the start, one\nat the end) to distinguish between barcode\napplications.",
151 | "example" => array (
152 | array (
153 | "caption" => "Numeric w/ A A start/stop. ",
154 | "content" => "A012345A"
155 | ),
156 | array (
157 | "caption" => "Extra allowable characters",
158 | "content" => "A012$+-./:A"
159 | )
160 | )
161 | ),
162 | Printer::BARCODE_CODE93 => array (
163 | "title" => "Code93",
164 | "caption" => "Variable length- any ASCII is available",
165 | "example" => array (
166 | array (
167 | "caption" => "Text",
168 | "content" => "012abcd"
169 | )
170 | )
171 | ),
172 | Printer::BARCODE_CODE128 => array (
173 | "title" => "Code128",
174 | "caption" => "Variable length- any ASCII is available",
175 | "example" => array (
176 | array (
177 | "caption" => "Code set A uppercase & symbols",
178 | "content" => "{A" . "012ABCD"
179 | ),
180 | array (
181 | "caption" => "Code set B general text",
182 | "content" => "{B" . "012ABCDabcd"
183 | ),
184 | array (
185 | "caption" => "Code set C compact numbers\n Sending chr(21) chr(32) chr(43)",
186 | "content" => "{C" . chr(21) . chr(32) . chr(43)
187 | )
188 | )
189 | )
190 | );
191 | $printer->setBarcodeTextPosition(Printer::BARCODE_TEXT_BELOW);
192 | foreach ($standards as $type => $standard) {
193 | $printer->selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_DOUBLE_WIDTH);
194 | $printer->text($standard ["title"] . "\n");
195 | $printer->selectPrintMode();
196 | $printer->text($standard ["caption"] . "\n\n");
197 | foreach ($standard ["example"] as $id => $barcode) {
198 | $printer->setEmphasis(true);
199 | $printer->text($barcode ["caption"] . "\n");
200 | $printer->setEmphasis(false);
201 | $printer->text("Content: " . $barcode ["content"] . "\n");
202 | $printer->barcode($barcode ["content"], $type);
203 | $printer->feed();
204 | }
205 | }
206 | $printer->cut();
207 | $printer->close();
208 |
--------------------------------------------------------------------------------
/example/bit-image.php:
--------------------------------------------------------------------------------
1 | text("These example images are printed with the older\nbit image print command. You should only use\n\$p -> bitImage() if \$p -> graphics() does not\nwork on your printer.\n\n");
15 |
16 | $printer -> bitImage($tux);
17 | $printer -> text("Regular Tux (bit image).\n");
18 | $printer -> feed();
19 |
20 | $printer -> bitImage($tux, Printer::IMG_DOUBLE_WIDTH);
21 | $printer -> text("Wide Tux (bit image).\n");
22 | $printer -> feed();
23 |
24 | $printer -> bitImage($tux, Printer::IMG_DOUBLE_HEIGHT);
25 | $printer -> text("Tall Tux (bit image).\n");
26 | $printer -> feed();
27 |
28 | $printer -> bitImage($tux, Printer::IMG_DOUBLE_WIDTH | Printer::IMG_DOUBLE_HEIGHT);
29 | $printer -> text("Large Tux in correct proportion (bit image).\n");
30 | } catch (Exception $e) {
31 | /* Images not supported on your PHP, or image file not found */
32 | $printer -> text($e -> getMessage() . "\n");
33 | }
34 |
35 | $printer -> cut();
36 | $printer -> close();
37 |
--------------------------------------------------------------------------------
/example/character-encodings-with-images.php:
--------------------------------------------------------------------------------
1 | selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_EMPHASIZED | Printer::MODE_DOUBLE_WIDTH);
30 | $printer -> text("Implemented languages\n");
31 | $printer -> selectPrintMode();
32 | foreach ($inputsOk as $label => $str) {
33 | $printer -> setEmphasis(true);
34 | $printer -> text($label . ":\n");
35 | $printer -> setEmphasis(false);
36 | foreach ($buffers as $buffer) {
37 | $printer -> setPrintBuffer($buffer);
38 | $printer -> text($str);
39 | }
40 | $printer -> setPrintBuffer($buffers[0]);
41 | }
42 | $printer -> feed();
43 |
44 | $printer -> selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_EMPHASIZED | Printer::MODE_DOUBLE_WIDTH);
45 | $printer -> text("Works in progress\n");
46 | $printer -> selectPrintMode();
47 | foreach ($inputsNotOk as $label => $str) {
48 | $printer -> setEmphasis(true);
49 | $printer -> text($label . ":\n");
50 | $printer -> setEmphasis(false);
51 | foreach ($buffers as $buffer) {
52 | $printer -> setPrintBuffer($buffer);
53 | $printer -> text($str);
54 | }
55 | $printer -> setPrintBuffer($buffers[0]);
56 | }
57 | $printer -> cut();
58 |
59 | /* Close printer */
60 | $printer -> close();
61 | } catch (Exception $e) {
62 | echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
63 | }
64 |
--------------------------------------------------------------------------------
/example/character-encodings.php:
--------------------------------------------------------------------------------
1 | selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_EMPHASIZED | Printer::MODE_DOUBLE_WIDTH);
35 | $printer -> text("Implemented languages\n");
36 | $printer -> selectPrintMode();
37 | foreach ($inputsOk as $label => $str) {
38 | $printer -> setEmphasis(true);
39 | $printer -> text($label . ":\n");
40 | $printer -> setEmphasis(false);
41 | $printer -> text($str);
42 | }
43 | $printer -> feed();
44 |
45 | $printer -> selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_EMPHASIZED | Printer::MODE_DOUBLE_WIDTH);
46 | $printer -> text("Works in progress\n");
47 | $printer -> selectPrintMode();
48 | foreach ($inputsNotOk as $label => $str) {
49 | $printer -> setEmphasis(true);
50 | $printer -> text($label . ":\n");
51 | $printer -> setEmphasis(false);
52 | $printer -> text($str);
53 | }
54 | $printer -> cut();
55 |
56 | /* Close printer */
57 | $printer -> close();
58 | } catch (Exception $e) {
59 | echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
60 | }
61 |
--------------------------------------------------------------------------------
/example/character-tables.php:
--------------------------------------------------------------------------------
1 | getCodePages();
30 | $first = true; // Print larger table for first code-page.
31 | foreach ($codePages as $table => $page) {
32 | /* Change printer code page */
33 | $printer -> selectCharacterTable(255);
34 | $printer -> selectCharacterTable($table);
35 | /* Select & print a label for it */
36 | $label = $page -> getId();
37 | if (!$page -> isEncodable()) {
38 | $label= " (not supported)";
39 | }
40 | $printer -> setEmphasis(true);
41 | $printer -> textRaw("Table $table: $label\n");
42 | $printer -> setEmphasis(false);
43 | if (!$page -> isEncodable() && !$verbose) {
44 | continue; // Skip non-recognised
45 | }
46 | /* Print a table of available characters (first table is larger than subsequent ones */
47 | if ($first) {
48 | $first = false;
49 | compactCharTable($printer, 1, true);
50 | } else {
51 | compactCharTable($printer);
52 | }
53 | }
54 | $printer -> cut();
55 | $printer -> close();
56 |
57 | function compactCharTable($printer, $start = 4, $header = false)
58 | {
59 | /* Output a compact character table for the current encoding */
60 | $chars = str_repeat(' ', 256);
61 | for ($i = 0; $i < 255; $i++) {
62 | $chars[$i] = ($i > 32 && $i != 127) ? chr($i) : ' ';
63 | }
64 | if ($header) {
65 | $printer -> setEmphasis(true);
66 | $printer -> textRaw(" 0123456789ABCDEF0123456789ABCDEF\n");
67 | $printer -> setEmphasis(false);
68 | }
69 | for ($y = $start; $y < 8; $y++) {
70 | $printer -> setEmphasis(true);
71 | $printer -> textRaw(strtoupper(dechex($y * 2)) . " ");
72 | $printer -> setEmphasis(false);
73 | $printer -> textRaw(substr($chars, $y * 32, 32) . "\n");
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/example/customer-display.php:
--------------------------------------------------------------------------------
1 | feed();
42 | $display -> text($line);
43 | usleep(500000);
44 | }
45 |
46 | // Finish by showing "Hello World"
47 | $display -> clear();
48 | $display -> text("Hello World\n");
49 |
50 | // Dont forget to close the device
51 | $display -> close();
52 |
--------------------------------------------------------------------------------
/example/demo.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | require __DIR__ . '/../vendor/autoload.php';
12 | use Mike42\Escpos\Printer;
13 | use Mike42\Escpos\PrintConnectors\FilePrintConnector;
14 | use Mike42\Escpos\EscposImage;
15 |
16 | $connector = new FilePrintConnector("php://stdout");
17 | $printer = new Printer($connector);
18 |
19 | /* Initialize */
20 | $printer -> initialize();
21 |
22 | /* Text */
23 | $printer -> text("Hello world\n");
24 | $printer -> cut();
25 |
26 | /* Line feeds */
27 | $printer -> text("ABC");
28 | $printer -> feed(7);
29 | $printer -> text("DEF");
30 | $printer -> feedReverse(3);
31 | $printer -> text("GHI");
32 | $printer -> feed();
33 | $printer -> cut();
34 |
35 | /* Font modes */
36 | $modes = array(
37 | Printer::MODE_FONT_B,
38 | Printer::MODE_EMPHASIZED,
39 | Printer::MODE_DOUBLE_HEIGHT,
40 | Printer::MODE_DOUBLE_WIDTH,
41 | Printer::MODE_UNDERLINE);
42 | for ($i = 0; $i < pow(2, count($modes)); $i++) {
43 | $bits = str_pad(decbin($i), count($modes), "0", STR_PAD_LEFT);
44 | $mode = 0;
45 | for ($j = 0; $j < strlen($bits); $j++) {
46 | if (substr($bits, $j, 1) == "1") {
47 | $mode |= $modes[$j];
48 | }
49 | }
50 | $printer -> selectPrintMode($mode);
51 | $printer -> text("ABCDEFGHIJabcdefghijk\n");
52 | }
53 | $printer -> selectPrintMode(); // Reset
54 | $printer -> cut();
55 |
56 | /* Underline */
57 | for ($i = 0; $i < 3; $i++) {
58 | $printer -> setUnderline($i);
59 | $printer -> text("The quick brown fox jumps over the lazy dog\n");
60 | }
61 | $printer -> setUnderline(0); // Reset
62 | $printer -> cut();
63 |
64 | /* Cuts */
65 | $printer -> text("Partial cut\n(not available on all printers)\n");
66 | $printer -> cut(Printer::CUT_PARTIAL);
67 | $printer -> text("Full cut\n");
68 | $printer -> cut(Printer::CUT_FULL);
69 |
70 | /* Emphasis */
71 | for ($i = 0; $i < 2; $i++) {
72 | $printer -> setEmphasis($i == 1);
73 | $printer -> text("The quick brown fox jumps over the lazy dog\n");
74 | }
75 | $printer -> setEmphasis(false); // Reset
76 | $printer -> cut();
77 |
78 | /* Double-strike (looks basically the same as emphasis) */
79 | for ($i = 0; $i < 2; $i++) {
80 | $printer -> setDoubleStrike($i == 1);
81 | $printer -> text("The quick brown fox jumps over the lazy dog\n");
82 | }
83 | $printer -> setDoubleStrike(false);
84 | $printer -> cut();
85 |
86 | /* Fonts (many printers do not have a 'Font C') */
87 | $fonts = array(
88 | Printer::FONT_A,
89 | Printer::FONT_B,
90 | Printer::FONT_C);
91 | for ($i = 0; $i < count($fonts); $i++) {
92 | $printer -> setFont($fonts[$i]);
93 | $printer -> text("The quick brown fox jumps over the lazy dog\n");
94 | }
95 | $printer -> setFont(); // Reset
96 | $printer -> cut();
97 |
98 | /* Justification */
99 | $justification = array(
100 | Printer::JUSTIFY_LEFT,
101 | Printer::JUSTIFY_CENTER,
102 | Printer::JUSTIFY_RIGHT);
103 | for ($i = 0; $i < count($justification); $i++) {
104 | $printer -> setJustification($justification[$i]);
105 | $printer -> text("A man a plan a canal panama\n");
106 | }
107 | $printer -> setJustification(); // Reset
108 | $printer -> cut();
109 |
110 | /* Barcodes - see barcode.php for more detail */
111 | $printer -> setBarcodeHeight(80);
112 | $printer->setBarcodeTextPosition(Printer::BARCODE_TEXT_BELOW);
113 | $printer -> barcode("9876");
114 | $printer -> feed();
115 | $printer -> cut();
116 |
117 | /* Graphics - this demo will not work on some non-Epson printers */
118 | try {
119 | $logo = EscposImage::load("resources/escpos-php.png", false);
120 | $imgModes = array(
121 | Printer::IMG_DEFAULT,
122 | Printer::IMG_DOUBLE_WIDTH,
123 | Printer::IMG_DOUBLE_HEIGHT,
124 | Printer::IMG_DOUBLE_WIDTH | Printer::IMG_DOUBLE_HEIGHT
125 | );
126 | foreach ($imgModes as $mode) {
127 | $printer -> graphics($logo, $mode);
128 | }
129 | } catch (Exception $e) {
130 | /* Images not supported on your PHP, or image file not found */
131 | $printer -> text($e -> getMessage() . "\n");
132 | }
133 | $printer -> cut();
134 |
135 | /* Bit image */
136 | try {
137 | $logo = EscposImage::load("resources/escpos-php.png", false);
138 | $imgModes = array(
139 | Printer::IMG_DEFAULT,
140 | Printer::IMG_DOUBLE_WIDTH,
141 | Printer::IMG_DOUBLE_HEIGHT,
142 | Printer::IMG_DOUBLE_WIDTH | Printer::IMG_DOUBLE_HEIGHT
143 | );
144 | foreach ($imgModes as $mode) {
145 | $printer -> bitImage($logo, $mode);
146 | }
147 | } catch (Exception $e) {
148 | /* Images not supported on your PHP, or image file not found */
149 | $printer -> text($e -> getMessage() . "\n");
150 | }
151 | $printer -> cut();
152 |
153 | /* QR Code - see also the more in-depth demo at qr-code.php */
154 | $testStr = "Testing 123";
155 | $models = array(
156 | Printer::QR_MODEL_1 => "QR Model 1",
157 | Printer::QR_MODEL_2 => "QR Model 2 (default)",
158 | Printer::QR_MICRO => "Micro QR code\n(not supported on all printers)");
159 | foreach ($models as $model => $name) {
160 | $printer -> qrCode($testStr, Printer::QR_ECLEVEL_L, 3, $model);
161 | $printer -> text("$name\n");
162 | $printer -> feed();
163 | }
164 | $printer -> cut();
165 |
166 | /* Pulse */
167 | $printer -> pulse();
168 |
169 | /* Always close the printer! On some PrintConnectors, no actual
170 | * data is sent until the printer is closed. */
171 | $printer -> close();
172 |
--------------------------------------------------------------------------------
/example/graphics.php:
--------------------------------------------------------------------------------
1 | graphics($tux);
16 | $printer -> text("Regular Tux.\n");
17 | $printer -> feed();
18 |
19 | $printer -> graphics($tux, Printer::IMG_DOUBLE_WIDTH);
20 | $printer -> text("Wide Tux.\n");
21 | $printer -> feed();
22 |
23 | $printer -> graphics($tux, Printer::IMG_DOUBLE_HEIGHT);
24 | $printer -> text("Tall Tux.\n");
25 | $printer -> feed();
26 |
27 | $printer -> graphics($tux, Printer::IMG_DOUBLE_WIDTH | Printer::IMG_DOUBLE_HEIGHT);
28 | $printer -> text("Large Tux in correct proportion.\n");
29 |
30 | $printer -> cut();
31 | } catch (Exception $e) {
32 | /* Images not supported on your PHP, or image file not found */
33 | $printer -> text($e -> getMessage() . "\n");
34 | }
35 |
36 | $printer -> close();
37 |
--------------------------------------------------------------------------------
/example/interface/README.md:
--------------------------------------------------------------------------------
1 | Interfaces
2 | ----------
3 | This directory contains boilerpalte code to show you how to open a print connector
4 | to printers which are connected in different ways.
5 |
6 | To get a list of supported interfaces and operating systems, see the main README.md file for the project.
7 |
8 | If you have a printer interface with no example, and you want to help put one together, then please lodge a request on the bug tracker: https://github.com/mike42/escpos-php/issues
9 |
--------------------------------------------------------------------------------
/example/interface/cups.php:
--------------------------------------------------------------------------------
1 | text("Hello World!\n");
13 | $printer -> cut();
14 |
15 | /* Close printer */
16 | $printer -> close();
17 | } catch (Exception $e) {
18 | echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
19 | }
20 |
--------------------------------------------------------------------------------
/example/interface/ethernet.php:
--------------------------------------------------------------------------------
1 | text("Hello World!\n");
16 | $printer -> cut();
17 |
18 | /* Close printer */
19 | $printer -> close();
20 | } catch (Exception $e) {
21 | echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
22 | }
23 |
--------------------------------------------------------------------------------
/example/interface/linux-usb.php:
--------------------------------------------------------------------------------
1 | text("Hello World!\n");
27 | $printer -> cut();
28 |
29 | /* Close printer */
30 | $printer -> close();
31 | } catch (Exception $e) {
32 | echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
33 | }
34 |
--------------------------------------------------------------------------------
/example/interface/smb.php:
--------------------------------------------------------------------------------
1 | testfile
19 | * ## If you need authentication, use "net use" to hook up the printer:
20 | * # net use "\\computername\Receipt Printer" /user:Guest
21 | * # net use "\\computername\Receipt Printer" /user:Bob secret
22 | * # net use "\\computername\Receipt Printer" /user:workgroup\Bob secret
23 | * copy testfile "\\computername\Receipt Printer"
24 | * del testfile
25 | *
26 | * GNU/Linux:
27 | * # No authentication
28 | * echo "Hello World" | smbclient "//computername/Receipt Printer" -c "print -" -N
29 | * # Guest login
30 | * echo "Hello World" | smbclient "//computername/Receipt Printer" -U Guest -c "print -" -N
31 | * # Basic username/password
32 | * echo "Hello World" | smbclient "//computername/Receipt Printer" secret -U "Bob" -c "print -"
33 | * # Including domain name
34 | * echo "Hello World" | smbclient "//computername/Receipt Printer" secret -U "workgroup\\Bob" -c "print -"
35 | */
36 | try {
37 | // Enter the share name for your printer here, as a smb:// url format
38 | $connector = new WindowsPrintConnector("smb://computername/Receipt Printer");
39 | //$connector = new WindowsPrintConnector("smb://Guest@computername/Receipt Printer");
40 | //$connector = new WindowsPrintConnector("smb://FooUser:secret@computername/workgroup/Receipt Printer");
41 | //$connector = new WindowsPrintConnector("smb://User:secret@computername/Receipt Printer");
42 |
43 | /* Print a "Hello world" receipt" */
44 | $printer = new Printer($connector);
45 | $printer -> text("Hello World!\n");
46 | $printer -> cut();
47 |
48 | /* Close printer */
49 | $printer -> close();
50 | } catch (Exception $e) {
51 | echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
52 | }
53 |
--------------------------------------------------------------------------------
/example/interface/windows-lpt.php:
--------------------------------------------------------------------------------
1 | LPT1
14 | */
15 | try {
16 | $connector = new WindowsPrintConnector("LPT1");
17 |
18 | // A FilePrintConnector will also work, but on non-Windows systems, writes
19 | // to an actual file called 'LPT1' rather than giving a useful error.
20 | // $connector = new FilePrintConnector("LPT1");
21 |
22 | /* Print a "Hello world" receipt" */
23 | $printer = new Printer($connector);
24 | $printer -> text("Hello World!\n");
25 | $printer -> cut();
26 |
27 | /* Close printer */
28 | $printer -> close();
29 | } catch (Exception $e) {
30 | echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
31 | }
32 |
--------------------------------------------------------------------------------
/example/interface/windows-usb.php:
--------------------------------------------------------------------------------
1 | testfile
17 | * copy testfile "\\%COMPUTERNAME%\Receipt Printer"
18 | * del testfile
19 | */
20 | try {
21 | // Enter the share name for your USB printer here
22 | $connector = null;
23 | //$connector = new WindowsPrintConnector("Receipt Printer");
24 |
25 | /* Print a "Hello world" receipt" */
26 | $printer = new Printer($connector);
27 | $printer -> text("Hello World!\n");
28 | $printer -> cut();
29 |
30 | /* Close printer */
31 | $printer -> close();
32 | } catch (Exception $e) {
33 | echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
34 | }
35 |
--------------------------------------------------------------------------------
/example/margins-and-spacing.php:
--------------------------------------------------------------------------------
1 | setEmphasis(true);
13 | $printer -> text("Line spacing\n");
14 | $printer -> setEmphasis(false);
15 | foreach(array(16, 32, 64, 128, 255) as $spacing) {
16 | $printer -> setLineSpacing($spacing);
17 | $printer -> text("Spacing $spacing: The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.\n");
18 | }
19 | $printer -> setLineSpacing(); // Back to default
20 | */
21 |
22 | /* Stuff around with left margin */
23 | $printer -> setEmphasis(true);
24 | $printer -> text("Left margin\n");
25 | $printer -> setEmphasis(false);
26 | $printer -> text("Default left\n");
27 | foreach(array(1, 2, 4, 8, 16, 32, 64, 128, 256, 512) as $margin) {
28 | $printer -> setPrintLeftMargin($margin);
29 | $printer -> text("left margin $margin\n");
30 | }
31 | /* Reset left */
32 | $printer -> setPrintLeftMargin(0);
33 |
34 | /* Stuff around with page width */
35 | $printer -> setEmphasis(true);
36 | $printer -> text("Page width\n");
37 | $printer -> setEmphasis(false);
38 | $printer -> setJustification(Printer::JUSTIFY_RIGHT);
39 | $printer -> text("Default width\n");
40 | foreach(array(512, 256, 128, 64) as $width) {
41 | $printer -> setPrintWidth($width);
42 | $printer -> text("page width $width\n");
43 | }
44 |
45 | /* Printer shutdown */
46 | $printer -> cut();
47 | $printer -> close();
48 |
49 |
--------------------------------------------------------------------------------
/example/pdf417-code.php:
--------------------------------------------------------------------------------
1 | pdf417Code($testStr);
14 | $printer -> text("Most simple example\n");
15 | $printer -> feed();
16 |
17 | // Demo that alignment is the same as text
18 | $printer -> setJustification(Printer::JUSTIFY_CENTER);
19 | $printer -> pdf417Code($testStr, 3, 3, 2);
20 | $printer -> text("Same content, narrow and centred\n");
21 | $printer -> setJustification();
22 | $printer -> feed();
23 |
24 | // Demo of error correction
25 | title($printer, "Error correction\n");
26 | $ec = array(0.1, 0.5, 1.0, 2.0, 4.0);
27 | foreach ($ec as $level) {
28 | $printer -> pdf417Code($testStr, 3, 3, 0, $level);
29 | $printer -> text("Error correction ratio $level\n");
30 | $printer -> feed();
31 | }
32 |
33 | // Change size
34 | title($printer, "Pixel size\n");
35 | $sizes = array(
36 | 2 => "(minimum)",
37 | 3 => "(default)",
38 | 4 => "",
39 | 8 => "(maximum)");
40 | foreach ($sizes as $size => $label) {
41 | $printer -> pdf417Code($testStr, $size);
42 | $printer -> text("Module width $size dots $label\n");
43 | $printer -> feed();
44 | }
45 |
46 | // Change height
47 | title($printer, "Height multiplier\n");
48 | $sizes = array(
49 | 2 => "(minimum)",
50 | 3 => "(default)",
51 | 4 => "",
52 | 8 => "(maximum)");
53 | foreach ($sizes as $size => $label) {
54 | $printer -> pdf417Code($testStr, 3, $size);
55 | $printer -> text("Height multiplier $size $label\n");
56 | $printer -> feed();
57 | }
58 |
59 | // Chage data column count
60 | title($printer, "Data column count\n");
61 | $columnCounts = array(
62 | 0 => "(auto, default)",
63 | 1 => "",
64 | 2 => "",
65 | 3 => "",
66 | 4 => "",
67 | 5 => "",
68 | 30 => "(maximum, doesnt fit!)");
69 | foreach ($columnCounts as $columnCount => $label) {
70 | $printer -> pdf417Code($testStr, 3, 3, $columnCount);
71 | $printer -> text("Column count $columnCount $label\n");
72 | $printer -> feed();
73 | }
74 |
75 | // Change options
76 | title($printer, "Options\n");
77 | $models = array(
78 | Printer::PDF417_STANDARD => "Standard",
79 | Printer::PDF417_TRUNCATED => "Truncated");
80 | foreach ($models as $model => $name) {
81 | $printer -> pdf417Code($testStr, 3, 3, 0, 0.10, $model);
82 | $printer -> text("$name\n");
83 | $printer -> feed();
84 | }
85 |
86 | // Cut & close
87 | $printer -> cut();
88 | $printer -> close();
89 |
90 | function title(Printer $printer, $str)
91 | {
92 | $printer -> selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_DOUBLE_WIDTH);
93 | $printer -> text($str);
94 | $printer -> selectPrintMode();
95 | }
96 |
--------------------------------------------------------------------------------
/example/print-from-html.php:
--------------------------------------------------------------------------------
1 | 225 below) and printing w/ Escpos::IMG_DOUBLE_WIDTH | Escpos::IMG_DOUBLE_HEIGHT
25 | */
26 | try {
27 | /* Set up command */
28 | $source = __DIR__ . "/resources/document.html";
29 | $width = 550;
30 | $dest = tempnam(sys_get_temp_dir(), 'escpos') . ".png";
31 | $command = sprintf(
32 | "xvfb-run wkhtmltoimage -n -q --width %s %s %s",
33 | escapeshellarg($width),
34 | escapeshellarg($source),
35 | escapeshellarg($dest)
36 | );
37 |
38 | /* Test for dependencies */
39 | foreach (array("xvfb-run", "wkhtmltoimage") as $cmd) {
40 | $testCmd = sprintf("which %s", escapeshellarg($cmd));
41 | exec($testCmd, $testOut, $testStatus);
42 | if ($testStatus != 0) {
43 | throw new Exception("You require $cmd but it could not be found");
44 | }
45 | }
46 |
47 |
48 | /* Run wkhtmltoimage */
49 | $descriptors = array(
50 | 1 => array("pipe", "w"),
51 | 2 => array("pipe", "w"),
52 | );
53 | $process = proc_open($command, $descriptors, $fd);
54 | if (is_resource($process)) {
55 | /* Read stdout */
56 | $outputStr = stream_get_contents($fd[1]);
57 | fclose($fd[1]);
58 | /* Read stderr */
59 | $errorStr = stream_get_contents($fd[2]);
60 | fclose($fd[2]);
61 | /* Finish up */
62 | $retval = proc_close($process);
63 | if ($retval != 0) {
64 | throw new Exception("Command $cmd failed: $outputStr $errorStr");
65 | }
66 | } else {
67 | throw new Exception("Command '$cmd' failed to start.");
68 | }
69 |
70 | /* Load up the image */
71 | try {
72 | $img = EscposImage::load($dest);
73 | } catch (Exception $e) {
74 | unlink($dest);
75 | throw $e;
76 | }
77 | unlink($dest);
78 |
79 | /* Print it */
80 | $printer -> bitImage($img); // bitImage() seems to allow larger images than graphics() on the TM-T20. bitImageColumnFormat() is another option.
81 | $printer -> cut();
82 | } catch (Exception $e) {
83 | echo $e -> getMessage();
84 | } finally {
85 | $printer -> close();
86 | }
87 |
--------------------------------------------------------------------------------
/example/print-from-pdf.php:
--------------------------------------------------------------------------------
1 | graphics($page);
22 | }
23 | $printer -> cut();
24 | } catch (Exception $e) {
25 | /*
26 | * loadPdf() throws exceptions if files or not found, or you don't have the
27 | * imagick extension to read PDF's
28 | */
29 | echo $e -> getMessage() . "\n";
30 | } finally {
31 | $printer -> close();
32 | }
33 |
34 |
35 | /*
36 | * 2: Speed up printing by roughly halving the resolution, and printing double-size.
37 | * This gives a 75% speed increase at the expense of some quality.
38 | *
39 | * Reduce the page width further if necessary: if it extends past the printing area, your prints will be very slow.
40 | */
41 | $connector = new FilePrintConnector("php://stdout");
42 | $printer = new Printer($connector);
43 | $pdf = 'resources/document.pdf';
44 | $pages = ImagickEscposImage::loadPdf($pdf, 260);
45 | foreach ($pages as $page) {
46 | $printer -> graphics($page, Printer::IMG_DOUBLE_HEIGHT | Printer::IMG_DOUBLE_WIDTH);
47 | }
48 | $printer -> cut();
49 | $printer -> close();
50 |
51 | /*
52 | * 3: PDF printing still too slow? If you regularly print the same files, serialize & compress your
53 | * EscposImage objects (after printing[1]), instead of throwing them away.
54 | *
55 | * (You can also do this to print logos on computers which don't have an
56 | * image processing library, by preparing a serialized version of your logo on your PC)
57 | *
58 | * [1]After printing, the pixels are loaded and formatted for the print command you used, so even a raspberry pi can print complex PDF's quickly.
59 | */
60 | $connector = new FilePrintConnector("php://stdout");
61 | $printer = new Printer($connector);
62 | $pdf = 'resources/document.pdf';
63 | $ser = 'resources/document.z';
64 | if (!file_exists($ser)) {
65 | $pages = ImagickEscposImage::loadPdf($pdf);
66 | } else {
67 | $pages = unserialize(gzuncompress(file_get_contents($ser)));
68 | }
69 |
70 | foreach ($pages as $page) {
71 | $printer -> graphics($page);
72 | }
73 | $printer -> cut();
74 | $printer -> close();
75 |
76 | if (!file_exists($ser)) {
77 | file_put_contents($ser, gzcompress(serialize($pages)));
78 | }
79 |
--------------------------------------------------------------------------------
/example/qr-code.php:
--------------------------------------------------------------------------------
1 | qrCode($testStr);
14 | $printer -> text("Most simple example\n");
15 | $printer -> feed();
16 |
17 | // Demo that alignment is the same as text
18 | $printer -> setJustification(Printer::JUSTIFY_CENTER);
19 | $printer -> qrCode($testStr);
20 | $printer -> text("Same example, centred\n");
21 | $printer -> setJustification();
22 | $printer -> feed();
23 |
24 | // Demo of numeric data being packed more densly
25 | title($printer, "Data encoding\n");
26 | $test = array(
27 | "Numeric" => "0123456789012345678901234567890123456789",
28 | "Alphanumeric" => "abcdefghijklmnopqrstuvwxyzabcdefghijklmn",
29 | "Binary" => str_repeat("\0", 40));
30 | foreach ($test as $type => $data) {
31 | $printer -> qrCode($data);
32 | $printer -> text("$type\n");
33 | $printer -> feed();
34 | }
35 |
36 | // Demo of error correction
37 | title($printer, "Error correction\n");
38 | $ec = array(
39 | Printer::QR_ECLEVEL_L => "L",
40 | Printer::QR_ECLEVEL_M => "M",
41 | Printer::QR_ECLEVEL_Q => "Q",
42 | Printer::QR_ECLEVEL_H => "H");
43 | foreach ($ec as $level => $name) {
44 | $printer -> qrCode($testStr, $level);
45 | $printer -> text("Error correction $name\n");
46 | $printer -> feed();
47 | }
48 |
49 | // Change size
50 | title($printer, "Pixel size\n");
51 | $sizes = array(
52 | 1 => "(minimum)",
53 | 2 => "",
54 | 3 => "(default)",
55 | 4 => "",
56 | 5 => "",
57 | 10 => "",
58 | 16 => "(maximum)");
59 | foreach ($sizes as $size => $label) {
60 | $printer -> qrCode($testStr, Printer::QR_ECLEVEL_L, $size);
61 | $printer -> text("Pixel size $size $label\n");
62 | $printer -> feed();
63 | }
64 |
65 | // Change model
66 | title($printer, "QR model\n");
67 | $models = array(
68 | Printer::QR_MODEL_1 => "QR Model 1",
69 | Printer::QR_MODEL_2 => "QR Model 2 (default)",
70 | Printer::QR_MICRO => "Micro QR code\n(not supported on all printers)");
71 | foreach ($models as $model => $name) {
72 | $printer -> qrCode($testStr, Printer::QR_ECLEVEL_L, 3, $model);
73 | $printer -> text("$name\n");
74 | $printer -> feed();
75 | }
76 |
77 | // Cut & close
78 | $printer -> cut();
79 | $printer -> close();
80 |
81 | function title(Printer $printer, $str)
82 | {
83 | $printer -> selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_DOUBLE_WIDTH);
84 | $printer -> text($str);
85 | $printer -> selectPrintMode();
86 | }
87 |
--------------------------------------------------------------------------------
/example/rawbt-receipt.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | RawBT Integration Demo
6 |
7 |
8 |
46 |
61 |
62 |
63 |
64 |
65 | RawBT Integration Demo
66 |
67 |
68 | window.location.href = ajax_backend_data;
69 |
70 |
71 |
72 |
73 |
74 | Visit RawBT site
75 |
76 |
77 |
--------------------------------------------------------------------------------
/example/rawbt-receipt.php:
--------------------------------------------------------------------------------
1 | getSupportsGraphics()) {
36 | $printer->graphics($logo);
37 | }
38 | if ($profile->getSupportsBitImageRaster() && !$profile->getSupportsGraphics()) {
39 | $printer->bitImage($logo);
40 | }
41 |
42 | /* Name of shop */
43 | $printer->setJustification(Printer::JUSTIFY_CENTER);
44 | $printer->selectPrintMode(Printer::MODE_DOUBLE_WIDTH);
45 | $printer->text("ExampleMart Ltd.\n");
46 | $printer->selectPrintMode();
47 | $printer->text("Shop No. 42.\n");
48 | $printer->feed();
49 |
50 |
51 | /* Title of receipt */
52 | $printer->setEmphasis(true);
53 | $printer->text("SALES INVOICE\n");
54 | $printer->setEmphasis(false);
55 |
56 | /* Items */
57 | $printer->setJustification(Printer::JUSTIFY_LEFT);
58 | $printer->setEmphasis(true);
59 | $printer->text(new item('', '$'));
60 | $printer->setEmphasis(false);
61 | foreach ($items as $item) {
62 | $printer->text($item->getAsString(32)); // for 58mm Font A
63 | }
64 | $printer->setEmphasis(true);
65 | $printer->text($subtotal->getAsString(32));
66 | $printer->setEmphasis(false);
67 | $printer->feed();
68 |
69 | /* Tax and total */
70 | $printer->text($tax->getAsString(32));
71 | $printer->selectPrintMode(Printer::MODE_DOUBLE_WIDTH);
72 | $printer->text($total->getAsString(32));
73 | $printer->selectPrintMode();
74 |
75 | /* Footer */
76 | $printer->feed(2);
77 | $printer->setJustification(Printer::JUSTIFY_CENTER);
78 | $printer->text("Thank you for shopping\n");
79 | $printer->text("at ExampleMart\n");
80 | $printer->text("For trading hours,\n");
81 | $printer->text("please visit example.com\n");
82 | $printer->feed(2);
83 | $printer->text($date . "\n");
84 |
85 | /* Barcode Default look */
86 |
87 | $printer->barcode("ABC", Printer::BARCODE_CODE39);
88 | $printer->feed();
89 | $printer->feed();
90 |
91 |
92 | // Demo that alignment QRcode is the same as text
93 | $printer2 = new Printer($connector); // dirty printer profile hack !!
94 | $printer2->setJustification(Printer::JUSTIFY_CENTER);
95 | $printer2->qrCode("https://rawbt.ru/mike42", Printer::QR_ECLEVEL_M, 8);
96 | $printer2->text("rawbt.ru/mike42\n");
97 | $printer2->setJustification();
98 | $printer2->feed();
99 |
100 |
101 | /* Cut the receipt and open the cash drawer */
102 | $printer->cut();
103 | $printer->pulse();
104 |
105 | } catch (Exception $e) {
106 | echo $e->getMessage();
107 | } finally {
108 | $printer->close();
109 | }
110 |
111 | /* A wrapper to do organise item names & prices into columns */
112 |
113 | class item
114 | {
115 | private $name;
116 | private $price;
117 | private $dollarSign;
118 |
119 | public function __construct($name = '', $price = '', $dollarSign = false)
120 | {
121 | $this->name = $name;
122 | $this->price = $price;
123 | $this->dollarSign = $dollarSign;
124 | }
125 |
126 | public function getAsString($width = 48)
127 | {
128 | $rightCols = 10;
129 | $leftCols = $width - $rightCols;
130 | if ($this->dollarSign) {
131 | $leftCols = $leftCols / 2 - $rightCols / 2;
132 | }
133 | $left = str_pad($this->name, $leftCols);
134 |
135 | $sign = ($this->dollarSign ? '$ ' : '');
136 | $right = str_pad($sign . $this->price, $rightCols, ' ', STR_PAD_LEFT);
137 | return "$left$right\n";
138 | }
139 |
140 | public function __toString()
141 | {
142 | return $this->getAsString();
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/example/receipt-with-logo.php:
--------------------------------------------------------------------------------
1 | setJustification(Printer::JUSTIFY_CENTER);
30 | $printer -> graphics($logo);
31 |
32 | /* Name of shop */
33 | $printer -> selectPrintMode(Printer::MODE_DOUBLE_WIDTH);
34 | $printer -> text("ExampleMart Ltd.\n");
35 | $printer -> selectPrintMode();
36 | $printer -> text("Shop No. 42.\n");
37 | $printer -> feed();
38 |
39 | /* Title of receipt */
40 | $printer -> setEmphasis(true);
41 | $printer -> text("SALES INVOICE\n");
42 | $printer -> setEmphasis(false);
43 |
44 | /* Items */
45 | $printer -> setJustification(Printer::JUSTIFY_LEFT);
46 | $printer -> setEmphasis(true);
47 | $printer -> text(new item('', '$'));
48 | $printer -> setEmphasis(false);
49 | foreach ($items as $item) {
50 | $printer -> text($item);
51 | }
52 | $printer -> setEmphasis(true);
53 | $printer -> text($subtotal);
54 | $printer -> setEmphasis(false);
55 | $printer -> feed();
56 |
57 | /* Tax and total */
58 | $printer -> text($tax);
59 | $printer -> selectPrintMode(Printer::MODE_DOUBLE_WIDTH);
60 | $printer -> text($total);
61 | $printer -> selectPrintMode();
62 |
63 | /* Footer */
64 | $printer -> feed(2);
65 | $printer -> setJustification(Printer::JUSTIFY_CENTER);
66 | $printer -> text("Thank you for shopping at ExampleMart\n");
67 | $printer -> text("For trading hours, please visit example.com\n");
68 | $printer -> feed(2);
69 | $printer -> text($date . "\n");
70 |
71 | /* Cut the receipt and open the cash drawer */
72 | $printer -> cut();
73 | $printer -> pulse();
74 |
75 | $printer -> close();
76 |
77 | /* A wrapper to do organise item names & prices into columns */
78 | class item
79 | {
80 | private $name;
81 | private $price;
82 | private $dollarSign;
83 |
84 | public function __construct($name = '', $price = '', $dollarSign = false)
85 | {
86 | $this -> name = $name;
87 | $this -> price = $price;
88 | $this -> dollarSign = $dollarSign;
89 | }
90 |
91 | public function __toString()
92 | {
93 | $rightCols = 10;
94 | $leftCols = 38;
95 | if ($this -> dollarSign) {
96 | $leftCols = $leftCols / 2 - $rightCols / 2;
97 | }
98 | $left = str_pad($this -> name, $leftCols) ;
99 |
100 | $sign = ($this -> dollarSign ? '$ ' : '');
101 | $right = str_pad($sign . $this -> price, $rightCols, ' ', STR_PAD_LEFT);
102 | return "$left$right\n";
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/example/resources/character-encoding-test-strings.inc:
--------------------------------------------------------------------------------
1 | "Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Wolther spillede på xylofon.\n",
7 | "German" => "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg.\n",
8 | "Greek" => "Ξεσκεπάζω την ψυχοφθόρα βδελυγμία\n",
9 | "English" => "The quick brown fox jumps over the lazy dog.\n",
10 | "Spanish" => "El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.\n",
11 | "French" => "Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en canoë au delà des îles, près du mälström où brûlent les novæ.\n",
12 | "Irish Gaelic" => "D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh.\n",
13 | "Hungarian" => "Árvíztűrő tükörfúrógép.\n",
14 | "Icelandic" => "Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa.\n",
15 | "Latvian" => "Glāžšķūņa rūķīši dzērumā čiepj Baha koncertflīģeļu vākus.\n",
16 | "Polish" => "Pchnąć w tę łódź jeża lub ośm skrzyń fig.\n",
17 | "Russian" => "В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!\n",
18 | "Turkish" => "Pijamalı hasta, yağız şoföre çabucak güvendi.\n",
19 | "Japanese (Katakana half-width)" => implode("\n", array("イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム", "ウイノオクヤマ ケフコエテ アサキユメミシ エヒモセスン")) . "\n",
20 | "Vietnamese" => "Tiếng Việt, còn gọi tiếng Việt Nam hay Việt ngữ, là ngôn ngữ của người Việt (người Kinh) và là ngôn ngữ chính thức tại Việt Nam.\n"
21 | );
22 |
23 | /*
24 | * These strings are not expected to print correctly, if at all, even on an Epson printer. This is due to a mix of
25 | * escpos driver, printer, and PHP language support issues.
26 | *
27 | * They are included here as a collection of things not yet implemented.
28 | */
29 | $inputsNotOk = array(
30 | "Thai (No character encoder available)" => "นายสังฆภัณฑ์ เฮงพิทักษ์ฝั่ง ผู้เฒ่าซึ่งมีอาชีพเป็นฅนขายฃวด ถูกตำรวจปฏิบัติการจับฟ้องศาล ฐานลักนาฬิกาคุณหญิงฉัตรชฎา ฌานสมาธิ\n",
31 | "Japanese (Hiragana)" => implode("\n", array("いろはにほへとちりぬるを", " わかよたれそつねならむ", "うゐのおくやまけふこえて", "あさきゆめみしゑひもせす")) . "\n",
32 | "Japanese (Katakana full-width)" => implode("\n", array("イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム", "ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン")) . "\n",
33 | "Arabic (RTL not supported, encoding issues)" => "صِف خَلقَ خَودِ كَمِثلِ الشَمسِ إِذ بَزَغَت — يَحظى الضَجيعُ بِها نَجلاءَ مِعطارِ" . "\n",
34 | "Hebrew (RTL not supported, line break issues)" => "דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה" . "\n"
35 | );
36 |
--------------------------------------------------------------------------------
/example/resources/document.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/example/resources/document.odt
--------------------------------------------------------------------------------
/example/resources/document.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/example/resources/document.pdf
--------------------------------------------------------------------------------
/example/resources/document.z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/example/resources/document.z
--------------------------------------------------------------------------------
/example/resources/escpos-php-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/example/resources/escpos-php-small.png
--------------------------------------------------------------------------------
/example/resources/escpos-php.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/example/resources/escpos-php.png
--------------------------------------------------------------------------------
/example/resources/rawbtlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/example/resources/rawbtlogo.png
--------------------------------------------------------------------------------
/example/resources/tulips.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/example/resources/tulips.png
--------------------------------------------------------------------------------
/example/resources/tux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/example/resources/tux.png
--------------------------------------------------------------------------------
/example/specific/123-code128-barcode.php:
--------------------------------------------------------------------------------
1 | setJustification(Printer::JUSTIFY_CENTER);
13 | $printer -> setBarcodeHeight(48);
14 | $printer->setBarcodeTextPosition(Printer::BARCODE_TEXT_BELOW);
15 | foreach(array($a, $b, $c) as $item) {
16 | $printer -> barcode($item, Printer::BARCODE_CODE128);
17 | $printer -> feed(1);
18 | }
19 | $printer -> cut();
20 | $printer -> close();
21 |
22 |
--------------------------------------------------------------------------------
/example/specific/141-custom-command.php:
--------------------------------------------------------------------------------
1 | getPrintConnector()->write($barcodeCommand);
34 | $printer->cut();
35 | $printer->close();
36 |
37 | /**
38 | * Generate two characters for a number: In lower and higher parts, or more parts as needed.
39 | *
40 | * @param int $input
41 | * Input number
42 | * @param int $length
43 | * The number of bytes to output (1 - 4).
44 | */
45 | function intLowHigh($input, $length)
46 | {
47 | $outp = "";
48 | for ($i = 0; $i < $length; $i ++) {
49 | $outp .= chr($input % 256);
50 | $input = (int) ($input / 256);
51 | }
52 | return $outp;
53 | }
54 | ?>
--------------------------------------------------------------------------------
/example/specific/148-data-uri.php:
--------------------------------------------------------------------------------
1 | setResourceLimit(6, 1); // Prevent libgomp1 segfaults, grumble grumble.
23 | $imagick -> readImageBlob($imageBlob, "input.png");
24 |
25 | // Load Imagick straight into an EscposImage object
26 | $im = new ImagickEscposImage();
27 | $im -> readImageFromImagick($imagick);
28 |
29 | // Do a test print to make sure that this EscposImage object has the right data
30 | // (should see a tiny bullet point)
31 | $connector = new FilePrintConnector("php://output");
32 | $printer = new Printer($connector);
33 | $printer -> bitImage($im);
34 | $printer -> cut();
35 | $printer -> close();
36 |
--------------------------------------------------------------------------------
/example/specific/235-get-data.php:
--------------------------------------------------------------------------------
1 | text("Hello world!\n");
17 | $printer -> cut();
18 |
19 | // Get the data out as a string
20 | $data = $connector -> getData();
21 |
22 | // Return it, check the manual for specifics.
23 | header('Content-type: application/octet-stream');
24 | header('Content-Length: '.strlen($data));
25 | echo $data;
26 |
27 | // Close the printer when done.
28 | $printer -> close();
29 |
--------------------------------------------------------------------------------
/example/specific/29-latvian-star-tup592.php:
--------------------------------------------------------------------------------
1 | text("Glāžšķūņa rūķīši dzērumā čiepj Baha koncertflīģeļu vākus\n");
15 | $printer -> cut();
16 | $printer -> close();
17 |
18 | /* Option 2: Image-based output (formatting not available using this output) */
19 | $buffer = new ImagePrintBuffer();
20 | $connector = new FilePrintConnector("php://stdout");
21 | $printer = new Printer($connector, $profile);
22 | $printer -> setPrintBuffer($buffer);
23 | $printer -> text("Glāžšķūņa rūķīši dzērumā čiepj Baha koncertflīģeļu vākus\n");
24 | $printer -> cut();
25 | $printer -> close();
26 |
--------------------------------------------------------------------------------
/example/specific/32-german-tm-t20-ii-custom-command.php:
--------------------------------------------------------------------------------
1 | getPrintConnector() -> write($cmd);
30 | $printer -> text("Beispieltext in Deutsch\n");
31 | $printer -> cut();
32 | $printer -> close();
33 | /*
34 | * Hex-dump of output confirms that ESC V 1 being sent:
35 | *
36 | * 0000000 033 @ 033 V 001 B e i s p i e l t e x
37 | * 0000010 t i n D e u t s c h \n 035 V A
38 | * 0000020 003
39 | */
40 |
--------------------------------------------------------------------------------
/example/specific/33-spanish-seypos-prp-300.php:
--------------------------------------------------------------------------------
1 | text("El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.\n");
18 | $printer -> cut();
19 | $printer -> close();
20 |
--------------------------------------------------------------------------------
/example/specific/37-chinese.php:
--------------------------------------------------------------------------------
1 | textChinese("艾德蒙 AOC E2450SWH 23.6吋 LED液晶寬螢幕特價$ 19900\n\n");
21 |
22 | // Note that on the printer tested (ZJ5890), the font only contained simplified characters.
23 | $printer -> textChinese("示例文本打印机!\n\n");
24 | $printer -> close();
25 |
--------------------------------------------------------------------------------
/example/specific/39-currency-symbols.php:
--------------------------------------------------------------------------------
1 | text("€ 9,95\n");
15 | $printer -> text("£ 9.95\n");
16 | $printer -> text("$ 9.95\n");
17 | $printer -> text("¥ 9.95\n");
18 | $printer -> cut();
19 | $printer -> close();
20 |
21 | /* Option 2: Image-based output (formatting not available using this output). */
22 | $buffer = new ImagePrintBuffer();
23 | $connector = new FilePrintConnector("php://stdout");
24 | $printer = new Printer($connector, $profile);
25 | $printer -> setPrintBuffer($buffer);
26 | $printer -> text("€ 9,95\n");
27 | $printer -> text("£ 9.95\n");
28 | $printer -> text("$ 9.95\n");
29 | $printer -> text("¥ 9.95\n");
30 | $printer -> cut();
31 | $printer -> close();
32 |
33 | /*
34 | Option 3: If the printer is configured to print in a specific code
35 | page, you can set up a CapabilityProfile which either references its
36 | iconv encoding name, or includes all of the available characters.
37 |
38 | Here, we make use of CP858 for its inclusion of currency symbols which
39 | are not available in CP437. CP858 has good printer support, but is not
40 | included in all iconv builds.
41 | */
42 | class CustomCapabilityProfile extends CapabilityProfile
43 | {
44 | function getCustomCodePages()
45 | {
46 | /*
47 | * Example to print in a specific, user-defined character set
48 | * on a printer which has been configured to use i
49 | */
50 | return array(
51 | 'CP858' => "ÇüéâäàåçêëèïîìÄÅ" .
52 | "ÉæÆôöòûùÿÖÜø£Ø×ƒ" .
53 | "áíóúñѪº¿®¬½¼¡«»" .
54 | "░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐" .
55 | "└┴┬├─┼ãÃ╚╔╩╦╠═╬¤" .
56 | "ðÐÊËÈ€ÍÎÏ┘┌█▄¦Ì▀" .
57 | "ÓßÔÒõÕµþÞÚÛÙýݯ´" .
58 | " ±‗¾¶§÷¸°¨·¹³²■ ");
59 | }
60 |
61 | function getSupportedCodePages()
62 | {
63 | return array(
64 | 0 => 'custom:CP858');
65 | }
66 | }
67 |
68 | $connector = new FilePrintConnector("php://stdout");
69 | $profile = CustomCapabilityProfile::getInstance();
70 | $printer = new Printer($connector, $profile);
71 | $printer -> text("€ 9,95\n");
72 | $printer -> text("£ 9.95\n");
73 | $printer -> text("$ 9.95\n");
74 | $printer -> text("¥ 9.95\n");
75 |
76 | $printer -> cut();
77 | $printer -> close();
78 |
--------------------------------------------------------------------------------
/example/specific/44-pound-symbol-star-tsp650.php:
--------------------------------------------------------------------------------
1 | textRaw("\x9C"); // based on position in CP437
24 | $printer -> text(" 1.95\n");
25 |
26 | // B) Manually encoded UTF8 pound symbol. Tests that the driver correctly
27 | // encodes this as CP437.
28 | $printer -> text(base64_decode("wqM=") . " 2.95\n");
29 |
30 | // C) Pasted in file. Tests that your files are being saved as UTF-8, which
31 | // escpos-php is able to convert automatically to a mix of code pages.
32 | $printer -> text("£ 3.95\n");
33 |
34 | $printer -> cut();
35 | $printer -> close();
36 |
--------------------------------------------------------------------------------
/example/specific/50-P-822D-greek.php:
--------------------------------------------------------------------------------
1 | text($text . "\n");
16 | $printer -> cut();
17 |
18 | // Close the connection
19 | $printer -> close();
20 |
--------------------------------------------------------------------------------
/example/specific/54-gfx-sidebyside.php:
--------------------------------------------------------------------------------
1 | setJustification(Printer::JUSTIFY_CENTER);
51 | $printer -> graphics($img);
52 | $printer -> cut();
53 | } finally {
54 | // Always close the connection
55 | $printer -> close();
56 | }
57 | } catch (Exception $e) {
58 | // Print out any errors: Eg. printer connection, image loading & external image manipulation.
59 | echo $e -> getMessage() . "\n";
60 | echo $e -> getTraceAsString();
61 | } finally {
62 | unlink($imgCombined_path);
63 | unlink($tmpf_path);
64 | }
65 |
--------------------------------------------------------------------------------
/example/specific/6-arabic-epos-tep-220m.php:
--------------------------------------------------------------------------------
1 | utf8Glyphs($textUtf8, $maxChars);
49 | $textLine = explode("\n", $textLtr);
50 |
51 | /*
52 | * Set up and use an image print buffer with a suitable font
53 | */
54 | $buffer = new ImagePrintBuffer();
55 | $buffer -> setFont($fontPath);
56 | $buffer -> setFontSize($fontSize);
57 |
58 | $profile = CapabilityProfile::load("TEP-200M");
59 | $connector = new FilePrintConnector("php://output");
60 | // = new WindowsPrintConnector("LPT2");
61 | // Windows LPT2 was used in the bug tracker
62 |
63 | $printer = new Printer($connector, $profile);
64 | $printer -> setPrintBuffer($buffer);
65 |
66 | $printer -> setJustification(Printer::JUSTIFY_RIGHT);
67 | foreach($textLine as $text) {
68 | // Print each line separately. We need to do this since Imagick thinks
69 | // text is left-to-right
70 | $printer -> text($text . "\n");
71 | }
72 |
73 | $printer -> cut();
74 | $printer -> close();
75 |
--------------------------------------------------------------------------------
/example/specific/62-greek-symbol-swap.php:
--------------------------------------------------------------------------------
1 | text("Μιχάλης Νίκος\n");
12 | $printer -> cut();
13 | $printer -> close();
14 |
15 | ?>
16 |
--------------------------------------------------------------------------------
/example/specific/68-redblack.php:
--------------------------------------------------------------------------------
1 | text("Hello World!\n");
13 | $printer -> setColor(Printer::COLOR_2);
14 | $printer -> text("Red?!\n");
15 | $printer -> setColor(Printer::COLOR_1);
16 | $printer -> text("Default color again?!\n");
17 | $printer -> cut();
18 | } finally {
19 | /* Always close the printer! */
20 | $printer -> close();
21 | }
22 |
--------------------------------------------------------------------------------
/example/specific/97-dithering.php:
--------------------------------------------------------------------------------
1 | bitImage($img1);
18 |
19 | /* Load with optimisations disabled, forcing the use of PHP to convert the
20 | pixels, which uses a threshold and is much slower.
21 | */
22 | $img2 = EscposImage::load(__DIR__ . '/../resources/tulips.png', false);
23 | $printer -> bitImage($img2);
24 | $printer -> cut();
25 | } finally {
26 | /* Always close the printer! */
27 | $printer -> close();
28 | }
29 |
--------------------------------------------------------------------------------
/example/specific/README.md:
--------------------------------------------------------------------------------
1 | Specific examples
2 | -----------------
3 |
4 | These examples are designed for specific combinations of language,
5 | printer and interface.
6 |
7 | They are documented here because the general examples all set up the printer in a similar way.
8 |
--------------------------------------------------------------------------------
/example/text-size.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 | require __DIR__ . '/../vendor/autoload.php';
9 | use Mike42\Escpos\Printer;
10 | use Mike42\Escpos\PrintConnectors\FilePrintConnector;
11 |
12 | $connector = new FilePrintConnector("php://stdout");
13 | $printer = new Printer($connector);
14 |
15 | /* Initialize */
16 | $printer -> initialize();
17 |
18 | /* Text of various (in-proportion) sizes */
19 | title($printer, "Change height & width\n");
20 | for ($i = 1; $i <= 8; $i++) {
21 | $printer -> setTextSize($i, $i);
22 | $printer -> text($i);
23 | }
24 | $printer -> text("\n");
25 |
26 | /* Width changing only */
27 | title($printer, "Change width only (height=4):\n");
28 | for ($i = 1; $i <= 8; $i++) {
29 | $printer -> setTextSize($i, 4);
30 | $printer -> text($i);
31 | }
32 | $printer -> text("\n");
33 |
34 | /* Height changing only */
35 | title($printer, "Change height only (width=4):\n");
36 | for ($i = 1; $i <= 8; $i++) {
37 | $printer -> setTextSize(4, $i);
38 | $printer -> text($i);
39 | }
40 | $printer -> text("\n");
41 |
42 | /* Very narrow text */
43 | title($printer, "Very narrow text:\n");
44 | $printer -> setTextSize(1, 8);
45 | $printer -> text("The quick brown fox jumps over the lazy dog.\n");
46 |
47 | /* Very flat text */
48 | title($printer, "Very wide text:\n");
49 | $printer -> setTextSize(4, 1);
50 | $printer -> text("Hello world!\n");
51 |
52 | /* Very large text */
53 | title($printer, "Largest possible text:\n");
54 | $printer -> setTextSize(8, 8);
55 | $printer -> text("Hello\nworld!\n");
56 |
57 | $printer -> cut();
58 | $printer -> close();
59 |
60 | function title(Printer $printer, $text)
61 | {
62 | $printer -> selectPrintMode(Printer::MODE_EMPHASIZED);
63 | $printer -> text("\n" . $text);
64 | $printer -> selectPrintMode(); // Reset
65 | }
66 |
--------------------------------------------------------------------------------
/example/unifont-print-buffer.php:
--------------------------------------------------------------------------------
1 | setPrintBuffer($unifontBuffer);
15 |
16 | // Most simple example
17 | $printer->text("Hello\n");
18 | $printer->setUpsideDown(true);
19 | $printer->text("World\n");
20 | $printer->cut();
21 | $printer->close();
22 |
23 |
--------------------------------------------------------------------------------
/example/upside-down.php:
--------------------------------------------------------------------------------
1 | text("Hello\n");
12 | $printer -> setUpsideDown(true);
13 | $printer -> text("World\n");
14 | $printer -> cut();
15 | $printer -> close();
16 |
17 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | test/unit
11 |
12 |
13 | test/integration
14 |
15 |
16 |
17 |
18 | src
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/CodePage.php:
--------------------------------------------------------------------------------
1 | ,
7 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
8 | *
9 | * This software is distributed under the terms of the MIT license. See LICENSE.md
10 | * for details.
11 | */
12 |
13 | namespace Mike42\Escpos;
14 |
15 | use \InvalidArgumentException;
16 |
17 | /**
18 | * Class to handle data about a particular CodePage, as loaded from the receipt print
19 | * database.
20 | *
21 | * Also computes map between UTF-8 and this encoding if necessary, using the intl library.
22 | */
23 | class CodePage
24 | {
25 | /**
26 | * Value to use when no character is set. This is a space in ASCII.
27 | */
28 | const MISSING_CHAR_CODE = 0x20;
29 |
30 | /**
31 | * @var array|null $data
32 | * Data string, null if not known (can be computed with iconv)
33 | */
34 | protected $data;
35 |
36 | /**
37 | * @var string|null $iconv
38 | * Iconv encoding name, null if not known
39 | */
40 | protected $iconv;
41 |
42 | /**
43 | * @var string $id
44 | * Internal ID of the CodePage
45 | */
46 | protected $id;
47 |
48 | /**
49 | * @var string $name
50 | * Name of the code page. Substituted with the ID if not set.
51 | */
52 | protected $name;
53 |
54 | /**
55 | * @var string|null $notes
56 | * Notes on this code page, or null if not set.
57 | */
58 | protected $notes;
59 |
60 | /**
61 | *
62 | * @param string $id
63 | * Unique internal identifier for the CodePage.
64 | * @param array $codePageData
65 | * Associative array of CodePage data, as
66 | * specified by the upstream receipt-print-hq/escpos-printer-db database.
67 | * May contain 'name', 'data', 'iconv', and 'notes' fields.
68 | */
69 | public function __construct($id, array $codePageData)
70 | {
71 | $this->id = $id;
72 | $this->name = isset($codePageData['name']) ? $codePageData['name'] : $id;
73 | $this->data = isset($codePageData['data']) ? self::encodingArrayFromData($codePageData['data']) : null;
74 | $this->iconv = isset($codePageData['iconv']) ? $codePageData['iconv'] : null;
75 | $this->notes = isset($codePageData['notes']) ? $codePageData['notes'] : null;
76 | }
77 |
78 | /**
79 | * Get a 128-entry array of unicode code-points from this code page.
80 | *
81 | * @throws InvalidArgumentException Where the data is now known or computable.
82 | * @return array Data for this encoding.
83 | */
84 | public function getDataArray() : array
85 | {
86 | // Make string
87 | if ($this->data !== null) {
88 | // Return data if known
89 | return $this->data;
90 | }
91 | if ($this->iconv !== null) {
92 | // Calculate with iconv if we know the encoding name
93 | $this->data = self::generateEncodingArray($this->iconv);
94 | return $this->data;
95 | }
96 | // Can't encode..
97 | throw new InvalidArgumentException("Cannot encode this code page");
98 | }
99 |
100 | /**
101 | *
102 | * @return string|null Iconv encoding name, or null if not set.
103 | */
104 | public function getIconv()
105 | {
106 | return $this->iconv;
107 | }
108 |
109 | /**
110 | *
111 | * @return string Unique identifier of the code page.
112 | */
113 | public function getId() : string
114 | {
115 | return $this->id;
116 | }
117 |
118 | /**
119 | * @return string Name of the code page.
120 | */
121 | public function getName() : string
122 | {
123 | return $this->name;
124 | }
125 |
126 | /**
127 | * The notes may explain quirks about a code-page, such as a source if it's non-standard or un-encodeable.
128 | *
129 | * @return string|null Notes on the code page, or null if not set.
130 | */
131 | public function getNotes()
132 | {
133 | return $this->notes;
134 | }
135 |
136 | /**
137 | *
138 | * @return boolean True if we can encode with this code page (ie, we know what data it holds).
139 | *
140 | * Many printers contain vendor-specific code pages, which are named but have not been identified or
141 | * typed out. For our purposes, this is an "un-encodeable" code page.
142 | */
143 | public function isEncodable()
144 | {
145 | return $this->iconv !== null || $this->data !== null;
146 | }
147 |
148 | /**
149 | * Given an ICU encoding name, generate a 128-entry array, with the unicode code points
150 | * for the character at positions 128-255 in this code page.
151 | *
152 | * @param string $encodingName Name of the encoding
153 | * @return array 128-entry array of code points
154 | */
155 | protected static function generateEncodingArray(string $encodingName) : array
156 | {
157 | // Set up converter for encoding
158 | $missingChar = chr(self::MISSING_CHAR_CODE);
159 | // Throws a lot of warnings for ambiguous code pages, but fallbacks seem fine.
160 | $converter = @new \UConverter("UTF-8", $encodingName);
161 | $converter -> setSubstChars($missingChar);
162 | // Loop through 128 code points
163 | $intArray = array_fill(0, 128, self::MISSING_CHAR_CODE);
164 | for ($char = 128; $char <= 255; $char++) {
165 | // Try to identify the UTF-8 character at this position in the code page
166 | $encodingChar = chr($char);
167 | $utf8 = $converter ->convert($encodingChar, false);
168 | if ($utf8 === $missingChar || $utf8 === false) {
169 | // Cannot be mapped to unicode
170 | continue;
171 | }
172 | $reverse = $converter ->convert($utf8, true);
173 | if ($reverse !== $encodingChar) {
174 | // Avoid conversions which don't reverse well (eg. multi-byte code pages)
175 | continue;
176 | }
177 | // Replace space with the correct character if we found it
178 | $intArray[$char - 128] = \IntlChar::ord($utf8);
179 | }
180 | assert(count($intArray) == 128);
181 | return $intArray;
182 | }
183 |
184 |
185 | private static function encodingArrayFromData(array $data) : array
186 | {
187 | $text = implode("", $data); // Join lines
188 | $codePointIterator = \IntlBreakIterator::createCodePointInstance();
189 | $codePointIterator -> setText($text);
190 | $ret = array_fill(0, 128, self::MISSING_CHAR_CODE);
191 | for ($i = 0; ($codePointIterator -> next() > 0) && ($i < 128); $i++) {
192 | $codePoint = $codePointIterator -> getLastCodePoint();
193 | $ret[$i] = $codePoint;
194 | }
195 | assert(count($ret) == 128);
196 | return $ret;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/Devices/AuresCustomerDisplay.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\Devices;
17 |
18 | use Mike42\Escpos\Printer;
19 |
20 | /**
21 | * A class for sending ESC/POS-like code to an Aures customer display.
22 | * The display has some features that printers do not, such as an ability to "clear" the screen.
23 | */
24 | class AuresCustomerDisplay extends Printer
25 | {
26 |
27 | /**
28 | * Indicates that the text should wrap and type over
29 | * existing text on the screen, rather than scroll.
30 | */
31 | const TEXT_OVERWRITE = 1;
32 |
33 | /**
34 | * Indicates that overflowing text should cause the
35 | * display to scroll vertically, like a computer terminal.
36 | */
37 | const TEXT_VERTICAL_SCROLL = 2;
38 |
39 | /**
40 | * Indicates that overflowing text should cause the
41 | * display to scroll horizontally, like a news ticker.
42 | */
43 | const TEXT_HORIZONTAL_SCROLL = 3;
44 |
45 | /**
46 | *
47 | * {@inheritdoc}
48 | *
49 | * @see \Mike42\Escpos\Printer::initialize()
50 | */
51 | public function initialize()
52 | {
53 | // Select ESC/POS mode first
54 | $this->selectEscposMode();
55 | parent::initialize();
56 | // ESC @ does not reset character table on this printer
57 | $this->selectCharacterTable(0);
58 | // Default to horizontal scroll mode. Behaves most like a printer.
59 | $this->selectTextScrollMode(AuresCustomerDisplay::TEXT_VERTICAL_SCROLL);
60 | }
61 |
62 | /**
63 | * Selects ESC/POS mode.
64 | *
65 | * This device supports other modes, which are not used.
66 | */
67 | protected function selectEscposMode()
68 | {
69 | $this->connector->write("\x02\x05\x43\x31\x03");
70 | }
71 |
72 | /**
73 | *
74 | * @param int $mode
75 | * The text scroll mode to use. One of
76 | * AuresCustomerDisplay::TEXT_OVERWRITE,
77 | * AuresCustomerDisplay::TEXT_VERTICAL_SCROLL or
78 | * AuresCustomerDisplay::TEXT_HORIZONTAL_SCROLL
79 | */
80 | public function selectTextScrollMode(int $mode = AuresCustomerDisplay::TEXT_VERTICAL_SCROLL)
81 | {
82 | self::validateInteger($mode, 1, 3, __FUNCTION__);
83 | $this->connector->write("\x1F" . chr($mode));
84 | }
85 |
86 | /**
87 | * Clear the display.
88 | */
89 | public function clear()
90 | {
91 | $this->connector->write("\x0c");
92 | }
93 |
94 | /**
95 | * Instruct the display to show the firmware version.
96 | */
97 | public function showFirmwareVersion()
98 | {
99 | $this->connector->write("\x02\x05\x56\x01\x03");
100 | }
101 |
102 | /**
103 | * Instruct the display to begin a self-test/demo sequence.
104 | */
105 | public function selfTest()
106 | {
107 | $this->connector->write("\x02\x05\x44\x08\x03");
108 | }
109 |
110 | /**
111 | * Instruct the display to show a pre-loaded logo.
112 | *
113 | * Note that this driver is not capable of uploading a
114 | * logo, but that the vendor supplies software
115 | * which has this function.
116 | */
117 | public function showLogo()
118 | {
119 | $this->connector->write("\x02\xFC\x55\xAA\x55\xAA");
120 | }
121 |
122 | /**
123 | *
124 | * {@inheritdoc}
125 | *
126 | * @see \Mike42\Escpos\Printer::text()
127 | */
128 | public function text(string $str)
129 | {
130 | // Need to intercept line-feeds, since "\n" is insufficient on this device.
131 | foreach (explode("\n", $str) as $id => $line) {
132 | if ($id > 0) {
133 | $this->feed();
134 | }
135 | parent::text($line);
136 | }
137 | }
138 |
139 | /**
140 | *
141 | * {@inheritdoc}
142 | *
143 | * @see \Mike42\Escpos\Printer::feed()
144 | */
145 | public function feed(int $lines = 1)
146 | {
147 | self::validateInteger($lines, 1, 255, __FUNCTION__);
148 | for ($i = 0; $i < $lines; $i ++) {
149 | $this->connector->write("\r\n");
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/Experimental/Unifont/ColumnFormatGlyph.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\Experimental\Unifont;
17 |
18 | class ColumnFormatGlyph
19 | {
20 | public $width;
21 | public $data;
22 |
23 | public function segment(int $maxWidth)
24 | {
25 | if ($this->width <= $maxWidth) {
26 | return [$this];
27 | }
28 | $dataChunks = str_split($this->data, $maxWidth * 3);
29 | $ret = [];
30 | foreach ($dataChunks as $chunk) {
31 | $g = new ColumnFormatGlyph();
32 | $g->data = $chunk;
33 | $g->width = strlen($chunk) / 3;
34 | $ret[] = $g;
35 | }
36 | return $ret;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/Experimental/Unifont/ColumnFormatGlyphFactory.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\Experimental\Unifont;
17 |
18 | interface ColumnFormatGlyphFactory
19 | {
20 | public function getGlyph($codePoint);
21 | }
22 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/Experimental/Unifont/FontMap.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\Experimental\Unifont;
17 |
18 | use InvalidArgumentException;
19 | use Mike42\Escpos\Printer;
20 |
21 | class FontMap
22 | {
23 | protected $printer;
24 |
25 | const MIN = 0x20;
26 | const MAX = 0x7E;
27 | const FONT_A_WIDTH = 12;
28 | const FONT_B_WIDTH = 9;
29 |
30 | // Map memory locations to code points
31 | protected $memory;
32 |
33 | // Map unicode code points to bytes
34 | protected $chars;
35 |
36 | // next available slot
37 | protected $next = 0;
38 |
39 | public function __construct(ColumnFormatGlyphFactory $glyphFactory, Printer $printer)
40 | {
41 | $this -> printer = $printer;
42 | $this -> glyphFactory = $glyphFactory;
43 | $this -> reset();
44 | }
45 |
46 | public function cacheChars(array $codePoints)
47 | {
48 | // TODO flush existing cache to fill with these chars.
49 | }
50 |
51 | public function writeChar(int $codePoint)
52 | {
53 | if (!$this -> addChar($codePoint, true)) {
54 | throw new InvalidArgumentException("Code point $codePoint not available");
55 | }
56 | $data = implode($this -> chars[$codePoint]);
57 | $this -> printer -> getPrintConnector() -> write($data);
58 | }
59 |
60 | public function reset()
61 | {
62 | $this -> chars = [];
63 | $this -> memory = array_fill(0, (\Mike42\Escpos\Experimental\Unifont\FontMap::MAX - FontMap::MIN) + 1, -1);
64 | }
65 |
66 | public function occupied($id)
67 | {
68 | return $this -> memory[$id] !== -1;
69 | }
70 |
71 | public function evict($id)
72 | {
73 | if (!$this -> occupied($id)) {
74 | return true;
75 | }
76 | unset($this -> chars[$this -> memory[$id]]);
77 | $this -> memory[$id] = -1;
78 | return true;
79 | }
80 |
81 | public function addChar(int $codePoint, $evict = true)
82 | {
83 | if (isset($this -> chars[$codePoint])) {
84 | // Char already available
85 | return true;
86 | }
87 | // Get glyph
88 | $glyph = $this -> glyphFactory -> getGlyph($codePoint);
89 | $glyphParts = $glyph -> segment(self::FONT_B_WIDTH);
90 | //print_r($glyphParts);
91 | //
92 | // Clear count($glyphParts) of space from $start
93 | $start = $this -> next;
94 | $chars = [];
95 | $submit = [];
96 | for ($i = 0; $i < count($glyphParts); $i++) {
97 | $id = ($this -> next + $i) % count($this -> memory);
98 | if ($this -> occupied($id)) {
99 | if ($evict) {
100 | $this -> evict($id);
101 | } else {
102 | return false;
103 | }
104 | }
105 | $thisChar = $id + self::MIN;
106 | $chars[] = chr($thisChar);
107 | $submit[$thisChar] = $glyphParts[$i];
108 | }
109 |
110 | // Success in locating memory space, move along counters
111 | $this -> next = ($this -> next + count($glyphParts)) % count($this -> memory);
112 | $this -> submitCharsToPrinterFont($submit);
113 | $this -> memory[$start] = $codePoint;
114 | $this -> chars[$codePoint] = $chars;
115 |
116 | return true;
117 | }
118 |
119 | public function submitCharsToPrinterFont(array $chars)
120 | {
121 | ksort($chars);
122 | // TODO We can sort into batches of contiguous characters here.
123 | foreach ($chars as $char => $glyph) {
124 | $verticalBytes = 3;
125 | $data = Printer::ESC . "&" . chr($verticalBytes) . chr($char) . chr($char) . chr($glyph -> width) . $glyph -> data;
126 | $this -> printer -> getPrintConnector() -> write($data);
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/Experimental/Unifont/UnifontPrintBuffer.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\Experimental\Unifont;
17 |
18 | use Mike42\Escpos\PrintBuffers\PrintBuffer;
19 | use Mike42\Escpos\Printer;
20 |
21 | class UnifontPrintBuffer implements PrintBuffer
22 | {
23 | private $printer;
24 | private $fontMap;
25 | private $started;
26 | private $unifont;
27 |
28 | public function __construct(string $unifontFilename)
29 | {
30 | // Create UnifontGlyphFactory by reading from file
31 | $unifont = file_get_contents($unifontFilename);
32 | if ($unifont === false) {
33 | throw new \Exception("Could not read $unifontFilename");
34 | }
35 | $unifontFileLines = explode("\n", $unifont);
36 | $this -> unifont = new UnifontGlyphFactory($unifontFileLines);
37 | // Everything else is null
38 | $this -> printer = null;
39 | $this -> fontMap = null;
40 | $this -> started = false;
41 | }
42 |
43 | public function writeChar(int $codePoint)
44 | {
45 | if ($codePoint == 10) {
46 | $this -> write("\n");
47 | } elseif ($codePoint == 13) {
48 | // Ignore CR char
49 | } else {
50 | // Straight column-format prints
51 | $this -> fontMap -> writeChar($codePoint);
52 | }
53 | }
54 |
55 | public function writeText(string $text)
56 | {
57 | if (!$this -> started) {
58 | $mode = Printer::MODE_FONT_B | Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_DOUBLE_WIDTH;
59 | $this -> printer -> getPrintConnector() -> write(Printer::ESC . "!" . chr($mode));
60 | $this -> printer -> selectUserDefinedCharacterSet(true);
61 | }
62 | // Normalize text - this replaces combining characters with composed glyphs, and also helps us eliminated bad UTF-8 early
63 | $text = \Normalizer::normalize($text);
64 | if ($text === false) {
65 | throw new \Exception("Input must be UTF-8");
66 | }
67 | // Iterate code points
68 | $codePointIterator = \IntlBreakIterator::createCodePointInstance();
69 | $codePointIterator->setText($text);
70 | while ($codePointIterator->next() > 0) {
71 | $codePoint = $codePointIterator->getLastCodePoint();
72 | $this->writeChar($codePoint);
73 | }
74 | }
75 |
76 | public function flush()
77 | {
78 | }
79 |
80 | public function setPrinter(Printer $printer = null)
81 | {
82 | $this -> printer = $printer;
83 | $this -> fontMap = new FontMap($this -> unifont, $this -> printer);
84 | }
85 |
86 | public function writeTextRaw(string $text)
87 | {
88 | }
89 |
90 | public function getPrinter()
91 | {
92 | return $this -> printer;
93 | }
94 |
95 | /**
96 | * Write data to the underlying connector.
97 | *
98 | * @param string $data
99 | */
100 | private function write($data)
101 | {
102 | $this -> printer -> getPrintConnector() -> write($data);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/GdEscposImage.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos;
17 |
18 | use Exception;
19 |
20 | /**
21 | * Implementation of EscposImage using the GD PHP plugin.
22 | */
23 | class GdEscposImage extends EscposImage
24 | {
25 | /**
26 | * Load an image from disk, into memory, using GD.
27 | *
28 | * @param string|null $filename The filename to load from
29 | * @throws Exception if the image format is not supported,
30 | * or the file cannot be opened.
31 | */
32 | protected function loadImageData(string $filename = null)
33 | {
34 | if ($filename === null) {
35 | /* Set to blank image */
36 | return parent::loadImageData($filename);
37 | }
38 |
39 | $ext = pathinfo($filename, PATHINFO_EXTENSION);
40 | switch ($ext) {
41 | case "png":
42 | $im = @imagecreatefrompng($filename);
43 | break;
44 | case "jpg":
45 | $im = @imagecreatefromjpeg($filename);
46 | break;
47 | case "gif":
48 | $im = @imagecreatefromgif($filename);
49 | break;
50 | default:
51 | throw new Exception("Image format not supported in GD");
52 | }
53 | $this -> readImageFromGdResource($im);
54 | }
55 |
56 | /**
57 | * Load actual image pixels from GD resource.
58 | *
59 | * @param resource $im GD resource to use
60 | * @throws Exception Where the image can't be read.
61 | */
62 | public function readImageFromGdResource($im)
63 | {
64 | if (!is_resource($im) && !$im instanceof \GdImage) {
65 | throw new Exception("Failed to load image.");
66 | } elseif (!EscposImage::isGdLoaded()) {
67 | throw new Exception(__FUNCTION__ . " requires 'gd' extension.");
68 | }
69 | /* Make a string of 1's and 0's */
70 | $imgHeight = imagesy($im);
71 | $imgWidth = imagesx($im);
72 | $imgData = str_repeat("\0", $imgHeight * $imgWidth);
73 | for ($y = 0; $y < $imgHeight; $y++) {
74 | for ($x = 0; $x < $imgWidth; $x++) {
75 | /* Faster to average channels, blend alpha and negate the image here than via filters (tested!) */
76 | $cols = imagecolorsforindex($im, imagecolorat($im, $x, $y));
77 | // 1 for white, 0 for black, ignoring transparency
78 | $greyness = (int)(($cols['red'] + $cols['green'] + $cols['blue']) / 3) >> 7;
79 | // 1 for black, 0 for white, taking into account transparency
80 | $black = (1 - $greyness) >> ($cols['alpha'] >> 6);
81 | $imgData[$y * $imgWidth + $x] = $black;
82 | }
83 | }
84 | $this -> setImgWidth($imgWidth);
85 | $this -> setImgHeight($imgHeight);
86 | $this -> setImgData($imgData);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/NativeEscposImage.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos;
17 |
18 | use Mike42\GfxPhp\Image;
19 |
20 | /**
21 | * Implementation of EscposImage using only native PHP.
22 | */
23 | class NativeEscposImage extends EscposImage
24 | {
25 | protected function loadImageData(string $filename = null)
26 | {
27 | $image = Image::fromFile($filename) -> toRgb() -> toBlackAndWhite();
28 | $imgHeight = $image -> getHeight();
29 | $imgWidth = $image -> getWidth();
30 | $imgData = str_repeat("\0", $imgHeight * $imgWidth);
31 | for ($y = 0; $y < $imgHeight; $y++) {
32 | for ($x = 0; $x < $imgWidth; $x++) {
33 | $imgData[$y * $imgWidth + $x] = $image -> getPixel($x, $y) == 0 ? 0: 1;
34 | }
35 | }
36 | $this -> setImgWidth($imgWidth);
37 | $this -> setImgHeight($imgHeight);
38 | $this -> setImgData($imgData);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintBuffers/ImagePrintBuffer.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintBuffers;
17 |
18 | use Exception;
19 | use LogicException;
20 | use Mike42\Escpos\Printer;
21 | use Mike42\Escpos\EscposImage;
22 | use Mike42\Escpos\ImagickEscposImage;
23 |
24 | /**
25 | * This class renders text to small images on-the-fly. It attempts to mimic the
26 | * behaviour of text output, whilst supporting any fonts & character encodings
27 | * which your system can handle. This class currently requires Imagick.
28 | */
29 | class ImagePrintBuffer implements PrintBuffer
30 | {
31 | private $printer;
32 |
33 | /**
34 | * @var string|null font to use
35 | */
36 | private $font;
37 |
38 | private $fontSize;
39 |
40 | public function __construct()
41 | {
42 | if (!EscposImage::isImagickLoaded()) {
43 | throw new Exception("ImagePrintBuffer requires the imagick extension");
44 | }
45 | $this -> font = null;
46 | $this -> fontSize = 24;
47 | }
48 |
49 | public function flush()
50 | {
51 | if ($this -> printer == null) {
52 | throw new LogicException("Not attached to a printer.");
53 | }
54 | }
55 |
56 | public function getPrinter()
57 | {
58 | return $this -> printer;
59 | }
60 |
61 | public function setPrinter(Printer $printer = null)
62 | {
63 | $this -> printer = $printer;
64 | }
65 |
66 | public function writeText(string $text)
67 | {
68 | if ($this -> printer == null) {
69 | throw new LogicException("Not attached to a printer.");
70 | }
71 | if ($text == null) {
72 | return;
73 | }
74 | $text = trim($text, "\n");
75 | /* Create Imagick objects */
76 | $image = new \Imagick();
77 | $draw = new \ImagickDraw();
78 | $color = new \ImagickPixel('#000000');
79 | $background = new \ImagickPixel('white');
80 |
81 | /* Create annotation */
82 | if ($this->font !== null) {
83 | // Allow fallback on defaults as necessary
84 | $draw->setFont($this->font);
85 | }
86 | /* In Arial, size 21 looks good as a substitute for FONT_B, 24 for FONT_A */
87 | $draw -> setFontSize($this -> fontSize);
88 | $draw -> setFillColor($color);
89 | $draw -> setStrokeAntialias(true);
90 | $draw -> setTextAntialias(true);
91 | $metrics = $image -> queryFontMetrics($draw, $text);
92 | $draw -> annotation(0, $metrics['ascender'], $text);
93 |
94 | /* Create image & draw annotation on it */
95 | $image -> newImage($metrics['textWidth'], $metrics['textHeight'], $background);
96 | $image -> setImageFormat('png');
97 | $image -> drawImage($draw);
98 | // debugging if you want to view the images yourself
99 | //$image -> writeImage("test.png");
100 |
101 | /* Save image */
102 | $escposImage = new ImagickEscposImage();
103 | $escposImage -> readImageFromImagick($image);
104 | $size = Printer::IMG_DEFAULT;
105 | $this -> printer -> bitImage($escposImage, $size);
106 | }
107 |
108 | public function writeTextRaw(string $text)
109 | {
110 | if ($this -> printer == null) {
111 | throw new LogicException("Not attached to a printer.");
112 | }
113 | $this -> printer -> getPrintConnector() -> write($text);
114 | }
115 |
116 | /**
117 | * Set path on disk to TTF font that will be used to render text to image,
118 | * or 'null' to use a default.
119 | *
120 | * ImageMagick will also accept a font name, but this will not port as well
121 | * between systems.
122 | *
123 | * @param string $font
124 | * Font name or a filename
125 | */
126 | public function setFont(string $font)
127 | {
128 | $this->font = $font;
129 | }
130 |
131 | /**
132 | * Numeric font size for rendering text to image
133 | */
134 | public function setFontSize(int $fontSize)
135 | {
136 | $this->fontSize = $fontSize;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintBuffers/PrintBuffer.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintBuffers;
17 |
18 | use Mike42\Escpos\Printer;
19 |
20 | /**
21 | * Print buffers manage newlines and character encoding for the target printer.
22 | * They are used as a swappable component: text or image-based output.
23 | *
24 | * - Text output (EscposPrintBuffer) is the fast default, and is recommended for
25 | * most people, as the text output can be more directly manipulated by ESC/POS
26 | * commands.
27 | * - Image output (ImagePrintBuffer) is designed to accept more encodings than the
28 | * physical printer supports, by rendering the text to small images on-the-fly.
29 | * This takes a lot more CPU than sending text, but is necessary for some users.
30 | * - If your use case fits outside these, then a further speed/flexibility trade-off
31 | * can be made by printing directly from generated HTML or PDF.
32 | */
33 | interface PrintBuffer
34 | {
35 | /**
36 | * Cause the buffer to send any partial input and wait on a newline.
37 | * If the printer is already on a new line, this does nothing.
38 | */
39 | public function flush();
40 |
41 | /**
42 | * Used by Escpos to check if a printer is set.
43 | */
44 | public function getPrinter();
45 |
46 | /**
47 | * Used by Escpos to hook up one-to-one link between buffers and printers.
48 | *
49 | * @param Printer|null $printer New printer
50 | */
51 | public function setPrinter(Printer $printer = null);
52 |
53 | /**
54 | * Accept UTF-8 text for printing.
55 | *
56 | * @param string $text Text to print
57 | */
58 | public function writeText(string $text);
59 |
60 | /**
61 | * Accept 8-bit text in the current encoding and add it to the buffer.
62 | *
63 | * @param string $text Text to print, already the target encoding.
64 | */
65 | public function writeTextRaw(string $text);
66 | }
67 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintBuffers/cache/Characters-OCD-300.ser.z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/src/Mike42/Escpos/PrintBuffers/cache/Characters-OCD-300.ser.z
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintBuffers/cache/Characters-default.ser.z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/src/Mike42/Escpos/PrintBuffers/cache/Characters-default.ser.z
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintBuffers/cache/Characters-simple.ser.z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/src/Mike42/Escpos/PrintBuffers/cache/Characters-simple.ser.z
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintConnectors/CupsPrintConnector.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintConnectors;
17 |
18 | use Exception;
19 | use BadMethodCallException;
20 |
21 | /**
22 | * Print connector that passes print data to CUPS print commands.
23 | * Your printer mut be installed on the local CUPS instance to use this connector.
24 | */
25 | class CupsPrintConnector implements PrintConnector
26 | {
27 |
28 | /**
29 | * @var array $buffer
30 | * Buffer of accumilated data.
31 | */
32 | private $buffer;
33 |
34 | /**
35 | *
36 | * @var string $printerName
37 | * The name of the target printer.
38 | */
39 | private $printerName;
40 |
41 | /**
42 | * Construct new CUPS print connector.
43 | *
44 | * @param string $dest
45 | * The CUPS printer name to print to. This must be loaded using a raw driver.
46 | * @throws BadMethodCallException
47 | */
48 | public function __construct($dest)
49 | {
50 | $valid = $this->getLocalPrinters();
51 | if (count($valid) == 0) {
52 | throw new BadMethodCallException("You do not have any printers installed on " .
53 | "this system via CUPS. Check 'lpr -a'.");
54 | }
55 |
56 | if (array_search($dest, $valid, true) === false) {
57 | throw new BadMethodCallException("'$dest' is not a printer on this system. " .
58 | "Printers are: [" . implode(", ", $valid) . "]");
59 | }
60 | $this->buffer = array ();
61 | $this->printerName = $dest;
62 | }
63 |
64 | /**
65 | * Cause a NOTICE if deconstructed before the job was printed.
66 | */
67 | public function __destruct()
68 | {
69 | if ($this->buffer !== null) {
70 | trigger_error("Print connector was not finalized. Did you forget to close the printer?", E_USER_NOTICE);
71 | }
72 | }
73 |
74 | /**
75 | * Send job to printer.
76 | */
77 | public function finalize()
78 | {
79 | $data = implode($this->buffer);
80 | $this->buffer = null;
81 |
82 | // Build command to work on data
83 | $tmpfname = tempnam(sys_get_temp_dir(), 'print-');
84 | if ($tmpfname === false) {
85 | throw new Exception("Failed to create temp file for printing.");
86 | }
87 | file_put_contents($tmpfname, $data);
88 | $cmd = sprintf(
89 | "lp -d %s %s",
90 | escapeshellarg($this->printerName),
91 | escapeshellarg($tmpfname)
92 | );
93 | try {
94 | $this->getCmdOutput($cmd);
95 | } catch (Exception $e) {
96 | unlink($tmpfname);
97 | throw $e;
98 | }
99 | unlink($tmpfname);
100 | }
101 |
102 | /**
103 | * Run a command and throw an exception if it fails, or return the output if it works.
104 | * (Basically exec() with good error handling)
105 | *
106 | * @param string $cmd
107 | * Command to run
108 | */
109 | protected function getCmdOutput($cmd)
110 | {
111 | $descriptors = array (
112 | 1 => array (
113 | "pipe",
114 | "w"
115 | ),
116 | 2 => array (
117 | "pipe",
118 | "w"
119 | )
120 | );
121 | $process = proc_open($cmd, $descriptors, $fd);
122 | if (! is_resource($process)) {
123 | throw new Exception("Command '$cmd' failed to start.");
124 | }
125 | /* Read stdout */
126 | $outputStr = stream_get_contents($fd [1]);
127 | fclose($fd [1]);
128 | /* Read stderr */
129 | $errorStr = stream_get_contents($fd [2]);
130 | fclose($fd [2]);
131 | /* Finish up */
132 | $retval = proc_close($process);
133 | if ($retval != 0) {
134 | throw new Exception("Command $cmd failed: $errorStr");
135 | }
136 | return $outputStr;
137 | }
138 |
139 | /**
140 | * Read data from the printer.
141 | *
142 | * @param string $len Length of data to read.
143 | * @return string Data read from the printer, or false where reading is not possible.
144 | */
145 | public function read($len)
146 | {
147 | return false;
148 | }
149 |
150 | /**
151 | * @param string $data
152 | */
153 | public function write($data)
154 | {
155 | $this->buffer [] = $data;
156 | }
157 |
158 | /**
159 | * Load a list of CUPS printers.
160 | *
161 | * @return array A list of printer names installed on this system. Any item
162 | * on this list is valid for constructing a printer.
163 | */
164 | protected function getLocalPrinters()
165 | {
166 | $outpStr = $this->getCmdOutput("lpstat -a");
167 | $outpLines = explode("\n", trim($outpStr));
168 | foreach ($outpLines as $line) {
169 | $ret [] = $this->chopLpstatLine($line);
170 | }
171 | return $ret;
172 | }
173 |
174 | /**
175 | * Get the item before the first space in a string
176 | *
177 | * @param string $line
178 | * @return string the string, up to the first space, or the whole string if it contains no spaces.
179 | */
180 | private function chopLpstatLine($line)
181 | {
182 | if (($pos = strpos($line, " ")) === false) {
183 | return $line;
184 | } else {
185 | return substr($line, 0, $pos);
186 | }
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintConnectors/DummyPrintConnector.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintConnectors;
17 |
18 | /**
19 | * Print connector that writes to nowhere, but allows the user to retrieve the
20 | * buffered data. Used for testing.
21 | */
22 | final class DummyPrintConnector implements PrintConnector
23 | {
24 | /**
25 | * @var array $buffer
26 | * Buffer of accumilated data.
27 | */
28 | private $buffer;
29 |
30 | /**
31 | * @var string data which the printer will provide on next read
32 | */
33 | private $readData;
34 |
35 | /**
36 | * Create new print connector
37 | */
38 | public function __construct()
39 | {
40 | $this -> buffer = [];
41 | }
42 |
43 | public function clear()
44 | {
45 | $this -> buffer = [];
46 | }
47 |
48 | public function __destruct()
49 | {
50 | if ($this -> buffer !== null) {
51 | trigger_error("Print connector was not finalized. Did you forget to close the printer?", E_USER_NOTICE);
52 | }
53 | }
54 |
55 | public function finalize()
56 | {
57 | $this -> buffer = null;
58 | }
59 |
60 | /**
61 | * @return string Get the accumulated data that has been sent to this buffer.
62 | */
63 | public function getData()
64 | {
65 | return implode($this -> buffer);
66 | }
67 |
68 | /**
69 | * {@inheritDoc}
70 | * @see PrintConnector::read()
71 | */
72 | public function read($len)
73 | {
74 | return $len >= strlen($this -> readData) ? $this -> readData : substr($this -> readData, 0, $len);
75 | }
76 |
77 | public function write($data)
78 | {
79 | $this -> buffer[] = $data;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintConnectors/FilePrintConnector.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintConnectors;
17 |
18 | use Exception;
19 |
20 | /**
21 | * PrintConnector for passing print data to a file.
22 | */
23 | class FilePrintConnector implements PrintConnector
24 | {
25 | /**
26 | * @var resource $fp
27 | * The file pointer to send data to.
28 | */
29 | protected $fp;
30 |
31 | /**
32 | * Construct new connector, given a filename
33 | *
34 | * @param string $filename
35 | */
36 | public function __construct($filename)
37 | {
38 | $this -> fp = fopen($filename, "wb+");
39 | if ($this -> fp === false) {
40 | throw new Exception("Cannot initialise FilePrintConnector.");
41 | }
42 | }
43 |
44 | public function __destruct()
45 | {
46 | if ($this -> fp !== false) {
47 | trigger_error("Print connector was not finalized. Did you forget to close the printer?", E_USER_NOTICE);
48 | }
49 | }
50 |
51 | /**
52 | * Close file pointer
53 | */
54 | public function finalize()
55 | {
56 | if ($this -> fp !== false) {
57 | fclose($this -> fp);
58 | $this -> fp = false;
59 | }
60 | }
61 |
62 | /* (non-PHPdoc)
63 | * @see PrintConnector::read()
64 | */
65 | public function read($len)
66 | {
67 | if ($this -> fp === false) {
68 | throw new Exception("PrintConnector has been closed, cannot read input.");
69 | }
70 | return fread($this -> fp, $len);
71 | }
72 |
73 | /**
74 | * Write data to the file
75 | *
76 | * @param string $data
77 | */
78 | public function write($data)
79 | {
80 | if ($this -> fp === false) {
81 | throw new Exception("PrintConnector has been closed, cannot send output.");
82 | }
83 | fwrite($this -> fp, $data);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintConnectors/MultiplePrintConnector.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintConnectors;
17 |
18 | /**
19 | * Wrap multiple connectors up, to print to several printers at the same time.
20 | */
21 | class MultiplePrintConnector implements PrintConnector
22 | {
23 | private $connectors;
24 |
25 | public function __construct(PrintConnector ...$connectors)
26 | {
27 | $this -> connectors = $connectors;
28 | }
29 |
30 | public function finalize()
31 | {
32 | foreach ($this -> connectors as $connector) {
33 | $connector -> finalize();
34 | }
35 | }
36 |
37 | public function read($len)
38 | {
39 | // Cannot write
40 | return false;
41 | }
42 |
43 | public function write($data)
44 | {
45 | foreach ($this -> connectors as $connector) {
46 | $connector -> write($data);
47 | }
48 | }
49 |
50 | public function __destruct()
51 | {
52 | // Do nothing
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintConnectors/NetworkPrintConnector.php:
--------------------------------------------------------------------------------
1 | ,
7 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
8 | *
9 | * This software is distributed under the terms of the MIT license. See LICENSE.md
10 | * for details.
11 | */
12 |
13 | namespace Mike42\Escpos\PrintConnectors;
14 |
15 | use Exception;
16 |
17 | /**
18 | * PrintConnector for directly opening a network socket to a printer to send it commands.
19 | */
20 | class NetworkPrintConnector extends FilePrintConnector
21 | {
22 | /**
23 | * Construct a new NetworkPrintConnector
24 | *
25 | * @param string $ip IP address or hostname to use.
26 | * @param int $port The port number to connect on.
27 | * @param int $timeout The connection timeout, in seconds.
28 | * @throws Exception Where the socket cannot be opened.
29 | */
30 | public function __construct(string $ip, int $port = 9100, int $timeout = -1)
31 | {
32 | // Note: Once the minimum PHP version is PHP 7.0 or higher, we can type $timeout as '?int' to make it optional
33 | // instead of using -1.
34 | if ($timeout == -1) {
35 | $this -> fp = @fsockopen($ip, $port, $errno, $errstr);
36 | } else {
37 | $this -> fp = @fsockopen($ip, $port, $errno, $errstr, (float)$timeout);
38 | }
39 | if ($this -> fp === false) {
40 | throw new Exception("Cannot initialise NetworkPrintConnector: " . $errstr);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintConnectors/PrintConnector.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintConnectors;
17 |
18 | /**
19 | * Interface passed to Escpos class for receiving print data. Print connectors
20 | * are responsible for transporting this to the actual printer.
21 | */
22 | interface PrintConnector
23 | {
24 | /**
25 | * Print connectors should cause a NOTICE if they are deconstructed
26 | * when they have not been finalized.
27 | */
28 | public function __destruct();
29 |
30 | /**
31 | * Finish using this print connector (close file, socket, send
32 | * accumulated output, etc).
33 | */
34 | public function finalize();
35 |
36 | /**
37 | * Read data from the printer.
38 | *
39 | * @param string $len Length of data to read.
40 | * @return string Data read from the printer, or false where reading is not possible.
41 | */
42 | public function read($len);
43 |
44 | /**
45 | * Write data to the print connector.
46 | *
47 | * @param string $data The data to write
48 | */
49 | public function write($data);
50 | }
51 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintConnectors/RawbtPrintConnector.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintConnectors;
17 |
18 | /**
19 | * Print connector for android RawBT application
20 | * https://play.google.com/store/apps/details?id=ru.a402d.rawbtprinter
21 | */
22 | final class RawbtPrintConnector implements PrintConnector
23 | {
24 | /**
25 | * @var array $buffer
26 | * Buffer of accumilated data.
27 | */
28 | private $buffer;
29 |
30 | /**
31 | * @var string data which the printer will provide on next read
32 | */
33 | private $readData;
34 |
35 | /**
36 | * Create new print connector
37 | */
38 | public function __construct()
39 | {
40 | ob_start();
41 | $this->buffer = [];
42 | }
43 |
44 | public function clear()
45 | {
46 | $this->buffer = [];
47 | }
48 |
49 | public function __destruct()
50 | {
51 | if ($this->buffer !== null) {
52 | trigger_error("Print connector was not finalized. Did you forget to close the printer?", E_USER_NOTICE);
53 | }
54 | }
55 |
56 | public function finalize()
57 | {
58 | ob_end_clean();
59 | echo "intent:base64," . base64_encode($this->getData()) . "#Intent;scheme=rawbt;package=ru.a402d.rawbtprinter;end;";
60 | $this->buffer = null;
61 | }
62 |
63 | /**
64 | * @return string Get the accumulated data that has been sent to this buffer.
65 | */
66 | public function getData()
67 | {
68 | return implode($this->buffer);
69 | }
70 |
71 | /**
72 | * {@inheritDoc}
73 | * @see PrintConnector::read()
74 | */
75 | public function read($len)
76 | {
77 | return $len >= strlen($this->readData) ? $this->readData : substr($this->readData, 0, $len);
78 | }
79 |
80 | public function write($data)
81 | {
82 | $this->buffer[] = $data;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Mike42/Escpos/PrintConnectors/UriPrintConnector.php:
--------------------------------------------------------------------------------
1 | ,
8 | * incorporating modifications by others. See CONTRIBUTORS.md for a full list.
9 | *
10 | * This software is distributed under the terms of the MIT license. See LICENSE.md
11 | * for details.
12 | */
13 |
14 | declare(strict_types=1);
15 |
16 | namespace Mike42\Escpos\PrintConnectors;
17 |
18 | class UriPrintConnector
19 | {
20 | const URI_ASSEMBLER_PATTERN = "~^(.+):/{2}(.+?)(?::(\d{1,4}))?$~";
21 |
22 | public static function get($uri)
23 | {
24 | // Parse URI
25 | $is_uri = preg_match(self::URI_ASSEMBLER_PATTERN, $uri, $uri_parts);
26 | if ($is_uri !== 1) {
27 | throw new \InvalidArgumentException("Malformed connector URI: {$uri}");
28 | }
29 | // Extract parts
30 | $protocol = $uri_parts[1];
31 | $printer = $uri_parts[2];
32 | $port = isset($uri_parts[3]) ? $uri_parts[3] : 9100;
33 | // Initialise the most applicable print connector
34 | switch ($protocol) {
35 | case "file":
36 | return new FilePrintConnector($printer);
37 | case "tcp":
38 | return new NetworkPrintConnector($printer, $port);
39 | case "smb":
40 | return new WindowsPrintConnector($uri);
41 | }
42 | // Fallthrough
43 | throw new \InvalidArgumentException("URI sheme is not supported: {$protocol}://");
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test/bootstrap.php:
--------------------------------------------------------------------------------
1 | $c) {
28 | $code = ord($c);
29 | if ($code < 32 || $code > 126) {
30 | $chars[$i] = "\\x" . bin2hex($c);
31 | }
32 | }
33 | return implode($chars);
34 | }
35 |
--------------------------------------------------------------------------------
/test/integration/ExampleTest.php:
--------------------------------------------------------------------------------
1 | exampleDir = dirname(__FILE__) . "/../../example/";
12 | }
13 |
14 | /**
15 | * @medium
16 | */
17 | public function testBitImage()
18 | {
19 | $this->markTestSkipped('Not repeatable on Travis CI.');
20 | $this -> requireGraphicsLibrary();
21 | $outp = $this -> runExample("bit-image.php");
22 | $this -> outpTest($outp, "bit-image.bin");
23 | }
24 |
25 | /**
26 | * @medium
27 | */
28 | public function testCharacterEncodings()
29 | {
30 | $outp = $this -> runExample("character-encodings.php");
31 | $this -> outpTest($outp, "character-encodings.bin");
32 | }
33 |
34 | /**
35 | * @medium
36 | */
37 | public function testCharacterTables()
38 | {
39 | $outp = $this -> runExample("character-tables.php");
40 | $this -> outpTest($outp, "character-tables.bin");
41 | }
42 |
43 | private function outpTest($outp, $fn)
44 | {
45 | $file = dirname(__FILE__) . "/resources/output/".$fn;
46 | if (!file_exists($file)) {
47 | file_put_contents($file, $outp);
48 | }
49 | $this -> assertEquals($outp, file_get_contents($file));
50 | }
51 |
52 | /**
53 | * @medium
54 | */
55 | public function testDemo()
56 | {
57 | $this->markTestSkipped('Not repeatable on Travis CI.');
58 | $this -> requireGraphicsLibrary();
59 | $outp = $this -> runExample("demo.php");
60 | $this -> outpTest($outp, "demo.bin");
61 | }
62 |
63 | /**
64 | * @medium
65 | */
66 | public function testGraphics()
67 | {
68 | $this->markTestSkipped('Not repeatable on Travis CI.');
69 | $this -> requireGraphicsLibrary();
70 | $outp = $this -> runExample("graphics.php");
71 | $this -> outpTest($outp, "graphics.bin");
72 | }
73 |
74 | /**
75 | * @medium
76 | */
77 | public function testReceiptWithLogo()
78 | {
79 | $this->markTestSkipped('Not repeatable on Travis CI.');
80 | $this -> requireGraphicsLibrary();
81 | $outp = $this -> runExample("receipt-with-logo.php");
82 | $this -> outpTest($outp, "receipt-with-logo.bin");
83 | }
84 |
85 | /**
86 | * @medium
87 | */
88 | public function testQrCode()
89 | {
90 | $outp = $this -> runExample("qr-code.php");
91 | $this -> outpTest($outp, "qr-code.bin");
92 | }
93 |
94 | /**
95 | * @medium
96 | */
97 | public function testBarcode()
98 | {
99 | $outp = $this -> runExample("barcode.php");
100 | $this -> outpTest($outp, "barcode.bin");
101 | }
102 |
103 | /**
104 | * @medium
105 | */
106 | public function testTextSize()
107 | {
108 | $outp = $this -> runExample("text-size.php");
109 | $this -> outpTest($outp, "text-size.bin");
110 | }
111 |
112 | /**
113 | * @medium
114 | */
115 | public function testMarginsAndSpacing()
116 | {
117 | $outp = $this -> runExample("margins-and-spacing.php");
118 | $this -> outpTest($outp, "margins-and-spacing.bin");
119 | }
120 |
121 | /**
122 | * @medium
123 | */
124 | public function testPdf417Code()
125 | {
126 | $outp = $this -> runExample("pdf417-code.php");
127 | $this -> outpTest($outp, "pdf417-code.bin");
128 | }
129 |
130 | /**
131 | * @medium
132 | */
133 | public function testUnifontPrintBuffer()
134 | {
135 | $this->markTestSkipped('Not repeatable on Travis CI.');
136 | if(!file_exists("/usr/share/unifont/unifont.hex")) {
137 | $this -> markTestSkipped("Test only repeatable w/ unifont installed");
138 | }
139 | $outp = $this -> runExample("unifont-print-buffer.php");
140 | $this -> outpTest($outp, "unifont-print-buffer.bin");
141 | }
142 |
143 | public function testInterfaceCups()
144 | {
145 | $outp = $this -> runSyntaxCheck("interface/cups.php");
146 | }
147 |
148 | public function testInterfaceEthernet()
149 | {
150 | $outp = $this -> runSyntaxCheck("interface/ethernet.php");
151 | }
152 |
153 | public function testInterfaceLinuxUSB()
154 | {
155 | $outp = $this -> runSyntaxCheck("interface/linux-usb.php");
156 | }
157 |
158 | public function testInterfaceWindowsUSB()
159 | {
160 | $outp = $this -> runSyntaxCheck("interface/windows-usb.php");
161 | }
162 |
163 | public function testInterfaceSMB()
164 | {
165 | $outp = $this -> runSyntaxCheck("interface/smb.php");
166 | }
167 |
168 | public function testInterfaceWindowsLPT()
169 | {
170 | $outp = $this -> runSyntaxCheck("interface/windows-lpt.php");
171 | }
172 |
173 | private function runSyntaxCheck($fn)
174 | {
175 | $this -> runExample($fn, true);
176 | }
177 |
178 | private function runExample($fn, $syntaxCheck = false)
179 | {
180 | // Change directory and check script
181 | chdir($this -> exampleDir);
182 | $this -> assertTrue(file_exists($fn), "Script $fn not found.");
183 | // Run command and save output
184 | $php = "php" . ($syntaxCheck ? " -l" : "");
185 | ob_start();
186 | passthru($php . " " . escapeshellarg($fn), $retval);
187 | $outp = ob_get_contents();
188 | ob_end_clean();
189 | // Check return value
190 | $this -> assertEquals(0, $retval, "Example $fn exited with status $retval");
191 | return $outp;
192 | }
193 |
194 | protected function requireGraphicsLibrary()
195 | {
196 | if (!EscposImage::isGdLoaded() && !EscposImage::isImagickLoaded()) {
197 | $this -> markTestSkipped("gd or imagick plugin is required for this test");
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/test/integration/resources/output/barcode.bin:
--------------------------------------------------------------------------------
1 | @!0Height and bar width
2 | ! Default look
3 | kEABC
4 | Height 1
5 | hkEABC
6 | Height 2
7 | hkEABC
8 | Height 4
9 | hkEABC
10 | Height 8
11 | hkEABC
12 | Height 16
13 | hkEABC
14 | Height 32
15 | h kEABC
16 | Width 1
17 | wkEABC
18 | Width 2
19 | wkEABC
20 | Width 3
21 | wkEABC
22 | Width 4
23 | wkEABC
24 | Width 5
25 | wkEABC
26 | Width 6
27 | wkEABC
28 | Width 7
29 | wkEABC
30 | Width 8
31 | wkEABC
32 | h(w!0Text position
33 | ! No text
34 | H kC012345678901
35 | Above
36 | HkC012345678901
37 | Below
38 | HkC012345678901
39 | Both
40 | HkC012345678901
41 | H!0UPC-A
42 | ! Fixed-length numeric product barcodes.
43 |
44 | E12 char numeric including (wrong) check digit.
45 | E Content: 012345678901
46 | kA012345678901
47 | ESend 11 chars to add check digit automatically.
48 | E Content: 01234567890
49 | kA01234567890
50 | !0UPC-E
51 | ! Fixed-length numeric compact product barcodes.
52 |
53 | E6 char numeric - auto check digit & NSC
54 | E Content: 123456
55 | kB123456
56 | E7 char numeric - auto check digit
57 | E Content: 0123456
58 | kB0123456
59 | E8 char numeric
60 | E Content: 01234567
61 | kB01234567
62 | E11 char numeric - auto check digit
63 | E Content: 01234567890
64 | kB01234567890
65 | E12 char numeric including (wrong) check digit
66 | E Content: 012345678901
67 | kB012345678901
68 | !0JAN13/EAN13
69 | ! Fixed-length numeric barcodes.
70 |
71 | E12 char numeric - auto check digit
72 | E Content: 012345678901
73 | kC012345678901
74 | E13 char numeric including (wrong) check digit
75 | E Content: 0123456789012
76 | kC
0123456789012
77 | !0JAN8/EAN8
78 | ! Fixed-length numeric barcodes.
79 |
80 | E7 char numeric - auto check digit
81 | E Content: 0123456
82 | kD0123456
83 | E8 char numeric including (wrong) check digit
84 | E Content: 01234567
85 | kD01234567
86 | !0Code39
87 | ! Variable length alphanumeric w/ some special chars.
88 |
89 | EText, numbers, spaces
90 | E Content: ABC 012
91 | kEABC 012
92 | ESpecial characters
93 | E Content: $%+-./
94 | kE$%+-./
95 | EExtra char (*) Used as start/stop
96 | E Content: *TEXT*
97 | kE*TEXT*
98 | !0ITF
99 | ! Variable length numeric w/even number of digits,
100 | as they are encoded in pairs.
101 |
102 | ENumeric- even number of digits
103 | E Content: 0123456789
104 | kF
105 | 0123456789
106 | !0Codabar
107 | ! Varaible length numeric with some allowable
108 | extra characters. ABCD/abcd must be used as
109 | start/stop characters (one at the start, one
110 | at the end) to distinguish between barcode
111 | applications.
112 |
113 | ENumeric w/ A A start/stop.
114 | E Content: A012345A
115 | kGA012345A
116 | EExtra allowable characters
117 | E Content: A012$+-./:A
118 | kGA012$+-./:A
119 | !0Code93
120 | ! Variable length- any ASCII is available
121 |
122 | EText
123 | E Content: 012abcd
124 | kH012abcd
125 | !0Code128
126 | ! Variable length- any ASCII is available
127 |
128 | ECode set A uppercase & symbols
129 | E Content: {A012ABCD
130 | kI {A012ABCD
131 | ECode set B general text
132 | E Content: {B012ABCDabcd
133 | kI
{B012ABCDabcd
134 | ECode set C compact numbers
135 | Sending chr(21) chr(32) chr(43)
136 | E Content: {C? +
137 | kI{C +
138 | VA
--------------------------------------------------------------------------------
/test/integration/resources/output/bit-image.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/integration/resources/output/bit-image.bin
--------------------------------------------------------------------------------
/test/integration/resources/output/character-encodings.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/integration/resources/output/character-encodings.bin
--------------------------------------------------------------------------------
/test/integration/resources/output/character-tables.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/integration/resources/output/character-tables.bin
--------------------------------------------------------------------------------
/test/integration/resources/output/demo.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/integration/resources/output/demo.bin
--------------------------------------------------------------------------------
/test/integration/resources/output/graphics.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/integration/resources/output/graphics.bin
--------------------------------------------------------------------------------
/test/integration/resources/output/margins-and-spacing.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/integration/resources/output/margins-and-spacing.bin
--------------------------------------------------------------------------------
/test/integration/resources/output/pdf417-code.bin:
--------------------------------------------------------------------------------
1 | @!0PDF417 code demo
2 | ! (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Most simple example
3 |
4 | a(k 0F (k 0A(k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Same content, narrow and centred
5 | a
6 | !0Error correction
7 | ! (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Error correction ratio 0.1
8 |
9 | (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Error correction ratio 0.5
10 |
11 | (k 0F (k 0A (k 0C(k 0D(k 0E1
12 | (k 0P0Testing 123(k 0Q0Error correction ratio 1
13 |
14 | (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Error correction ratio 2
15 |
16 | (k 0F (k 0A (k 0C(k 0D(k 0E1((k 0P0Testing 123(k 0Q0Error correction ratio 4
17 |
18 | !0Pixel size
19 | ! (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Module width 2 dots (minimum)
20 |
21 | (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Module width 3 dots (default)
22 |
23 | (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Module width 4 dots
24 |
25 | (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Module width 8 dots (maximum)
26 |
27 | !0Height multiplier
28 | ! (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Height multiplier 2 (minimum)
29 |
30 | (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Height multiplier 3 (default)
31 |
32 | (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Height multiplier 4
33 |
34 | (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Height multiplier 8 (maximum)
35 |
36 | !0Data column count
37 | ! (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Column count 0 (auto, default)
38 |
39 | (k 0F (k 0A(k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Column count 1
40 |
41 | (k 0F (k 0A(k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Column count 2
42 |
43 | (k 0F (k 0A(k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Column count 3
44 |
45 | (k 0F (k 0A(k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Column count 4
46 |
47 | (k 0F (k 0A(k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Column count 5
48 |
49 | (k 0F (k 0A(k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Column count 30 (maximum, doesnt fit!)
50 |
51 | !0Options
52 | ! (k 0F (k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Standard
53 |
54 | (k 0F(k 0A (k 0C(k 0D(k 0E1(k 0P0Testing 123(k 0Q0Truncated
55 |
56 | VA
--------------------------------------------------------------------------------
/test/integration/resources/output/qr-code.bin:
--------------------------------------------------------------------------------
1 | @!0QR code demo
2 | ! (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Most simple example
3 |
4 | a(k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Same example, centred
5 | a
6 | !0Data encoding
7 | ! (k 1A2 (k 1C(k 1E0(k+ 1P00123456789012345678901234567890123456789(k 1Q0Numeric
8 |
9 | (k 1A2 (k 1C(k 1E0(k+ 1P0abcdefghijklmnopqrstuvwxyzabcdefghijklmn(k 1Q0Alphanumeric
10 |
11 | (k 1A2 (k 1C(k 1E0(k+ 1P0 (k 1Q0Binary
12 |
13 | !0Error correction
14 | ! (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Error correction L
15 |
16 | (k 1A2 (k 1C(k 1E1(k 1P0Testing 123(k 1Q0Error correction M
17 |
18 | (k 1A2 (k 1C(k 1E2(k 1P0Testing 123(k 1Q0Error correction Q
19 |
20 | (k 1A2 (k 1C(k 1E3(k 1P0Testing 123(k 1Q0Error correction H
21 |
22 | !0Pixel size
23 | ! (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Pixel size 1 (minimum)
24 |
25 | (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Pixel size 2
26 |
27 | (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Pixel size 3 (default)
28 |
29 | (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Pixel size 4
30 |
31 | (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Pixel size 5
32 |
33 | (k 1A2 (k 1C
34 | (k 1E0(k 1P0Testing 123(k 1Q0Pixel size 10
35 |
36 | (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Pixel size 16 (maximum)
37 |
38 | !0QR model
39 | ! (k 1A1 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0QR Model 1
40 |
41 | (k 1A2 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0QR Model 2 (default)
42 |
43 | (k 1A3 (k 1C(k 1E0(k 1P0Testing 123(k 1Q0Micro QR code
44 | (not supported on all printers)
45 |
46 | VA
--------------------------------------------------------------------------------
/test/integration/resources/output/receipt-with-logo.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/integration/resources/output/receipt-with-logo.bin
--------------------------------------------------------------------------------
/test/integration/resources/output/text-size.bin:
--------------------------------------------------------------------------------
1 | @@!
2 | Change height & width
3 | ! ! 1!2!"3!34!D5!U6!f7!w8
4 | !
5 | Change width only (height=4):
6 | ! !1!2!#3!34!C5!S6!c7!s8
7 | !
8 | Change height only (width=4):
9 | ! !01!12!23!34!45!56!67!78
10 | !
11 | Very narrow text:
12 | ! !The quick brown fox jumps over the lazy dog.
13 | !
14 | Very wide text:
15 | ! !0Hello world!
16 | !
17 | Largest possible text:
18 | ! !wHello
19 | world!
20 | VA
--------------------------------------------------------------------------------
/test/integration/resources/output/unifont-print-buffer.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/integration/resources/output/unifont-print-buffer.bin
--------------------------------------------------------------------------------
/test/unit/AuresCustomerDisplayTest.php:
--------------------------------------------------------------------------------
1 | outputConnector = new DummyPrintConnector();
16 | $profile = CapabilityProfile::load('OCD-300');
17 | $this -> printer = new AuresCustomerDisplay($this -> outputConnector, $profile);
18 | }
19 |
20 | protected function checkOutput($expected = null)
21 | {
22 | /* Check those output strings */
23 | $outp = $this -> outputConnector -> getData();
24 | if ($expected === null) {
25 | echo "\nOutput was:\n\"" . friendlyBinary($outp) . "\"\n";
26 | }
27 | $this -> assertEquals($expected, $outp);
28 | }
29 |
30 | protected function tearDown(): void
31 | {
32 | $this -> outputConnector -> finalize();
33 | }
34 |
35 | public function testInitializeOutput()
36 | {
37 | $this -> checkOutput("\x02\x05C1\x03\x1b@\x1bt\x00\x1f\x02");
38 | }
39 |
40 | public function testselectTextScrollMode() {
41 | $this -> outputConnector -> clear();
42 | $this -> printer -> selectTextScrollMode(AuresCustomerDisplay::TEXT_OVERWRITE);
43 | $this -> checkOutput("\x1f\x01");
44 | }
45 |
46 | public function testClear() {
47 | $this -> outputConnector -> clear();
48 | $this -> printer -> clear();
49 | $this -> checkOutput("\x0c");
50 | }
51 |
52 | public function testShowFirmwareVersion() {
53 | $this -> outputConnector -> clear();
54 | $this -> printer -> showFirmwareVersion();
55 | $this -> checkOutput("\x02\x05V\x01\x03");
56 | }
57 |
58 | public function testSelfTest() {
59 | $this -> outputConnector -> clear();
60 | $this -> printer -> selfTest();
61 | $this -> checkOutput("\x02\x05D\x08\x03");
62 | }
63 |
64 | public function testShowLogo() {
65 | $this -> outputConnector -> clear();
66 | $this -> printer -> showLogo();
67 | $this -> checkOutput("\x02\xfcU\xaaU\xaa");
68 | }
69 |
70 | public function testTest() {
71 | $this -> outputConnector -> clear();
72 | // Handling of line-endings differs to regular printers, need to use \r\n
73 | $this -> printer -> text("Hello\nWorld\n");
74 | $this -> checkOutput("Hello\x0d\x0aWorld\x0d\x0a");
75 | }
76 | }
--------------------------------------------------------------------------------
/test/unit/CapabilityProfileTest.php:
--------------------------------------------------------------------------------
1 | assertFalse(array_search('simple', $names) === false);
12 | $this->assertFalse(array_search('default', $names) === false);
13 | $this->assertTrue(array_search('lalalalala', $names) === false);
14 | }
15 |
16 | public function testLoadDefault()
17 | {
18 | // Just load the default profile and check it out
19 | $profile = CapabilityProfile::load('default');
20 | $this->assertEquals("default", $profile->getId());
21 | $this->assertEquals("Default", $profile->getName());
22 | $this->assertTrue($profile->getSupportsBarcodeB());
23 | $this->assertTrue($profile->getSupportsBitImageRaster());
24 | $this->assertTrue($profile->getSupportsGraphics());
25 | $this->assertTrue($profile->getSupportsQrCode());
26 | $this->assertTrue($profile->getSupportsPdf417Code());
27 | $this->assertFalse($profile->getSupportsStarCommands());
28 | $this->assertArrayHasKey('0', $profile->getCodePages());
29 | }
30 |
31 | public function testCodePageCacheKey()
32 | {
33 | $default = CapabilityProfile::load('default');
34 | $simple = CapabilityProfile::load('simple');
35 | $this->assertNotEquals($default->getCodePageCacheKey(), $simple->getCodePageCacheKey());
36 | }
37 |
38 | public function testBadProfileNameSuggestion()
39 | {
40 | $this->expectException(InvalidArgumentException::class);
41 | $profile = CapabilityProfile::load('simpel');
42 | }
43 |
44 | public function testBadFeatureNameSuggestion()
45 | {
46 | $this->expectException(InvalidArgumentException::class);
47 | $profile = CapabilityProfile::load('default');
48 | $profile->getFeature('graphicx');
49 | }
50 |
51 | public function testSuggestions()
52 | {
53 | $input = "orangee";
54 | $choices = array("apple", "orange", "pear");
55 | $suggestions = CapabilityProfile::suggestNearest($input, $choices, 1);
56 | $this->assertEquals(1, count($suggestions));
57 | $this->assertEquals("orange", $suggestions[0]);
58 | }
59 | }
--------------------------------------------------------------------------------
/test/unit/CodePageTest.php:
--------------------------------------------------------------------------------
1 | "CP437",
11 | "iconv" => "CP437"
12 | ));
13 | $dataArray = $cp->getDataArray();
14 | $this->assertEquals(128, count($dataArray));
15 | $expected = "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσμτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ";
16 | $this->assertEquals($expected, self::dataArrayToString($dataArray));
17 | }
18 |
19 | public function testDataGenerateFailed()
20 | {
21 | // No errors raised, you just get an empty list of supported characters if you try to compute a fake code page
22 | $cp = new CodePage("foo", array(
23 | "name" => "foo",
24 | "iconv" => "foo"
25 | ));
26 | $this->assertTrue($cp->isEncodable());
27 | $this->assertEquals($cp->getIconv(), "foo");
28 | $this->assertEquals($cp->getName(), "foo");
29 | $this->assertEquals($cp->getId(), "foo");
30 | $this->assertEquals($cp->getNotes(), null);
31 | $dataArray = $cp->getDataArray();
32 | $expected = str_repeat(" ", 128);
33 | $this->assertEquals($expected, self::dataArrayToString($dataArray));
34 | // Do this twice (caching behaviour)
35 | $dataArray = $cp->getDataArray();
36 | $this->assertEquals($expected, self::dataArrayToString($dataArray));
37 | }
38 |
39 | public function testDataDefined()
40 | {
41 | // A made up code page called "baz", which is the same as CP437 but with some unmapped values at the start.
42 | $cp = new CodePage("baz", array(
43 | "name" => "baz",
44 | "iconv" => "baz",
45 | "data" => [
46 | " âäàåçêëèïîìÄÅ",
47 | "ÉæÆôöòûùÿÖÜ¢£¥₧ƒ",
48 | "áíóúñѪº¿⌐¬½¼¡«»",
49 | "░▒▓│┤╡╢╖╕╣║╗╝╜╛┐",
50 | "└┴┬├─┼╞╟╚╔╩╦╠═╬╧",
51 | "╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀",
52 | "αßΓπΣσμτΦΘΩδ∞φε∩",
53 | "≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ "]
54 | ));
55 | $dataArray = $cp->getDataArray();
56 | $this->assertEquals(128, count($dataArray));
57 | $expected = " âäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσμτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ";
58 | $this->assertEquals($expected, self::dataArrayToString($dataArray));
59 | }
60 |
61 | public function testDataCannotEncode()
62 | {
63 | $this->expectException(InvalidArgumentException::class);
64 | $cp = new CodePage("foo", array(
65 | "name" => "foo"
66 | ));
67 | $this->assertFalse($cp->isEncodable());
68 | $cp->getDataArray();
69 | }
70 |
71 | private static function dataArrayToString(array $codePoints) : string
72 | {
73 | // Assemble into character string so that the assertion is more compact
74 | return implode(array_map("IntlChar::chr", $codePoints));
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/test/unit/CupsPrintConnectorTest.php:
--------------------------------------------------------------------------------
1 | getMockConnector("FooPrinter", array("FooPrinter"));
10 | $connector->expects($this->once())->method('getCmdOutput')->with($this->stringContains("lp -d 'FooPrinter' "));
11 | $connector->finalize();
12 | }
13 | public function testPrinterDoesntExist()
14 | {
15 | $this -> expectException(BadMethodCallException::class);
16 | $connector = $this->getMockConnector("FooPrinter", array("OtherPrinter"));
17 | $connector->expects($this->once())->method('getCmdOutput')->with($this->stringContains("lp -d 'FooPrinter' "));
18 | $connector->finalize();
19 | }
20 | public function testNoPrinter()
21 | {
22 | $this -> expectException(BadMethodCallException::class);
23 | $connector = $this->getMockConnector("FooPrinter", array(""));
24 | }
25 | private function getMockConnector($path, array $printers)
26 | {
27 | $stub = $this->getMockBuilder('Mike42\Escpos\PrintConnectors\CupsPrintConnector')->setMethods(array (
28 | 'getCmdOutput',
29 | 'getLocalPrinters'
30 | ))->disableOriginalConstructor()->getMock();
31 | $stub->method('getCmdOutput')->willReturn("");
32 | $stub->method('getLocalPrinters')->willReturn($printers);
33 | $stub->__construct($path);
34 | return $stub;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/test/unit/EscposImageTest.php:
--------------------------------------------------------------------------------
1 | expectException(Exception::class);
9 | $img = EscposImage::load('not-a-real-file.png');
10 | }
11 | public function testImageNotSupportedException()
12 | {
13 | $this -> expectException(InvalidArgumentException::class);
14 | $img = EscposImage::load('/dev/null', false, array());
15 | }
16 | }
--------------------------------------------------------------------------------
/test/unit/Experimental/Unifont/UnifontPrintBufferTest.php:
--------------------------------------------------------------------------------
1 | outputConnector = new DummyPrintConnector();
17 | $this -> printer = new Printer($this -> outputConnector);
18 | $filename = tempnam(sys_get_temp_dir(), "escpos-php-");
19 | $glyphs = [
20 | "0020:00000000000000000000000000000000", // space is guessed
21 | "0041:0000000018242442427E424242420000" // Letter "A" from Wikipedia
22 | ];
23 | file_put_contents($filename, implode("\n", $glyphs));
24 | $printBuffer = new UnifontPrintBuffer($filename);
25 | $this -> printer -> setPrintBuffer($printBuffer);
26 | }
27 |
28 | protected function checkOutput($expected = null)
29 | {
30 | /* Check those output strings */
31 | $outp = $this -> outputConnector -> getData();
32 | if ($expected === null) {
33 | echo "\nOutput was:\n\"" . friendlyBinary($outp) . "\"\n";
34 | }
35 | $this -> assertEquals($expected, $outp);
36 | }
37 |
38 | protected function tearDown(): void
39 | {
40 | $this -> outputConnector -> finalize();
41 | }
42 |
43 | public function testString()
44 | {
45 | // Render the text "AA A" rendered via used-defined font.
46 | $this -> printer -> text("AA A\r\n");
47 | $this -> checkOutput("\x1b@\x1b!1\x1b%\x01\x1b&\x03 \x08\x00\x00\x00\x01\xfc\x00\x06@\x00\x08@\x00\x08@\x00\x06@\x00\x01\xfc\x00\x00\x00\x00 \x1b&\x03!!\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00! \x0a");
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/test/unit/FilePrintConnectorTest.php:
--------------------------------------------------------------------------------
1 | finalize();
12 | $connector -> finalize(); // Silently do nothing if printer already closed
13 | $this -> assertEquals("", file_get_contents($tmpfname));
14 | unlink($tmpfname);
15 | }
16 |
17 | public function testReadAfterClose()
18 | {
19 | // Should attempt to send data to the local printer by writing to it
20 | $this -> expectException(Exception::class);
21 | $tmpfname = tempnam("/tmp", "php");
22 | $connector = new FilePrintConnector($tmpfname);
23 | $connector -> finalize();
24 | $connector -> write("Test");
25 | unlink($tmpfname);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/test/unit/GdEscposImageTest.php:
--------------------------------------------------------------------------------
1 | expectException(Exception::class);
15 | $this -> loadAndCheckImg('not a real file.png', 1, 1, null, null);
16 | }
17 |
18 | /**
19 | * @medium
20 | */
21 | public function testGdEmpty()
22 | {
23 | $this -> loadAndCheckImg(null, 0, 0, "", array());
24 | }
25 |
26 | /**
27 | * @medium
28 | */
29 | public function testGdBlack()
30 | {
31 | foreach (array('png', 'jpg', 'gif') as $format) {
32 | $this -> loadAndCheckImg('canvas_black.' . $format, 1, 1, "\x80", array("\x80"));
33 | }
34 | }
35 |
36 | /**
37 | * @medium
38 | */
39 | public function testGdBlackTransparent()
40 | {
41 | foreach (array('png', 'gif') as $format) {
42 | $this -> loadAndCheckImg('black_transparent.' . $format, 2, 2, "\xc0\x00", array("\x80\x80"));
43 | }
44 | }
45 |
46 | /**
47 | * @medium
48 | */
49 | public function testGdBlackWhite()
50 | {
51 | foreach (array('png', 'jpg', 'gif') as $format) {
52 | $this -> loadAndCheckImg('black_white.' . $format, 2, 2, "\xc0\x00", array("\x80\x80"));
53 | }
54 | }
55 |
56 | /**
57 | * @medium
58 | */
59 | public function testGdWhite()
60 | {
61 | foreach (array('png', 'jpg', 'gif') as $format) {
62 | $this -> loadAndCheckImg('canvas_white.' . $format, 1, 1, "\x00", array("\x00"));
63 | }
64 | }
65 |
66 | /**
67 | * Load an EscposImage with (optionally) certain libraries disabled and run a check.
68 | */
69 | private function loadAndCheckImg($fn, $width, $height, $rasterFormat = null, $columnFormat = null)
70 | {
71 | if (!EscposImage::isGdLoaded()) {
72 | $this -> markTestSkipped("gd plugin is required for this test");
73 | }
74 | $onDisk = ($fn === null ? null : (dirname(__FILE__) . "/resources/$fn"));
75 | // With optimisations
76 | $imgOptimised = new GdEscposImage($onDisk, true);
77 | $this -> checkImg($imgOptimised, $width, $height, $rasterFormat, $columnFormat);
78 | // ... and without
79 | $imgUnoptimised = new GdEscposImage($onDisk, false);
80 | $this -> checkImg($imgUnoptimised, $width, $height, $rasterFormat, $columnFormat);
81 | }
82 |
83 | /**
84 | * Check image against known width, height, output.
85 | */
86 | private function checkImg(EscposImage $img, $width, $height, $rasterFormatExpected = null, $columnFormatExpected = null)
87 | {
88 | $rasterFormatActual = $img -> toRasterFormat();
89 | $columnFormatActual = $img -> toColumnFormat();
90 | if ($rasterFormatExpected === null) {
91 | echo "\nImage was: " . $img -> getWidth() . "x" . $img -> getHeight() . ", raster data \"" . friendlyBinary($rasterFormatActual) . "\"";
92 | }
93 | if ($columnFormatExpected === null) {
94 | echo "\nImage was: " . $img -> getWidth() . "x" . $img -> getHeight() . ", column data \"" . friendlyBinary($columnFormatActual) . "\"";
95 | }
96 | $this -> assertTrue($img -> getHeight() == $height);
97 | $this -> assertTrue($img -> getWidth() == $width);
98 | $this -> assertTrue($rasterFormatExpected === $rasterFormatActual);
99 | $this -> assertTrue($columnFormatExpected === $columnFormatActual);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/test/unit/ImagickEscposImageTest.php:
--------------------------------------------------------------------------------
1 | expectException(Exception::class);
15 | $this -> loadAndCheckImg('not a real file.png', 1, 1, null, null);
16 | }
17 |
18 | /**
19 | * @medium
20 | */
21 | public function testImagickEmpty()
22 | {
23 | $this -> loadAndCheckImg(null, 0, 0, "", array());
24 | }
25 |
26 | /**
27 | * @medium
28 | */
29 | public function testImagickBlack()
30 | {
31 | foreach (array('png', 'jpg', 'gif') as $format) {
32 | $this -> loadAndCheckImg('canvas_black.' . $format, 1, 1, "\x80", array("\x80"));
33 | }
34 | }
35 |
36 | /**
37 | * @medium
38 | */
39 | public function testImagickBlackTransparent()
40 | {
41 | foreach (array('png', 'gif') as $format) {
42 | $this -> loadAndCheckImg('black_transparent.' . $format, 2, 2, "\xc0\x00", array("\x80\x80"));
43 | }
44 | }
45 |
46 | /**
47 | * @medium
48 | */
49 | public function testImagickBlackWhite()
50 | {
51 | foreach (array('png', 'jpg', 'gif') as $format) {
52 | $this -> loadAndCheckImg('black_white.' . $format, 2, 2, "\xc0\x00", array("\x80\x80"));
53 | }
54 | }
55 |
56 | /**
57 | * @medium
58 | */
59 | public function testImagickBlackWhiteTall()
60 | {
61 | // We're very interested in correct column format chopping here at 8 pixels
62 | $this -> loadAndCheckImg('black_white_tall.png', 2, 16,
63 | "\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x00\x00\x00\x00\x00\x00\x00\x00", array("\xff\xff", "\x00\x00"));
64 | }
65 |
66 | /**
67 | * @medium
68 | */
69 | public function testImagickWhite()
70 | {
71 | foreach (array('png', 'jpg', 'gif') as $format) {
72 | $this -> loadAndCheckImg('canvas_white.' . $format, 1, 1, "\x00", array("\x00"));
73 | }
74 | }
75 |
76 | /**
77 | * PDF test - load tiny PDF and check for well-formedness
78 | * These are also skipped if you don't have imagick
79 | * @medium
80 | */
81 | public function testPdfAllPages()
82 | {
83 | // This is expected to fail on many distributions with an error, due to GhostScript defaults.
84 | // 'Exception: not authorized `/path/to/doc.pdf' @error/constitute.c/ReadImage/412'
85 | // The defaults were changed to prevent a vulnerability (arbitrary code execution), and can be bypassed if you
86 | // trust the source of PDF files.
87 | // https://stackoverflow.com/a/52661288/1808534
88 | $this -> markTestSkipped('unsupported feature');
89 | $this -> loadAndCheckPdf('doc.pdf', 1, 1, array("\x00", "\x80"), array(array("\x00"), array("\x80")));
90 | }
91 |
92 | public function testPdfBadFilename()
93 | {
94 | $this -> expectException(Exception::class);
95 | $this -> loadAndCheckPdf('not a real file', 1, 1, array(), array());
96 | }
97 |
98 | /**
99 | * Load an EscposImage and run a check.
100 | */
101 | private function loadAndCheckImg($fn, $width, $height, $rasterFormat = null, $columnFormat = null)
102 | {
103 | if (!EscposImage::isImagickLoaded()) {
104 | $this -> markTestSkipped("imagick plugin is required for this test");
105 | }
106 | $onDisk = ($fn === null ? null : (dirname(__FILE__) . "/resources/$fn"));
107 | // With optimisations
108 | $imgOptimised = new ImagickEscposImage($onDisk, true);
109 | $this -> checkImg($imgOptimised, $width, $height, $rasterFormat, $columnFormat);
110 | // ... and without
111 | $imgUnoptimised = new ImagickEscposImage($onDisk, false);
112 | $this -> checkImg($imgUnoptimised, $width, $height, $rasterFormat, $columnFormat);
113 | }
114 |
115 | /**
116 | * Same as above, loading document and checking pages against some expected values.
117 | */
118 | private function loadAndCheckPdf($fn, $width, $height, array $rasterFormat = null, array $columnFormat = null)
119 | {
120 | if (!EscposImage::isImagickLoaded()) {
121 | $this -> markTestSkipped("imagick plugin required for this test");
122 | }
123 | $pdfPages = ImagickEscposImage::loadPdf(dirname(__FILE__) . "/resources/$fn", $width);
124 | $this -> assertTrue(count($pdfPages) == count($rasterFormat), "Got back wrong number of pages");
125 | foreach ($pdfPages as $id => $img) {
126 | $this -> checkImg($img, $width, $height, $rasterFormat[$id], $columnFormat[$id]);
127 | }
128 | }
129 |
130 | /**
131 | * Check image against known width, height, output.
132 | */
133 | private function checkImg(EscposImage $img, $width, $height, $rasterFormatExpected = null, $columnFormatExpected = null)
134 | {
135 | $rasterFormatActual = $img -> toRasterFormat();
136 | $columnFormatActual = $img -> toColumnFormat();
137 | if ($rasterFormatExpected === null) {
138 | echo "\nImage was: " . $img -> getWidth() . "x" . $img -> getHeight() . ", raster data \"" . friendlyBinary($rasterFormatActual) . "\"";
139 | }
140 | if ($columnFormatExpected === null) {
141 | echo "\nImage was: " . $img -> getWidth() . "x" . $img -> getHeight() . ", column data \"" . friendlyBinary($columnFormatActual) . "\"";
142 | }
143 | $this -> assertEquals($height , $img -> getHeight());
144 | $this -> assertEquals($width, $img -> getWidth());
145 | $this -> assertEquals($rasterFormatExpected, $rasterFormatActual, "Raster format did not match expected");
146 | $this -> assertEquals($columnFormatExpected, $columnFormatActual, "Column format did not match expected");
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/test/unit/MultiplePrintConnectorTest.php:
--------------------------------------------------------------------------------
1 | text("Hello World\n");
18 | $printer->cut();
19 | // Get data out and close the printer
20 | $kitchenText = $kitchenPrinter->getData();
21 | $barText = $barPrinter->getData();
22 | $printer->close();
23 | // Should have matching prints to each printer
24 | $this->assertEquals("\x1b@Hello World\x0a\x1dVA\x03", $kitchenText);
25 | $this->assertEquals("\x1b@Hello World\x0a\x1dVA\x03", $barText);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/test/unit/NativeEscposImageTest.php:
--------------------------------------------------------------------------------
1 | expectException(Exception::class);
14 | $this -> loadAndCheckImg('not a real file.png', 1, 1, null, null);
15 | }
16 |
17 | /**
18 | * @medium
19 | */
20 | public function testBlack()
21 | {
22 | foreach (array('bmp', 'gif', 'png') as $format) {
23 | $this -> loadAndCheckImg('canvas_black.' . $format, 1, 1, "\x80", array("\x80"));
24 | }
25 | }
26 |
27 | /**
28 | * @medium
29 | */
30 | public function testBlackTransparent()
31 | {
32 | foreach (array('gif', 'png') as $format) {
33 | $this -> loadAndCheckImg('black_transparent.' . $format, 2, 2, "\xc0\x00", array("\x80\x80"));
34 | }
35 | }
36 |
37 | /**
38 | * @medium
39 | */
40 | public function testBlackWhite()
41 | {
42 | foreach (array('bmp', 'png', 'gif') as $format) {
43 | $this -> loadAndCheckImg('black_white.' . $format, 2, 2, "\xc0\x00", array("\x80\x80"));
44 | }
45 | }
46 |
47 | /**
48 | * @medium
49 | */
50 | public function testBlackWhiteTall()
51 | {
52 | // We're very interested in correct column format chopping here at 8 pixels
53 | $this -> loadAndCheckImg('black_white_tall.png', 2, 16,
54 | "\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x00\x00\x00\x00\x00\x00\x00\x00", array("\xff\xff", "\x00\x00"));
55 | }
56 |
57 | /**
58 | * @medium
59 | */
60 | public function testWhite()
61 | {
62 | foreach (array('bmp', 'png', 'gif') as $format) {
63 | $this -> loadAndCheckImg('canvas_white.' . $format, 1, 1, "\x00", array("\x00"));
64 | }
65 | }
66 |
67 | /**
68 | * Load an EscposImage and run a check.
69 | */
70 | private function loadAndCheckImg($fn, $width, $height, $rasterFormat = null, $columnFormat = null)
71 | {
72 | $onDisk = ($fn === null ? null : (dirname(__FILE__) . "/resources/$fn"));
73 | // With optimisations
74 | $imgOptimised = new NativeEscposImage($onDisk, true);
75 | $this -> checkImg($imgOptimised, $width, $height, $rasterFormat, $columnFormat);
76 | // ... and without
77 | $imgUnoptimised = new NativeEscposImage($onDisk, false);
78 | $this -> checkImg($imgUnoptimised, $width, $height, $rasterFormat, $columnFormat);
79 | }
80 |
81 | /**
82 | * Check image against known width, height, output.
83 | */
84 | private function checkImg(EscposImage $img, $width, $height, $rasterFormatExpected = null, $columnFormatExpected = null)
85 | {
86 | $rasterFormatActual = $img -> toRasterFormat();
87 | $columnFormatActual = $img -> toColumnFormat();
88 | if ($rasterFormatExpected === null) {
89 | echo "\nImage was: " . $img -> getWidth() . "x" . $img -> getHeight() . ", raster data \"" . friendlyBinary($rasterFormatActual) . "\"";
90 | }
91 | if ($columnFormatExpected === null) {
92 | echo "\nImage was: " . $img -> getWidth() . "x" . $img -> getHeight() . ", column data \"" . friendlyBinary($columnFormatActual) . "\"";
93 | }
94 | $this -> assertEquals($height , $img -> getHeight());
95 | $this -> assertEquals($width, $img -> getWidth());
96 | $this -> assertEquals($rasterFormatExpected, $rasterFormatActual, "Raster format did not match expected");
97 | $this -> assertEquals($columnFormatExpected, $columnFormatActual, "Column format did not match expected");
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/test/unit/UriPrintConnectorTest.php:
--------------------------------------------------------------------------------
1 | write("AAA");
13 | $connector -> finalize();
14 | $this -> assertEquals("AAA", file_get_contents($filename));
15 | $this -> assertEquals('Mike42\Escpos\PrintConnectors\FilePrintConnector', get_class($connector));
16 | unlink($filename);
17 | }
18 |
19 | public function testSmb()
20 | {
21 | $this->expectNotice();
22 | $this->expectNoticeMessage("not finalized");
23 | $connector = UriPrintConnector::get("smb://windows/printer");
24 | $this -> assertEquals('Mike42\Escpos\PrintConnectors\WindowsPrintConnector', get_class($connector));
25 | // We expect that this will throw an exception, we can't
26 | // realistically print to a real printer in this test though... :)
27 | $connector -> __destruct();
28 | }
29 |
30 | public function testBadUri()
31 | {
32 | $this->expectException(InvalidArgumentException::class);
33 | $this->expectExceptionMessage("Malformed connector URI");
34 | $connector = UriPrintConnector::get("foooooo");
35 | }
36 |
37 | public function testNetwork()
38 | {
39 | $this->expectExceptionMessage("Connection refused");
40 | $this->expectException(Exception::class);
41 | // Port should be closed so we can catch an error and move on
42 | $connector = UriPrintConnector::get("tcp://localhost:45987/");
43 | }
44 |
45 | public function testUnsupportedUri()
46 | {
47 | $this->expectExceptionMessage("URI sheme is not supported: ldap://");
48 | $this->expectException(InvalidArgumentException::class);
49 | // Try to print to something silly
50 | $connector = UriPrintConnector::get("ldap://host:1234/");
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test/unit/resources/black_transparent.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/black_transparent.gif
--------------------------------------------------------------------------------
/test/unit/resources/black_transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/black_transparent.png
--------------------------------------------------------------------------------
/test/unit/resources/black_white.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/black_white.bmp
--------------------------------------------------------------------------------
/test/unit/resources/black_white.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/black_white.gif
--------------------------------------------------------------------------------
/test/unit/resources/black_white.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/black_white.jpg
--------------------------------------------------------------------------------
/test/unit/resources/black_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/black_white.png
--------------------------------------------------------------------------------
/test/unit/resources/black_white_tall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/black_white_tall.png
--------------------------------------------------------------------------------
/test/unit/resources/canvas_black.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/canvas_black.bmp
--------------------------------------------------------------------------------
/test/unit/resources/canvas_black.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/canvas_black.gif
--------------------------------------------------------------------------------
/test/unit/resources/canvas_black.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/canvas_black.jpg
--------------------------------------------------------------------------------
/test/unit/resources/canvas_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/canvas_black.png
--------------------------------------------------------------------------------
/test/unit/resources/canvas_white.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/canvas_white.bmp
--------------------------------------------------------------------------------
/test/unit/resources/canvas_white.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/canvas_white.gif
--------------------------------------------------------------------------------
/test/unit/resources/canvas_white.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/canvas_white.jpg
--------------------------------------------------------------------------------
/test/unit/resources/canvas_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/canvas_white.png
--------------------------------------------------------------------------------
/test/unit/resources/demo.php:
--------------------------------------------------------------------------------
1 | readImage("doc.pdf[5]");
5 | $im -> destroy();
6 | } catch (ImagickException $e) {
7 | echo "Error: " . $e -> getMessage() . "\n";
8 | }
9 |
10 | $im = new Imagick();
11 | try {
12 | ob_start();
13 | @$im -> readImage("doc.pdf[5]");
14 | ob_end_clean();
15 | $im -> destroy();
16 | } catch (ImagickException $e) {
17 | echo "Error: " . $e -> getMessage() . "\n";
18 | }
19 |
--------------------------------------------------------------------------------
/test/unit/resources/doc.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mike42/escpos-php/f414320fc510afcacd4cbb75902f827399dee429/test/unit/resources/doc.pdf
--------------------------------------------------------------------------------