├── .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: [![Caption](https://example.com/target)](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 | black & white picture 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 | HkC 012345678901 35 | Above 36 | HkC 012345678901 37 | Below 38 | HkC 012345678901 39 | Both 40 | HkC 012345678901 41 | H!0UPC-A 42 | !Fixed-length numeric product barcodes. 43 | 44 | E12 char numeric including (wrong) check digit. 45 | EContent: 012345678901 46 | kA 012345678901 47 | ESend 11 chars to add check digit automatically. 48 | EContent: 01234567890 49 | kA 01234567890 50 | !0UPC-E 51 | !Fixed-length numeric compact product barcodes. 52 | 53 | E6 char numeric - auto check digit & NSC 54 | EContent: 123456 55 | kB123456 56 | E7 char numeric - auto check digit 57 | EContent: 0123456 58 | kB0123456 59 | E8 char numeric 60 | EContent: 01234567 61 | kB01234567 62 | E11 char numeric - auto check digit 63 | EContent: 01234567890 64 | kB 01234567890 65 | E12 char numeric including (wrong) check digit 66 | EContent: 012345678901 67 | kB 012345678901 68 | !0JAN13/EAN13 69 | !Fixed-length numeric barcodes. 70 | 71 | E12 char numeric - auto check digit 72 | EContent: 012345678901 73 | kC 012345678901 74 | E13 char numeric including (wrong) check digit 75 | EContent: 0123456789012 76 | kC 0123456789012 77 | !0JAN8/EAN8 78 | !Fixed-length numeric barcodes. 79 | 80 | E7 char numeric - auto check digit 81 | EContent: 0123456 82 | kD0123456 83 | E8 char numeric including (wrong) check digit 84 | EContent: 01234567 85 | kD01234567 86 | !0Code39 87 | !Variable length alphanumeric w/ some special chars. 88 | 89 | EText, numbers, spaces 90 | EContent: ABC 012 91 | kEABC 012 92 | ESpecial characters 93 | EContent: $%+-./ 94 | kE$%+-./ 95 | EExtra char (*) Used as start/stop 96 | EContent: *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 | EContent: 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 | EContent: A012345A 115 | kGA012345A 116 | EExtra allowable characters 117 | EContent: A012$+-./:A 118 | kG A012$+-./:A 119 | !0Code93 120 | !Variable length- any ASCII is available 121 | 122 | EText 123 | EContent: 012abcd 124 | kH012abcd 125 | !0Code128 126 | !Variable length- any ASCII is available 127 | 128 | ECode set A uppercase & symbols 129 | EContent: {A012ABCD 130 | kI {A012ABCD 131 | ECode set B general text 132 | EContent: {B012ABCDabcd 133 | kI {B012ABCDabcd 134 | ECode set C compact numbers 135 | Sending chr(21) chr(32) chr(43) 136 | EContent: {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 | !(k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Most simple example 3 | 4 | a(k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Same content, narrow and centred 5 | a 6 | !0Error correction 7 | !(k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Error correction ratio 0.1 8 | 9 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Error correction ratio 0.5 10 | 11 | (k0F(k0A(k0C(k0D(k0E1 12 | (k0P0Testing 123(k0Q0Error correction ratio 1 13 | 14 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Error correction ratio 2 15 | 16 | (k0F(k0A(k0C(k0D(k0E1((k0P0Testing 123(k0Q0Error correction ratio 4 17 | 18 | !0Pixel size 19 | !(k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Module width 2 dots (minimum) 20 | 21 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Module width 3 dots (default) 22 | 23 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Module width 4 dots 24 | 25 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Module width 8 dots (maximum) 26 | 27 | !0Height multiplier 28 | !(k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Height multiplier 2 (minimum) 29 | 30 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Height multiplier 3 (default) 31 | 32 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Height multiplier 4 33 | 34 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Height multiplier 8 (maximum) 35 | 36 | !0Data column count 37 | !(k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Column count 0 (auto, default) 38 | 39 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Column count 1 40 | 41 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Column count 2 42 | 43 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Column count 3 44 | 45 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Column count 4 46 | 47 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Column count 5 48 | 49 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Column count 30 (maximum, doesnt fit!) 50 | 51 | !0Options 52 | !(k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Standard 53 | 54 | (k0F(k0A(k0C(k0D(k0E1(k0P0Testing 123(k0Q0Truncated 55 | 56 | VA -------------------------------------------------------------------------------- /test/integration/resources/output/qr-code.bin: -------------------------------------------------------------------------------- 1 | @!0QR code demo 2 | !(k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Most simple example 3 | 4 | a(k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Same example, centred 5 | a 6 | !0Data encoding 7 | !(k1A2(k1C(k1E0(k+1P00123456789012345678901234567890123456789(k1Q0Numeric 8 | 9 | (k1A2(k1C(k1E0(k+1P0abcdefghijklmnopqrstuvwxyzabcdefghijklmn(k1Q0Alphanumeric 10 | 11 | (k1A2(k1C(k1E0(k+1P0(k1Q0Binary 12 | 13 | !0Error correction 14 | !(k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Error correction L 15 | 16 | (k1A2(k1C(k1E1(k1P0Testing 123(k1Q0Error correction M 17 | 18 | (k1A2(k1C(k1E2(k1P0Testing 123(k1Q0Error correction Q 19 | 20 | (k1A2(k1C(k1E3(k1P0Testing 123(k1Q0Error correction H 21 | 22 | !0Pixel size 23 | !(k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Pixel size 1 (minimum) 24 | 25 | (k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Pixel size 2 26 | 27 | (k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Pixel size 3 (default) 28 | 29 | (k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Pixel size 4 30 | 31 | (k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Pixel size 5 32 | 33 | (k1A2(k1C 34 | (k1E0(k1P0Testing 123(k1Q0Pixel size 10 35 | 36 | (k1A2(k1C(k1E0(k1P0Testing 123(k1Q0Pixel size 16 (maximum) 37 | 38 | !0QR model 39 | !(k1A1(k1C(k1E0(k1P0Testing 123(k1Q0QR Model 1 40 | 41 | (k1A2(k1C(k1E0(k1P0Testing 123(k1Q0QR Model 2 (default) 42 | 43 | (k1A3(k1C(k1E0(k1P0Testing 123(k1Q0Micro 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 --------------------------------------------------------------------------------