Receipt Printer

This commit is contained in:
frederic34 2015-11-01 00:58:08 +01:00
parent c9e80fd148
commit 2f3e6958f9
99 changed files with 9983 additions and 0 deletions

View File

@ -16,6 +16,7 @@ AdoDb-Date 0.33 Modified BSD License Yes
ChromePHP 4.1.0 Apache Software License 2.0 Yes Return server log to chrome browser console
CKEditor 4.3.3 LGPL-2.1+ Yes Editor WYSIWYG
EvalMath 1.0 BSD Yes Safe math expressions evaluation
Escpos-php MIT License Yes Thermal receipt printer library, for use with ESC/POS compatible printers
FirePHPCore 0.4.0 MIT License Yes Send logs to Firefox Firebug console
FPDI 1.5.2 Apache Software License 2.0 Yes PDF templates management
GeoIP 1.4 LGPL-2.1+ Yes Sample code to make geoip convert (not into deb package)

View File

@ -0,0 +1,111 @@
<?php
/*
* Copyright (C) 2015 Frederic France <frederic.france@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* or see http://www.gnu.org/
*/
/**
* \file htdocs/core/class/dolreceiptprinter.class.php
* \brief Print receipt ticket on various printer
*/
/*
* codes for ticket template
*
* <align_left> Left align text
* <align_center> Center text
* <align_right> Right align text
* <use_font_a> Use font A of printer
* <use_font_b> Use font B of printer
* <use_font_c> Use font C of printer
* <bold> </bold> Text Bold
* <double_height> </double_height> Text double height
* <double_width> </double_width> Text double width
* <underline> </underline> Underline text
* <underline_2dots> </underline> Underline with double line
* <emphasized> </emphasized> Emphasized text
* <switch_colors> </switch_colors> Print in white on black
* <print_barcode> Print barcode
* <print_barcode_customer_id> Print barcode customer id
* <set_print_width_57> Ticket print width of 57mm
* <cut_paper_full> Cut ticket completely
* <cut_paper_partial> Cut ticket partially
* <open_drawer> Open cash drawer
* <activate_buzzer> Activate buzzer
*
* Code which can be placed everywhere
* <print_qrcode> Print QR Code
* <print_date> Print date (format : AAAA-MM-DD)
* <print_date_time> Print date and time (format AAAA-MM-DD HH:MM:SS)
* <print_year> Print Year
* <print_month_letters> Print month in letters (example : november)
* <print_month> Print month number
* <print_day> Print day number
* <print_table> Print table number
* <print_cutlery> Print cutlery number
* <print_payment> Print payment method
* <print_logo> Print logo stored on printer. Example : <print_logo>32|32
* <print_logo_deprecated> Print logo stored on printer. Must be followed by logo code. For old printers.
* <print_num_order> Print order number
* <print_num_order_unique> Print order number after validation
* <print_customer_first_name> Print customer firstname
* <print_customer_last_name> Print customer name
* <print_customer_mail> Print customer mail
* <print_customer_telephone> Print customer phone
* <print_customer_mobile> Print customer mobile
* <print_customer_skype> Print customer skype
* <print_customer_tax_number> Print customer VAT number
* <print_customer_account_balance> Print customer account balance
* <print_vendor_last_name> Print vendor name
* <print_vendor_first_name> Print vendor firstname
* <print_customer_points> Print customer points
* <print_order_points> Print number of points for this order
*
* Conditional code at line start (if…then Print)
* <print_if_customer> Print the line IF a customer is affected to the order
* <print_if_vendor> Print the line IF a vendor is affected to the order
* <print_if_happy_hour> Print the line IF Happy Hour
* <print_if_num_order_unique> Print the line IF order is validated
* <print_if_customer_points> Print the line IF customer points > 0
* <print_if_order_points> Print the line IF points of the order > 0
* <print_if_customer_tax_number> Print the line IF customer has vat number
* <print_if_customer_account_balance_positive> Print the line IF customer balance > 0
*
*/
/**
* Class to manage Receipt Printers
*/
class dolReceiptPrinter
{
var $db;
var $error;
var $errors;
/**
* Constructor
*
* @param DoliDB $db database
*/
function __construct($db)
{
$this->db=$db;
}
}

View File

@ -0,0 +1,123 @@
<?php
/* Copyright (C) 2014-2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2015 Frederic France <frederic.france@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \defgroup printing Module Receipt Printer
* \brief Module for activation of printing icon to make receipt ticket
*/
/**
* \file htdocs/core/modules/modReceiptPrinter.class.php
* \ingroup printing
* \brief File of class to describe and activate module Receipt Printer
*/
include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php';
/**
* Class to describe and activate module Receipt Printer
*/
class modReceiptPrinter extends DolibarrModules
{
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
function __construct($db)
{
$this->db = $db ;
$this->numero = 67000;
// Family can be 'crm','financial','hr','projects','products','ecm','technic','other'
// It is used to group modules in module setup page
$this->family = "technic";
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
$this->name = preg_replace('/^mod/i','',get_class($this));
// Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module)
$this->description = "Receipt Printer.";
$this->version = 'dolibarr'; // 'development' or 'experimental' or 'dolibarr' or version
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
// Where to store the module in setup page (0=common,1=interface,2=others,3=very specific)
$this->special = 1;
// Name of image file used for this module.
// If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
// If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
$this->picto = 'printer';
// Data directories to create when module is enabled.
$this->dirs = array();
// Config pages
$this->config_page_url = array("receiptprinter.php");
// Dependencies
$this->depends = array();
$this->requiredby = array();
$this->phpmin = array(5,1); // Minimum version of PHP required by module
$this->need_dolibarr_version = array(3,7,-2); // Minimum version of Dolibarr required by module
$this->conflictwith = array();
$this->langfiles = array("receiptprinter");
// Constants
$this->const = array();
// Boxes
$this->boxes = array();
// Permissions
$this->rights = array();
$this->rights_class = 'receiptprinter';
$r=0;
// $this->rights[$r][0] Id permission (unique tous modules confondus)
// $this->rights[$r][1] Libelle par defaut si traduction de cle "PermissionXXX" non trouvee (XXX = Id permission)
// $this->rights[$r][2] Non utilise
// $this->rights[$r][3] 1=Permis par defaut, 0=Non permis par defaut
// $this->rights[$r][4] Niveau 1 pour nommer permission dans code
// $this->rights[$r][5] Niveau 2 pour nommer permission dans code
$r++;
$this->rights[$r][0] = 67001;
$this->rights[$r][1] = 'ReceiptPrinter';
$this->rights[$r][2] = 'r';
$this->rights[$r][3] = 1;
$this->rights[$r][4] = 'read';
// Main menu entries
$this->menus = array(); // List of menus to add
$r=0;
// This is to declare the Top Menu entry:
//$this->menu[$r]=array( 'fk_menu'=>'fk_mainmenu=home,fk_leftmenu=modulesadmintools', // Put 0 if this is a top menu
// 'type'=>'left', // This is a Top menu entry
// 'titre'=>'MenuDirectPrinting',
// 'mainmenu'=>'printing',
// 'url'=>'/printing/index.php',
// 'langs'=>'printing', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
// 'position'=>300,
// 'enabled'=>'$conf->printing->enabled && $leftmenu==\'modulesadmintools\'',
// 'perms'=>'$user->rights->printing->read', // Use 'perms'=>'1' if you want your menu with no permission rules
// 'target'=>'',
// 'user'=>0); // 0=Menu for internal users, 1=external users, 2=both
$r++;
}
}

12
htdocs/includes/escpos/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# Eclipse files
.settings/*
.project
.buildpath
# doxygen files
doc/html
doc/latex
doc/doxygen_sqlite3.db
# composer files
vendor/

View File

@ -0,0 +1,851 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This class generates ESC/POS printer control commands for compatible printers.
* See README.md for a summary of compatible printers and supported commands, and
* basic usage.
*
* See example/demo.php for a detailed print-out demonstrating the range of commands
* implemented in this project.
*
* Note that some functions have not been implemented:
* - Set paper sensors
* - Select print colour
*
* Please direct feature requests, bug reports and contributions to escpos-php
* on Github:
* - https://github.com/mike42/escpos-php
*/
require_once(dirname(__FILE__) . "/src/EscposImage.php");
require_once(dirname(__FILE__) . "/src/PrintBuffer.php");
require_once(dirname(__FILE__) . "/src/EscposPrintBuffer.php");
require_once(dirname(__FILE__) . "/src/PrintConnector.php");
require_once(dirname(__FILE__) . "/src/WindowsPrintConnector.php");
require_once(dirname(__FILE__) . "/src/FilePrintConnector.php");
require_once(dirname(__FILE__) . "/src/NetworkPrintConnector.php");
require_once(dirname(__FILE__) . "/src/AbstractCapabilityProfile.php");
require_once(dirname(__FILE__) . "/src/DefaultCapabilityProfile.php");
require_once(dirname(__FILE__) . "/src/SimpleCapabilityProfile.php");
require_once(dirname(__FILE__) . "/src/EposTepCapabilityProfile.php");
require_once(dirname(__FILE__) . "/src/StarCapabilityProfile.php");
require_once(dirname(__FILE__) . "/src/P822DCapabilityProfile.php");
require_once(dirname(__FILE__) . "/src/CodePage.php");
require_once(dirname(__FILE__) . "/src/ImagePrintBuffer.php");
class Escpos {
/* ASCII codes */
const NUL = "\x00";
const LF = "\x0a";
const ESC = "\x1b";
const FS = "\x1c";
const FF = "\x0c";
const GS = "\x1d";
const DLE = "\x10";
const EOT = "\x04";
/* Barcode types */
const BARCODE_UPCA = 65;
const BARCODE_UPCE = 66;
const BARCODE_JAN13 = 67;
const BARCODE_JAN8 = 68;
const BARCODE_CODE39 = 69;
const BARCODE_ITF = 70;
const BARCODE_CODABAR = 71;
const BARCODE_CODE93 = 72;
const BARCODE_CODE128 = 73;
/* Barcode HRI (human-readable interpretation) text position */
const BARCODE_TEXT_NONE = 0;
const BARCODE_TEXT_ABOVE = 1;
const BARCODE_TEXT_BELOW = 2;
/* Cut types */
const CUT_FULL = 65;
const CUT_PARTIAL = 66;
/* Fonts */
const FONT_A = 0;
const FONT_B = 1;
const FONT_C = 2;
/* Image sizing options */
const IMG_DEFAULT = 0;
const IMG_DOUBLE_WIDTH = 1;
const IMG_DOUBLE_HEIGHT = 2;
/* Justifications */
const JUSTIFY_LEFT = 0;
const JUSTIFY_CENTER = 1;
const JUSTIFY_RIGHT = 2;
/* Print mode constants */
const MODE_FONT_A = 0;
const MODE_FONT_B = 1;
const MODE_EMPHASIZED = 8;
const MODE_DOUBLE_HEIGHT = 16;
const MODE_DOUBLE_WIDTH = 32;
const MODE_UNDERLINE = 128;
/* QR code error correction levels */
const QR_ECLEVEL_L = 0;
const QR_ECLEVEL_M = 1;
const QR_ECLEVEL_Q = 2;
const QR_ECLEVEL_H = 3;
/* QR code models */
const QR_MODEL_1 = 1;
const QR_MODEL_2 = 2;
const QR_MICRO = 3;
/* Printer statuses */
const STATUS_PRINTER = 1;
const STATUS_OFFLINE_CAUSE = 2;
const STATUS_ERROR_CAUSE = 3;
const STATUS_PAPER_ROLL = 4;
const STATUS_INK_A = 7;
const STATUS_INK_B = 6;
const STATUS_PEELER = 8;
/* Underline */
const UNDERLINE_NONE = 0;
const UNDERLINE_SINGLE = 1;
const UNDERLINE_DOUBLE = 2;
/**
* @var PrintBuffer The printer's output buffer.
*/
private $buffer;
/**
* @var PrintConnector
*/
private $connector;
/**
* @var AbstractCapabilityProfile
*/
private $profile;
/**
* @var int Current character code table
*/
private $characterTable;
/**
* Construct a new print object
*
* @param PrintConnector $connector The PrintConnector to send data to. If not set, output is sent to standard output.
* @param AbstractCapabilityProfile $profile Supported features of this printer. If not set, the DefaultCapabilityProfile will be used, which is suitable for Epson printers.
* @throws InvalidArgumentException
*/
function __construct(PrintConnector $connector = null, AbstractCapabilityProfile $profile = null) {
if(is_null($connector)) {
if(php_sapi_name() == 'cli') {
$connector = new FilePrintConnector("php://stdout");
} else {
throw new InvalidArgumentException("Argument passed to Escpos::__construct() must implement interface PrintConnector, null given.");
}
}
/* Set connector */
$this -> connector = $connector;
/* Set capability profile */
if($profile === null) {
$profile = DefaultCapabilityProfile::getInstance();
}
$this -> profile = $profile;
/* Set buffer */
$buffer = new EscposPrintBuffer();
$this -> buffer = null;
$this -> setPrintBuffer($buffer);
$this -> initialize();
}
/**
* Print a barcode.
*
* @param string $content The information to encode.
* @param int $type The barcode standard to output. If not specified, `Escpos::BARCODE_CODE39` will be used. Note that some barcode formats only support specific lengths or sets of characters.
* @throws InvalidArgumentException Where the length or characters used in $content is invalid for the requested barcode format.
*/
function barcode($content, $type = self::BARCODE_CODE39) {
/* Validate input */
self::validateInteger($type, 65, 73, __FUNCTION__, "Barcode type");
$len = strlen($content);
switch($type) {
case self::BARCODE_UPCA:
self::validateInteger($len, 11, 12, __FUNCTION__, "UPCA barcode content length");
self::validateStringRegex($content, __FUNCTION__, "/^[0-9]{11,12}$/", "UPCA barcode content");
break;
case self::BARCODE_UPCE:
self::validateIntegerMulti($len, array(array(6, 8), array(11, 12)), __FUNCTION__, "UPCE barcode content length");
self::validateStringRegex($content, __FUNCTION__, "/^([0-9]{6,8}|[0-9]{11,12})$/", "UPCE barcode content");
break;
case self::BARCODE_JAN13:
self::validateInteger($len, 12, 13, __FUNCTION__, "JAN13 barcode content length");
self::validateStringRegex($content, __FUNCTION__, "/^[0-9]{12,13}$/", "JAN13 barcode content");
break;
case self::BARCODE_JAN8:
self::validateInteger($len, 7, 8, __FUNCTION__, "JAN8 barcode content length");
self::validateStringRegex($content, __FUNCTION__, "/^[0-9]{7,8}$/", "JAN8 barcode content");
break;
case self::BARCODE_CODE39:
self::validateInteger($len, 1, 255, __FUNCTION__, "CODE39 barcode content length"); // 255 is a limitation of the "function b" command, not the barcode format.
self::validateStringRegex($content, __FUNCTION__, "/^([0-9A-Z \$\%\+\-\.\/]+|\*[0-9A-Z \$\%\+\-\.\/]+\*)$/", "CODE39 barcode content");
break;
case self::BARCODE_ITF:
self::validateInteger($len, 2, 255, __FUNCTION__, "ITF barcode content length"); // 255 is a limitation of the "function b" command, not the barcode format.
self::validateStringRegex($content, __FUNCTION__, "/^([0-9]{2})+$/", "ITF barcode content");
break;
case self::BARCODE_CODABAR:
self::validateInteger($len, 1, 255, __FUNCTION__, "Codabar barcode content length"); // 255 is a limitation of the "function b" command, not the barcode format.
self::validateStringRegex($content, __FUNCTION__, "/^[A-Da-d][0-9\$\+\-\.\/\:]+[A-Da-d]$/", "Codabar barcode content");
break;
case self::BARCODE_CODE93:
self::validateInteger($len, 1, 255, __FUNCTION__, "Code93 barcode content length"); // 255 is a limitation of the "function b" command, not the barcode format.
self::validateStringRegex($content, __FUNCTION__, "/^[\\x00-\\x7F]+$/", "Code93 barcode content");
break;
case self::BARCODE_CODE128:
self::validateInteger($len, 1, 255, __FUNCTION__, "Code128 barcode content length"); // 255 is a limitation of the "function b" command, not the barcode format.
// The CODE128 encoder is quite complex, so only a very basic header-check is applied here.
self::validateStringRegex($content, __FUNCTION__, "/^\{[A-C][\\x00-\\x7F]+$/", "Code128 barcode content");
break;
}
if(!$this -> profile -> getSupportsBarcodeB()) {
// A simpler barcode command which supports fewer codes
self::validateInteger($type, 65, 71, __FUNCTION__);
$this -> connector -> write(self::GS . "k" . chr($type - 65) . $content . self::NUL);
return;
}
// More advanced function B, used in preference
$this -> connector -> write(self::GS . "k" . chr($type) . chr(strlen($content)) . $content);
}
/**
* Print an image, using the older "bit image" command. This creates padding on the right of the image,
* if its width is not divisible by 8.
*
* Should only be used if your printer does not support the graphics() command.
*
* @param EscposImage $img The image to print
* @param EscposImage $size Size modifier for the image.
*/
function bitImage(EscposImage $img, $size = self::IMG_DEFAULT) {
self::validateInteger($size, 0, 3, __FUNCTION__);
$header = self::dataHeader(array($img -> getWidthBytes(), $img -> getHeight()), true);
$this -> connector -> write(self::GS . "v0" . chr($size) . $header);
$this -> connector -> write($img -> toRasterFormat());
}
/**
* Close the underlying buffer. With some connectors, the
* job will not actually be sent to the printer until this is called.
*/
function close() {
$this -> connector -> finalize();
}
/**
* Cut the paper.
*
* @param int $mode Cut mode, either Escpos::CUT_FULL or Escpos::CUT_PARTIAL. If not specified, `Escpos::CUT_FULL` will be used.
* @param int $lines Number of lines to feed
*/
function cut($mode = self::CUT_FULL, $lines = 3) {
// TODO validation on cut() inputs
$this -> connector -> write(self::GS . "V" . chr($mode) . chr($lines));
}
/**
* Print and feed line / Print and feed n lines.
*
* @param int $lines Number of lines to feed
*/
function feed($lines = 1) {
self::validateInteger($lines, 1, 255, __FUNCTION__);
if($lines <= 1) {
$this -> connector -> write(self::LF);
} else {
$this -> connector -> write(self::ESC . "d" . chr($lines));
}
}
/**
* Some printers require a form feed to release the paper. On most printers, this
* command is only useful in page mode, which is not implemented in this driver.
*/
function feedForm() {
$this -> connector -> write(self::FF);
}
/**
* Print and reverse feed n lines.
*
* @param int $lines number of lines to feed. If not specified, 1 line will be fed.
*/
function feedReverse($lines = 1) {
self::validateInteger($lines, 1, 255, __FUNCTION__);
$this -> connector -> write(self::ESC . "e" . chr($lines));
}
/**
* @return number
*/
function getCharacterTable() {
return $this -> characterTable;
}
/**
* @return PrintBuffer
*/
function getPrintBuffer() {
return $this -> buffer;
}
/**
* @return PrintConnector
*/
function getPrintConnector() {
return $this -> connector;
}
/**
* @return AbstractCapabilityProfile
*/
function getPrinterCapabilityProfile() {
return $this -> profile;
}
/**
* @param int $type The type of status to request
* @return stdClass Class containing requested status, or null if either no status was received, or your print connector is unable to read from the printer.
*/
function getPrinterStatus($type = self::STATUS_PRINTER) {
self::validateIntegerMulti($type, array(array(1, 4), array(6, 8)), __FUNCTION__);
// Determine which flags we are looking for
$statusFlags = array(
self::STATUS_PRINTER => array(
4 => "pulseHigh", // connector pin 3, see pulse().
8 => "offline",
32 => "waitingForOnlineRecovery",
64 => "feedButtonPressed"
),
self::STATUS_OFFLINE_CAUSE => array(
4 => "coverOpen",
8 => "paperManualFeed",
32 => "paperEnd",
64 => "errorOccurred"
),
self::STATUS_ERROR_CAUSE => array(
4 => "recoverableError",
8 => "autocutterError",
32 => "unrecoverableError",
64 => "autorecoverableError"
),
self::STATUS_PAPER_ROLL => array(
4 => "paperNearEnd",
32 => "paperNotPresent"
),
self::STATUS_INK_A => array(
4 => "inkNearEnd",
8 => "inkEnd",
32 => "inkNotPresent",
64 => "cleaning"
),
self::STATUS_INK_B => array(
4 => "inkNearEnd",
8 => "inkEnd",
32 => "inkNotPresent"
),
self::STATUS_PEELER => array(
4 => "labelWaitingForRemoval",
32 => "labelPaperNotDetected"
)
);
$flags = $statusFlags[$type];
// Clear any previous statuses which haven't been read yet
$f = $this -> connector -> read(1);
// Make request
$reqC = chr($type);
switch($type) {
// Special cases: These are two-character requests
case self::STATUS_INK_A:
$reqC = chr(7) . chr(1);
break;
case self::STATUS_INK_B:
$reqC = chr(7) . chr(2);
break;
case self::STATUS_PEELER:
$reqC = chr(8) . chr(3);
break;
}
$this -> connector -> write(self::DLE . self::EOT . $reqC);
// Wait for single-character response
$f = $this -> connector -> read(1);
$i = 0;
while($f === false && $i < 50000) {
usleep(100);
$f = $this -> connector -> read(1);
$i++;
}
if($f === false) {
// Timeout
return null;
}
$ret = new stdClass();
foreach($flags as $num => $name) {
$ret -> $name = (ord($f) & $num) != 0;
}
return $ret;
}
/**
* Print an image to the printer.
*
* Size modifiers are:
* - IMG_DEFAULT (leave image at original size)
* - IMG_DOUBLE_WIDTH
* - IMG_DOUBLE_HEIGHT
*
* See the example/ folder for detailed examples.
*
* The function bitImage() takes the same parameters, and can be used if
* your printer doesn't support the newer graphics commands.
*
* @param EscposImage $img The image to print.
* @param int $size Output size modifier for the image.
*/
function graphics(EscposImage $img, $size = self::IMG_DEFAULT) {
self::validateInteger($size, 0, 3, __FUNCTION__);
$imgHeader = self::dataHeader(array($img -> getWidth(), $img -> getHeight()), true);
$tone = '0';
$colors = '1';
$xm = (($size & self::IMG_DOUBLE_WIDTH) == self::IMG_DOUBLE_WIDTH) ? chr(2) : chr(1);
$ym = (($size & self::IMG_DOUBLE_HEIGHT) == self::IMG_DOUBLE_HEIGHT) ? chr(2) : chr(1);
$header = $tone . $xm . $ym . $colors . $imgHeader;
$this -> wrapperSendGraphicsData('0', 'p', $header . $img -> toRasterFormat());
$this -> wrapperSendGraphicsData('0', '2');
}
/**
* Initialize printer. This resets formatting back to the defaults.
*/
function initialize() {
$this -> connector -> write(self::ESC . "@");
$this -> characterTable = 0;
}
/**
* Generate a pulse, for opening a cash drawer if one is connected.
* The default settings should open an Epson drawer.
*
* @param int $pin 0 or 1, for pin 2 or pin 5 kick-out connector respectively.
* @param int $on_ms pulse ON time, in milliseconds.
* @param int $off_ms pulse OFF time, in milliseconds.
*/
function pulse($pin = 0, $on_ms = 120, $off_ms = 240) {
self::validateInteger($pin, 0, 1, __FUNCTION__);
self::validateInteger($on_ms, 1, 511, __FUNCTION__);
self::validateInteger($off_ms, 1, 511, __FUNCTION__);
$this -> connector -> write(self::ESC . "p" . chr($pin + 48) . chr($on_ms / 2) . chr($off_ms / 2));
}
/**
* Print the given data as a QR code on the printer.
*
* @param string $content The content of the code. Numeric data will be more efficiently compacted.
* @param int $ec Error-correction level to use. One of Escpos::QR_ECLEVEL_L (default), Escpos::QR_ECLEVEL_M, Escpos::QR_ECLEVEL_Q or Escpos::QR_ECLEVEL_H. Higher error correction results in a less compact code.
* @param int $size Pixel size to use. Must be 1-16 (default 3)
* @param int $model QR code model to use. Must be one of Escpos::QR_MODEL_1, Escpos::QR_MODEL_2 (default) or Escpos::QR_MICRO (not supported by all printers).
*/
function qrCode($content, $ec = self::QR_ECLEVEL_L, $size = 3, $model = self::QR_MODEL_2) {
self::validateString($content, __FUNCTION__);
self::validateInteger($ec, 0, 3, __FUNCTION__);
self::validateInteger($size, 1, 16, __FUNCTION__);
self::validateInteger($model, 1, 3, __FUNCTION__);
if($content == "") {
return;
}
if(!$this -> profile -> getSupportsQrCode()) {
// TODO use software rendering via phpqrcode instead
throw new Exception("QR codes are not supported on your printer.");
}
$cn = '1'; // Code type for QR code
// Select model: 1, 2 or micro.
$this -> wrapperSend2dCodeData(chr(65), $cn, chr(48 + $model) . chr(0));
// Set dot size.
$this -> wrapperSend2dCodeData(chr(67), $cn, chr($size));
// Set error correction level: L, M, Q, or H
$this -> wrapperSend2dCodeData(chr(69), $cn, chr(48 + $ec));
// Send content & print
$this -> wrapperSend2dCodeData(chr(80), $cn, $content, '0');
$this -> wrapperSend2dCodeData(chr(81), $cn, '', '0');
}
/**
* Switch character table (code page) manually. Used in conjunction with textRaw() to
* print special characters which can't be encoded automatically.
*
* @param int $table The table to select. Available code tables are model-specific.
*/
function selectCharacterTable($table = 0) {
self::validateInteger($table, 0, 255, __FUNCTION__);
$supported = $this -> profile -> getSupportedCodePages();
if(!isset($supported[$table])) {
throw new InvalidArgumentException("There is no code table $table allowed by this printer's capability profile.");
}
$this -> characterTable = $table;
if($this -> profile -> getSupportsStarCommands()) {
/* Not an ESC/POS command: STAR printers stash all the extra code pages under a different command. */
$this -> connector -> write(self::ESC . self::GS . "t" . chr($table));
return;
}
$this -> connector -> write(self::ESC . "t" . chr($table));
}
/**
* Select print mode(s).
*
* Several MODE_* constants can be OR'd together passed to this function's `$mode` argument. The valid modes are:
* - MODE_FONT_A
* - MODE_FONT_B
* - MODE_EMPHASIZED
* - MODE_DOUBLE_HEIGHT
* - MODE_DOUBLE_WIDTH
* - MODE_UNDERLINE
*
* @param int $mode The mode to use. Default is Escpos::MODE_FONT_A, with no special formatting. This has a similar effect to running initialize().
*/
function selectPrintMode($mode = self::MODE_FONT_A) {
$allModes = self::MODE_FONT_B | self::MODE_EMPHASIZED | self::MODE_DOUBLE_HEIGHT | self::MODE_DOUBLE_WIDTH | self::MODE_UNDERLINE;
if(!is_integer($mode) || $mode < 0 || ($mode & $allModes) != $mode) {
throw new InvalidArgumentException("Invalid mode");
}
$this -> connector -> write(self::ESC . "!" . chr($mode));
}
/**
* Set barcode height.
*
* @param int $height Height in dots. If not specified, 8 will be used.
*/
function setBarcodeHeight($height = 8) {
self::validateInteger($height, 1, 255, __FUNCTION__);
$this -> connector -> write(self::GS . "h" . chr($height));
}
/**
* Set the position for the Human Readable Interpretation (HRI) of barcode characters.
*
* @param position $position. Use Escpos::BARCODE_TEXT_NONE to hide the text (default), or any combination of Escpos::BARCODE_TEXT_TOP and Escpos::BARCODE_TEXT_BOTTOM flags to display the text.
*/
function setBarcodeTextPosition($position = self::BARCODE_TEXT_NONE) {
self::validateInteger($position, 0, 3, __FUNCTION__, "Barcode text position");
$this -> connector -> write(self::GS . "H" . chr($position));
}
/**
* Turn double-strike mode on/off.
*
* @param boolean $on true for double strike, false for no double strike
*/
function setDoubleStrike($on = true) {
self::validateBoolean($on, __FUNCTION__);
$this -> connector -> write(self::ESC . "G". ($on ? chr(1) : chr(0)));
}
/**
* Turn emphasized mode on/off.
*
* @param boolean $on true for emphasis, false for no emphasis
*/
function setEmphasis($on = true) {
self::validateBoolean($on, __FUNCTION__);
$this -> connector -> write(self::ESC . "E". ($on ? chr(1) : chr(0)));
}
/**
* Select font. Most printers have two fonts (Fonts A and B), and some have a third (Font C).
*
* @param int $font The font to use. Must be either Escpos::FONT_A, Escpos::FONT_B, or Escpos::FONT_C.
*/
function setFont($font = self::FONT_A) {
self::validateInteger($font, 0, 2, __FUNCTION__);
$this -> connector -> write(self::ESC . "M" . chr($font));
}
/**
* Select justification.
*
* @param int $justification One of Escpos::JUSTIFY_LEFT, Escpos::JUSTIFY_CENTER, or Escpos::JUSTIFY_RIGHT.
*/
function setJustification($justification = self::JUSTIFY_LEFT) {
self::validateInteger($justification, 0, 2, __FUNCTION__);
$this -> connector -> write(self::ESC . "a" . chr($justification));
}
/**
* Attach a different print buffer to the printer. Buffers are responsible for handling text output to the printer.
*
* @param PrintBuffer $buffer The buffer to use.
* @throws InvalidArgumentException Where the buffer is already attached to a different printer.
*/
function setPrintBuffer(PrintBuffer $buffer) {
if($buffer === $this -> buffer) {
return;
}
if($buffer -> getPrinter() != null) {
throw new InvalidArgumentException("This buffer is already attached to a printer.");
}
if($this -> buffer !== null) {
$this -> buffer -> setPrinter(null);
}
$this -> buffer = $buffer;
$this -> buffer -> setPrinter($this);
}
/**
* Set black/white reverse mode on or off. In this mode, text is printed white on a black background.
*
* @param boolean $on True to enable, false to disable.
*/
function setReverseColors($on = true) {
self::validateBoolean($on, __FUNCTION__);
$this -> connector -> write(self::GS . "B" . ($on ? chr(1) : chr(0)));
}
/**
* Set the size of text, as a multiple of the normal size.
*
* @param int $widthMultiplier Multiple of the regular height to use (range 1 - 8)
* @param int $heightMultiplier Multiple of the regular height to use (range 1 - 8)
*/
function setTextSize($widthMultiplier, $heightMultiplier) {
self::validateInteger($widthMultiplier, 1, 8, __FUNCTION__);
self::validateInteger($heightMultiplier, 1, 8, __FUNCTION__);
$c = pow(2,4) * ($widthMultiplier - 1) + ($heightMultiplier - 1);
$this -> connector -> write(self::GS . "!" . chr($c));
}
/**
* Set underline for printed text.
*
* Argument can be true/false, or one of UNDERLINE_NONE,
* UNDERLINE_SINGLE or UNDERLINE_DOUBLE.
*
* @param int $underline Either true/false, or one of Escpos::UNDERLINE_NONE, Escpos::UNDERLINE_SINGLE or Escpos::UNDERLINE_DOUBLE. Defaults to Escpos::UNDERLINE_SINGLE.
*/
function setUnderline($underline = self::UNDERLINE_SINGLE) {
/* Map true/false to underline constants */
if($underline === true) {
$underline = self::UNDERLINE_SINGLE;
} else if($underline === false) {
$underline = self::UNDERLINE_NONE;
}
/* Set the underline */
self::validateInteger($underline, 0, 2, __FUNCTION__);
$this -> connector -> write(self::ESC . "-". chr($underline));
}
/**
* Add text to the buffer.
*
* Text should either be followed by a line-break, or feed() should be called
* after this to clear the print buffer.
*
* @param string $str Text to print
*/
function text($str = "") {
self::validateString($str, __FUNCTION__);
$this -> buffer -> writeText((string)$str);
}
/**
* Add text to the buffer without attempting to interpret chararacter codes.
*
* Text should either be followed by a line-break, or feed() should be called
* after this to clear the print buffer.
*
* @param string $str Text to print
*/
function textRaw($str = "") {
self::validateString($str, __FUNCTION__);
$this -> buffer -> writeTextRaw((string)$str);
}
/**
* Wrapper for GS ( k, to calculate and send correct data length.
*
* @param string $fn Function to use
* @param string $cn Output code type. Affects available data
* @param string $data Data to send.
* @param string $m Modifier/variant for function. Often '0' where used.
* @throws InvalidArgumentException Where the input lengths are bad.
*/
private function wrapperSend2dCodeData($fn, $cn, $data = '', $m = '') {
if(strlen($m) > 1 || strlen($cn) != 1 || strlen($fn) != 1) {
throw new InvalidArgumentException("wrapperSend2dCodeData: cn and fn must be one character each.");
}
$header = $this -> intLowHigh(strlen($data) + strlen($m) + 2, 2);
$this -> connector -> write(self::GS . "(k" . $header . $cn . $fn . $m . $data);
}
/**
* Wrapper for GS ( L, to calculate and send correct data length.
*
* @param string $m Modifier/variant for function. Usually '0'.
* @param string $fn Function number to use, as character.
* @param string $data Data to send.
* @throws InvalidArgumentException Where the input lengths are bad.
*/
private function wrapperSendGraphicsData($m, $fn, $data = '') {
if(strlen($m) != 1 || strlen($fn) != 1) {
throw new InvalidArgumentException("wrapperSendGraphicsData: m and fn must be one character each.");
}
$header = $this -> intLowHigh(strlen($data) + 2, 2);
$this -> connector -> write(self::GS . "(L" . $header . $m . $fn . $data);
}
/**
* Convert widths and heights to characters. Used before sending graphics to set the size.
*
* @param array $inputs
* @param boolean $long True to use 4 bytes, false to use 2
* @return string
*/
private static function dataHeader(array $inputs, $long = true) {
$outp = array();
foreach($inputs as $input) {
if($long) {
$outp[] = Escpos::intLowHigh($input, 2);
} else {
self::validateInteger($input, 0 , 255, __FUNCTION__);
$outp[] = chr($input);
}
}
return implode("", $outp);
}
/**
* Generate two characters for a number: In lower and higher parts, or more parts as needed.
* @param int $int Input number
* @param int $length The number of bytes to output (1 - 4).
*/
private static function intLowHigh($input, $length) {
$maxInput = (256 << ($length * 8) - 1);
self::validateInteger($length, 1, 4, __FUNCTION__);
self::validateInteger($input, 0, $maxInput, __FUNCTION__);
$outp = "";
for($i = 0; $i < $length; $i++) {
$outp .= chr($input % 256);
$input = (int)($input / 256);
}
return $outp;
}
/**
* Throw an exception if the argument given is not a boolean
*
* @param boolean $test the input to test
* @param string $source the name of the function calling this
*/
protected static function validateBoolean($test, $source) {
if(!($test === true || $test === false)) {
throw new InvalidArgumentException("Argument to $source must be a boolean");
}
}
/**
* Throw an exception if the argument given is not an integer within the specified range
*
* @param int $test the input to test
* @param int $min the minimum allowable value (inclusive)
* @param int $max the maximum allowable value (inclusive)
* @param string $source the name of the function calling this
* @param string $argument the name of the invalid parameter
*/
protected static function validateInteger($test, $min, $max, $source, $argument = "Argument") {
self::validateIntegerMulti($test, array(array($min, $max)), $source, $argument);
}
/**
* Throw an exception if the argument given is not an integer within one of the specified ranges
*
* @param int $test the input to test
* @param arrray $ranges array of two-item min/max ranges.
* @param string $source the name of the function calling this
* @param string $source the name of the function calling this
* @param string $argument the name of the invalid parameter
*/
protected static function validateIntegerMulti($test, array $ranges, $source, $argument = "Argument") {
if(!is_integer($test)) {
throw new InvalidArgumentException("$argument given to $source must be a number, but '$test' was given.");
}
$match = false;
foreach($ranges as $range) {
$match |= $test >= $range[0] && $test <= $range[1];
}
if(!$match) {
// Put together a good error "range 1-2 or 4-6"
$rangeStr = "range ";
for($i = 0; $i < count($ranges); $i++) {
$rangeStr .= $ranges[$i][0] . "-" . $ranges[$i][1];
if($i == count($ranges) - 1) {
continue;
} else if($i == count($ranges) - 2) {
$rangeStr .= " or ";
} else {
$rangeStr .= ", ";
}
}
throw new InvalidArgumentException("$argument given to $source must be in $rangeStr, but $test was given.");
}
}
/**
* Throw an exception if the argument given can't be cast to a string
*
* @param string $test the input to test
* @param string $source the name of the function calling this
* @param string $argument the name of the invalid parameter
*/
protected static function validateString($test, $source, $argument = "Argument") {
if (is_object($test) && !method_exists($test, '__toString')) {
throw new InvalidArgumentException("$argument to $source must be a string");
}
}
protected static function validateStringRegex($test, $source, $regex, $argument = "Argument") {
if(preg_match($regex, $test) === 0) {
throw new InvalidArgumentException("$argument given to $source is invalid. It should match regex '$regex', but '$test' was given.");
}
}
}

View File

@ -0,0 +1,27 @@
escpos-php, a Thermal receipt printer library, for use with
ESC/POS compatible printers.
Copyright (c) 2014-15 Michael Billington <michael.billington@gmail.com>,
incorporating modifications by:
- Roni Saha <roni.cse@gmail.com>
- Gergely Radics <gerifield@ustream.tv>
- Warren Doyle <w.doyle@fuelled.co>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,352 @@
ESC/POS Print Driver for PHP
============================
This project implements a subset of Epson's ESC/POS protocol for thermal receipt printers. It allows you to generate and print receipts with basic formatting, cutting, and barcodes on a compatible printer.
The library was developed to add drop-in support for receipt printing to any PHP app, including web-based point-of-sale (POS) applications.
Basic usage
-----------
A "hello world" receipt can be generated easily (Call this `hello-world.php`):
```php
<?php
require_once(dirname(__FILE__) . "/Escpos.php");
$printer = new Escpos();
$printer -> text("Hello World!\n");
$printer -> cut();
$printer -> close();
```
This would be printed as:
```
# Networked printer
php hello-world.php | nc 10.x.x.x. 9100
# Local printer
php hello-world.php > /dev/...
# Windows local printer
php hello-world.php > foo.txt
net use LPT1 \\server\printer
copy foo.txt LPT1
del foo.txt
```
From your web app, you could pass the output directly to a socket if your printer is networked:
```php
<?php
require_once(dirname(__FILE__) . "/Escpos.php");
$connector = new NetworkPrintConnector("10.x.x.x", 9100);
$printer = new Escpos($connector);
$printer -> text("Hello World!\n");
$printer -> cut();
$printer -> close();
```
Or to a local printer:
```php
<?php
require_once(dirname(__FILE__) . "/Escpos.php");
$connector = new FilePrintConnector("/dev/ttyS0");
$printer = new Escpos($connector);
$printer -> text("Hello World!\n");
$printer -> cut();
$printer -> close();
```
### Basic workflow
The library should be initialised with a PrintConnector, which will pass on the data to your printer.
Use the table under "Compatibility", or the examples below to choose the appropriate connector for your
platform & interface. If no connector is specified, then standard output is used.
When you have finished using the print object, call `close()` to finalize any data transfers.
### Tips & examples
On Linux, your printer device file will be somewhere like `/dev/lp0` (parallel), `/dev/usb/lp1` (USB), `/dev/ttyUSB0` (USB-Serial), `/dev/ttyS0` (serial).
On Windows, the device files will be along the lines of `LPT1` (parallel) or `COM1` (serial). Use the `WindowsPrintConnector` to tap into system printing on Windows (eg. [Windows USB](https://github.com/mike42/escpos-php/tree/master/example/interface/windows-usb.php), [SMB](https://github.com/mike42/escpos-php/tree/master/example/interface/smb.php) or [Windows LPT](https://github.com/mike42/escpos-php/tree/master/example/interface/windows-lpt.php)) - this submits print jobs via a queue rather than communicating directly with the printer.
A complete real-world receipt can be found in the code of [Auth](https://github.com/mike42/Auth) in [ReceiptPrinter.php](https://github.com/mike42/Auth/blob/master/lib/misc/ReceiptPrinter.php). It includes justification, boldness, and a barcode.
Other examples are located in the [example/](https://github.com/mike42/escpos-php/blob/master/example/) directory.
Compatibility
-------------
### Interfaces and operating systems
This driver is known to work with the following OS/interface combinations:
<table>
<tr>
<th>&nbsp;</th>
<th>Linux</th>
<th>Mac</th>
<th>Windows</th>
</tr>
<tr>
<th>Ethernet</th>
<td><a href="https://github.com/mike42/escpos-php/tree/master/example/interface/ethernet.php">Yes</a></td>
<td><a href="https://github.com/mike42/escpos-php/tree/master/example/interface/ethernet.php">Yes</a></td>
<td><a href="https://github.com/mike42/escpos-php/tree/master/example/interface/ethernet.php">Yes</a></td>
</tr>
<tr>
<th>USB</th>
<td><a href="https://github.com/mike42/escpos-php/tree/master/example/interface/linux-usb.php">Yes</a></td>
<td>Not tested</td>
<td><a href="https://github.com/mike42/escpos-php/tree/master/example/interface/windows-usb.php">Yes</a></td>
</tr>
<tr>
<th>USB-serial</th>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<th>Serial</th>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<th>Parallel</th>
<td><a href="https://github.com/mike42/escpos-php/tree/master/example/interface/windows-lpt.php">Yes</a></td>
<td>Not tested</td>
<td>Yes</td>
</tr>
<tr>
<th>SMB shared</th>
<td><a href="https://github.com/mike42/escpos-php/tree/master/example/interface/smb.php">Yes</a></td>
<td>No</td>
<td><a href="https://github.com/mike42/escpos-php/tree/master/example/interface/smb.php">Yes</a></td>
</tr>
</table>
### Printers
Many thermal receipt printers support ESC/POS to some degree. This driver has been known to work with:
- EPOS TEP 220M
- Epson TM-T88III
- Epson TM-T88IV
- Epson TM-T70
- Epson TM-T82II
- Epson TM-T20
- Epson TM-T70II
- Epson TM-U220
- Epson FX-890 (requires `feedForm()` to release paper).
- Okipos 80 Plus III
- P-822D
- SEYPOS PRP-300 (Also marketed as TYSSO PRP-300)
- Star TSP-650
- Star TUP-592
- Xprinter XP-Q800
- Zijang NT-58H
- Zijang ZJ-5870
- Zijang ZJ-5890T (Marketed as POS 5890T)
If you use any other printer with this code, please let me know so I can add it to the list.
Available methods
-----------------
### __construct(PrintConnector $connector, AbstractCapabilityProfile $profile)
Construct new print object.
Parameters:
- `PrintConnector $connector`: The PrintConnector to send data to. If not set, output is sent to standard output.
- `AbstractCapabilityProfile $profile` Supported features of this printer. If not set, the DefaultCapabilityProfile will be used, which is suitable for Epson printers.
See [example/interface/]("https://github.com/mike42/escpos-php/tree/master/example/interface/) for ways to open connections for different platforms and interfaces.
### barcode($content, $type)
Print a barcode.
Parameters:
- `string $content`: The information to encode.
- `int $type`: The barcode standard to output. If not specified, `Escpos::BARCODE_CODE39` will be used.
Currently supported barcode standards are (depending on your printer):
- `BARCODE_UPCA`
- `BARCODE_UPCE`
- `BARCODE_JAN13`
- `BARCODE_JAN8`
- `BARCODE_CODE39`
- `BARCODE_ITF`
- `BARCODE_CODABAR`
Note that some barcode standards can only encode numbers, so attempting to print non-numeric codes with them may result in strange behaviour.
### bitImage(EscposImage $image, $size)
See [graphics()](#graphicsescposimage-image-size) below.
### cut($mode, $lines)
Cut the paper.
Parameters:
- `int $mode`: Cut mode, either `Escpos::CUT_FULL` or `Escpos::CUT_PARTIAL`. If not specified, `Escpos::CUT_FULL` will be used.
- `int $lines`: Number of lines to feed before cutting. If not specified, 3 will be used.
### feed($lines)
Print and feed line / Print and feed n lines.
Parameters:
- `int $lines`: Number of lines to feed
### feedForm()
Some printers require a form feed to release the paper. On most printers, this command is only useful in page mode, which is not implemented in this driver.
### feedReverse($lines)
Print and reverse feed n lines.
Parameters:
- `int $lines`: number of lines to feed. If not specified, 1 line will be fed.
### graphics(EscposImage $image, $size)
Print an image to the printer.
Parameters:
- `EscposImage $img`: The image to print.
- `int $size`: Output size modifier for the image.
Size modifiers are:
- `IMG_DEFAULT` (leave image at original size)
- `IMG_DOUBLE_WIDTH`
- `IMG_DOUBLE_HEIGHT`
A minimal example:
```php
<?php
$img = new EscposImage("logo.png");
$printer -> graphics($img);
```
See the [example/](https://github.com/mike42/escpos-php/blob/master/example/) folder for detailed examples.
The function [bitImage()](#bitimageescposimage-image-size) takes the same parameters, and can be used if your printer doesn't support the newer graphics commands.
### initialize()
Initialize printer. This resets formatting back to the defaults.
### pulse($pin, $on_ms, $off_ms)
Generate a pulse, for opening a cash drawer if one is connected. The default settings (0, 120, 240) should open an Epson drawer.
Parameters:
- `int $pin`: 0 or 1, for pin 2 or pin 5 kick-out connector respectively.
- `int $on_ms`: pulse ON time, in milliseconds.
- `int $off_ms`: pulse OFF time, in milliseconds.
### qrCode($content, $ec, $size, $model)
Print the given data as a QR code on the printer.
- `string $content`: The content of the code. Numeric data will be more efficiently compacted.
- `int $ec` Error-correction level to use. One of `Escpos::QR_ECLEVEL_L` (default), `Escpos::QR_ECLEVEL_M`, `Escpos::QR_ECLEVEL_Q` or `Escpos::QR_ECLEVEL_H`. Higher error correction results in a less compact code.
- `int $size`: Pixel size to use. Must be 1-16 (default 3)
- `int $model`: QR code model to use. Must be one of `Escpos::QR_MODEL_1`, `Escpos::QR_MODEL_2` (default) or `Escpos::QR_MICRO` (not supported by all printers).
### selectPrintMode($mode)
Select print mode(s).
Parameters:
- `int $mode`: The mode to use. Default is `Escpos::MODE_FONT_A`, with no special formatting. This has a similar effect to running `initialize()`.
Several MODE_* constants can be OR'd together passed to this function's `$mode` argument. The valid modes are:
- `MODE_FONT_A`
- `MODE_FONT_B`
- `MODE_EMPHASIZED`
- `MODE_DOUBLE_HEIGHT`
- `MODE_DOUBLE_WIDTH`
- `MODE_UNDERLINE`
### setBarcodeHeight($height)
Set barcode height.
Parameters:
- `int $height`: Height in dots. If not specified, 8 will be used.
### setDoubleStrike($on)
Turn double-strike mode on/off.
Parameters:
- `boolean $on`: true for double strike, false for no double strike.
### setEmphasis($on)
Turn emphasized mode on/off.
Parameters:
- `boolean $on`: true for emphasis, false for no emphasis.
### setFont($font)
Select font. Most printers have two fonts (Fonts A and B), and some have a third (Font C).
Parameters:
- `int $font`: The font to use. Must be either `Escpos::FONT_A`, `Escpos::FONT_B`, or `Escpos::FONT_C`.
### setJustification($justification)
Select justification.
Parameters:
- `int $justification`: One of `Escpos::JUSTIFY_LEFT`, `Escpos::JUSTIFY_CENTER`, or `Escpos::JUSTIFY_RIGHT`.
### setReverseColors($on)
Set black/white reverse mode on or off. In this mode, text is printed white on a black background.
Parameters:
- `boolean $on`: True to enable, false to disable.
### setTextSize($widthMultiplier, $heightMultiplier)
Set the size of text, as a multiple of the normal size.
Parameters:
- `int $widthMultiplier`: Multiple of the regular height to use (range 1 - 8).
- `int $heightMultiplier`: Multiple of the regular height to use (range 1 - 8).
### setUnderline($underline)
Set underline for printed text.
Parameters:
- `int $underline`: Either `true`/`false`, or one of `Escpos::UNDERLINE_NONE`, `Escpos::UNDERLINE_SINGLE` or `Escpos::UNDERLINE_DOUBLE`. Defaults to `Escpos::UNDERLINE_SINGLE`.
### text($str)
Add text to the buffer. Text should either be followed by a line-break, or `feed()` should be called after this.
Parameters:
- `string $str`: The string to print.
Further notes
-------------
Posts I've written up for people who are learning how to use receipt printers:
* [What is ESC/POS, and how do I use it?](http://mike.bitrevision.com/blog/what-is-escpos-and-how-do-i-use-it), which documents the output of test.php.
* [Setting up an Epson receipt printer](http://mike.bitrevision.com/blog/2014-20-26-setting-up-an-epson-receipt-printer)
* [Getting a USB receipt printer working on Linux](http://mike.bitrevision.com/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux)
Other versions
--------------
Some forks of this project have been developed by others for specific use cases. Improvements from the following projects have been incorporated into escpos-php:
- [wdoyle/EpsonESCPOS-PHP](https://github.com/wdoyle/EpsonESCPOS-PHP)
- [ronisaha/php-esc-pos](https://github.com/ronisaha/php-esc-pos)
Vendor documentation
--------------------
Epson notes that not all of its printers support all ESC/POS features, and includes a table in their documentation:
* [FAQ about ESC/POS from Epson](http://content.epson.de/fileadmin/content/files/RSD/downloads/escpos.pdf)
Note that many printers produced by other vendors use the same standard, and are compatible by varying degrees.

View File

@ -0,0 +1,36 @@
{
"name": "mike42/escpos-php",
"type": "library",
"description": "Thermal receipt printer library, for use with ESC/POS compatible printers",
"homepage": "https://github.com/mike42/escpos-php",
"keywords": ["receipt", "print", "escpos", "ESC-POS", "driver"],
"license": "MIT",
"authors": [
{
"name": "Michael Billington",
"email": "michael.billington@gmail.com"
},
{
"name": "Roni Saha",
"email": "roni.cse@gmail.com"
},
{
"name": "Gergely Radics",
"email": "gerifield@ustream.tv"
},
{
"name": "Warren Doyle",
"email": "w.doyle@fuelled.co"
},
{
"name": "vharo",
"email": "vharo@geepok.com"
}
],
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.5.*"
}
}

975
htdocs/includes/escpos/composer.lock generated Normal file
View File

@ -0,0 +1,975 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "fd25f2b816df83dabf03fe7259ad4018",
"packages": [],
"packages-dev": [
{
"name": "doctrine/instantiator",
"version": "1.0.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "f976e5de371104877ebc89bd8fecb0019ed9c119"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119",
"reference": "f976e5de371104877ebc89bd8fecb0019ed9c119",
"shasum": ""
},
"require": {
"php": ">=5.3,<8.0-DEV"
},
"require-dev": {
"athletic/athletic": "~0.1.8",
"ext-pdo": "*",
"ext-phar": "*",
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "2.0.*@ALPHA"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Instantiator\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.com/"
}
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"homepage": "https://github.com/doctrine/instantiator",
"keywords": [
"constructor",
"instantiate"
],
"time": "2014-10-13 12:58:55"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
"reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"suggest": {
"dflydev/markdown": "~1.0",
"erusev/parsedown": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-0": {
"phpDocumentor": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "mike.vanriel@naenius.com"
}
],
"time": "2015-02-03 12:10:50"
},
{
"name": "phpspec/prophecy",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5",
"reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"phpdocumentor/reflection-docblock": "~2.0",
"sebastian/comparator": "~1.1"
},
"require-dev": {
"phpspec/phpspec": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
}
},
"autoload": {
"psr-0": {
"Prophecy\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
},
{
"name": "Marcello Duarte",
"email": "marcello.duarte@gmail.com"
}
],
"description": "Highly opinionated mocking framework for PHP 5.3+",
"homepage": "https://github.com/phpspec/prophecy",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"spy",
"stub"
],
"time": "2015-03-27 19:31:25"
},
{
"name": "phpunit/php-code-coverage",
"version": "2.0.15",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "34cc484af1ca149188d0d9e91412191e398e0b67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/34cc484af1ca149188d0d9e91412191e398e0b67",
"reference": "34cc484af1ca149188d0d9e91412191e398e0b67",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.2",
"phpunit/php-token-stream": "~1.3",
"sebastian/environment": "~1.0",
"sebastian/version": "~1.0"
},
"require-dev": {
"ext-xdebug": ">=2.1.4",
"phpunit/phpunit": "~4"
},
"suggest": {
"ext-dom": "*",
"ext-xdebug": ">=2.2.1",
"ext-xmlwriter": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
"coverage",
"testing",
"xunit"
],
"time": "2015-01-24 10:06:35"
},
{
"name": "phpunit/php-file-iterator",
"version": "1.3.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"File/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
"filesystem",
"iterator"
],
"time": "2013-10-10 15:34:57"
},
{
"name": "phpunit/php-text-template",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
"reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"Text/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Simple template engine.",
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
"keywords": [
"template"
],
"time": "2014-01-30 17:20:04"
},
{
"name": "phpunit/php-timer",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
"reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"PHP/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Utility class for timing",
"homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
"timer"
],
"time": "2013-08-02 07:42:54"
},
{
"name": "phpunit/php-token-stream",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74",
"reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Wrapper around PHP's tokenizer extension.",
"homepage": "https://github.com/sebastianbergmann/php-token-stream/",
"keywords": [
"tokenizer"
],
"time": "2015-01-17 09:51:32"
},
{
"name": "phpunit/phpunit",
"version": "4.5.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "d6429b0995b24a2d9dfe5587ee3a7071c1161af4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d6429b0995b24a2d9dfe5587ee3a7071c1161af4",
"reference": "d6429b0995b24a2d9dfe5587ee3a7071c1161af4",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.3.3",
"phpspec/prophecy": "~1.3,>=1.3.1",
"phpunit/php-code-coverage": "~2.0,>=2.0.11",
"phpunit/php-file-iterator": "~1.3.2",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "~1.0.2",
"phpunit/phpunit-mock-objects": "~2.3",
"sebastian/comparator": "~1.1",
"sebastian/diff": "~1.1",
"sebastian/environment": "~1.2",
"sebastian/exporter": "~1.2",
"sebastian/global-state": "~1.0",
"sebastian/version": "~1.0",
"symfony/yaml": "~2.0"
},
"suggest": {
"phpunit/php-invoker": "~1.1"
},
"bin": [
"phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.5.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "The PHP Unit Testing framework.",
"homepage": "https://phpunit.de/",
"keywords": [
"phpunit",
"testing",
"xunit"
],
"time": "2015-03-29 09:24:05"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "2.3.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "74ffb87f527f24616f72460e54b595f508dccb5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/74ffb87f527f24616f72460e54b595f508dccb5c",
"reference": "74ffb87f527f24616f72460e54b595f508dccb5c",
"shasum": ""
},
"require": {
"doctrine/instantiator": "~1.0,>=1.0.2",
"php": ">=5.3.3",
"phpunit/php-text-template": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"suggest": {
"ext-soap": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Mock Object library for PHPUnit",
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
"keywords": [
"mock",
"xunit"
],
"time": "2015-04-02 05:36:41"
},
{
"name": "sebastian/comparator",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "1dd8869519a225f7f2b9eb663e225298fade819e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e",
"reference": "1dd8869519a225f7f2b9eb663e225298fade819e",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/diff": "~1.2",
"sebastian/exporter": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides the functionality to compare PHP values for equality",
"homepage": "http://www.github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
"time": "2015-01-29 16:28:08"
},
{
"name": "sebastian/diff",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "863df9687835c62aa423a22412d26fa2ebde3fd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3",
"reference": "863df9687835c62aa423a22412d26fa2ebde3fd3",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Kore Nordmann",
"email": "mail@kore-nordmann.de"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Diff implementation",
"homepage": "http://www.github.com/sebastianbergmann/diff",
"keywords": [
"diff"
],
"time": "2015-02-22 15:13:53"
},
{
"name": "sebastian/environment",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "5a8c7d31914337b69923db26c4221b81ff5a196e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e",
"reference": "5a8c7d31914337b69923db26c4221b81ff5a196e",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
"homepage": "http://www.github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
"hhvm"
],
"time": "2015-01-01 10:01:08"
},
{
"name": "sebastian/exporter",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "84839970d05254c73cde183a721c7af13aede943"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943",
"reference": "84839970d05254c73cde183a721c7af13aede943",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/recursion-context": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"time": "2015-01-27 07:23:06"
},
{
"name": "sebastian/global-state",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01",
"reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"suggest": {
"ext-uopz": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Snapshotting of global state",
"homepage": "http://www.github.com/sebastianbergmann/global-state",
"keywords": [
"global state"
],
"time": "2014-10-06 09:23:50"
},
{
"name": "sebastian/recursion-context",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "3989662bbb30a29d20d9faa04a846af79b276252"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252",
"reference": "3989662bbb30a29d20d9faa04a846af79b276252",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
}
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2015-01-24 09:48:32"
},
{
"name": "sebastian/version",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
"reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
"reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
"shasum": ""
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"time": "2015-02-24 06:35:25"
},
{
"name": "symfony/yaml",
"version": "v2.6.6",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "174f009ed36379a801109955fc5a71a49fe62dd4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/174f009ed36379a801109955fc5a71a49fe62dd4",
"reference": "174f009ed36379a801109955fc5a71a49fe62dd4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.6-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Yaml\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2015-03-30 15:54:10"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.3.0"
},
"platform-dev": []
}

View File

@ -0,0 +1,9 @@
html: ../Escpos.php escpos.conf
doxygen escpos.conf
latex: html
# Do nothing
clean:
rm --preserve-root -Rf html latex doxygen_sqlite3.db

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
Examples
--------
This folder contains a collectoion of feature examples.
Generally, demo.php is the fastest way to find out which features your
printer supports.
## Subfolders
- `interface/` - contains examples for output interfaces: eg, parallel, serial, USB, network, file-based.
- `specific/` - examples made in response to issues & questions. These cover specific languages, printers and interfaces, so hit narrower use cases.
## List of examples
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!
- `bit-image.php` - Prints a images to the printer using the older "bit image" commands.
- `demo.php` - Demonstrates output using a large subset of availale features.
- `qr-code.php` - Prints QR codes, if your printer supports it.
- `character-encodings.php` - Shows available character encodings. Change from the DefaultCapabilityProfile to get more useful output for your specific printer.
- `graphics.php` - The same output as `bit-image.php`, printed with the newer graphics commands (not supported on many non-Epson printers)
- `receipt-with-logo.php` - A simple receipt containing a logo and basic formating.
- `character-encodings-with-images.php` - The same as `character-encodings.php`, but also prints each string using an `ImagePrintBuffer`, showing compatibility gaps.
- `print-from-html.php` - Runs `wkhtmltoimage` to convert HTML to an image, and then prints the image. (This is very slow)
- `character-tables.php` - Prints a compact character code table for each available character set. Used to debug incorrect output from `character-encodings.php`.
- `print-from-pdf.php` - Loads a PDF and prints each page in a few different ways (very slow as well)

View File

@ -0,0 +1,181 @@
<?php
require_once (dirname ( __FILE__ ) . "/../Escpos.php");
$printer = new Escpos ();
$printer->setBarcodeHeight ( 40 );
/* Text position */
$printer->selectPrintMode ( Escpos::MODE_DOUBLE_HEIGHT | Escpos::MODE_DOUBLE_WIDTH );
$printer->text ( "Text position\n" );
$printer->selectPrintMode ();
$hri = array (
Escpos::BARCODE_TEXT_NONE => "No text",
Escpos::BARCODE_TEXT_ABOVE => "Above",
Escpos::BARCODE_TEXT_BELOW => "Below",
Escpos::BARCODE_TEXT_ABOVE | Escpos::BARCODE_TEXT_BELOW => "Both"
);
foreach ( $hri as $position => $caption ) {
$printer->text ( $caption . "\n" );
$printer->setBarcodeTextPosition ( $position );
$printer->barcode ( "012345678901", Escpos::BARCODE_JAN13 );
$printer->feed ();
}
/* Barcode types */
$standards = array (
Escpos::BARCODE_UPCA => array (
"title" => "UPC-A",
"caption" => "Fixed-length numeric product barcodes.",
"example" => array (
array (
"caption" => "12 char numeric including (wrong) check digit.",
"content" => "012345678901"
),
array (
"caption" => "Send 11 chars to add check digit automatically.",
"content" => "01234567890"
)
)
),
Escpos::BARCODE_UPCE => array (
"title" => "UPC-E",
"caption" => "Fixed-length numeric compact product barcodes.",
"example" => array (
array (
"caption" => "6 char numeric - auto check digit & NSC",
"content" => "123456"
),
array (
"caption" => "7 char numeric - auto check digit",
"content" => "0123456"
),
array (
"caption" => "8 char numeric",
"content" => "01234567"
),
array (
"caption" => "11 char numeric - auto check digit",
"content" => "01234567890"
),
array (
"caption" => "12 char numeric including (wrong) check digit",
"content" => "012345678901"
)
)
),
Escpos::BARCODE_JAN13 => array (
"title" => "JAN13/EAN13",
"caption" => "Fixed-length numeric barcodes.",
"example" => array (
array (
"caption" => "12 char numeric - auto check digit",
"content" => "012345678901"
),
array (
"caption" => "13 char numeric including (wrong) check digit",
"content" => "0123456789012"
)
)
),
Escpos::BARCODE_JAN8 => array (
"title" => "JAN8/EAN8",
"caption" => "Fixed-length numeric barcodes.",
"example" => array (
array (
"caption" => "7 char numeric - auto check digit",
"content" => "0123456"
),
array (
"caption" => "8 char numeric including (wrong) check digit",
"content" => "01234567"
)
)
),
Escpos::BARCODE_CODE39 => array (
"title" => "Code39",
"caption" => "Variable length alphanumeric w/ some special chars.",
"example" => array (
array (
"caption" => "Text, numbers, spaces",
"content" => "ABC 012"
),
array (
"caption" => "Special characters",
"content" => "$%+-./"
),
array (
"caption" => "Extra char (*) Used as start/stop",
"content" => "*TEXT*"
)
)
),
Escpos::BARCODE_ITF => array (
"title" => "ITF",
"caption" => "Variable length numeric w/even number of digits,\nas they are encoded in pairs.",
"example" => array (
array (
"caption" => "Numeric- even number of digits",
"content" => "0123456789"
)
)
),
Escpos::BARCODE_CODABAR => array (
"title" => "Codabar",
"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.",
"example" => array (
array (
"caption" => "Numeric w/ A A start/stop. ",
"content" => "A012345A"
),
array (
"caption" => "Extra allowable characters",
"content" => "A012$+-./:A"
)
)
),
Escpos::BARCODE_CODE93 => array (
"title" => "Code93",
"caption" => "Variable length- any ASCII is available",
"example" => array (
array (
"caption" => "Text",
"content" => "012abcd"
)
)
),
Escpos::BARCODE_CODE128 => array (
"title" => "Code128",
"caption" => "Variable length- any ASCII is available",
"example" => array (
array (
"caption" => "Code set A uppercase & symbols",
"content" => "{A" . "012ABCD"
),
array (
"caption" => "Code set B general text",
"content" => "{B" . "012ABCDabcd"
),
array (
"caption" => "Code set C compact numbers\n Sending chr(21) chr(32) chr(43)",
"content" => "{C" . chr ( 21 ) . chr ( 32 ) . chr ( 43 )
)
)
)
);
$printer->setBarcodeTextPosition ( Escpos::BARCODE_TEXT_BELOW );
foreach ( $standards as $type => $standard ) {
$printer->selectPrintMode ( Escpos::MODE_DOUBLE_HEIGHT | Escpos::MODE_DOUBLE_WIDTH );
$printer->text ( $standard ["title"] . "\n" );
$printer->selectPrintMode ();
$printer->text ( $standard ["caption"] . "\n\n" );
foreach ( $standard ["example"] as $id => $barcode ) {
$printer->setEmphasis ( true );
$printer->text ( $barcode ["caption"] . "\n" );
$printer->setEmphasis ( false );
$printer->text ( "Content: " . $barcode ["content"] . "\n" );
$printer->barcode ( $barcode ["content"], $type );
$printer->feed ();
}
}
$printer->cut ();
$printer->close ();

View File

@ -0,0 +1,32 @@
<?php
/* Example print-outs using the older bit image print command */
require_once(dirname(__FILE__) . "/../Escpos.php");
$printer = new Escpos();
try {
$tux = new EscposImage("resources/tux.png");
$printer -> 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");
$printer -> bitImage($tux);
$printer -> text("Regular Tux (bit image).\n");
$printer -> feed();
$printer -> bitImage($tux, Escpos::IMG_DOUBLE_WIDTH);
$printer -> text("Wide Tux (bit image).\n");
$printer -> feed();
$printer -> bitImage($tux, Escpos::IMG_DOUBLE_HEIGHT);
$printer -> text("Tall Tux (bit image).\n");
$printer -> feed();
$printer -> bitImage($tux, Escpos::IMG_DOUBLE_WIDTH | Escpos::IMG_DOUBLE_HEIGHT);
$printer -> text("Large Tux in correct proportion (bit image).\n");
} catch(Exception $e) {
/* Images not supported on your PHP, or image file not found */
$printer -> text($e -> getMessage() . "\n");
}
$printer -> cut();
$printer -> close();
?>

View File

@ -0,0 +1,59 @@
<?php
/* Change to the correct path if you copy this example! */
require_once(dirname(__FILE__) . "/../Escpos.php");
/**
* This example builds on character-encodings.php, also providing an image-based rendering.
* This is quite slow, since a) the buffers are changed dozens of
* times in the example, and b) It involves sending very wide images, which printers don't like!
*
* There are currently no test cases around the image printing, since it is an experimental feature.
*
* It does, however, illustrate the way that more encodings are available when image output is used.
*/
include(dirname(__FILE__) . '/resources/character-encoding-test-strings.inc');
try {
// Enter connector and capability profile
$connector = new FilePrintConnector("php://stdout");
$profile = DefaultCapabilityProfile::getInstance();
$buffers = array(new EscposPrintBuffer(), new ImagePrintBuffer());
/* Print a series of receipts containing i18n example strings */
$printer = new Escpos($connector, $profile);
$printer -> selectPrintMode(Escpos::MODE_DOUBLE_HEIGHT | Escpos::MODE_EMPHASIZED | Escpos::MODE_DOUBLE_WIDTH);
$printer -> text("Implemented languages\n");
$printer -> selectPrintMode();
foreach($inputsOk as $label => $str) {
$printer -> setEmphasis(true);
$printer -> text($label . ":\n");
$printer -> setEmphasis(false);
foreach($buffers as $buffer) {
$printer -> setPrintBuffer($buffer);
$printer -> text($str);
}
$printer -> setPrintBuffer($buffers[0]);
}
$printer -> feed();
$printer -> selectPrintMode(Escpos::MODE_DOUBLE_HEIGHT | Escpos::MODE_EMPHASIZED | Escpos::MODE_DOUBLE_WIDTH);
$printer -> text("Works in progress\n");
$printer -> selectPrintMode();
foreach($inputsNotOk as $label => $str) {
$printer -> setEmphasis(true);
$printer -> text($label . ":\n");
$printer -> setEmphasis(false);
foreach($buffers as $buffer) {
$printer -> setPrintBuffer($buffer);
$printer -> text($str);
}
$printer -> setPrintBuffer($buffers[0]);
}
$printer -> cut();
/* Close printer */
$printer -> close();
} catch(Exception $e) {
echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
}

View File

@ -0,0 +1,58 @@
<?php
/* Change to the correct path if you copy this example! */
require_once(dirname(__FILE__) . "/../Escpos.php");
/**
* This demonstrates available character encodings. Escpos-php accepts UTF-8,
* and converts this to lower-level data to the printer. This is a complex area, so be
* prepared to code a model-specific hack ('CapabilityProfile') for your printer.
*
* If you run into trouble, please file an issue on GitHub, including at a minimum:
* - A UTF-8 test string in the language you're working in, and
* - A test print or link to a technical document which lists the available
* code pages ('character code tables') for your printer.
*
* The DefaultCapabilityProfile works for Espson-branded printers. For other models, you
* must use/create a PrinterCapabilityProfile for your printer containing a list of code
* page numbers for your printer- otherwise you will get mojibake.
*
* If you do not intend to use non-English characters, then use SimpleCapabilityProfile,
* which has only the default encoding, effectively disabling code page changes.
*/
include(dirname(__FILE__) . '/resources/character-encoding-test-strings.inc');
try {
// Enter connector and capability profile (to match your printer)
$connector = new FilePrintConnector("php://stdout");
$profile = DefaultCapabilityProfile::getInstance();
/* Print a series of receipts containing i18n example strings */
$printer = new Escpos($connector, $profile);
$printer -> selectPrintMode(Escpos::MODE_DOUBLE_HEIGHT | Escpos::MODE_EMPHASIZED | Escpos::MODE_DOUBLE_WIDTH);
$printer -> text("Implemented languages\n");
$printer -> selectPrintMode();
foreach($inputsOk as $label => $str) {
$printer -> setEmphasis(true);
$printer -> text($label . ":\n");
$printer -> setEmphasis(false);
$printer -> text($str);
}
$printer -> feed();
$printer -> selectPrintMode(Escpos::MODE_DOUBLE_HEIGHT | Escpos::MODE_EMPHASIZED | Escpos::MODE_DOUBLE_WIDTH);
$printer -> text("Works in progress\n");
$printer -> selectPrintMode();
foreach($inputsNotOk as $label => $str) {
$printer -> setEmphasis(true);
$printer -> text($label . ":\n");
$printer -> setEmphasis(false);
$printer -> text($str);
}
$printer -> cut();
/* Close printer */
$printer -> close();
} catch(Exception $e) {
echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
}

View File

@ -0,0 +1,71 @@
<?php
/**
* This demo prints out supported code pages on your printer. This is intended
* for debugging character-encoding issues: If your printer does not work with
* a built-in capability profile, you need to check its documentation for
* supported code pages.
*
* These are then loaded into a capability profile, which maps code page
* numbers to iconv encoding names on your particular printer. This script
* will print all configured code pages, so that you can check that the chosen
* iconv encoding name matches the actual code page contents.
*
* If this is correctly set up for your printer, then the driver will try its
* best to map UTF-8 text into these code pages for you, allowing you to accept
* arbitrary input from a database, without worrying about encoding it for the printer.
*/
require_once(dirname(__FILE__) . "/../Escpos.php");
// Enter connector and capability profile (to match your printer)
$connector = new FilePrintConnector("php://stdout");
$profile = DefaultCapabilityProfile::getInstance();
$verbose = false; // Skip tables which iconv wont convert to (ie, only print characters available with UTF-8 input)
/* Print a series of receipts containing i18n example strings - Code below shouldn't need changing */
$printer = new Escpos($connector, $profile);
$codePages = $profile -> getSupportedCodePages();
$first = true; // Print larger table for first code-page.
foreach($codePages as $table => $name) {
/* Change printer code page */
$printer -> selectCharacterTable(255);
$printer -> selectCharacterTable($table);
/* Select & print a label for it */
$label = $name;
if($name === false) {
$label= " (not matched to iconv table)";
}
$printer -> setEmphasis(true);
$printer -> textRaw("Table $table: $label\n");
$printer -> setEmphasis(false);
if($name === false && !$verbose) {
continue; // Skip non-recognised
}
/* Print a table of available characters (first table is larger than subsequent ones */
if($first) {
$first = false;
compactCharTable($printer, 1, true);
} else {
compactCharTable($printer);
}
}
$printer -> cut();
$printer -> close();
function compactCharTable($printer, $start = 4, $header = false) {
/* Output a compact character table for the current encoding */
$chars = str_repeat(' ', 256);
for($i = 0; $i < 255; $i++) {
$chars[$i] = ($i > 32 && $i != 127) ? chr($i) : ' ';
}
if($header) {
$printer -> setEmphasis(true);
$printer -> textRaw(" 0123456789ABCDEF0123456789ABCDEF\n");
$printer -> setEmphasis(false);
}
for($y = $start; $y < 8; $y++) {
$printer -> setEmphasis(true);
$printer -> textRaw(strtoupper(dechex($y * 2)) . " ");
$printer -> setEmphasis(false);
$printer -> textRaw(substr($chars, $y * 32, 32) . "\n");
}
}

View File

@ -0,0 +1,167 @@
<?php
/**
* This is a demo script for the functions of the PHP ESC/POS print driver,
* Escpos.php.
*
* Most printers implement only a subset of the functionality of the driver, so
* will not render this output correctly in all cases.
*
* @author Michael Billington <michael.billington@gmail.com>
*/
require_once(dirname(__FILE__) . "/../Escpos.php");
$printer = new Escpos();
/* Initialize */
$printer -> initialize();
/* Text */
$printer -> text("Hello world\n");
$printer -> cut();
/* Line feeds */
$printer -> text("ABC");
$printer -> feed(7);
$printer -> text("DEF");
$printer -> feedReverse(3);
$printer -> text("GHI");
$printer -> feed();
$printer -> cut();
/* Font modes */
$modes = array(
Escpos::MODE_FONT_B,
Escpos::MODE_EMPHASIZED,
Escpos::MODE_DOUBLE_HEIGHT,
Escpos::MODE_DOUBLE_WIDTH,
Escpos::MODE_UNDERLINE);
for($i = 0; $i < pow(2, count($modes)); $i++) {
$bits = str_pad(decbin($i), count($modes), "0", STR_PAD_LEFT);
$mode = 0;
for($j = 0; $j < strlen($bits); $j++) {
if(substr($bits, $j, 1) == "1") {
$mode |= $modes[$j];
}
}
$printer -> selectPrintMode($mode);
$printer -> text("ABCDEFGHIJabcdefghijk\n");
}
$printer -> selectPrintMode(); // Reset
$printer -> cut();
/* Underline */
for($i = 0; $i < 3; $i++) {
$printer -> setUnderline($i);
$printer -> text("The quick brown fox jumps over the lazy dog\n");
}
$printer -> setUnderline(0); // Reset
$printer -> cut();
/* Cuts */
$printer -> text("Partial cut\n(not available on all printers)\n");
$printer -> cut(Escpos::CUT_PARTIAL);
$printer -> text("Full cut\n");
$printer -> cut(Escpos::CUT_FULL);
/* Emphasis */
for($i = 0; $i < 2; $i++) {
$printer -> setEmphasis($i == 1);
$printer -> text("The quick brown fox jumps over the lazy dog\n");
}
$printer -> setEmphasis(false); // Reset
$printer -> cut();
/* Double-strike (looks basically the same as emphasis) */
for($i = 0; $i < 2; $i++) {
$printer -> setDoubleStrike($i == 1);
$printer -> text("The quick brown fox jumps over the lazy dog\n");
}
$printer -> setDoubleStrike(false);
$printer -> cut();
/* Fonts (many printers do not have a 'Font C') */
$fonts = array(
Escpos::FONT_A,
Escpos::FONT_B,
Escpos::FONT_C);
for($i = 0; $i < count($fonts); $i++) {
$printer -> setFont($fonts[$i]);
$printer -> text("The quick brown fox jumps over the lazy dog\n");
}
$printer -> setFont(); // Reset
$printer -> cut();
/* Justification */
$justification = array(
Escpos::JUSTIFY_LEFT,
Escpos::JUSTIFY_CENTER,
Escpos::JUSTIFY_RIGHT);
for($i = 0; $i < count($justification); $i++) {
$printer -> setJustification($justification[$i]);
$printer -> text("A man a plan a canal panama\n");
}
$printer -> setJustification(); // Reset
$printer -> cut();
/* Barcodes - see barcode.php for more detail */
$printer -> setBarcodeHeight(80);
$printer->setBarcodeTextPosition ( Escpos::BARCODE_TEXT_BELOW );
$printer -> barcode("9876");
$printer -> feed();
$printer -> cut();
/* Graphics - this demo will not work on some non-Epson printers */
try {
$logo = new EscposImage("resources/escpos-php.png");
$imgModes = array(
Escpos::IMG_DEFAULT,
Escpos::IMG_DOUBLE_WIDTH,
Escpos::IMG_DOUBLE_HEIGHT,
Escpos::IMG_DOUBLE_WIDTH | Escpos::IMG_DOUBLE_HEIGHT
);
foreach($imgModes as $mode) {
$printer -> graphics($logo, $mode);
}
} catch(Exception $e) {
/* Images not supported on your PHP, or image file not found */
$printer -> text($e -> getMessage() . "\n");
}
$printer -> cut();
/* Bit image */
try {
$logo = new EscposImage("resources/escpos-php.png");
$imgModes = array(
Escpos::IMG_DEFAULT,
Escpos::IMG_DOUBLE_WIDTH,
Escpos::IMG_DOUBLE_HEIGHT,
Escpos::IMG_DOUBLE_WIDTH | Escpos::IMG_DOUBLE_HEIGHT
);
foreach($imgModes as $mode) {
$printer -> bitImage($logo, $mode);
}
} catch(Exception $e) {
/* Images not supported on your PHP, or image file not found */
$printer -> text($e -> getMessage() . "\n");
}
$printer -> cut();
/* QR Code - see also the more in-depth demo at qr-code.php */
$testStr = "Testing 123";
$models = array(
Escpos::QR_MODEL_1 => "QR Model 1",
Escpos::QR_MODEL_2 => "QR Model 2 (default)",
Escpos::QR_MICRO => "Micro QR code\n(not supported on all printers)");
foreach($models as $model => $name) {
$printer -> qrCode($testStr, Escpos::QR_ECLEVEL_L, 3, $model);
$printer -> text("$name\n");
$printer -> feed();
}
$printer -> cut();
/* Pulse */
$printer -> pulse();
/* Always close the printer! On some PrintConnectors, no actual
* data is sent until the printer is closed. */
$printer -> close();
?>

View File

@ -0,0 +1,32 @@
<?php
/* Print-outs using the newer graphics print command */
require_once(dirname(__FILE__) . "/../Escpos.php");
$printer = new Escpos();
try {
$tux = new EscposImage("resources/tux.png");
$printer -> graphics($tux);
$printer -> text("Regular Tux.\n");
$printer -> feed();
$printer -> graphics($tux, Escpos::IMG_DOUBLE_WIDTH);
$printer -> text("Wide Tux.\n");
$printer -> feed();
$printer -> graphics($tux, Escpos::IMG_DOUBLE_HEIGHT);
$printer -> text("Tall Tux.\n");
$printer -> feed();
$printer -> graphics($tux, Escpos::IMG_DOUBLE_WIDTH | Escpos::IMG_DOUBLE_HEIGHT);
$printer -> text("Large Tux in correct proportion.\n");
$printer -> cut();
} catch(Exception $e) {
/* Images not supported on your PHP, or image file not found */
$printer -> text($e -> getMessage() . "\n");
}
$printer -> close();
?>

View File

@ -0,0 +1,8 @@
Interfaces
----------
This directory contains boilerpalte code to show you how to open a print connector
to printers which are connected in different ways.
To get a list of supported interfaces and operating systems, see the main README.md file for the project.
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

View File

@ -0,0 +1,22 @@
<?php
/* Change to the correct path if you copy this example! */
require_once(dirname(__FILE__) . "/../../Escpos.php");
/* Most printers are open on port 9100, so you just need to know the IP
* address of your receipt printer, and then fsockopen() it on that port.
*/
try {
$connector = null;
//$connector = new NetworkPrintConnector("10.x.x.x", 9100);
/* Print a "Hello world" receipt" */
$printer = new Escpos($connector);
$printer -> text("Hello World!\n");
$printer -> cut();
/* Close printer */
$printer -> close();
} catch(Exception $e) {
echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
}

View File

@ -0,0 +1,33 @@
<?php
/* Change to the correct path if you copy this example! */
require_once(dirname(__FILE__) . "/../../Escpos.php");
/**
* On Linux, use the usblp module to make your printer available as a device
* file. This is generally the default behaviour if you don't install any
* vendor drivers.
*
* Once this is done, use a FilePrintConnector to open the device.
*
* Troubleshooting: On Debian, you must be in the lp group to access this file.
* dmesg to see what happens when you plug in your printer to make sure no
* other drivers are unloading the module.
*/
try {
// Enter the device file for your USB printer here
$connector = null;
//$connector = new FilePrintConnector("/dev/usb/lp0");
//$connector = new FilePrintConnector("/dev/usb/lp1");
//$connector = new FilePrintConnector("/dev/usb/lp2");
/* Print a "Hello world" receipt" */
$printer = new Escpos($connector);
$printer -> text("Hello World!\n");
$printer -> cut();
/* Close printer */
$printer -> close();
} catch(Exception $e) {
echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
}

View File

@ -0,0 +1,51 @@
<?php
/* Change to the correct path if you copy this example! */
require_once(dirname(__FILE__) . "/../../Escpos.php");
/**
* Install the printer using USB printing support, and the "Generic / Text Only" driver,
* then share it.
*
* Use a WindowsPrintConnector with the share name to print. This works on either
* Windows or Linux.
*
* Troubleshooting: Fire up a command prompt/terminal, and ensure that (if your printer is
* shared as "Receipt Printer"), the following commands work.
*
* Windows: (use an appropriate "net use" command if you need authentication)
* echo "Hello World" > testfile
* ## If you need authentication, use "net use" to hook up the printer:
* # net use "\\computername\Receipt Printer" /user:Guest
* # net use "\\computername\Receipt Printer" /user:Bob secret
* # net use "\\computername\Receipt Printer" /user:workgroup\Bob secret
* copy testfile "\\computername\Receipt Printer"
* del testfile
*
* GNU/Linux:
* # No authentication
* echo "Hello World" | smbclient "//computername/Receipt Printer" -c "print -" -N
* # Guest login
* echo "Hello World" | smbclient "//computername/Receipt Printer" -U Guest -c "print -" -N
* # Basic username/password
* echo "Hello World" | smbclient "//computername/Receipt Printer" secret -U "Bob" -c "print -"
* # Including domain name
* echo "Hello World" | smbclient "//computername/Receipt Printer" secret -U "workgroup\\Bob" -c "print -"
*/
try {
// Enter the share name for your printer here, as a smb:// url format
$connector = null;
//$connector = new WindowsPrintConnector("smb://computername/Receipt Printer");
//$connector = new WindowsPrintConnector("smb://Guest@computername/Receipt Printer");
//$connector = new WindowsPrintConnector("smb://FooUser:secret@computername/workgroup/Receipt Printer");
//$connector = new WindowsPrintConnector("smb://User:secret@computername/Receipt Printer");
/* Print a "Hello world" receipt" */
$printer = new Escpos($connector);
$printer -> text("Hello World!\n");
$printer -> cut();
/* Close printer */
$printer -> close();
} catch(Exception $e) {
echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
}

View File

@ -0,0 +1,30 @@
<?php
/* Change to the correct path if you copy this example! */
require_once(dirname(__FILE__) . "/../../Escpos.php");
/**
* Assuming your printer is available at LPT1,
* simpy instantiate a WindowsPrintConnector to it.
*
* When troubleshooting, make sure you can send it
* data from the command-line first:
* echo "Hello World" > LPT1
*/
try {
$connector = null;
//$connector = new WindowsPrintConnector("LPT1");
// A FilePrintConnector will also work, but on non-Windows systems, writes
// to an actual file called 'LPT1' rather than giving a useful error.
// $connector = new FilePrintConnector("LPT1");
/* Print a "Hello world" receipt" */
$printer = new Escpos($connector);
$printer -> text("Hello World!\n");
$printer -> cut();
/* Close printer */
$printer -> close();
} catch(Exception $e) {
echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
}

View File

@ -0,0 +1,32 @@
<?php
/* Change to the correct path if you copy this example! */
require_once(dirname(__FILE__) . "/../../Escpos.php");
/**
* Install the printer using USB printing support, and the "Generic / Text Only" driver,
* then share it (you can use a firewall so that it can only be seen locally).
*
* Use a WindowsPrintConnector with the share name to print.
*
* Troubleshooting: Fire up a command prompt, and ensure that (if your printer is shared as
* "Receipt Printer), the following commands work:
*
* echo "Hello World" > testfile
* copy testfile "\\%COMPUTERNAME%\Receipt Printer"
* del testfile
*/
try {
// Enter the share name for your USB printer here
$connector = null;
//$connector = new WindowsPrintConnector("Receipt Printer");
/* Print a "Hello world" receipt" */
$printer = new Escpos($connector);
$printer -> text("Hello World!\n");
$printer -> cut();
/* Close printer */
$printer -> close();
} catch(Exception $e) {
echo "Couldn't print to this printer: " . $e -> getMessage() . "\n";
}

View File

@ -0,0 +1,53 @@
<?php
require_once(dirname(__FILE__)."/../Escpos.php");
/*
* Due to its complxity, escpos-php does not support HTML input. To print HTML,
* either convert it to calls on the Escpos() object, or rasterise the page with
* wkhtmltopdf, an external package which is designed to handle HTML efficiently.
*
* This example is provided to get you started.
*
* Note: Depending on the height of your pages, it is suggested that you chop it
* into smaller sections, as printers simply don't have the buffer capacity for
* very large images.
*
* As always, you can trade off quality for capacity by halving the width
* (550 -> 225 below) and printing w/ Escpos::IMG_DOUBLE_WIDTH | Escpos::IMG_DOUBLE_HEIGHT
*/
try {
/* Set up command */
$source = "http://en.m.wikipedia.org/wiki/ESC/P";
$width = 550;
$dest = tempnam(sys_get_temp_dir(), 'escpos') . ".png";
$cmd = sprintf("wkhtmltoimage -n -q --width %s %s %s",
escapeshellarg($width),
escapeshellarg($source),
escapeshellarg($dest));
/* Run wkhtmltoimage */
ob_start();
system($cmd); // Can also use popen() for better control of process
$outp = ob_get_contents();
ob_end_clean();
if(!file_exists($dest)) {
throw new Exception("Command $cmd failed: $outp");
}
/* Load up the image */
try {
$img = new EscposImage($dest);
} catch(Exception $e) {
unlink($dest);
throw $e;
}
unlink($dest);
/* Print it */
$printer = new Escpos(); // Add connector for your printer here.
$printer -> bitImage($img); // bitImage() seems to allow larger images than graphics() on the TM-T20.
$printer -> cut();
$printer -> close();
} catch(Exception $e) {
echo $e -> getMessage();
}

View File

@ -0,0 +1,71 @@
<?php
require_once(dirname(__FILE__) . '/../Escpos.php');
/*
* This is three examples in one:
* 1: Print an entire PDF, normal quality.
* 2: Print at a lower quality for speed increase (CPU & transfer)
* 3: Cache rendered documents for a speed increase (removes CPU image processing completely on subsequent prints)
*/
/* 1: Print an entire PDF, start-to-finish (shorter form of the example) */
$pdf = 'resources/document.pdf';
try {
$pages = EscposImage::loadPdf($pdf);
$printer = new Escpos();
foreach($pages as $page) {
$printer -> graphics($page);
}
$printer -> cut();
$printer -> close();
} catch(Exception $e) {
/*
* loadPdf() throws exceptions if files or not found, or you don't have the
* imagick extension to read PDF's
*/
echo $e -> getMessage() . "\n";
exit(0);
}
/*
* 2: Speed up printing by roughly halving the resolution, and printing double-size.
* This gives a 75% speed increase at the expense of some quality.
*
* Reduce the page width further if necessary: if it extends past the printing area, your prints will be very slow.
*/
$printer = new Escpos();
$pdf = 'resources/document.pdf';
$pages = EscposImage::loadPdf($pdf, 260);
foreach($pages as $page) {
$printer -> graphics($page, Escpos::IMG_DOUBLE_HEIGHT | Escpos::IMG_DOUBLE_WIDTH);
}
$printer -> cut();
$printer -> close();
/*
* 3: PDF printing still too slow? If you regularly print the same files, serialize & compress your
* EscposImage objects (after printing[1]), instead of throwing them away.
*
* (You can also do this to print logos on computers which don't have an
* image processing library, by preparing a serialized version of your logo on your PC)
*
* [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.
*/
$printer = new Escpos();
$pdf = 'resources/document.pdf';
$ser = 'resources/document.z';
if(!file_exists($ser)) {
$pages = EscposImage::loadPdf($pdf);
} else {
$pages = unserialize(gzuncompress(file_get_contents($ser)));
}
foreach($pages as $page) {
$printer -> graphics($page);
}
$printer -> cut();
$printer -> close();
if(!file_exists($ser)) {
file_put_contents($ser, gzcompress(serialize($pages)));
}

View File

@ -0,0 +1,81 @@
<?php
/* Demonstration of available options on the qrCode() command */
require_once(dirname(__FILE__) . "/../Escpos.php");
$printer = new Escpos();
// Most simple example
title($printer, "QR code demo\n");
$testStr = "Testing 123";
$printer -> qrCode($testStr);
$printer -> text("Most simple example\n");
$printer -> feed();
// Demo that alignment is the same as text
$printer -> setJustification(Escpos::JUSTIFY_CENTER);
$printer -> qrCode($testStr);
$printer -> text("Same example, centred\n");
$printer -> setJustification();
$printer -> feed();
// Demo of numeric data being packed more densly
title($printer, "Data encoding\n");
$test = array(
"Numeric" => "0123456789012345678901234567890123456789",
"Alphanumeric" => "abcdefghijklmnopqrstuvwxyzabcdefghijklmn",
"Binary" => str_repeat("\0", 40));
foreach($test as $type => $data) {
$printer -> qrCode($data);
$printer -> text("$type\n");
$printer -> feed();
}
// Demo of error correction
title($printer, "Error correction\n");
$ec = array(
Escpos::QR_ECLEVEL_L => "L",
Escpos::QR_ECLEVEL_M => "M",
Escpos::QR_ECLEVEL_Q => "Q",
Escpos::QR_ECLEVEL_H => "H");
foreach($ec as $level => $name) {
$printer -> qrCode($testStr, $level);
$printer -> text("Error correction $name\n");
$printer -> feed();
}
// Change size
title($printer, "Pixel size\n");
$sizes = array(
1 => "(minimum)",
2 => "",
3 => "(default)",
4 => "",
5 => "",
10 => "",
16 => "(maximum)");
foreach($sizes as $size => $label) {
$printer -> qrCode($testStr, Escpos::QR_ECLEVEL_L, $size);
$printer -> text("Pixel size $size $label\n");
$printer -> feed();
}
// Change model
title($printer, "QR model\n");
$models = array(
Escpos::QR_MODEL_1 => "QR Model 1",
Escpos::QR_MODEL_2 => "QR Model 2 (default)",
Escpos::QR_MICRO => "Micro QR code\n(not supported on all printers)");
foreach($models as $model => $name) {
$printer -> qrCode($testStr, Escpos::QR_ECLEVEL_L, 3, $model);
$printer -> text("$name\n");
$printer -> feed();
}
// Cut & close
$printer -> cut();
$printer -> close();
function title(Escpos $printer, $str) {
$printer -> selectPrintMode(Escpos::MODE_DOUBLE_HEIGHT | Escpos::MODE_DOUBLE_WIDTH);
$printer -> text($str);
$printer -> selectPrintMode();
}

View File

@ -0,0 +1,96 @@
<?php
require_once(dirname(__FILE__) . "/../Escpos.php");
/* Information for the receipt */
$items = array(
new item("Example item #1", "4.00"),
new item("Another thing", "3.50"),
new item("Something else", "1.00"),
new item("A final item", "4.45"),
);
$subtotal = new item('Subtotal', '12.95');
$tax = new item('A local tax', '1.30');
$total = new item('Total', '14.25', true);
/* Date is kept the same for testing */
// $date = date('l jS \of F Y h:i:s A');
$date = "Monday 6th of April 2015 02:56:25 PM";
/* Start the printer */
$logo = new EscposImage("resources/escpos-php.png");
$printer = new Escpos();
/* Print top logo */
$printer -> setJustification(Escpos::JUSTIFY_CENTER);
$printer -> graphics($logo);
/* Name of shop */
$printer -> selectPrintMode(Escpos::MODE_DOUBLE_WIDTH);
$printer -> text("ExampleMart Ltd.\n");
$printer -> selectPrintMode();
$printer -> text("Shop No. 42.\n");
$printer -> feed();
/* Title of receipt */
$printer -> setEmphasis(true);
$printer -> text("SALES INVOICE\n");
$printer -> setEmphasis(false);
/* Items */
$printer -> setJustification(Escpos::JUSTIFY_LEFT);
$printer -> setEmphasis(true);
$printer -> text(new item('', '$'));
$printer -> setEmphasis(false);
foreach($items as $item) {
$printer -> text($item);
}
$printer -> setEmphasis(true);
$printer -> text($subtotal);
$printer -> setEmphasis(false);
$printer -> feed();
/* Tax and total */
$printer -> text($tax);
$printer -> selectPrintMode(Escpos::MODE_DOUBLE_WIDTH);
$printer -> text($total);
$printer -> selectPrintMode();
/* Footer */
$printer -> feed(2);
$printer -> setJustification(Escpos::JUSTIFY_CENTER);
$printer -> text("Thank you for shopping at ExampleMart\n");
$printer -> text("For trading hours, please visit example.com\n");
$printer -> feed(2);
$printer -> text($date . "\n");
/* Cut the receipt and open the cash drawer */
$printer -> cut();
$printer -> pulse();
$printer -> close();
/* A wrapper to do organise item names & prices into columns */
class item {
private $name;
private $price;
private $dollarSign;
public function __construct($name = '', $price = '', $dollarSign = false) {
$this -> name = $name;
$this -> price = $price;
$this -> dollarSign = $dollarSign;
}
public function __toString() {
$rightCols = 10;
$leftCols = 38;
if($this -> dollarSign) {
$leftCols = $leftCols / 2 - $rightCols / 2;
}
$left = str_pad($this -> name, $leftCols) ;
$sign = ($this -> dollarSign ? '$ ' : '');
$right = str_pad($sign . $this -> price, $rightCols, ' ', STR_PAD_LEFT);
return "$left$right\n";
}
}
?>

View File

@ -0,0 +1,35 @@
<?php
/* All strings from EscposPrintBufferTest are included below- These are fully supported
* on the default profile, so you can use them to test modified profiles (using the wrong
* profile for a printer produces mojibake) */
$inputsOk = array(
"Danish" => "Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Wolther spillede på xylofon.\n",
"German" => "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg.\n",
"Greek" => "Ξεσκεπάζω την ψυχοφθόρα βδελυγμία\n",
"English" => "The quick brown fox jumps over the lazy dog.\n",
"Spanish" => "El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.\n",
"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",
"Irish Gaelic" => "D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh.\n",
"Hungarian" => "Árvíztűrő tükörfúrógép.\n",
"Icelandic" => "Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa.\n",
"Latvian" => "Glāžšķūņa rūķīši dzērumā čiepj Baha koncertflīģeļu vākus.\n",
"Polish" => "Pchnąć w tę łódź jeża lub ośm skrzyń fig.\n",
"Russian" => "В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!\n",
"Turkish" => "Pijamalı hasta, yağız şoföre çabucak güvendi.\n",
"Japanese (Katakana half-width)" => implode("\n", array("イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム", "ウイノオクヤマ ケフコエテ アサキユメミシ エヒモセスン")) . "\n"
);
/*
* These strings are not expected to print correctly, if at all, even on an Epson printer. This is due to a mix of
* escpos driver, printer, and PHP language support issues.
*
* They are included here as a collection of things not yet implemented.
*/
$inputsNotOk = array(
"Thai (No character encoder available)" => "นายสังฆภัณฑ์ เฮงพิทักษ์ฝั่ง ผู้เฒ่าซึ่งมีอาชีพเป็นฅนขายฃวด ถูกตำรวจปฏิบัติการจับฟ้องศาล ฐานลักนาฬิกาคุณหญิงฉัตรชฎา ฌานสมาธิ\n",
"Japanese (Hiragana)" => implode("\n", array("いろはにほへとちりぬるを", " わかよたれそつねならむ", "うゐのおくやまけふこえて", "あさきゆめみしゑひもせす")) . "\n",
"Japanese (Katakana full-width)" => implode("\n", array("イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム", "ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン")) . "\n",
"Arabic (RTL not supported, encoding issues)" => "صِف خَلقَ خَودِ كَمِثلِ الشَمسِ إِذ بَزَغَت — يَحظى الضَجيعُ بِها نَجلاءَ مِعطارِ" . "\n",
"Hebrew (RTL not supported, line break issues)" => "דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה" . "\n"
);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -0,0 +1,21 @@
<?php
require_once(dirname(__FILE__) . "/../../Escpos.php");
/* This example shows the printing of Latvian text on the Star TUP 592 printer */
$profile = StarCapabilityProfile::getInstance();
/* Option 1: Native character encoding */
$connector = new FilePrintConnector("php://stdout");
$printer = new Escpos($connector, $profile);
$printer -> text("Glāžšķūņa rūķīši dzērumā čiepj Baha koncertflīģeļu vākus\n");
$printer -> cut();
$printer -> close();
/* Option 2: Image-based output (formatting not available using this output) */
$buffer = new ImagePrintBuffer();
$connector = new FilePrintConnector("php://stdout");
$printer = new Escpos($connector, $profile);
$printer -> setPrintBuffer($buffer);
$printer -> text("Glāžšķūņa rūķīši dzērumā čiepj Baha koncertflīģeļu vākus\n");
$printer -> cut();
$printer -> close();
?>

View File

@ -0,0 +1,36 @@
<?php
require_once(dirname(__FILE__) . "/../../Escpos.php");
/*
* This example shows how tok send a custom command to the printer-
* The use case here is an Epson TM-T20II and German text.
*
* Background: Not all ESC/POS features are available in the driver, so sometimes
* you might want to send a custom commnad. This is useful for testing
* new features.
*
* The Escpos::text() function removes non-printable characters as a precaution,
* so that commands cannot be injected into user input. To send raw data to
* the printer, you need to write bytes to the underlying PrintConnector.
*
* If you get a new command working, please file an issue on GitHub with a code
* snippet so that it can be incorporated into escpos-php.
*/
/* Set up profile & connector */
$connector = new FilePrintConnector("php://output");
$profile = DefaultCapabilityProfile::getInstance(); // Works for Epson printers
$printer = new Escpos($connector, $profile);
$cmd = Escpos::ESC . "V" . chr(1); // Try out 90-degree rotation.
$printer -> getPrintConnector() -> write($cmd);
$printer -> text("Beispieltext in Deutsch\n");
$printer -> cut();
$printer -> close();
/*
* Hex-dump of output confirms that ESC V 1 being sent:
*
* 0000000 033 @ 033 V 001 B e i s p i e l t e x
* 0000010 t i n D e u t s c h \n 035 V A
* 0000020 003
*/

View File

@ -0,0 +1,16 @@
<?php
/*
* Example of printing Spanish text on SEYPOS PRP-300 thermal line printer.
* The characters in Spanish are available in code page 437, so no special
* code pages are needed in this case (SimpleCapabilityProfile).
*
* Use the hardware switch to activate "Two-byte Character Code"
*/
require_once(dirname(__FILE__) . "/../../Escpos.php");
$connector = new FilePrintConnector("php://output");
$profile = SimpleCapabilityProfile::getInstance();
$printer = new Escpos($connector);
$printer -> text("El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.\n");
$printer -> cut();
$printer -> close();

View File

@ -0,0 +1,69 @@
<?php
require_once(dirname(__FILE__) . "/../../Escpos.php");
$profile = DefaultCapabilityProfile::getInstance();
// This is a quick demo of currency symbol issues in #39.
/* Option 1: Native ESC/POS characters, depends on printer and is buggy. */
$connector = new FilePrintConnector("php://stdout");
$printer = new Escpos($connector, $profile);
$printer -> text("€ 9,95\n");
$printer -> text("£ 9.95\n");
$printer -> text("$ 9.95\n");
$printer -> text("¥ 9.95\n");
$printer -> cut();
$printer -> close();
/* Option 2: Image-based output (formatting not available using this output). */
$buffer = new ImagePrintBuffer();
$connector = new FilePrintConnector("php://stdout");
$printer = new Escpos($connector, $profile);
$printer -> setPrintBuffer($buffer);
$printer -> text("€ 9,95\n");
$printer -> text("£ 9.95\n");
$printer -> text("$ 9.95\n");
$printer -> text("¥ 9.95\n");
$printer -> cut();
$printer -> close();
/*
Option 3: If the printer is configured to print in a specific code
page, you can set up a CapabilityProfile which either references its
iconv encoding name, or includes all of the available characters.
Here, we make use of CP858 for its inclusion of currency symbols which
are not available in CP437. CP858 has good printer support, but is not
included in all iconv builds.
*/
class CustomCapabilityProfile extends SimpleCapabilityProfile {
function getCustomCodePages() {
/*
* Example to print in a specific, user-defined character set
* on a printer which has been configured to use i
*/
return array(
'CP858' => "ÇüéâäàåçêëèïîìÄÅ" .
"ÉæÆôöòûùÿÖÜø£Ø×ƒ" .
"áíóúñѪº¿®¬½¼¡«»" .
"░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐" .
"└┴┬├─┼ãÃ╚╔╩╦╠═╬¤" .
"ðÐÊËÈ€ÍÎÏ┘┌█▄¦Ì▀" .
"ÓßÔÒõÕµþÞÚÛÙýݯ´" .
" ±‗¾¶§÷¸°¨·¹³²■ ");
}
function getSupportedCodePages() {
return array(
0 => 'custom:CP858');
}
}
$connector = new FilePrintConnector("php://stdout");
$profile = CustomCapabilityProfile::getInstance();
$printer = new Escpos($connector, $profile);
$printer -> text("€ 9,95\n");
$printer -> text("£ 9.95\n");
$printer -> text("$ 9.95\n");
$printer -> text("¥ 9.95\n");
$printer -> cut();
$printer -> close();

View File

@ -0,0 +1,31 @@
<?php
/* Example of printing the GBP pound symbol on a STAR TSP650
*
* In this example, it's shown how to check that your PHP files are actually being
* saved in unicode. Sections B) and C) are identical in UTF-8, but different
* if you are saving to a retro format like Windows-1252.
*/
// Adjust these to your environment
require_once(dirname(__FILE__) . "/../../Escpos.php");
$connector = new FilePrintConnector("php://stdout");
// Start printer
$profile = SimpleCapabilityProfile::getInstance();
$printer = new Escpos($connector, $profile);
// A) Raw pound symbol
// This is the most likely thing to work, and bypasses all the fancy stuff.
$printer -> textRaw("\x9C"); // based on position in CP437
$printer -> text(" 1.95\n");
// B) Manually encoded UTF8 pound symbol. Tests that the driver correctly
// encodes this as CP437.
$printer -> text(base64_decode("wqM=") . " 2.95\n");
// C) Pasted in file. Tests that your files are being saved as UTF-8, which
// escpos-php is able to convert automatically to a mix of code pages.
$printer -> text("£ 3.95\n");
$printer -> cut();
$printer -> close();

View File

@ -0,0 +1,16 @@
<?php
/* Example of Greek text on the P-822D */
require_once(dirname(__FILE__) . "/../../Escpos.php");
// Setup the printer
$connector = new FilePrintConnector("php://stdout");
$profile = P822DCapabilityProfile::getInstance();
$printer = new Escpos($connector, $profile);
// Print a Greek pangram
$text = "Ξεσκεπάζω την ψυχοφθόρα βδελυγμία";
$printer -> text($text . "\n");
$printer -> cut();
// Close the connection
$printer -> close();

View File

@ -0,0 +1,47 @@
<?php
/*
* This example shows Arabic image-based output on the EPOS TEP 220m.
*
* Because escpos-php is not yet able to render Arabic correctly
* on thermal line printers, small images are generated and sent
* instead. This is a bit slower, and only limited formatting
* is currently available in this mode.
*
* Requirements are:
* - imagick extension (For the ImagePrintBuffer, which does not
* support gd at the time of writing)
* - Ar-PHP library, available from sourceforge, for the first
* part of this example. Drop it in the folder listed below:
*/
require_once(dirname(__FILE__) . "/../../Escpos.php");
require_once(dirname(__FILE__) . "/../../vendor/I18N/Arabic.php");
/*
* First, convert the text into LTR byte order with joined letters,
* Using the Ar-PHP library.
*
* The Ar-PHP library uses the default internal encoding, and can print
* a lot of errors depending on the input, so be prepared to debug
* the next four lines.
*
* Note that this output shows that numerals are converted to placeholder
* characters, indicating that western numerals (123) have to be used instead.
*/
mb_internal_encoding("UTF-8");
$Arabic = new I18N_Arabic('Glyphs');
$text = "صِف خَلقَ خَودِ كَمِثلِ الشَمسِ إِذ بَزَغَت — يَحظى الضَجيعُ بِها نَجلاءَ مِعطارِ";
$text = $Arabic -> utf8Glyphs($text);
/*
* Set up and use the printer
*/
$buffer = new ImagePrintBuffer();
$profile = EposTepCapabilityProfile::getInstance();
$connector = new FilePrintConnector("php://output");
// = WindowsPrintConnector("LPT2");
// Windows LPT2 was used in the bug tracker
$printer = new Escpos($connector, $profile);
$printer -> setPrintBuffer($buffer);
$printer -> text($text . "\n");
$printer -> close();

View File

@ -0,0 +1,7 @@
Specific examples
-----------------
These examples are designed for specific combinations of language,
printer and interface.
They are documented here because the general examples all set up the printer in a similar way.

View File

@ -0,0 +1,62 @@
<?php
/**
* This print-out shows how large the available font sizes are. It is included
* separately due to the amount of text it prints.
*
* @author Michael Billington <michael.billington@gmail.com>
*/
require_once(dirname(__FILE__) . "/../Escpos.php");
$printer = new Escpos();
/* Initialize */
$printer -> initialize();
/* Text of various (in-proportion) sizes */
title($printer, "Change height & width\n");
for($i = 1; $i <= 8; $i++) {
$printer -> setTextSize($i, $i);
$printer -> text($i);
}
$printer -> text("\n");
/* Width changing only */
title($printer, "Change width only (height=4):\n");
for($i = 1; $i <= 8; $i++) {
$printer -> setTextSize($i, 4);
$printer -> text($i);
}
$printer -> text("\n");
/* Height changing only */
title($printer, "Change height only (width=4):\n");
for($i = 1; $i <= 8; $i++) {
$printer -> setTextSize(4, $i);
$printer -> text($i);
}
$printer -> text("\n");
/* Very narrow text */
title($printer, "Very narrow text:\n");
$printer -> setTextSize(1, 8);
$printer -> text("The quick brown fox jumps over the lazy dog.\n");
/* Very flat text */
title($printer, "Very wide text:\n");
$printer -> setTextSize(4, 1);
$printer -> text("Hello world!\n");
/* Very large text */
title($printer, "Largest possible text:\n");
$printer -> setTextSize(8,8);
$printer -> text("Hello\nworld!\n");
$printer -> cut();
$printer -> close();
function title(Escpos $printer, $text) {
$printer -> selectPrintMode(Escpos::MODE_EMPHASIZED);
$printer -> text("\n" . $text);
$printer -> selectPrintMode(); // Reset
}
?>

View File

@ -0,0 +1,61 @@
<?php
/**
* Not all printers support the same subset of available Esc/POS commands. Profiles allow you to specify
* which features are available on your printer, so that Escpos is less likely to send unsupported commands.
*/
abstract class AbstractCapabilityProfile {
/**
* Sub-classes must be retrieved via getInstance(), so that validation
* can be attached to guarantee that dud profiles are not used on an Escpos object.
*/
protected final function __construct() {
// This space intentionally left blank.
}
/**
* If getSupportedCodePages contains custom code pages, their character maps must be provided here.
*/
abstract function getCustomCodePages();
/**
* Return a map of code page numbers to names for this printer. Names
* should match iconv code page names where possible (non-matching names will not be used).
*/
abstract function getSupportedCodePages();
/**
* True to support barcode "function b", false to use only function A.
*/
abstract function getSupportsBarcodeB();
/**
* True for bitImage support, false for no bitImage support.
*/
abstract function getSupportsBitImage();
/**
* True for graphics support, false for no graphics support.
*/
abstract function getSupportsGraphics();
/**
* True for 'STAR original' commands, false for standard ESC/POS only.
*/
abstract function getSupportsStarCommands();
/**
* True if the printer renders its own QR codes, false to send an image.
*/
abstract function getSupportsQrCode();
/**
* @return AbstractCapabilityProfile Instance of sub-class.
*/
public static final function getInstance() {
static $profile = null;
if ($profile === null) {
$profile = new static();
}
return $profile;
}
}

View File

@ -0,0 +1,181 @@
<?php
abstract class CodePage {
/** Code page constants, exported from iconv -l. Can be cut down*/
const CP037 = "CP037";
const CP038 = "CP038";
const CP273 = "CP273";
const CP274 = "CP274";
const CP275 = "CP275";
const CP278 = "CP278";
const CP280 = "CP280";
const CP281 = "CP281";
const CP282 = "CP282";
const CP284 = "CP284";
const CP285 = "CP285";
const CP290 = "CP290";
const CP297 = "CP297";
const CP367 = "CP367";
const CP420 = "CP420";
const CP423 = "CP423";
const CP424 = "CP424";
const CP437 = "CP437";
const CP500 = "CP500";
const CP737 = "CP737";
const CP770 = "CP770";
const CP771 = "CP771";
const CP772 = "CP772";
const CP773 = "CP773";
const CP774 = "CP774";
const CP775 = "CP775";
const CP803 = "CP803";
const CP813 = "CP813";
const CP819 = "CP819";
const CP850 = "CP850";
const CP851 = "CP851";
const CP852 = "CP852";
const CP855 = "CP855";
const CP856 = "CP856";
const CP857 = "CP857";
const CP860 = "CP860";
const CP861 = "CP861";
const CP862 = "CP862";
const CP863 = "CP863";
const CP864 = "CP864";
const CP865 = "CP865";
const CP866 = "CP866";
const CP866NAV = "CP866NAV";
const CP868 = "CP868";
const CP869 = "CP869";
const CP870 = "CP870";
const CP871 = "CP871";
const CP874 = "CP874";
const CP875 = "CP875";
const CP880 = "CP880";
const CP891 = "CP891";
const CP901 = "CP901";
const CP902 = "CP902";
const CP903 = "CP903";
const CP904 = "CP904";
const CP905 = "CP905";
const CP912 = "CP912";
const CP915 = "CP915";
const CP916 = "CP916";
const CP918 = "CP918";
const CP920 = "CP920";
const CP921 = "CP921";
const CP922 = "CP922";
const CP930 = "CP930";
const CP932 = "CP932";//
const CP933 = "CP933";
const CP935 = "CP935";
const CP936 = "CP936";
const CP937 = "CP937";
const CP939 = "CP939";
const CP949 = "CP949";
const CP950 = "CP950";
const CP1004 = "CP1004";
const CP1008 = "CP1008";
const CP1025 = "CP1025";
const CP1026 = "CP1026";
const CP1046 = "CP1046";
const CP1047 = "CP1047";
const CP1070 = "CP1070";
const CP1079 = "CP1079";
const CP1081 = "CP1081";
const CP1084 = "CP1084";
const CP1089 = "CP1089";
const CP1097 = "CP1097";
const CP1112 = "CP1112";
const CP1122 = "CP1122";
const CP1123 = "CP1123";
const CP1124 = "CP1124";
const CP1125 = "CP1125";
const CP1129 = "CP1129";
const CP1130 = "CP1130";
const CP1132 = "CP1132";
const CP1133 = "CP1133";
const CP1137 = "CP1137";
const CP1140 = "CP1140";
const CP1141 = "CP1141";
const CP1142 = "CP1142";
const CP1143 = "CP1143";
const CP1144 = "CP1144";
const CP1145 = "CP1145";
const CP1146 = "CP1146";
const CP1147 = "CP1147";
const CP1148 = "CP1148";
const CP1149 = "CP1149";
const CP1153 = "CP1153";
const CP1154 = "CP1154";
const CP1155 = "CP1155";
const CP1156 = "CP1156";
const CP1157 = "CP1157";
const CP1158 = "CP1158";
const CP1160 = "CP1160";
const CP1161 = "CP1161";
const CP1162 = "CP1162";
const CP1163 = "CP1163";
const CP1164 = "CP1164";
const CP1166 = "CP1166";
const CP1167 = "CP1167";
const CP1250 = "CP1250";
const CP1251 = "CP1251";
const CP1252 = "CP1252";
const CP1253 = "CP1253";
const CP1254 = "CP1254";
const CP1255 = "CP1255";
const CP1256 = "CP1256";
const CP1257 = "CP1257";
const CP1258 = "CP1258";
const CP1282 = "CP1282";
const CP1361 = "CP1361";
const CP1364 = "CP1364";
const CP1371 = "CP1371";
const CP1388 = "CP1388";
const CP1390 = "CP1390";
const CP1399 = "CP1399";
const CP4517 = "CP4517";
const CP4899 = "CP4899";
const CP4909 = "CP4909";
const CP4971 = "CP4971";
const CP5347 = "CP5347";
const CP9030 = "CP9030";
const CP9066 = "CP9066";
const CP9448 = "CP9448";
const CP10007 = "CP10007";
const CP12712 = "CP12712";
const CP16804 = "CP16804";
const ISO8859_7 = "ISO_8859-7";
const ISO8859_2 = "ISO_8859-2";
const ISO8859_15 = "ISO_8859-15";
const RK1048 = "RK1048";
// Code pages which are not built in
// to default iconv on Debian.
const CP720 = false;
const CP853 = false;
const CP858 = false;
const CP928 = false;
const CP1098 = false;
const CP747 = false;
/*
* Below code pages appear to be vendor-specific (Star), so iconv wont use them
* They are being merged gradually into the StarCapabilityProfile.
*/
const CP3840 = false;
const CP3841 = false;
const CP3843 = false;
const CP3844 = false;
const CP3845 = false;
const CP3847 = false;
const CP3846 = false;
const CP3848 = false;
const CP1001 = false;
const CP2001 = false;
const CP3001 = false;
const CP3002 = false;
const CP3011 = false;
const CP3012 = false;
const CP3021 = false;
const CP3041 = false;
}

View File

@ -0,0 +1,103 @@
<?php
/**
* This capability profile matches many recent Epson-branded thermal receipt printers.
*
* For non-Epson printers, try the SimpleCapabilityProfile.
*/
class DefaultCapabilityProfile extends AbstractCapabilityProfile {
function getCustomCodePages() {
return array();
}
function getSupportedCodePages() {
/* Character code tables which the printer understands, mapping to known encoding standards we may be able to encode to.
*
* See CodePage.php for the mapping of these standards to encoding names for use in the backing library.
*
* Any entry with 'false' means I haven't compared the print-out of the code page to a table.
*/
return array(
0 => CodePage::CP437,
1 => CodePage::CP932,
2 => CodePage::CP850,
3 => CodePage::CP860,
4 => CodePage::CP863,
5 => CodePage::CP865,
6 => false, // Hiragana
7 => false, // One-pass printing Kanji characters
8 => false, // Page 8 [One-pass printing Kanji characters]
11 => CodePage::CP851,
12 => CodePage::CP853,
13 => CodePage::CP857,
14 => CodePage::CP737,
15 => CodePage::ISO8859_7,
16 => CodePage::CP1252,
17 => CodePage::CP866,
18 => CodePage::CP852,
19 => CodePage::CP858,
20 => false, // Thai Character Code 42
21 => CodePage::CP874, // Thai Character Code 11
22 => false, // Thai Character Code 13
23 => false, // Thai Character Code 14
24 => false, // Thai Character Code 16
25 => false, // Thai Character Code 17
26 => false, // Thai Character Code 18
30 => false, // TCVN-3: Vietnamese
31 => false, // TCVN-3: Vietnamese
32 => CodePage::CP720,
33 => CodePage::CP775,
34 => CodePage::CP855,
35 => CodePage::CP861,
36 => CodePage::CP862,
37 => CodePage::CP864,
38 => CodePage::CP869,
39 => CodePage::ISO8859_2,
40 => CodePage::ISO8859_15,
41 => CodePage::CP1098, // PC1098: Farsi
42 => CodePage::CP774,
43 => CodePage::CP772,
44 => CodePage::CP1125,
45 => CodePage::CP1250,
46 => CodePage::CP1251,
47 => CodePage::CP1253,
48 => CodePage::CP1254,
49 => CodePage::CP1255,
50 => CodePage::CP1256,
51 => CodePage::CP1257,
52 => CodePage::CP1258,
53 => CodePage::RK1048,
66 => false, // Devanagari
67 => false, // Bengali
68 => false, // Tamil
69 => false, // Telugu
70 => false, // Assamese
71 => false, // Oriya
72 => false, // Kannada
73 => false, // Malayalam
74 => false, // Gujarati
75 => false, // Punjabi
82 => false, // Marathi
254 => false,
255 => false);
}
function getSupportsBarcodeB() {
return true;
}
function getSupportsBitImage() {
return true;
}
function getSupportsGraphics() {
return true;
}
function getSupportsStarCommands() {
return false;
}
function getSupportsQrCode() {
return true;
}
}

View File

@ -0,0 +1,78 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Print connector that writes to nowhere, but allows the user to retrieve the
* buffered data. Used for testing.
*/
final class DummyPrintConnector implements PrintConnector {
/**
* @var array Buffer of accumilated data.
*/
private $buffer;
/**
* @var string data which the printer will provide on next read
*/
private $readData;
/**
* Create new print connector
*/
public function __construct() {
$this -> buffer = array();
}
public function __destruct() {
if($this -> buffer !== null) {
trigger_error("Print connector was not finalized. Did you forget to close the printer?", E_USER_NOTICE);
}
}
public function finalize() {
$this -> buffer = null;
}
/**
* @return string Get the accumulated data that has been sent to this buffer.
*/
public function getData() {
return implode($this -> buffer);
}
/* (non-PHPdoc)
* @see PrintConnector::read()
*/
public function read($len) {
return $len >= strlen($this -> readData) ? $this -> readData : substr($this -> readData, 0, $len);
}
public function write($data) {
$this -> buffer[] = $data;
}
}

View File

@ -0,0 +1,4 @@
<?php
class EposTepCapabilityProfile extends DefaultCapabilityProfile {
// TODO override list of code pages
}

View File

@ -0,0 +1,405 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This class deals with images in raster formats, and converts them into formats
* which are suitable for use on thermal receipt printers. Currently, only PNG
* images (in) and ESC/POS raster format (out) are implemeted.
*
* Input formats:
* - Currently, only PNG is supported.
* - Other easily read raster formats (jpg, gif) will be added at a later date, as this is not complex.
* - The BMP format can be directly read by some commands, but this has not yet been implemented.
*
* Output formats:
* - Currently, only ESC/POS raster format is supported
* - ESC/POS 'column format' support is partially implemented, but is not yet used by Escpos.php library.
* - Output as multiple rows of column format image is not yet in the works.
*
* Libraries:
* - Currently, php-gd is used to read the input. Support for imagemagick where gd is not installed is
* also not complex to add, and is a likely future feature.
* - Support for native use of the BMP format is a goal, for maximum compatibility with target environments.
*/
class EscposImage {
/**
* @var string The image's bitmap data (if it is a Windows BMP).
*/
protected $imgBmpData;
/**
* @var string image data in rows: 1 for black, 0 for white.
*/
protected $imgData;
/**
* @var string cached raster format data to avoid re-computation
*/
protected $imgRasterData;
/**
* @var int height of the image
*/
protected $imgHeight;
/**
* @var int width of the image
*/
protected $imgWidth;
/**
* Load up an image from a filename
*
* @param string $imgPath The path to the image to load, or null to skip
* loading the image (some other functions are available for
* populating the data). Supported graphics types depend on your PHP configuration.
*/
public function __construct($imgPath = null) {
/* Can't use bitmaps yet */
$this -> imgBmpData = null;
$this -> imgRasterData = null;
if($imgPath === null) {
// Blank image
$this -> imgHeight = 0;
$this -> imgWidth = 0;
$this -> imgData = "";
return;
}
/* Load up using GD */
if(!file_exists($imgPath)) {
throw new Exception("File '$imgPath' does not exist.");
}
$ext = pathinfo($imgPath, PATHINFO_EXTENSION);
if($ext == "bmp") {
// The plan is to implement BMP handling directly in
// PHP, as some printers understand this format themselves.
// TODO implement PHP bitmap handling
throw new Exception("Native bitmaps not yet supported. Please convert the file to a supported raster format.");
}
if($this -> isGdSupported()) {
// Prefer to use gd. It is installed by default, so
// most systems will have it, giving a consistent UX.
switch($ext) {
case "png":
$im = @imagecreatefrompng($imgPath);
$this -> readImageFromGdResource($im);
return;
case "jpg":
$im = @imagecreatefromjpeg($imgPath);
$this -> readImageFromGdResource($im);
return;
case "gif":
$im = @imagecreatefromgif($imgPath);
$this -> readImageFromGdResource($im);
return;
}
}
if($this -> isImagickSupported()) {
$im = new Imagick();
try {
// Throws an ImagickException if the format is not supported or file is not found
$im -> readImage($imgPath);
} catch(ImagickException $e) {
// Wrap in normal exception, so that classes which call this do not themselves require imagick as a dependency.
throw new Exception($e);
}
/* Flatten by doing a composite over white, in case of transparency */
$flat = new Imagick();
$flat -> newImage($im -> getimagewidth(), $im -> getimageheight(), "white");
$flat -> compositeimage($im, Imagick::COMPOSITE_OVER, 0, 0);
$this -> readImageFromImagick($flat);
return;
}
throw new Exception("Images are not supported on your PHP. Please install either the gd or imagick extension.");
}
/**
* @return int height of the image in pixels
*/
public function getHeight() {
return $this -> imgHeight;
}
/**
* @return int Number of bytes to represent a row of this image
*/
public function getHeightBytes() {
return (int)(($this -> imgHeight + 7) / 8);
}
/**
* @return int Width of the image
*/
public function getWidth() {
return $this -> imgWidth;
}
/**
* @return int Number of bytes to represent a row of this image
*/
public function getWidthBytes() {
return (int)(($this -> imgWidth + 7) / 8);
}
/**
* @return string binary data of the original file, for function which accept bitmaps.
*/
public function getWindowsBMPData() {
return $this -> imgBmpData;
}
/**
* @return boolean True if the image was a windows bitmap, false otherwise
*/
public function isWindowsBMP() {
return $this -> imgBmpData != null;
}
/**
* Load actual image pixels from GD resource.
*
* @param resouce $im GD resource to use
* @throws Exception Where the image can't be read.
*/
public function readImageFromGdResource($im) {
if(!is_resource($im)) {
throw new Exception("Failed to load image.");
} else if(!$this -> isGdSupported()) {
throw new Exception(__FUNCTION__ . " requires 'gd' extension.");
}
/* Make a string of 1's and 0's */
$this -> imgHeight = imagesy($im);
$this -> imgWidth = imagesx($im);
$this -> imgData = str_repeat("\0", $this -> imgHeight * $this -> imgWidth);
for($y = 0; $y < $this -> imgHeight; $y++) {
for($x = 0; $x < $this -> imgWidth; $x++) {
/* Faster to average channels, blend alpha and negate the image here than via filters (tested!) */
$cols = imagecolorsforindex($im, imagecolorat($im, $x, $y));
$greyness = (int)(($cols['red'] + $cols['green'] + $cols['blue']) / 3) >> 7; // 1 for white, 0 for black
$black = (1 - $greyness) >> ($cols['alpha'] >> 6); // 1 for black, 0 for white, taking into account transparency
$this -> imgData[$y * $this -> imgWidth + $x] = $black;
}
}
}
/**
* Load actual image pixels from Imagick object
*
* @param Imagick $im Image to load from
*/
public function readImageFromImagick(Imagick $im) {
/* Threshold */
$im -> setImageType(Imagick::IMGTYPE_TRUECOLOR); // Remove transparency (good for PDF's)
$max = $im->getQuantumRange();
$max = $max["quantumRangeLong"];
$im -> thresholdImage(0.5 * $max);
/* Make a string of 1's and 0's */
$geometry = $im -> getimagegeometry();
$this -> imgHeight = $im -> getimageheight();
$this -> imgWidth = $im -> getimagewidth();
$this -> imgData = str_repeat("\0", $this -> imgHeight * $this -> imgWidth);
for($y = 0; $y < $this -> imgHeight; $y++) {
for($x = 0; $x < $this -> imgWidth; $x++) {
/* Faster to average channels, blend alpha and negate the image here than via filters (tested!) */
$cols = $im -> getImagePixelColor($x, $y);
$cols = $cols -> getcolor();
$greyness = (int)(($cols['r'] + $cols['g'] + $cols['b']) / 3) >> 7; // 1 for white, 0 for black
$this -> imgData[$y * $this -> imgWidth + $x] = (1 - $greyness); // 1 for black, 0 for white
}
}
}
/**
* Output the image in raster (row) format. This can result in padding on the right of the image, if its width is not divisible by 8.
*
* @throws Exception Where the generated data is unsuitable for the printer (indicates a bug or oversized image).
* @return string The image in raster format.
*/
public function toRasterFormat() {
if($this -> imgRasterData != null) {
/* Use previous calculation */
return $this -> imgRasterData;
}
/* Loop through and convert format */
$widthPixels = $this -> getWidth();
$heightPixels = $this -> getHeight();
$widthBytes = $this -> getWidthBytes();
$heightBytes = $this -> getHeightBytes();
$x = $y = $bit = $byte = $byteVal = 0;
$data = str_repeat("\0", $widthBytes * $heightPixels);
if(strlen($data) == 0) {
return $data;
}
do {
$byteVal |= (int)$this -> imgData[$y * $widthPixels + $x] << (7 - $bit);
$x++;
$bit++;
if($x >= $widthPixels) {
$x = 0;
$y++;
$bit = 8;
if($y >= $heightPixels) {
$data[$byte] = chr($byteVal);
break;
}
}
if($bit >= 8) {
$data[$byte] = chr($byteVal);
$byteVal = 0;
$bit = 0;
$byte++;
}
} while(true);
if(strlen($data) != ($this -> getWidthBytes() * $this -> getHeight())) {
throw new Exception("Bug in " . __FUNCTION__ . ", wrong number of bytes.");
}
$this -> imgRasterData = $data;
return $this -> imgRasterData;
}
/**
* Output image in column format. This format results in padding at the base and right of the image, if its height and width are not divisible by 8.
*/
private function toColumnFormat() {
/* Note: This function is marked private, as it is not yet used/tested and may be buggy. */
$widthPixels = $this -> getWidth();
$heightPixels = $this -> getHeight();
$widthBytes = $this -> getWidthBytes();
$heightBytes = $this -> getHeightBytes();
$x = $y = $bit = $byte = $byteVal = 0;
$data = str_repeat("\0", $widthBytes * $heightBytes * 8);
do {
$byteVal |= (int)$this -> imgData[$y * $widthPixels + $x] << (8 - $bit);
$y++;
$bit++;
if($y >= $heightPixels) {
$y = 0;
$x++;
$bit = 8;
if($x >= $widthPixels) {
$data[$byte] = chr($byteVal);
break;
}
}
if($bit >= 8) {
$data[$byte] = chr($byteVal);
$byteVal = 0;
$bit = 0;
$byte++;
}
} while(true);
if(strlen($data) != ($widthBytes * $heightBytes * 8)) {
throw new Exception("Bug in " . __FUNCTION__ . ", wrong number of bytes. Should be " . ($widthBytes * $heightBytes * 8) . " but was " . strlen($data));
}
return $data;
}
/**
* @return boolean True if GD is supported, false otherwise (a wrapper for the static version, for mocking in tests)
*/
protected function isGdSupported() {
return self::isGdLoaded();
}
/**
* @return boolean True if Imagick is supported, false otherwise (a wrapper for the static version, for mocking in tests)
*/
protected function isImagickSupported() {
return self::isImagickLoaded();
}
/**
* @return boolean True if GD is loaded, false otherwise
*/
public static function isGdLoaded() {
return extension_loaded('gd');
}
/**
* @return boolean True if Imagick is loaded, false otherwise
*/
public static function isImagickLoaded() {
return extension_loaded('imagick');
}
/**
* Load a PDF for use on the printer
*
* @param string $pdfFile The file to load
* @param string $pageWidth The width, in pixels, of the printer's output. The first page of the PDF will be scaled to approximately fit in this area.
* @param array $range array indicating the first and last page (starting from 0) to load. If not set, the entire document is loaded.
* @throws Exception Where Imagick is not loaded, or where a missing file or invalid page number is requested.
* @return multitype:EscposImage Array of images, retrieved from the PDF file.
*/
public static function loadPdf($pdfFile, $pageWidth = 550, array $range = null) {
if(!extension_loaded('imagick')) {
throw new Exception(__FUNCTION__ . " requires imagick extension.");
}
/*
* Load first page at very low density (resolution), to figure out what
* density to use to achieve $pageWidth
*/
try {
$image = new Imagick();
$testRes = 2; // Test resolution
$image -> setresolution($testRes, $testRes);
$image -> readimage($pdfFile."[0]");
$geo = $image -> getimagegeometry();
$image -> destroy();
$width = $geo['width'];
$newRes = $pageWidth / $width * $testRes;
/* Load actual document (can be very slow!) */
$rangeStr = ""; // Set to [0] [0-1] page range if $range is set
if($range != null) {
if(count($range) != 2 || !isset($range[0]) || !is_integer($range[0]) || !isset($range[1]) || !is_integer($range[1]) || $range[0] > $range[1]) {
throw new Exception("Invalid range. Must be two numbers in the array: The start and finish page indexes, starting from 0.");
}
$rangeStr = "[" . ($range[0] == $range[1] ? $range[0] : implode($range, "-")) . "]";
}
$image -> setresolution($newRes, $newRes);
$image -> readImage($pdfFile."$rangeStr");
$pages = $image -> getNumberImages();
/* Convert images to Escpos objects */
$ret = array();
for($i = 0;$i < $pages; $i++) {
$image -> setIteratorIndex($i);
$ep = new EscposImage();
$ep -> readImageFromImagick($image);
$ret[] = $ep;
}
return $ret;
} catch(ImagickException $e) {
// Wrap in normal exception, so that classes which call this do not themselves require imagick as a dependency.
throw new Exception($e);
}
}
}

View File

@ -0,0 +1,304 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This class manages newlines and character encoding for the target printer, and
* can be interchanged for an image-bassed buffer (ImagePrintBuffer) if you can't
* get it operating properly on your machine.
*/
class EscposPrintBuffer implements PrintBuffer {
/**
* @var boolean True to cache output as .gz, false to leave un-compressed (useful for debugging)
*/
const COMPRESS_CACHE = true;
/**
* @var string The input encoding of the buffer.
*/
const INPUT_ENCODING = "UTF-8";
/**
* @var string Un-recorgnised characters will be replaced with this.
*/
const REPLACEMENT_CHAR = "?";
/**
* This array Maps ESC/POS character tables to names iconv encodings
*/
private $available = null;
/**
* @var array Maps of UTF-8 to code-pages
*/
private $encode = null;
/**
* @var Escpos Printer for output
*/
private $printer;
/**
* Empty print buffer.
*/
function __construct() {
$this -> printer = null;
}
public function flush() {
if($this -> printer == null) {
throw new LogicException("Not attached to a printer.");
}
// TODO Not yet implemented for this buffer: This indicates that the printer needs the current line to be ended.
}
public function getPrinter() {
return $this -> printer;
}
public function setPrinter(Escpos $printer = null) {
$this -> printer = $printer;
if($printer != null) {
$this -> loadAvailableCharacters();
}
}
public function writeText($text) {
if($this -> printer == null) {
throw new LogicException("Not attached to a printer.");
}
if($text == null) {
return;
}
if(!mb_detect_encoding($text, self::INPUT_ENCODING, true)) {
// Assume that the user has already put non-UTF8 into the target encoding.
return $this -> writeTextRaw($text);
}
$i = 0;
$j = 0;
$len = mb_strlen($text, self::INPUT_ENCODING);
while($i < $len) {
$matching = true;
if(($encoding = $this -> identifyText(mb_substr($text, $i, 1, self::INPUT_ENCODING))) === false) {
// Un-encodeable text
$encoding = $this -> getPrinter() -> getCharacterTable();
}
$i++;
$j = 1;
do {
$char = mb_substr($text, $i, 1, self::INPUT_ENCODING);
$matching = !isset($this -> available[$char]) || isset($this -> available[$char][$encoding]);
if($matching) {
$i++;
$j++;
}
} while($matching && $i < $len);
$this -> writeTextUsingEncoding(mb_substr($text, $i - $j, $j, self::INPUT_ENCODING), $encoding);
}
}
public function writeTextRaw($text) {
if($this -> printer == null) {
throw new LogicException("Not attached to a printer.");
}
if(strlen($text) == 0) {
return;
}
// Pass only printable characters
for($i = 0; $i < strlen($text); $i++) {
$c = substr($text, $i, 1);
if(!self::asciiCheck($c, true)) {
$text[$i] = self::REPLACEMENT_CHAR;
}
}
$this -> write($text);
}
/**
* Return an encoding which we can start to use for outputting this text. Later parts of the text need not be included in the returned code page.
*
* @param string $text Input text to check.
* @return boolean|integer Code page number, or FALSE if the text is not printable on any supported encoding.
*/
private function identifyText($text) {
// TODO Replace this with an algorithm to choose the encoding which will encode the farthest into the string, to minimise code page changes.
$char = mb_substr($text, 0, 1, self::INPUT_ENCODING);
if(!isset($this -> available[$char])) {
/* Character not available anywhere */
return false;
}
foreach($this -> available[$char] as $encodingNo => $true) {
/* Return first code-page where it is available */
return $encodingNo;
}
return false;
}
/**
* Based on the printer's connector, compute (or load a cached copy of) maps of UTF character to unicode characters for later use.
*/
private function loadAvailableCharacters() {
$supportedCodePages = $this -> printer -> getPrinterCapabilityProfile() -> getSupportedCodePages();
$capabilityClassName = get_class($this -> printer -> getPrinterCapabilityProfile());
$cacheFile = dirname(__FILE__) . "/cache/Characters-" . $capabilityClassName . ".ser" . (self::COMPRESS_CACHE ? ".gz" : "");
$cacheKey = md5(serialize($supportedCodePages));
/* Check for pre-generated file */
if(file_exists($cacheFile)) {
$cacheData = file_get_contents($cacheFile);
if(self::COMPRESS_CACHE) {
$cacheData = gzdecode($cacheData);
}
if($cacheData) {
$dataArray = unserialize($cacheData);
if(isset($dataArray["key"]) && isset($dataArray["available"]) && isset($dataArray["encode"]) && $dataArray["key"] == $cacheKey) {
$this -> available = $dataArray["available"];
$this -> encode = $dataArray["encode"];
return;
}
}
}
/* Generate conversion tables */
$encode = array();
$available = array();
$custom = $this -> printer -> getPrinterCapabilityProfile() -> getCustomCodePages();
foreach($supportedCodePages as $num => $characterMap) {
$encode[$num] = array();
if($characterMap === false) {
continue;
} else if(strpos($characterMap, ":") !== false) {
/* Load a pre-defined custom map (vendor-specific code pages) */
$i = strpos($characterMap, ":");
if(substr($characterMap, 0, $i) !== "custom") {
continue;
}
$i++;
$mapName = substr($characterMap, $i, strlen($characterMap) - $i);
if(!isset($custom[$mapName]) || mb_strlen($custom[$mapName], self::INPUT_ENCODING) != 128) {
throw new Exception("Capability profile referenced invalid custom map '$mapName'.");
}
$map = $custom[$mapName];
for($char = 128; $char <= 255; $char++) {
$utf8 = mb_substr($map, $char - 128, 1, self::INPUT_ENCODING);
if($utf8 == " ") { // Skip placeholders
continue;
}
if(!isset($available[$utf8])) {
$available[$utf8] = array();
}
$available[$utf8][$num] = true;
$encode[$num][$utf8] = chr($char);
}
} else {
/* Generate map using iconv */
for($char = 128; $char <= 255; $char++) {
$utf8 = @iconv($characterMap, self::INPUT_ENCODING, chr($char));
if($utf8 == '') {
continue;
}
if(iconv(self::INPUT_ENCODING, $characterMap, $utf8) != chr($char)) {
// Avoid non-canonical conversions
continue;
}
if(!isset($available[$utf8])) {
$available[$utf8] = array();
}
$available[$utf8][$num] = true;
$encode[$num][$utf8] = chr($char);
}
}
}
/* Use generated data */
$dataArray = array("available" => $available, "encode" => $encode, "key" => $cacheKey);
$this -> available = $dataArray["available"];
$this -> encode = $dataArray["encode"];
$cacheData = serialize($dataArray);
if(self::COMPRESS_CACHE) {
$cacheData = gzencode($cacheData);
}
/* Attempt to cache, but don't worry if we can't */
@file_put_contents($cacheFile, $cacheData);
}
/**
* Encode a block of text using the specified map, and write it to the printer.
*
* @param string $text Text to print, UTF-8 format.
* @param integer $encodingNo Encoding number to use- assumed to exist.
*/
private function writeTextUsingEncoding($text, $encodingNo) {
$encodeMap = $this -> encode[$encodingNo];
$len = mb_strlen($text, self::INPUT_ENCODING);
$rawText = str_repeat(self::REPLACEMENT_CHAR, $len);
for($i = 0; $i < $len; $i++) {
$char = mb_substr($text, $i, 1, self::INPUT_ENCODING);
if(isset($encodeMap[$char])) {
$rawText[$i] = $encodeMap[$char];
} else if(self::asciiCheck($char)) {
$rawText[$i] = $char;
}
}
if($this -> printer -> getCharacterTable() != $encodingNo) {
$this -> printer -> selectCharacterTable($encodingNo);
}
$this -> writeTextRaw($rawText);
}
/**
* Write data to the underlying printer.
*
* @param string $data
*/
private function write($data) {
$this -> printer -> getPrintConnector() -> write($data);
}
/**
* Return true if a character is an ASCII printable character.
*
* @param string $char Character to check
* @param boolean $extended True to allow 128-256 values also (excluded by default)
* @return boolean True if the character is printable, false if it is not.
*/
private static function asciiCheck($char, $extended = false) {
if(strlen($char) != 1) {
// Multi-byte string
return false;
}
$num = ord($char);
if($num > 31 && $num < 127) { // Printable
return true;
}
if($num == 10) { // New-line (printer will take these)
return true;
}
if($extended && $num > 127) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,80 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* PrintConnector for passing print data to a file.
*/
class FilePrintConnector implements PrintConnector {
/**
* @var resource The file pointer to send data to.
*/
protected $fp;
/**
* Construct new connector, given a filename
*
* @param string $filename
*/
public function __construct($filename) {
$this -> fp = fopen($filename, "wb+");
if($this -> fp === false) {
throw new Exception("Cannot initialise FilePrintConnector.");
}
}
public function __destruct() {
if($this -> fp !== false) {
trigger_error("Print connector was not finalized. Did you forget to close the printer?", E_USER_NOTICE);
}
}
/**
* Close file pointer
*/
public function finalize() {
fclose($this -> fp);
$this -> fp = false;
}
/* (non-PHPdoc)
* @see PrintConnector::read()
*/
public function read($len) {
rewind($this -> fp);
return fgets($this -> fp, $len + 1);
}
/**
* Write data to the file
*
* @param string $data
*/
public function write($data) {
fwrite($this -> fp, $data);
}
}

View File

@ -0,0 +1,99 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This class renders text to small images on-the-fly. It attempts to mimic the
* behaviour of text output, whilst supporting any fonts & character encodings
* which your system can handle. This class currently requires Imagick.
*/
class ImagePrintBuffer implements PrintBuffer {
private $printer;
function __construct() {
if(!EscposImage::isImagickLoaded()) {
throw new Exception("ImagePrintBuffer requires the imagick extension");
}
}
function flush() {
if($this -> printer == null) {
throw new LogicException("Not attached to a printer.");
}
}
function getPrinter() {
return $this -> printer;
}
function setPrinter(Escpos $printer = null) {
$this -> printer = $printer;
}
function writeText($text) {
if($this -> printer == null) {
throw new LogicException("Not attached to a printer.");
}
if($text == null) {
return;
}
$text = trim($text, "\n");
/* Create Imagick objects */
$image = new Imagick();
$draw = new ImagickDraw();
$color = new ImagickPixel('#000000');
$background = new ImagickPixel('white');
/* Create annotation */
//$draw -> setFont('Arial');// (not necessary?)
$draw -> setFontSize(24); // Size 21 looks good for FONT B
$draw -> setFillColor($color);
$draw -> setStrokeAntialias(true);
$draw -> setTextAntialias(true);
$metrics = $image -> queryFontMetrics($draw, $text);
$draw -> annotation(0, $metrics['ascender'], $text);
/* Create image & draw annotation on it */
$image -> newImage($metrics['textWidth'], $metrics['textHeight'], $background);
$image -> setImageFormat('png');
$image -> drawImage($draw);
//$image -> writeImage("test.png");
/* Save image */
$escposImage = new EscposImage();
$escposImage -> readImageFromImagick($image);
$size = Escpos::IMG_DEFAULT;
$this -> printer -> bitImage($escposImage, $size);
}
function writeTextRaw($text) {
if($this -> printer == null) {
throw new LogicException("Not attached to a printer.");
}
$this -> printer -> getPrintConnector() -> write($data);
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* PrintConnector for directly opening a network socket to a printer to send it commands.
*/
class NetworkPrintConnector extends FilePrintConnector {
public function __construct($ip, $port = "9100") {
$this -> fp = @fsockopen($ip, $port, $errno, $errstr);
if($this -> fp === false) {
throw new Exception("Cannot initialise NetworkPrintConnector: " . $errstr);
}
}
}

View File

@ -0,0 +1,90 @@
<?php
/**
* This capability profile is designed for the P-822D.
*
* See
* https://github.com/mike42/escpos-php/issues/50
*/
class P822DCapabilityProfile extends DefaultCapabilityProfile {
function getSupportedCodePages() {
return array(
0 => CodePage::CP437,
1 => false, // Katakana
2 => CodePage::CP850,
3 => CodePage::CP860,
4 => CodePage::CP863,
5 => CodePage::CP865,
6 => false, // Western Europe
7 => false, // Greek
8 => false, // Hebrew
9 => false, // Eastern europe
10 => false, // Iran
16 => CodePage::CP1252 ,
17 => CodePage::CP866 ,
18 => CodePage::CP852 ,
19 => CodePage::CP858,
20 => false, // Iran II
21 => false, // latvian
22 => false, //Arabic
23 => false, // PT151, 1251
24 => CodePage::CP747,
25 => CodePage::CP1257,
27 => false, // Vietnam,
28 => CodePage::CP864,
29 => CodePage::CP1001,
30 => false, // Uigur
31 => false, // Hebrew
32 => CodePage::CP1255,
33 => CodePage::CP720,
34 => CodePage::CP1256,
35 => CodePage::CP1257,
255 => false, // Thai
50 => CodePage::CP437,
51 => false, // Jatakana,
52 => CodePage::CP437,
53 => CodePage::CP858,
54 => CodePage::CP852,
55 => CodePage::CP860,
56 => CodePage::CP861,
57 => CodePage::CP863,
58 => CodePage::CP865,
59 => CodePage::CP866,
60 => CodePage::CP855,
61 => CodePage::CP857,
62 => CodePage::CP862,
63 => CodePage::CP864,
64 => CodePage::CP737,
65 => CodePage::CP851,
66 => CodePage::CP869,
67 => CodePage::CP928,
68 => CodePage::CP772,
69 => CodePage::CP774,
70 => CodePage::CP874,
71 => CodePage::CP1252,
72 => CodePage::CP1250,
73 => CodePage::CP1251,
74 => CodePage::CP3840,
75 => CodePage::CP3841,
76 => CodePage::CP3843,
77 => CodePage::CP3844,
78 => CodePage::CP3845,
79 => CodePage::CP3846,
80 => CodePage::CP3847,
81 => CodePage::CP3848,
82 => CodePage::CP1001,
83 => CodePage::CP2001,
84 => CodePage::CP3001,
85 => CodePage::CP3002,
86 => CodePage::CP3011,
87 => CodePage::CP3012,
88 => CodePage::CP3021,
89 => CodePage::CP3041
);
}
public function getSupportsGraphics() {
/* Ask the driver to use bitImage wherever possible instead of graphics */
return false;
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Print buffers manage newlines and character encoding for the target printer.
* They are used as a swappable component: text or image-based output.
*
* - Text output (EscposPrintBuffer) is the fast default, and is recommended for
* most people, as the text output can be more directly manipulated by ESC/POS
* commands.
* - Image output (ImagePrintBuffer) is designed to accept more encodings than the
* physical printer supports, by rendering the text to small images on-the-fly.
* This takes a lot more CPU than sending text, but is necessary for some users.
* - If your use case fits outside these, then a further speed/flexibility trade-off
* can be made by printing directly from generated HTML or PDF.
*/
interface PrintBuffer {
/**
* Cause the buffer to send any partial input and wait on a newline.
* If the printer is already on a new line, this does nothing.
*/
function flush();
/**
* Used by Escpos to check if a printer is set.
*/
function getPrinter();
/**
* Used by Escpos to hook up one-to-one link between buffers and printers.
*
* @param Escpos $printer New printer
*/
function setPrinter(Escpos $printer = null);
/**
* Accept UTF-8 text for printing.
*
* @param string $text Text to print
*/
function writeText($text);
/**
* Accept 8-bit text in the current encoding and add it to the buffer.
*
* @param string $text Text to print, already the target encoding.
*/
function writeTextRaw($text);
}
?>

View File

@ -0,0 +1,56 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Interface passed to Escpos class for receiving print data. Print connectors
* are responsible for transporting this to the actual printer.
*/
interface PrintConnector {
/**
* Print connectors should cause a NOTICE if they are deconstructed
* when they have not been finalized.
*/
public function __destruct();
/**
* Finish using this print connector (close file, socket, send
* accumulated output, etc).
*/
public function finalize();
/**
* @param string $data
* @return Data read from the printer, or false where reading is not possible.
*/
public function read($len);
/**
* @param string $data
*/
public function write($data);
}

View File

@ -0,0 +1,17 @@
<?php
/**
* This capability profile is designed for non-Epson printers sold online. Without knowing
* their character encoding table, only CP437 output is assumed, and graphics() calls will
* be disabled, as it usually prints junk on these models.
*/
class SimpleCapabilityProfile extends DefaultCapabilityProfile {
function getSupportedCodePages() {
/* Use only CP437 output */
return array(0 => CodePage::CP437);
}
public function getSupportsGraphics() {
/* Ask the driver to use bitImage wherever possible instead of graphics */
return false;
}
}

View File

@ -0,0 +1,82 @@
<?php
class StarCapabilityProfile extends DefaultCapabilityProfile {
function getCustomCodePages() {
// Code table reference: http://www.starmicronics.com/support/mannualfolder/sp2000pm.pdf
return array(
'CP3011' => "ÇüéâäàåçêëèïîìÄÅ" .
"ÉæÆôöòûùÿÖÜ¢£¥₧ƒ" .
"áíóúñѪº¿⌐¬½¼¡«»" .
"░▒▓│┤Ā╢ņ╕╣║╗╝╜╛┐" .
"└┴┬├─┼ā╟╚╔╩╦╠═╬╧" .
"Š╤čČ╘╒ģĪī┘┌█▄ūŪ▀" .
"αßΓπΣσµτΦΘΩδ∞φε∩" .
"ĒēĢķĶļĻžŽ∙·√Ņš■ ",
'CP3012' => "АБВГДЕЖЗИЙКЛМНОП" .
"РСТУФХЦЧШЩЪЫЬЭЮЯ" .
"абвгдежзийклмноп" .
"░▒▓│┤Ā╢ņ╕╣║╗╝Ō╛┐" .
"└┴┬├─┼ā╟╚╔╩╦╠═╬╧" .
"Š╤čČ╘╒ģĪī┘┌█▄ūŪ▀" .
"рстуфхцчшщъыьэюя" .
"ĒēĢķĶļĻžŽ∙·√Ņš■ "
);
}
function getSupportedCodePages() {
return array(
0 => CodePage::CP437, // "Normal"
1 => CodePage::CP437,
2 => CodePage::CP932,
3 => CodePage::CP437,
4 => CodePage::CP858,
5 => CodePage::CP852,
6 => CodePage::CP860,
7 => CodePage::CP861,
8 => CodePage::CP863,
9 => CodePage::CP865,
10 => CodePage::CP866,
11 => CodePage::CP855,
12 => CodePage::CP857,
13 => CodePage::CP862,
14 => CodePage::CP864,
15 => CodePage::CP737,
16 => CodePage::CP851,
17 => CodePage::CP869,
18 => CodePage::CP928,
19 => CodePage::CP772,
20 => CodePage::CP774,
21 => CodePage::CP874,
32 => CodePage::CP1252,
33 => CodePage::CP1250,
34 => CodePage::CP1251,
64 => CodePage::CP3840,
65 => CodePage::CP3841,
66 => CodePage::CP3843,
67 => CodePage::CP3844,
68 => CodePage::CP3845,
69 => CodePage::CP3846,
70 => CodePage::CP3847,
71 => CodePage::CP3848,
72 => CodePage::CP1001,
73 => CodePage::CP2001,
74 => CodePage::CP3001,
75 => CodePage::CP3002,
76 => 'custom:CP3011',
77 => 'custom:CP3012',
78 => CodePage::CP3021,
79 => CodePage::CP3041,
96 => false, // Thai Character Code 42
97 => false, // Thai Character Code 11
98 => false, // Thai Character Code 13
99 => false, // Thai Character Code 14
100 => false, // Thai Character Code 16
101 => false, // Thai Character Code 17
102 => false, // Thai Character Code 18
255 => false);
}
function getSupportsStarCommands() {
/* Allows Escpos.php to substitute emulated ESC/POS commands with native ones for this printer. */
return true;
}
}

View File

@ -0,0 +1,356 @@
<?php
/**
* escpos-php, a Thermal receipt printer library, for use with
* ESC/POS compatible printers.
*
* Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>,
* incorporating modifications by:
* - Roni Saha <roni.cse@gmail.com>
* - Gergely Radics <gerifield@ustream.tv>
* - Warren Doyle <w.doyle@fuelled.co>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Connector for sending print jobs to
* - local ports on windows (COM1, LPT1, etc)
* - shared (SMB) printers from any platform (\\server\foo)
* For USB printers or other ports, the trick is to share the printer with a generic text driver, then access it locally.
*/
class WindowsPrintConnector implements PrintConnector {
/**
* @var array Accumulated lines of output for later use.
*/
private $buffer;
/**
* @var string The hostname of the target machine, or null if this is a local connection.
*/
private $hostname;
/**
* @var boolean True if a port is being used directly (must be Windows), false if network shares will be used.
*/
private $isLocal;
/**
* @var int Platform we're running on, for selecting different commands. See PLATFORM_* constants.
*/
private $platform;
/**
* @var string The name of the target printer (eg "Foo Printer") or port ("COM1", "LPT1").
*/
private $printerName;
/**
* @var string Login name for network printer, or null if not using authentication.
*/
private $userName;
/**
* @var string Password for network printer, or null if no password is required.
*/
private $userPassword;
/**
* @var string Workgroup that the printer is located on
*/
private $workgroup;
/**
* @var int represents Linux
*/
const PLATFORM_LINUX = 0;
/**
* @var int represents Mac
*/
const PLATFORM_MAC = 1;
/**
* @var int represents Windows
*/
const PLATFORM_WIN = 2;
/**
* @var string Valid local ports.
*/
const REGEX_LOCAL = "/^(LPT\d|COM\d)$/";
/**
* @var string Valid printer name.
*/
const REGEX_PRINTERNAME = "/^(\w-+)(\s\w-*)*$/";
/**
* @var string Valid smb:// URI containing hostname & printer with optional user & optional password only.
*/
const REGEX_SMB = "/^smb:\/\/(\s\w-+(:\s\w-+)?@)?[\w-]+\/([\w-]+\/)?(\w-+)(\s\w-+)*$/";
/**
* @param string $dest
* @throws BadMethodCallException
*/
public function __construct($dest) {
$this -> platform = $this -> getCurrentPlatform();
$this -> isLocal = false;
$this -> buffer = null;
$this -> userName = null;
$this -> userPassword = null;
$this -> workgroup = null;
if(preg_match(self::REGEX_LOCAL, $dest) == 1) {
// Straight to LPT1, COM1 or other local port. Allowed only if we are actually on windows.
if($this -> platform !== self::PLATFORM_WIN) {
throw new BadMethodCallException("WindowsPrintConnector can only be used to print to a local printer ('".$dest."') on a Windows computer.");
}
$this -> isLocal = true;
$this -> hostname = null;
$this -> printerName = $dest;
} else if(preg_match(self::REGEX_SMB, $dest) == 1) {
// Connect to samba share, eg smb://host/printer
$part = parse_url($dest);
$this -> hostname = $part['host'];
/* Printer name and optional workgroup */
$path = ltrim($part['path'], '/');
if(strpos($path, "/") !== false) {
$pathPart = explode("/", $path);
$this -> workgroup = $pathPart[0];
$this -> printerName = $pathPart[1];
} else {
$this -> printerName = $path;
}
/* Username and password if set */
if(isset($part['user'])) {
$this -> userName = $part['user'];
if(isset($part['pass'])) {
$this -> userPassword = $part['pass'];
}
}
} else if(preg_match(self::REGEX_PRINTERNAME, $dest) == 1) {
// Just got a printer name. Assume it's on the current computer.
$hostname = gethostname();
if(!$hostname) {
$hostname = "localhost";
}
$this -> hostname = $hostname;
$this -> printerName = $dest;
} else {
throw new BadMethodCallException("Printer '" . $dest . "' is not a valid printer name. Use local port (LPT1, COM1, etc) or smb://computer/printer notation.");
}
$this -> buffer = array();
}
public function __destruct() {
if($this -> buffer !== null) {
trigger_error("Print connector was not finalized. Did you forget to close the printer?", E_USER_NOTICE);
}
}
public function finalize() {
$data = implode($this -> buffer);
$this -> buffer = null;
if($this -> platform == self::PLATFORM_WIN) {
$this -> finalizeWin($data);
} else if($this -> platform == self::PLATFORM_LINUX) {
$this -> finalizeLinux($data);
} else {
$this -> finalizeMac($data);
}
}
/**
* Send job to printer -- platform-specific Linux code.
*
* @param string $data Print data
* @throws Exception
*/
protected function finalizeLinux($data) {
/* Non-Windows samba printing */
$device = "//" . $this -> hostname . "/" . $this -> printerName;
if($this -> userName !== null) {
$user = ($this -> workgroup != null ? ($this -> workgroup . "\\") : "") . $this -> userName;
if($this -> userPassword == null) {
// No password
$command = sprintf("smbclient %s -U %s -c %s -N",
escapeshellarg($device),
escapeshellarg($user),
escapeshellarg("print -"));
$redactedCommand = $command;
} else {
// With password
$command = sprintf("smbclient %s %s -U %s -c %s",
escapeshellarg($device),
escapeshellarg($this -> userPassword),
escapeshellarg($user),
escapeshellarg("print -"));
$redactedCommand = sprintf("smbclient %s %s -U %s -c %s",
escapeshellarg($device),
escapeshellarg("*****"),
escapeshellarg($user),
escapeshellarg("print -"));
}
} else {
// No authentication information at all
$command = sprintf("smbclient %s -c %s -N",
escapeshellarg($device),
escapeshellarg("print -"));
$redactedCommand = $command;
}
$retval = $this -> runCommand($command, $outputStr, $errorStr, $data);
if($retval != 0) {
throw new Exception("Failed to print. Command \"$redactedCommand\" failed with exit code $retval: " . trim($outputStr));
}
}
protected function finalizeMac($data) {
throw new Exception("Mac printing not implemented.");
}
/**
* Send data to printer -- platform-specific Windows code.
*
* @param string $data
*/
protected function finalizeWin($data) {
/* Windows-friendly printing of all sorts */
if(!$this -> isLocal) {
/* Networked printing */
$device = "\\\\" . $this -> hostname . "\\" . $this -> printerName;
if($this -> userName !== null) {
/* Log in */
$user = "/user:" . ($this -> workgroup != null ? ($this -> workgroup . "\\") : "") . $this -> userName;
if($this -> userPassword == null) {
$command = sprintf("net use %s %s",
escapeshellarg($device),
escapeshellarg($user));
$redactedCommand = $command;
} else {
$command = sprintf("net use %s %s %s",
escapeshellarg($device),
escapeshellarg($user),
escapeshellarg($this -> userPassword));
$redactedCommand = sprintf("net use %s %s %s",
escapeshellarg($device),
escapeshellarg($user),
escapeshellarg("*****"));
}
$retval = $this -> runCommand($command, $outputStr, $errorStr);
if($retval != 0) {
throw new Exception("Failed to print. Command \"$redactedCommand\" failed with exit code $retval: " . trim($errorStr));
}
}
/* Final print-out */
$filename = tempnam(sys_get_temp_dir(), "escpos");
file_put_contents($filename, $data);
if(!$this -> runCopy($filename, $device)){
throw new Exception("Failed to copy file to printer");
}
unlink($filename);
} else {
/* Drop data straight on the printer */
if(!$this -> runWrite($data, $this -> printerName)) {
throw new Exception("Failed to write file to printer at " . $this -> printerName);
}
}
}
/**
* @return string Current platform. Separated out for testing purposes.
*/
protected function getCurrentPlatform() {
if(PHP_OS == "WINNT") {
return self::PLATFORM_WIN;
}
if(PHP_OS == "Darwin") {
return self::PLATFORM_MAC;
}
return self::PLATFORM_LINUX;
}
/* (non-PHPdoc)
* @see PrintConnector::read()
*/
public function read($len) {
/* Two-way communication is not supported */
return false;
}
/**
* Run a command, pass it data, and retrieve its return value, standard output, and standard error.
*
* @param string $command the command to run.
* @param string $outputStr variable to fill with standard output.
* @param string $errorStr variable to fill with standard error.
* @param string $inputStr text to pass to the command's standard input (optional).
* @return number
*/
protected function runCommand($command, &$outputStr, &$errorStr, $inputStr = null) {
$descriptors = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w"),
);
$process = proc_open($command, $descriptors, $fd);
if (is_resource($process)) {
/* Write to input */
if($inputStr !== null) {
fwrite($fd[0], $inputStr);
}
fclose($fd[0]);
/* Read stdout */
$outputStr = stream_get_contents($fd[1]);
fclose($fd[1]);
/* Read stderr */
$errorStr = stream_get_contents($fd[2]);
fclose($fd[2]);
/* Finish up */
$retval = proc_close($process);
return $retval;
} else {
/* Method calling this should notice a non-zero exit and print an error */
return -1;
}
}
/**
* Copy a file. Separated out so that nothing is actually printed during test runs.
*
* @param string $from Source file
* @param string $to Destination file
* @return boolean True if copy was successful, false otherwise
*/
protected function runCopy($from, $to) {
return copy($from, $to);
}
/**
* Write data to a file. Separated out so that nothing is actually printed during test runs.
*
* @param string $data Data to print
* @param string $to Destination file
* @return boolean True if write was successful, false otherwise
*/
protected function runWrite($data, $to) {
return file_put_contents($data, $to) !== false;
}
public function write($data) {
$this -> buffer[] = $data;
}
}

View File

@ -0,0 +1,27 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
require_once(dirname(__FILE__) . "/../vendor/autoload.php");
require_once(dirname(__FILE__) . "/../Escpos.php");
require_once(dirname(__FILE__) . "/../src/DummyPrintConnector.php");
/**
* Used in many of the tests to to output known-correct
* strings for use in tests.
*/
function friendlyBinary($in) {
if(strlen($in) == 0) {
return $in;
}
/* Print out binary data with PHP \x00 escape codes,
for builting test cases. */
$chars = str_split($in);
foreach($chars as $i => $c) {
$code = ord($c);
if($code < 32 || $code > 126) {
$chars[$i] = "\\x" . bin2hex($c);
}
}
return implode($chars);
}

View File

@ -0,0 +1,126 @@
<?php
class ExampleTest extends PHPUnit_Framework_TestCase {
/* Verify that the examples don't fizzle out with fatal errors */
private $exampleDir;
public function setup() {
$this -> exampleDir = dirname(__FILE__) . "/../../example/";
}
public function testBitImage() {
$this -> requireGraphicsLibrary();
$outp = $this -> runExample("bit-image.php");
$this -> outpTest($outp, "bit-image.bin");
}
public function testCharacterEncodings() {
$outp = $this -> runExample("character-encodings.php");
$this -> outpTest($outp, "character-encodings.bin");
}
public function testCharacterTables() {
$outp = $this -> runExample("character-tables.php");
$this -> outpTest($outp, "character-tables.bin");
}
private function outpTest($outp, $fn) {
$file = dirname(__FILE__) . "/resources/output/".$fn;
if(!file_exists($file)) {
file_put_contents($file, $outp);
}
$this -> assertEquals($outp, file_get_contents($file));
}
public function testDemo() {
$this -> requireGraphicsLibrary();
$outp = $this -> runExample("demo.php");
$this -> outpTest($outp, "demo.bin");
}
public function testGraphics() {
$this -> requireGraphicsLibrary();
$outp = $this -> runExample("graphics.php");
$this -> outpTest($outp, "graphics.bin");
}
public function testReceiptWithLogo() {
$this -> requireGraphicsLibrary();
$outp = $this -> runExample("receipt-with-logo.php");
$this -> outpTest($outp, "receipt-with-logo.bin");
}
public function testQrCode() {
$outp = $this -> runExample("qr-code.php");
$this -> outpTest($outp, "qr-code.bin");
}
public function testBarcode() {
$outp = $this -> runExample("barcode.php");
$this -> outpTest($outp, "barcode.bin");
}
public function testTextSize() {
$outp = $this -> runExample("text-size.php");
$this -> outpTest($outp, "text-size.bin");
}
/**
* @large
*/
public function testPrintFromPdf() {
if(!EscposImage::isImagickLoaded()) {
$this -> markTestSkipped("imagick plugin required for this test");
}
$outp = $this -> runExample("print-from-pdf.php");
$this -> outpTest(gzcompress($outp, 9), "print-from-pdf.bin.z"); // Compressing output because it's ~1MB
}
public function testInterfaceEthernet() {
// Test attempts DNS lookup on some machine
$outp = $this -> runExample("interface/ethernet.php");
$this -> outpTest($outp, "interface.bin");
}
public function testInterfaceLinuxUSB() {
$outp = $this -> runExample("interface/linux-usb.php");
$this -> outpTest($outp, "interface.bin");
}
public function testInterfaceWindowsUSB() {
// Output varies between platforms, not checking.
$outp = $this -> runExample("interface/windows-usb.php");
$this -> outpTest($outp, "interface.bin");
}
public function testInterfaceSMB() {
// Output varies between platforms, not checking.
$outp = $this -> runExample("interface/smb.php");
$this -> outpTest($outp, "interface.bin");
}
public function testInterfaceWindowsLPT() {
// Output varies between platforms, not checking.
$outp = $this -> runExample("interface/windows-lpt.php");
$this -> outpTest($outp, "interface.bin");
}
private function runExample($fn) {
// Change directory and check script
chdir($this -> exampleDir);
$this -> assertTrue(file_exists($fn), "Script $fn not found.");
// Run command and save output
ob_start();
passthru("php " . escapeshellarg($fn), $retval);
$outp = ob_get_contents();
ob_end_clean();
// Check return value
$this -> assertEquals(0, $retval, "Example $fn exited with status $retval");
return $outp;
}
protected function requireGraphicsLibrary() {
if(!EscposImage::isGdLoaded() && !EscposImage::isImagickLoaded()) {
$this -> markTestSkipped("This test requires a graphics library.");
}
}
}

View File

@ -0,0 +1,2 @@
@Hello World!
VA

View File

@ -0,0 +1,16 @@
<phpunit bootstrap="bootstrap.php"
timeoutForSmallTests="1"
timeoutForMediumTests="10"
timeoutForLargeTests="60"
verbose="true"
strict="true"
>
<testsuites>
<testsuite name="unit">
<directory>unit</directory>
</testsuite>
<testsuite name="integration">
<directory>integration</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@ -0,0 +1,69 @@
<?php
/**
* Test that all sub-classes of AbstractCapabilityProfile
* are creating data in the right format.
*/
class EscposCapabilityProfileTest extends PHPUnit_Framework_TestCase {
private $profiles;
private $checklist;
function setup() {
$this -> profiles = array('DefaultCapabilityProfile', 'EposTepCapabilityProfile', 'SimpleCapabilityProfile', 'StarCapabilityProfile', 'P822DCapabilityProfile');
$this -> checklist = array();
foreach($this -> profiles as $profile) {
$this-> checklist[] = $profile::getInstance();
}
}
function testSupportedCodePages() {
foreach($this -> checklist as $obj) {
$check = $obj -> getSupportedCodePages();
$this -> assertTrue(is_array($check) && isset($check[0]) && $check[0] == 'CP437');
$custom = $obj -> getCustomCodePages();
foreach($check as $num => $page) {
$this -> assertTrue(is_numeric($num) && ($page === false || is_string($page)));
if($page === false || strpos($page, ":") === false) {
continue;
}
$part = explode(":", $page);
if(!array_shift($part) == "custom") {
continue;
}
$this -> assertTrue(isset($custom[implode(":", $part)]));
}
}
}
function testCustomCodePages() {
foreach($this -> checklist as $obj) {
$check = $obj -> getCustomCodePages();
$this -> assertTrue(is_array($check));
foreach($check as $name => $customMap) {
$this -> assertTrue(is_string($name));
$this -> assertTrue(is_string($customMap) && mb_strlen($customMap, 'UTF-8') == 128);
}
}
}
function testSupportsBitImage() {
foreach($this -> checklist as $obj) {
$check = $obj -> getSupportsBitImage();
$this -> assertTrue(is_bool($check));
}
}
function testSupportsGraphics() {
foreach($this -> checklist as $obj) {
$check = $obj -> getSupportsGraphics();
$this -> assertTrue(is_bool($check));
}
}
function testSupportsQrCode() {
foreach($this -> checklist as $obj) {
$check = $obj -> getSupportsQrCode();
$this -> assertTrue(is_bool($check));
}
}
}
?>

View File

@ -0,0 +1,235 @@
<?php
class EscposImageTest extends PHPUnit_Framework_TestCase {
/**
* Checking loading of an empty image - requires no libraries
*/
public function testNoLibrariesBlank() {
$this -> loadAndCheckImg(null, false, false, 0, 0, "");
}
/**
* BMP handling not yet implemented, but these will use
* a native PHP bitmap reader.
* This just tests that they are not being passed on to another library.
*/
public function testBmpBadFilename() {
$this -> setExpectedException('Exception');
$this -> loadAndCheckImg('not a real file.bmp', false, false, 1, 1, "\x80");
}
public function testBmpBlack() {
$this -> setExpectedException('Exception');
$this -> loadAndCheckImg("canvas_black.bmp", false, false, 0, 0, "\x80");
}
public function testBmpBlackWhite() {
$this -> setExpectedException('Exception');
$this -> loadAndCheckImg("black_white.bmp", false, false, 0, 0, "\xc0\x00");
}
public function testBmpWhite() {
$this -> setExpectedException('Exception');
$this -> loadAndCheckImg("canvas_white.bmp", false, false, 0, 0, "\x00");
}
/**
* GD tests - Load tiny images and check how they are printed.
* These are skipped if you don't have gd.
*/
public function testGdBadFilename() {
$this -> setExpectedException('Exception');
$this -> loadAndCheckImg('not a real file.png', true, false, 1, 1, "\x80");
}
public function testGdBlack() {
foreach(array('png', 'jpg', 'gif') as $format) {
$this -> loadAndCheckImg('canvas_black.' . $format, true, false, 1, 1, "\x80");
}
}
public function testGdBlackTransparent() {
foreach(array('png', 'gif') as $format) {
$this -> loadAndCheckImg('black_transparent.' . $format, true, false, 2, 2, "\xc0\x00");
}
}
public function testGdBlackWhite() {
foreach(array('png', 'jpg', 'gif') as $format) {
$this -> loadAndCheckImg('black_white.' . $format, true, false, 2, 2, "\xc0\x00");
}
}
public function testGdWhite() {
foreach(array('png', 'jpg', 'gif') as $format) {
$this -> loadAndCheckImg('canvas_white.' . $format, true, false, 1, 1, "\x00");
}
}
/**
* Imagick tests - Load tiny images and check how they are printed
* These are skipped if you don't have imagick
*/
public function testImagickBadFilename() {
$this -> setExpectedException('Exception');
$this -> loadAndCheckImg('not a real file.png', false, true, 1, 1, "\x80");
}
public function testImagickBlack() {
foreach(array('png', 'jpg', 'gif') as $format) {
$this -> loadAndCheckImg('canvas_black.' . $format, false, true, 1, 1, "\x80");
}
}
public function testImagickBlackTransparent() {
foreach(array('png', 'gif') as $format) {
$this -> loadAndCheckImg('black_transparent.' . $format, false, true, 2, 2, "\xc0\x00");
}
}
public function testImagickBlackWhite() {
foreach(array('png', 'jpg', 'gif') as $format) {
$this -> loadAndCheckImg('black_white.' . $format, false, true, 2, 2, "\xc0\x00");
}
}
public function testImagickWhite() {
foreach(array('png', 'jpg', 'gif') as $format) {
$this -> loadAndCheckImg('canvas_white.' . $format, false, true, 1, 1, "\x00");
}
}
/**
* Mixed test - Same as above, but confirms that each tiny image can be loaded
* under any supported library configuration with the same results.
* These are skipped if you don't have gd AND imagick
*/
public function testLibraryDifferences() {
if(!EscposImage::isGdLoaded() || !EscposImage::isImagickLoaded()) {
$this -> markTestSkipped("both gd and imagick plugin are required for this test");
}
$inFile = array('black_white.png', 'canvas_black.png', 'canvas_white.png');
foreach($inFile as $fn) {
// Default check
$im = new EscposImage(dirname(__FILE__) . "/resources/$fn");
$width = $im -> getWidth();
$height = $im -> getHeight();
$data = $im -> toRasterFormat();
// Gd check
$this -> loadAndCheckImg($fn, true, false, $width, $height, $data);
// Imagick check
$this -> loadAndCheckImg($fn, false, true, $width, $height, $data);
}
}
/**
* PDF tests - load tiny PDF and check for well-formedness
* These are also skipped if you don't have imagick
* @medium
*/
public function testPdfAllPages() {
$this -> loadAndCheckPdf('doc.pdf', null, 1, 1, array("\x00", "\x80"));
}
public function testPdfBadFilename() {
$this -> setExpectedException('Exception');
$this -> loadAndCheckPdf('not a real file', null, 1, 1, array());
}
/**
* @medium
*/
public function testPdfBadRange() {
// Start page is after end page.
$this -> setExpectedException('Exception');
$this -> loadAndCheckPdf('doc.pdf', array(1, 0), 1, 1, array("\x00", "\x80"));
}
/**
* @medium
*/
public function testPdfFirstPage() {
$this -> loadAndCheckPdf('doc.pdf', array(0, 0), 1, 1, array("\x00"));
}
/**
* @medium
*/
public function testPdfMorePages() {
$this -> loadAndCheckPdf('doc.pdf', array(1, 20), 1, 1, array("\x80"));
}
/**
* @medium
*/
public function testPdfSecondPage() {
$this -> loadAndCheckPdf('doc.pdf', array(1, 1), 1, 1, array("\x80"));
}
/**
* @medium
*/
public function testPdfStartPastEndOfDoc() {
// Doc only has pages 0 and 1, can't start reading from 2.
$this -> markTestIncomplete("Test needs revising- produces output due to apparent imagick bug.");
$this -> setExpectedException('ImagickException');
$this -> loadAndCheckPdf('doc.pdf', array(2, 3), 1, 1, array());
}
/**
* Load an EscposImage with (optionally) certain libraries disabled and run a check.
*/
private function loadAndCheckImg($fn, $gd, $imagick, $width, $height, $rasterFormat = null) {
$img = $this -> getMockImage($fn === null ? null : dirname(__FILE__) . "/resources/$fn", $gd, $imagick);
$this -> checkImg($img, $width, $height, $rasterFormat);
}
/**
* Same as above, loading document and checking pages against some expected values.
*/
private function loadAndCheckPdf($fn, array $range = null, $width, $height, array $rasterFormat = null) {
if(!EscposImage::isImagickLoaded()) {
$this -> markTestSkipped("imagick plugin required for this test");
}
$pdfPages = EscposImage::loadPdf(dirname(__FILE__) . "/resources/$fn", $width, $range);
$this -> assertTrue(count($pdfPages) == count($rasterFormat), "Got back wrong number of pages");
foreach($pdfPages as $id => $img) {
$this -> checkImg($img, $width, $height, $rasterFormat[$id]);
}
}
/**
* Check image against known width, height, output.
*/
private function checkImg(EscposImage $img, $width, $height, $rasterFormat = null) {
if($rasterFormat === null) {
echo "\nImage was: " . $img -> getWidth() . "x" . $img -> getHeight() . ", data \"" . friendlyBinary($img -> toRasterFormat()) . "\"";
}
$this -> assertTrue($img -> getHeight() == $height);
$this -> assertTrue($img -> getWidth() == $width);
$this -> assertTrue($img -> toRasterFormat() == $rasterFormat);
}
/**
* Load up an EsposImage with given libraries disabled or enabled. Marks the test
* as skipped if you ask for a library which is not loaded.
*/
private function getMockImage($path, $gd, $imagick) {
/* Sanity checks */
if($gd && !EscposImage::isGdLoaded()) {
$this -> markTestSkipped("gd plugin required for this test");
}
if($imagick && !EscposImage::isImagickLoaded()) {
$this -> markTestSkipped("imagick plugin required for this test");
}
$stub = $this -> getMockBuilder('EscposImage')
-> setMethods(array('isGdSupported', 'isImagickSupported'))
-> disableOriginalConstructor()
-> getMock();
$stub -> method('isGdSupported')
-> willReturn($gd);
$stub -> method('isImagickSupported')
-> willReturn($imagick);
$stub -> __construct($path);
return $stub;
}
}

View File

@ -0,0 +1,150 @@
<?php
/**
* Example strings are pangrams using different character sets, and are
* testing correct code-table switching.
*
* When printed, they should appear the same as in this source file.
*
* Many of these test strings are from:
* - http://www.cl.cam.ac.uk/~mgk25/ucs/examples/quickbrown.txt
* - http://clagnut.com/blog/2380/ (mirrored from the English Wikipedia)
*/
class EscposPrintBufferTest extends PHPUnit_Framework_TestCase {
protected $buffer;
protected $outputConnector;
protected function setup() {
$this -> outputConnector = new DummyPrintConnector();
$printer = new Escpos($this -> outputConnector);
$this -> buffer = $printer -> getPrintBuffer();
}
protected function checkOutput($expected = null) {
/* Check those output strings */
$outp = $this -> outputConnector -> getData();
if($expected === null) {
echo "\nOutput was:\n\"" . friendlyBinary($outp) . "\"\n";
}
$this -> assertEquals($expected, $outp);
}
protected function tearDown() {
$this -> outputConnector -> finalize();
}
public function testRawTextNonprintable() {
$this -> buffer -> writeTextRaw("Test" . Escpos::ESC . "v1\n");
$this -> checkOutput("\x1b@Test?v1\x0a"); // ASCII ESC character is substituted for '?'
}
public function testDanish() {
$this -> buffer -> writeText("Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Wolther spillede på xylofon.\n");
$this -> checkOutput("\x1b@Quizdeltagerne spiste jordb\x91r med fl\x1bt\x02\x9bde, mens cirkusklovnen Wolther spillede p\x86 xylofon.\x0a");
}
public function testGerman() {
$this -> buffer -> writeText("Falsches Üben von Xylophonmusik quält jeden größeren Zwerg.\n");
$this -> checkOutput("\x1b@Falsches \x9aben von Xylophonmusik qu\x84lt jeden gr\x94\xe1eren Zwerg.\x0a");
}
public function testGreek() {
$this -> buffer -> writeText("Ξεσκεπάζω την ψυχοφθόρα βδελυγμία");
$this -> checkOutput("\x1b@\x1bt\x0b\xbd\xde\xec\xe4\xde\xea\x9b\xe0\xfa \xee\xe1\xe7 \xf6\xf2\xf4\xe9\xf3\xe2\xa2\xeb\xd6 \xd7\xdd\xde\xe5\xf2\xd8\xe6\x9f\xd6");
}
public function testGreekWithDiacritics() {
// This is a string which is known to be un-printable in ESC/POS (the grave-accented letters are not in any code page),
// so we are checking the substitution '?' for unknown characters.
$this -> buffer -> writeText("Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο.\n");
$this -> checkOutput("\x1b@\xe2\xe0\x1bt\x0b\xe0\x9d\xde\xed \xe4\xd6? \xe6\xf2\xeb\xee\xe3?\xed \xdd?\xe7 \xe2? \xd7\xeb? \xea\xe3? \xec\xee? \xf4\xeb\xf2\xec\xd6\xf3? \xe8\x9d\xf3\xfa\xee\xe9.\x0a");
}
public function testEnglish() {
$this -> buffer -> writeText("The quick brown fox jumps over the lazy dog.\n");
$this -> checkOutput("\x1b@The quick brown fox jumps over the lazy dog.\n");
}
public function testSpanish() {
// This one does not require changing code-pages at all, so characters are just converted from Unicode to CP437.
$this -> buffer -> writeText("El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.\n");
$this -> checkOutput("\x1b@El ping\x81ino Wenceslao hizo kil\xa2metros bajo exhaustiva lluvia y fr\xa1o, a\xa4oraba a su querido cachorro.\x0a");
}
public function testFrench() {
$this -> buffer -> writeText("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");
$this -> checkOutput("\x1b@Le c\x1bt\x10\x9cur d\xe9\xe7u mais l'\xe2me plut\xf4t na\xefve, Lou\xffs r\xeava de crapa\xfcter en cano\xeb au del\xe0 des \xeeles, pr\xe8s du m\xe4lstr\xf6m o\xf9 br\xfblent les nov\xe6.\x0a");
}
public function testIrishGaelic() {
// Note that some letters with diacritics cannot be printed for Irish Gaelic text, so text may need to be simplified.
$this -> buffer -> writeText("D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh.\n");
$this -> checkOutput("\x1b@D'fhuascail \x1bt\x02\xd6osa, \xe9rmhac na h\xe0ighe Beannaithe, p\xa2r \x90ava agus \xb5dhaimh.\x0a");
}
public function testHungarian() {
$this -> buffer -> writeText("Árvíztűrő tükörfúrógép.\n");
$this -> checkOutput("\x1b@\x1bt\x02\xb5rv\xa1zt\x1bt\x12\xfbr\x8b t\x81k\x94rf\xa3r\xa2g\x82p.\x0a");
}
public function testIcelandic() {
$this -> buffer -> writeText("Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa.");
$this -> checkOutput("\x1b@K\x91mi n\x1bt\x02\xec \x94xi h\x82r ykist \xe7j\xa2fum n\xa3 b\x91\xd0i v\xa1l og \xa0drepa.");
}
public function testJapaneseHiragana() {
$this -> markTestIncomplete("Non-ASCII character sets not yet supported.");
$this -> buffer -> writeText(implode("\n", array("いろはにほへとちりぬるを", " わかよたれそつねならむ", "うゐのおくやまけふこえて", "あさきゆめみしゑひもせす")) . "\n");
$this -> checkOutput();
}
public function testJapaneseKatakana() {
$this -> markTestIncomplete("Non-ASCII character sets not yet supported.");
$this -> buffer -> writeText(implode("\n", array("イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム", "ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン")) . "\n");
$this -> checkOutput("\x1b@\x1bt\x01\xb2\xdb\xca\xc6\xce\xcd\xc4 \xc1\xd8\xc7\xd9\xa6 \xdc\xb6\xd6\xc0\xda\xbf \xc2\xc8\xc5\xd7\xd1\x0a\xb3\xb2\xc9\xb5\xb8\xd4\xcf \xb9\xcc\xba\xb4\xc3 \xb1\xbb\xb7\xd5\xd2\xd0\xbc \xb4\xcb\xd3\xbe\xbd\xdd\x0a");
}
public function testJapaneseKataKanaHalfWidth() {
$this -> buffer -> writeText(implode("\n", array("イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム", "ウイノオクヤマ ケフコエテ アサキユメミシ エヒモセスン")) . "\n");
$this -> checkOutput("\x1b@\x1bt\x01\xb2\xdb\xca\xc6\xce\xcd\xc4 \xc1\xd8\xc7\xd9\xa6 \xdc\xb6\xd6\xc0\xda\xbf \xc2\xc8\xc5\xd7\xd1\x0a\xb3\xb2\xc9\xb5\xb8\xd4\xcf \xb9\xcc\xba\xb4\xc3 \xb1\xbb\xb7\xd5\xd2\xd0\xbc \xb4\xcb\xd3\xbe\xbd\xdd\x0a");
}
public function testLatvian() {
$this -> buffer -> writeText("Glāžšķūņa rūķīši dzērumā čiepj Baha koncertflīģeļu vākus.\n");
$this -> checkOutput("\x1b@Gl\x1bt!\x83\xd8\xd5\xe9\xd7\xeca r\xd7\xe9\x8c\xd5i dz\x89rum\x83 \xd1iepj Baha koncertfl\x8c\x85e\xebu v\x83kus.\x0a");
}
public function testPolish() {
$this -> buffer -> writeText("Pchnąć w tę łódź jeża lub ośm skrzyń fig.\n");
$this -> checkOutput("\x1b@Pchn\x1bt\x12\xa5\x86 w t\xa9 \x88\xa2d\xab je\xbea lub o\x98m skrzy\xe4 fig.\x0a");
}
public function testRussian() {
$this -> buffer -> writeText("В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!\n");
$this -> checkOutput("\x1b@\x1bt\x11\x82 \xe7\xa0\xe9\xa0\xe5 \xee\xa3\xa0 \xa6\xa8\xab \xa1\xeb \xe6\xa8\xe2\xe0\xe3\xe1? \x84\xa0, \xad\xae \xe4\xa0\xab\xec\xe8\xa8\xa2\xeb\xa9 \xed\xaa\xa7\xa5\xac\xaf\xab\xef\xe0!\x0a");
}
public function testThai() {
$this -> markTestIncomplete("Non-ASCII character sets not yet supported.");
$this -> buffer -> writeText("นายสังฆภัณฑ์ เฮงพิทักษ์ฝั่ง ผู้เฒ่าซึ่งมีอาชีพเป็นฅนขายฃวด ถูกตำรวจปฏิบัติการจับฟ้องศาล ฐานลักนาฬิกาคุณหญิงฉัตรชฎา ฌานสมาธิ\n"); // Quotation from Wikipedia
$this -> checkOutput();
}
public function testTurkish() {
$this -> buffer -> writeText("Pijamalı hasta, yağız şoföre çabucak güvendi.\n");
$this -> checkOutput("\x1b@Pijamal\x1bt\x02\xd5 hasta, ya\x1bt\x0d\xa7\x8dz \x9fof\x94re \x87abucak g\x81vendi.\x0a");
}
public function testArabic() {
$this -> markTestIncomplete("Right-to-left text not yet supported.");
$this -> buffer -> writeText("صِف خَلقَ خَودِ كَمِثلِ الشَمسِ إِذ بَزَغَت — يَحظى الضَجيعُ بِها نَجلاءَ مِعطارِ" . "\n"); // Quotation from Wikipedia
$this -> checkOutput();
}
public function testHebrew() {
// RTL text is more complex than the above.
$this -> markTestIncomplete("Right-to-left text not yet supported.");
$this -> buffer -> writeText("דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה" . "\n");
$this -> checkOutput();
}
}

View File

@ -0,0 +1,765 @@
<?php
class EscposTest extends PHPUnit_Framework_TestCase {
protected $printer;
protected $outputConnector;
protected function setup() {
/* Print to nowhere- for testing which inputs are accepted */
$this -> outputConnector = new DummyPrintConnector();
$this -> printer = new Escpos($this -> outputConnector);
}
protected function checkOutput($expected = null) {
/* Check those output strings */
$outp = $this -> outputConnector -> getData();
if($expected === null) {
echo "\nOutput was:\n\"" . friendlyBinary($outp) . "\"\n";
}
$this -> assertEquals($expected, $outp);
}
protected function tearDown() {
$this -> outputConnector -> finalize();
}
protected function requireGraphicsLibrary() {
if(!EscposImage::isGdLoaded() && !EscposImage::isImagickLoaded()) {
// If the test is about to do something which requires a library,
// something must throw an exception.
$this -> setExpectedException('Exception');
}
}
public function testInitializeOutput() {
$this -> checkOutput("\x1b\x40");
}
public function testTextStringOutput() {
$this -> printer -> text("The quick brown fox jumps over the lazy dog\n");
$this -> checkOutput("\x1b@The quick brown fox jumps over the lazy dog\n");
}
public function testTextDefault() {
$this -> printer -> text();
$this -> checkOutput("\x1b@");
}
public function testTextString() {
$this -> printer -> text("String");
$this -> printer -> text(123);
$this -> printer -> text();
$this -> printer -> text(null);
$this -> printer -> text(1.2);
$this -> printer -> text(new FooBar("FooBar"));
$this -> checkOutput("\x1b@String1231.2FooBar");
}
public function testTextObject() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> text(new DateTime());
}
public function testFeedDefault() {
$this -> printer -> feed();
$this -> checkOutput("\x1b@\x0a");
}
public function testFeed3Lines() {
$this -> printer -> feed(3);
$this -> checkOutput("\x1b@\x1bd\x03");
}
public function testFeedZero() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> feed(0);
}
public function testFeedNonInteger() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> feed("ab");
}
public function testFeedTooLarge() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> feed(256);
}
/* Print mode */
public function testSelectPrintModeDefault() {
$this -> printer -> selectPrintMode();
$this -> checkOutput("\x1b@\x1b!\x00");
}
public function testSelectPrintModeAcceptedValues() {
/* This iterates over a bunch of numbers, figures out which
ones contain invalid flags, and checks that the driver
rejects those, but accepts the good inputs */
for($i = -1; $i <= 256; $i++) {
$invalid = ($i < 0) || ($i > 255) || (($i & 2) == 2) || (($i & 4) == 4) || (($i & 64) == 64);
$failed = false;
try {
$this -> printer -> selectPrintMode($i);
} catch(Exception $e) {
$failed = true;
}
$this -> assertEquals($failed, $invalid);
}
}
/* Underline */
public function testSetUnderlineDefault() {
$this -> printer -> setUnderline();
$this -> checkOutput("\x1b@\x1b-\x01");
}
public function testSetUnderlineOff() {
$this -> printer -> setUnderline(Escpos::UNDERLINE_NONE);
$this -> checkOutput("\x1b@\x1b-\x00");
}
public function testSetUnderlineOn() {
$this -> printer -> setUnderline(Escpos::UNDERLINE_SINGLE);
$this -> checkOutput("\x1b@\x1b-\x01");
}
public function testSetUnderlineDbl() {
$this -> printer -> setUnderline(Escpos::UNDERLINE_DOUBLE);
$this -> checkOutput("\x1b@\x1b-\x02");
}
public function testSetUnderlineAcceptedValues() {
$this -> printer -> setUnderline(0);
$this -> printer -> setUnderline(1);
$this -> printer -> setUnderline(2);
/* These map to 0 & 1 for interchangeability with setEmphasis */
$this -> printer -> setUnderline(true);
$this -> printer -> setUnderline(false);
$this -> checkOutput("\x1b@\x1b-\x00\x1b-\x01\x1b-\x02\x1b-\x01\x1b-\x00");
}
public function testSetUnderlineTooLarge() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setUnderline(3);
}
public function testSetUnderlineNegative() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setUnderline(-1);
}
public function testSetUnderlineNonInteger() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setUnderline("Hello");
}
/* Emphasis */
public function testSetEmphasisDefault() {
$this -> printer -> setEmphasis();
$this -> checkOutput("\x1b@\x1bE\x01");
}
public function testSetEmphasisOn() {
$this -> printer -> setEmphasis(true);
$this -> checkOutput("\x1b@\x1bE\x01");
}
public function testSetEmphasisOff() {
$this -> printer -> setEmphasis(false);
$this -> checkOutput("\x1b@\x1bE\x00");
}
public function testSetEmphasisNonBoolean() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setEmphasis(7);
}
/* Double strike */
public function testSetDoubleStrikeDefault() {
$this -> printer -> setDoubleStrike();
$this -> checkOutput("\x1b@\x1bG\x01");
}
public function testSetDoubleStrikeOn() {
$this -> printer -> setDoubleStrike(true);
$this -> checkOutput("\x1b@\x1bG\x01");
}
public function testSetDoubleStrikeOff() {
$this -> printer -> setDoubleStrike(false);
$this -> checkOutput("\x1b@\x1bG\x00");
}
public function testSetDoubleStrikeNonBoolean() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setDoubleStrike(4);
}
/* Font */
public function testSetFontDefault() {
$this -> printer -> setFont();
$this -> checkOutput("\x1b@\x1bM\x00");
}
public function testSetFontAcceptedValues() {
$this -> printer -> setFont(Escpos::FONT_A);
$this -> printer -> setFont(Escpos::FONT_B);
$this -> printer -> setFont(Escpos::FONT_C);
$this -> checkOutput("\x1b@\x1bM\x00\x1bM\x01\x1bM\x02");
}
public function testSetFontNegative() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setFont(-1);
}
public function testSetFontTooLarge() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setFont(3);
}
public function testSetFontNonInteger() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setFont('hello');
}
/* Justification */
public function testSetJustificationDefault() {
$this -> printer -> setJustification();
$this -> checkOutput("\x1b@\x1ba\x00");
}
public function testSetJustificationLeft() {
$this -> printer -> setJustification(Escpos::JUSTIFY_LEFT);
$this -> checkOutput("\x1b@\x1ba\x00");
}
public function testSetJustificationRight() {
$this -> printer -> setJustification(Escpos::JUSTIFY_RIGHT);
$this -> checkOutput("\x1b@\x1ba\x02");
}
public function testSetJustificationCenter() {
$this -> printer -> setJustification(Escpos::JUSTIFY_CENTER);
$this -> checkOutput("\x1b@\x1ba\x01");
}
public function testSetJustificationNegative() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setJustification(-1);
}
public function testSetJustificationTooLarge() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setFont(3);
}
public function testSetJustificationNonInteger() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setJustification('hello');
}
/* Reverse feed */
public function testFeedReverseDefault() {
$this -> printer -> feedReverse();
$this -> checkOutput("\x1b@\x1be\x01");
}
public function testFeedReverse3() {
$this -> printer -> feedReverse(3);
$this -> checkOutput("\x1b@\x1be\x03");
}
public function testFeedReverseNegative() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> feedReverse(-1);
}
public function testFeedReverseTooLarge() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> feedReverse(256);
}
public function testFeedReverseNonInteger() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> feedReverse('hello');
}
/* Cut */
public function testCutDefault() {
// TODO check what the accepted range of values should be for $line
// cut($mode = self::CUT_FULL, $lines = 3)
$this -> printer -> cut();
$this -> checkOutput("\x1b@\x1dVA\x03");
}
/* Set barcode height */
public function testSetBarcodeHeightDefault() {
$this -> printer -> setBarcodeHeight();
$this -> checkOutput("\x1b@\x1dh\x08");
}
public function testBarcodeHeight10() {
$this -> printer -> setBarcodeHeight(10);
$this -> checkOutput("\x1b@\x1dh\x0a");
}
public function testSetBarcodeHeightNegative() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setBarcodeHeight(-1);
}
public function testSetBarcodeHeightTooLarge() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setBarcodeHeight(256);
}
public function tesSetBarcodeHeightNonInteger() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setBarcodeHeight('hello');
}
/* Barcode text position */
public function testSetBarcodeTextPositionDefault() {
$this -> printer -> setBarcodeTextPosition();
$this -> checkOutput("\x1b@\x1dH\x00");
}
public function testSetBarcodeTextPositionBelow() {
$this -> printer -> setBarcodeTextPosition(Escpos::BARCODE_TEXT_BELOW);
$this -> checkOutput("\x1b@\x1dH\x02");
}
public function testSetBarcodeTextPositionBoth() {
$this -> printer -> setBarcodeTextPosition(Escpos::BARCODE_TEXT_BELOW | Escpos::BARCODE_TEXT_ABOVE);
$this -> checkOutput("\x1b@\x1dH\x03");
}
public function testSetBarcodeTextPositionNegative() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setBarcodeTextPosition(-1);
}
public function testSetBarcodeTextPositionTooLarge() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setBarcodeTextPosition(4);
}
public function tesSetBarcodeTextPositionNonInteger() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setBarcodeTextPosition('hello');
}
/* Barcode - UPC-A */
public function testBarcodeUpcaNumeric11Char() {
$this -> printer -> barcode("01234567890", Escpos::BARCODE_UPCA);
$this -> checkOutput("\x1b@\x1dkA\x0b01234567890");
}
public function testBarcodeUpcaNumeric12Char() {
$this -> printer -> barcode("012345678901", Escpos::BARCODE_UPCA);
$this -> checkOutput("\x1b@\x1dkA\x0c012345678901");
}
public function testBarcodeUpcaNumeric13Char() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("0123456789012", Escpos::BARCODE_UPCA);
}
public function testBarcodeUpcaNonNumeric12Char() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("A12345678901", Escpos::BARCODE_UPCA);
}
/* Barcode - UPC-E */
public function testBarcodeUpceNumeric6Char() {
$this -> printer -> barcode("123456", Escpos::BARCODE_UPCE);
$this -> checkOutput("\x1b@\x1dkB\x06123456");
}
public function testBarcodeUpceNumeric7Char() {
$this -> printer -> barcode("0123456", Escpos::BARCODE_UPCE);
$this -> checkOutput("\x1b@\x1dkB\x070123456");
}
public function testBarcodeUpceNumeric8Char() {
$this -> printer -> barcode("01234567", Escpos::BARCODE_UPCE);
$this -> checkOutput("\x1b@\x1dkB\x0801234567");
}
public function testBarcodeUpceNumeric11Char() {
$this -> printer -> barcode("01234567890", Escpos::BARCODE_UPCE);
$this -> checkOutput("\x1b@\x1dkB\x0b01234567890");
}
public function testBarcodeUpceNumeric12Char() {
$this -> printer -> barcode("012345678901", Escpos::BARCODE_UPCE);
$this -> checkOutput("\x1b@\x1dkB\x0c012345678901");
}
public function testBarcodeUpceNumeric9Char() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("012345678", Escpos::BARCODE_UPCE);
}
public function testBarcodeUpceNonNumeric12Char() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("A12345678901", Escpos::BARCODE_UPCE);
}
/* Barcode - JAN13 */
public function testBarcodeJan13Numeric12Char() {
$this -> printer -> barcode("012345678901", Escpos::BARCODE_JAN13);
$this -> checkOutput("\x1b@\x1dkC\x0c012345678901");
}
public function testBarcodeJan13Numeric13Char() {
$this -> printer -> barcode("0123456789012", Escpos::BARCODE_JAN13);
$this -> checkOutput("\x1b@\x1dkC\x0d0123456789012");
}
public function testBarcodeJan13Numeric11Char() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("01234567890", Escpos::BARCODE_JAN13);
}
public function testBarcodeJan13NonNumeric13Char() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("A123456789012", Escpos::BARCODE_JAN13);
}
/* Barcode - JAN8 */
public function testBarcodeJan8Numeric7Char() {
$this -> printer -> barcode("0123456", Escpos::BARCODE_JAN8);
$this -> checkOutput("\x1b@\x1dkD\x070123456");
}
public function testBarcodeJan8Numeric8Char() {
$this -> printer -> barcode("01234567", Escpos::BARCODE_JAN8);
$this -> checkOutput("\x1b@\x1dkD\x0801234567");
}
public function testBarcodeJan8Numeric9Char() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("012345678", Escpos::BARCODE_JAN8);
}
public function testBarcodeJan8NonNumeric8Char() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("A1234567", Escpos::BARCODE_JAN8);
}
/* Barcode - Code39 */
public function testBarcodeCode39AsDefault() {
$this -> printer -> barcode("1234");
$this -> checkOutput("\x1b@\x1dkE\x041234");
}
public function testBarcodeCode39Text() {
$this -> printer -> barcode("ABC 012", Escpos::BARCODE_CODE39);
$this -> checkOutput("\x1b@\x1dkE\x07ABC 012");
}
public function testBarcodeCode39SpecialChars() {
$this -> printer -> barcode("$%+-./", Escpos::BARCODE_CODE39);
$this -> checkOutput("\x1b@\x1dkE\x06$%+-./");
}
public function testBarcodeCode39Asterisks() {
$this -> printer -> barcode("*TEXT*", Escpos::BARCODE_CODE39);
$this -> checkOutput("\x1b@\x1dkE\x06*TEXT*");
}
public function testBarcodeCode39AsterisksUnmatched() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("*TEXT", Escpos::BARCODE_CODE39);
}
public function testBarcodeCode39AsteriskInText() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("12*34", Escpos::BARCODE_CODE39);
}
public function testBarcodeCode39Lowercase() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("abcd", Escpos::BARCODE_CODE39);
}
public function testBarcodeCode39Empty() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("**", Escpos::BARCODE_CODE39);
}
/* Barcode - ITF */
public function testBarcodeItfNumericEven() {
$this -> printer -> barcode("1234", Escpos::BARCODE_ITF);
$this -> checkOutput("\x1b@\x1dkF\x041234");
}
public function testBarcodeItfNumericOdd() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("123", Escpos::BARCODE_ITF);
}
public function testBarcodeItfNonNumericEven() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("A234", Escpos::BARCODE_ITF);
}
/* Barcode - Codabar */
public function testBarcodeCodabarNumeric() {
$this -> printer -> barcode("A012345A", Escpos::BARCODE_CODABAR);
$this -> checkOutput("\x1b@\x1dkG\x08A012345A");
}
public function testBarcodeCodabarSpecialChars() {
$this -> printer -> barcode("A012$+-./:A", Escpos::BARCODE_CODABAR);
$this -> checkOutput("\x1b@\x1dkG\x0bA012$+-./:A");
}
public function testBarcodeCodabarNotWrapped() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("012345", Escpos::BARCODE_CODABAR);
}
public function testBarcodeCodabarStartStopWrongPlace() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("012A45", Escpos::BARCODE_CODABAR);
}
/* Barcode - Code93 */
public function testBarcodeCode93Valid() {
$this -> printer -> barcode("012abcd", Escpos::BARCODE_CODE93);
$this -> checkOutput("\x1b@\x1dkH\x07012abcd");
}
public function testBarcodeCode93Empty() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("", Escpos::BARCODE_CODE93);
}
/* Barcode - Code128 */
public function testBarcodeCode128ValidA() {
$this -> printer -> barcode("{A" . "012ABCD", Escpos::BARCODE_CODE128);
$this -> checkOutput("\x1b@\x1dkI\x09{A012ABCD");
}
public function testBarcodeCode128ValidB() {
$this -> printer -> barcode("{B" . "012ABCDabcd", Escpos::BARCODE_CODE128);
$this -> checkOutput("\x1b@\x1dkI\x0d{B012ABCDabcd");
}
public function testBarcodeCode128ValidC() {
$this -> printer -> barcode("{C" . chr ( 21 ) . chr ( 32 ) . chr ( 43 ), Escpos::BARCODE_CODE128);
$this -> checkOutput("\x1b@\x1dkI\x05{C\x15 +");
}
public function testBarcodeCode128NoCodeSet() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> barcode("ABCD", Escpos::BARCODE_CODE128);
}
/* Pulse */
function testPulseDefault() {
$this -> printer -> pulse();
$this -> checkOutput("\x1b@\x1bp0<x");
}
function testPulse1() {
$this -> printer -> pulse(1);
$this -> checkOutput("\x1b@\x1bp1<x");
}
function testPulseEvenMs() {
$this -> printer -> pulse(0, 2, 2);
$this -> checkOutput("\x1b@\x1bp0\x01\x01");
}
function testPulseOddMs() {
$this -> printer -> pulse(0, 3, 3); // Should be rounded down and give same output
$this -> checkOutput("\x1b@\x1bp0\x01\x01");
}
function testPulseTooHigh() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> pulse(0, 512, 2);
}
function testPulseTooLow() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> pulse(0, 0, 2);
}
function testPulseNotANumber() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> pulse("fish");
}
/* Set reverse */
public function testSetReverseColorsDefault() {
$this -> printer -> setReverseColors();
$this -> checkOutput("\x1b@\x1dB\x01");
}
public function testSetReverseColorsOn() {
$this -> printer -> setReverseColors(true);
$this -> checkOutput("\x1b@\x1dB\x01");
}
public function testSetReverseColorsOff() {
$this -> printer -> setReverseColors(false);
$this -> checkOutput("\x1b@\x1dB\x00");
}
public function testSetReverseColorsNonBoolean() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setReverseColors(7);
}
/* Bit image print */
public function testBitImageBlack() {
$this -> requireGraphicsLibrary();
$img = new EscposImage(dirname(__FILE__)."/resources/canvas_black.png");
$this -> printer -> bitImage($img);
$this -> checkOutput("\x1b@\x1dv0\x00\x01\x00\x01\x00\x80");
}
public function testBitImageWhite() {
$this -> requireGraphicsLibrary();
$img = new EscposImage(dirname(__FILE__)."/resources/canvas_white.png");
$this -> printer -> bitImage($img);
$this -> checkOutput("\x1b@\x1dv0\x00\x01\x00\x01\x00\x00");
}
public function testBitImageBoth() {
$this -> requireGraphicsLibrary();
$img = new EscposImage(dirname(__FILE__)."/resources/black_white.png");
$this -> printer -> bitImage($img);
$this -> checkOutput("\x1b@\x1dv0\x00\x01\x00\x02\x00\xc0\x00");
}
public function testBitImageTransparent() {
$this -> requireGraphicsLibrary();
$img = new EscposImage(dirname(__FILE__)."/resources/black_transparent.png");
$this -> printer -> bitImage($img);
$this -> checkOutput("\x1b@\x1dv0\x00\x01\x00\x02\x00\xc0\x00");
}
/* Graphics print */
public function testGraphicsWhite() {
$this -> requireGraphicsLibrary();
$img = new EscposImage(dirname(__FILE__)."/resources/canvas_white.png");
$this -> printer -> graphics($img);
$this -> checkOutput("\x1b@\x1d(L\x0b\x000p0\x01\x011\x01\x00\x01\x00\x00\x1d(L\x02\x0002");
}
public function testGraphicsBlack() {
$this -> requireGraphicsLibrary();
$img = new EscposImage(dirname(__FILE__)."/resources/canvas_black.png");
$this -> printer -> graphics($img);
$this -> checkOutput("\x1b@\x1d(L\x0b\x000p0\x01\x011\x01\x00\x01\x00\x80\x1d(L\x02\x0002");
}
public function testGraphicsBoth() {
$this -> requireGraphicsLibrary();
$img = new EscposImage(dirname(__FILE__)."/resources/black_white.png");
$this -> printer -> graphics($img);
$this -> checkOutput("\x1b@\x1d(L\x0c\x000p0\x01\x011\x02\x00\x02\x00\xc0\x00\x1d(L\x02\x0002");
}
public function testGraphicsTransparent() {
$this -> requireGraphicsLibrary();
$img = new EscposImage(dirname(__FILE__)."/resources/black_transparent.png");
$this -> printer -> graphics($img);
$this -> checkOutput("\x1b@\x1d(L\x0c\x000p0\x01\x011\x02\x00\x02\x00\xc0\x00\x1d(L\x02\x0002");
}
/* QR code */
public function testQRCodeDefaults() {
// Test will fail if default values change
$this -> printer -> qrCode("1234");
$this -> checkOutput("\x1b@\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0");
}
public function testQRCodeDefaultsAreCorrect() {
// Below tests assume that defaults are as written here (output string should be same as above)
$this -> printer -> qrCode("1234", Escpos::QR_ECLEVEL_L, 3, Escpos::QR_MODEL_2);
$this -> checkOutput("\x1b@\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0");
}
public function testQRCodeEmpty() {
$this -> printer -> qrCode('');
$this -> checkOutput("\x1b@"); // No commands actually sent
}
public function testQRCodeChangeEC() {
$this -> printer -> qrCode("1234", Escpos::QR_ECLEVEL_H);
$this -> checkOutput("\x1b@\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E3\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0");
}
public function testQRCodeChangeSize() {
$this -> printer -> qrCode("1234", Escpos::QR_ECLEVEL_L, 7);
$this -> checkOutput("\x1b@\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x07\x1d(k\x03\x001E0\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0");
}
public function testQRCodeChangeModel() {
$this -> printer -> qrCode("1234", Escpos::QR_ECLEVEL_L, 3, Escpos::QR_MODEL_1);
$this -> checkOutput("\x1b@\x1d(k\x04\x001A1\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0");
}
/* Feed form - Required on page-mode only printers */
public function testFeedForm() {
$this -> printer -> feedForm();
$this -> checkOutput("\x1b@\x0c");
}
/* Get status */
public function testGetStatus() {
$this -> markTestIncomplete("Status check test code not implemented.");
// TODO some unit testing here on statuses
// $a = $this -> printer -> getPrinterStatus(Escpos::STATUS_PRINTER);
}
/* Set text size */
public function testSetTextSizeNormal() {
$this -> printer -> setTextSize(1, 1);
$this -> checkOutput("\x1b@\x1d!\x00");
}
public function testSetTextSizeWide() {
$this -> printer -> setTextSize(4, 1);
$this -> checkOutput("\x1b@\x1d!0");
}
public function testSetTextSizeNarrow() {
$this -> printer -> setTextSize(1, 4);
$this -> checkOutput("\x1b@\x1d!\x03");
}
public function testSetTextSizeLarge() {
$this -> printer -> setTextSize(4, 4);
$this -> checkOutput("\x1b@\x1d!3");
}
public function testSetTextSizeInvalid() {
$this -> setExpectedException('InvalidArgumentException');
$this -> printer -> setTextSize(0, 9);
}
}
/*
* For testing that string-castable objects are handled
*/
class FooBar {
private $foo;
public function __construct($foo) {
$this -> foo = $foo;
}
public function __toString() {
return $this -> foo;
}
}
?>

View File

@ -0,0 +1,252 @@
<?php
class WindowsPrintConnectorTest extends PHPUnit_Framework_TestCase {
private $connector;
public function testLptWindows() {
// Should attempt to send data to the local printer by writing to it
$connector = $this -> getMockConnector("LPT1", WindowsPrintConnector::PLATFORM_WIN);
$connector -> expects($this -> once())
-> method('runWrite')
-> with($this -> equalTo(''), $this -> equalTo("LPT1"));
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> finalize();
}
public function testLptMac() {
// Cannot print to local printer on Mac with this connector
$this -> setExpectedException('BadMethodCallException');
$connector = $this -> getMockConnector("LPT1", WindowsPrintConnector::PLATFORM_MAC);
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> finalize();
}
public function testLptLinux() {
// Cannot print to local printer on Linux with this connector
$this -> setExpectedException('BadMethodCallException');
$connector = $this -> getMockConnector("LPT1", WindowsPrintConnector::PLATFORM_LINUX);
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> finalize();
}
public function testComWindows() {
// Simple file write
$connector = $this -> getMockConnector("COM1", WindowsPrintConnector::PLATFORM_WIN);
$connector -> expects($this -> once())
-> method('runWrite')
-> with($this -> equalTo(''), $this -> equalTo("COM1"));
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> finalize();
}
public function testComMac() {
// Cannot print to local printer on Mac with this connector
$this -> setExpectedException('BadMethodCallException');
$connector = $this -> getMockConnector("COM1", WindowsPrintConnector::PLATFORM_MAC);
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> finalize();
}
public function testComLinux() {
// Cannot print to local printer on Linux with this connector
$this -> setExpectedException('BadMethodCallException');
$connector = $this -> getMockConnector("COM1", WindowsPrintConnector::PLATFORM_LINUX);
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> finalize();
}
public function testLocalShareWindows() {
$connector = $this -> getMockConnector("Printer", WindowsPrintConnector::PLATFORM_WIN);
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> once())
-> method('runCopy')
-> with($this -> anything(), $this -> stringContains('\\Printer'));
$connector -> finalize();
}
public function testSharedPrinterWindows() {
$connector = $this -> getMockConnector("smb://example-pc/Printer", WindowsPrintConnector::PLATFORM_WIN);
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> once())
-> method('runCopy')
-> with($this -> anything(), $this -> equalTo('\\\\example-pc\\Printer'));
$connector -> finalize();
}
public function testSharedPrinterWindowsUsername() {
$connector = $this -> getMockConnector("smb://bob@example-pc/Printer", WindowsPrintConnector::PLATFORM_WIN);
$connector -> expects($this -> once())
-> method('runCommand')
-> with($this -> equalTo('net use \'\\\\example-pc\\Printer\' \'/user:bob\''));
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> once())
-> method('runCopy')
-> with($this -> anything(), $this -> equalTo('\\\\example-pc\\Printer'));
$connector -> finalize();
}
public function testSharedPrinterWindowsUsernameDomain() {
$connector = $this -> getMockConnector("smb://bob@example-pc/home/Printer", WindowsPrintConnector::PLATFORM_WIN);
$connector -> expects($this -> once())
-> method('runCommand')
-> with($this -> equalTo('net use \'\\\\example-pc\\Printer\' \'/user:home\\bob\''));
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> once())
-> method('runCopy')
-> with($this -> anything(), $this -> equalTo('\\\\example-pc\\Printer'));
$connector -> finalize();
}
public function testSharedPrinterWindowsUsernamePassword() {
$connector = $this -> getMockConnector("smb://bob:secret@example-pc/Printer", WindowsPrintConnector::PLATFORM_WIN);
$connector -> expects($this -> once())
-> method('runCommand')
-> with($this -> equalTo('net use \'\\\\example-pc\\Printer\' \'/user:bob\' \'secret\''));
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> once())
-> method('runCopy')
-> with($this -> anything(), $this -> equalTo('\\\\example-pc\\Printer'));
$connector -> finalize();
}
public function testSharedPrinterMac() {
// Not implemented
$this -> setExpectedException('Exception');
$connector = $this -> getMockConnector("smb://Guest@example-pc/Printer", WindowsPrintConnector::PLATFORM_MAC);
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> expects($this -> exactly(0))
-> method('runCommand');
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> finalize();
}
public function testSharedPrinterLinux() {
$connector = $this -> getMockConnector("smb://example-pc/Printer", WindowsPrintConnector::PLATFORM_LINUX);
$connector -> expects($this -> once())
-> method('runCommand')
-> with($this -> equalTo('smbclient \'//example-pc/Printer\' -c \'print -\' -N'));
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> finalize();
}
public function testSharedPrinterLinuxUsername() {
$connector = $this -> getMockConnector("smb://bob@example-pc/Printer", WindowsPrintConnector::PLATFORM_LINUX);
$connector -> expects($this -> once())
-> method('runCommand')
-> with($this -> equalTo('smbclient \'//example-pc/Printer\' -U \'bob\' -c \'print -\' -N'));
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> finalize();
}
public function testSharedPrinterLinuxUsernameDomain() {
$connector = $this -> getMockConnector("smb://bob@example-pc/home/Printer", WindowsPrintConnector::PLATFORM_LINUX);
$connector -> expects($this -> once())
-> method('runCommand')
-> with($this -> equalTo('smbclient \'//example-pc/Printer\' -U \'home\\bob\' -c \'print -\' -N'));
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> finalize();
}
public function testSharedPrinterLinuxUsernamePassword() {
$connector = $this -> getMockConnector("smb://bob:secret@example-pc/Printer", WindowsPrintConnector::PLATFORM_LINUX);
$connector -> expects($this -> once())
-> method('runCommand')
-> with($this -> equalTo('smbclient \'//example-pc/Printer\' \'secret\' -U \'bob\' -c \'print -\''));
$connector -> expects($this -> exactly(0))
-> method('runCopy');
$connector -> expects($this -> exactly(0))
-> method('runWrite');
$connector -> finalize();
}
private function getMockConnector($path, $platform) {
$stub = $this -> getMockBuilder('WindowsPrintConnector')
-> setMethods(array('runCopy', 'runCommand', 'getCurrentPlatform', 'runWrite'))
-> disableOriginalConstructor()
-> getMock();
$stub -> method('runCommand')
-> willReturn(0);
$stub -> method('runCopy')
-> willReturn(true);
$stub -> method('runWrite')
-> willReturn(true);
$stub -> method('getCurrentPlatform')
-> willReturn($platform);
$stub -> __construct($path);
return $stub;
}
/**
* Test for correct identification of bogus or non-supported Samba strings.
*/
public function testSambaRegex() {
$good = array("smb://foo/bar",
"smb://foo/bar baz",
"smb://bob@foo/bar",
"smb://bob:secret@foo/bar",
"smb://foo-computer/FooPrinter",
"smb://foo-computer/workgroup/FooPrinter",
"smb://foo-computer/Foo Printer");
$bad = array("",
"http://google.com",
"smb:/foo/bar",
"smb://",
"smb:///bar",
"smb://@foo/bar",
"smb://bob:@foo/bar",
"smb://:secret@foo/bar",
"smb://foo/bar/baz/quux",
"smb://foo-computer//FooPrinter");
foreach($good as $item) {
$this -> assertTrue(preg_match(WindowsPrintConnector::REGEX_SMB, $item) == 1, "Windows samba regex should pass '$item'.");
}
foreach($bad as $item) {
$this -> assertTrue(preg_match(WindowsPrintConnector::REGEX_SMB, $item) != 1, "Windows samba regex should fail '$item'.");
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

View File

@ -0,0 +1,19 @@
<?php
$im = new Imagick();
try {
$im -> readImage("doc.pdf[5]");
$im -> destroy();
} catch(ImagickException $e) {
echo "Error: " . $e -> getMessage() . "\n";
}
$im = new Imagick();
try {
ob_start();
@$im -> readImage("doc.pdf[5]");
ob_end_clean();
$im -> destroy();
} catch(ImagickException $e) {
echo "Error: " . $e -> getMessage() . "\n";
}

Binary file not shown.