Impresión a impresora POS desde PHP
printing kiosk (1)
Estamos buscando imprimir en una impresora POS conectada donde se está ejecutando Apache. Debido al diseño de la aplicación y la implementación, la impresión debe realizarse desde el Servidor (debe detectar el pedido y enviarse a diferentes impresoras y diferentes formatos de impresión ... facturas, pedidos de cocina, etc.). Por esta razón y otras (como la aplicación de acceso desde un iPad, por ejemplo) descartamos opciones como el applet QZ-Print y necesitamos imprimir directamente desde el lado del servidor.
Buscamos mucho y encontramos que hay una extensión llamada php-printer pero parece estar desactualizada, y simplemente funciona bajo Windows.
Seguimos este código: ( http://mocopat.wordpress.com/2012/01/18/php-direct-printing-printer-dot-matrix-lx-300/ )
$tmpdir = sys_get_temp_dir(); # ambil direktori temporary untuk simpan file.
$file = tempnam($tmpdir, ''ctk''); # nama file temporary yang akan dicetak
$handle = fopen($file, ''w'');
$condensed = Chr(27) . Chr(33) . Chr(4);
$bold1 = Chr(27) . Chr(69);
$bold0 = Chr(27) . Chr(70);
$initialized = chr(27).chr(64);
$condensed1 = chr(15);
$condensed0 = chr(18);
$corte = Chr(27) . Chr(109);
$Data = $initialized;
$Data .= $condensed1;
$Data .= "==========================/n";
$Data .= "| ".$bold1."OFIDZ MAJEZTY".$bold0." |/n";
$Data .= "==========================/n";
$Data .= "Ofidz Majezty is here/n";
$Data .= "We Love PHP Indonesia/n";
$Data .= "We Love PHP Indonesia/n";
$Data .= "We Love PHP Indonesia/n";
$Data .= "We Love PHP Indonesia/n";
$Data .= "We Love PHP Indonesia/n";
$Data .= "--------------------------/n";
$Data .= $corte;
fwrite($handle, $Data);
fclose($handle);
copy($file, "//localhost/KoTickets"); # Lakukan cetak
unlink($file);
Y funciona, pero esto envía texto sin formato, y necesitamos enviar imagen (logotipo) y formatear una factura más linda. Intentamos crear un PDF y "enviar" a la impresora de la misma manera, pero solo imprime en blanco.
Encontré una biblioteca para trabajar con impresoras de red (escpos-php en github), pero también necesitamos trabajar con impresoras USB para evitar que nuestros clientes cambien el hardware.
Algunas ideas de cómo lograr esto?
Gracias por adelantado.
Autor de escpos-php aquí.
Si sus impresoras son compatibles con ESC / POS (la mayoría de las impresoras térmicas de recibos parecen usar algún subconjunto de la misma), entonces creo que el controlador se adaptará a su caso de uso: USB o impresión en red, logotipo, algún formato. Algunos de estos son adiciones bastante recientes.
Impresión USB
escpos-php imprime a un apuntador de archivo. En Linux, puede hacer que la impresora USB sea visible como un archivo usando el controlador usblp
, y luego simplemente fopen()
( ejemplo de recibo USB , publicación de blog sobre la instalación de una impresora USB en Linux ).
Por lo tanto, imprimir "Hello world" en una impresora USB es ligeramente diferente a imprimir en una impresora en red:
<?php
require __DIR__ . ''/vendor/autoload.php'';
use Mike42/Escpos/PrintConnectors/FilePrintConnector;
use Mike42/Escpos/Printer;
$connector = new FilePrintConnector("/dev/usb/lp0");
$printer = new Printer($connector);
$printer -> text("Hello World!/n");
$printer -> cut();
$printer -> close();
O, más como el código que está utilizando con éxito, puede escribir en un archivo temporal y copiarlo:
<?php
require __DIR__ . ''/vendor/autoload.php'';
use Mike42/Escpos/PrintConnectors/FilePrintConnector;
use Mike42/Escpos/Printer;
/* Open file */
$tmpdir = sys_get_temp_dir();
$file = tempnam($tmpdir, ''ctk'');
/* Do some printing */
$connector = new FilePrintConnector($file);
$printer = new Printer($connector);
$printer -> text("Hello World!/n");
$printer -> cut();
$printer -> close();
/* Copy it over to the printer */
copy($file, "//localhost/KoTickets");
unlink($file);
Por lo tanto, en su sistema POS, necesitará una función que devuelva un puntero de archivo según la configuración de su cliente y el destino preferido. Las impresoras de recibos responden con bastante rapidez, pero si tiene algunos iPads haciendo pedidos, debe ajustar las operaciones a cada impresora con un bloqueo de archivo ( flock() ) para evitar problemas relacionados con la concurrencia.
También tenga en cuenta que la compatibilidad con USB en Windows no está probada.
Logo y Formato
Una vez que haya descubierto cómo planea hablar con la impresora, puede utilizar el conjunto completo de comandos de formato e imagen.
Un logotipo se puede imprimir desde un archivo PNG de la siguiente manera:
use Mike42/Escpos/EscposImage;
$logo = EscposImage::load("foo.png");
$printer -> graphics($logo);
Y para formatear, el README.md y el ejemplo a continuación deberían comenzar. Para la mayoría de los recibos, solo necesita realmente:
-
selectPrintMode()
para alterar los tamaños de fuente. -
setEmphasis()
para alternar en negrita. -
setJustification()
para alinear a la izquierda o centrar texto o imágenes. -
cut()
después de cada recibo.
También sugeriría que, en la actualidad, esté utilizando un ejemplo que dibuje cuadros como este:
=========
| |
=========
Puede utilizar los caracteres en la página 437 de IBM Code, diseñados para dibujar cuadros que son compatibles con muchas impresoras; solo incluya los caracteres 0xB3 a 0xDA en la salida. No son perfectos, pero parece mucho menos "texto" -y.
$box = "/xda".str_repeat("/xc4", 10)."/xbf/n";
$box .= "/xb3".str_repeat(" ", 10)."/xb3/n";
$box .= "/xc0".str_repeat("/xc4", 10)."/xd9/n";
$printer -> textRaw($box);
Ejemplo completo
El siguiente ejemplo también se incluye con el controlador. Creo que parece un recibo de tienda bastante típico, en cuanto a formato, y podría adaptarse fácilmente al escenario de su cocina.
Salida escaneada:
Código fuente PHP para generarlo:
<?php
require __DIR__ . ''/vendor/autoload.php'';
use Mike42/Escpos/Printer;
use Mike42/Escpos/EscposImage;
use Mike42/Escpos/PrintConnectors/FilePrintConnector;
/* Open the printer; this will change depending on how it is connected */
$connector = new FilePrintConnector("/dev/usb/lp0");
$printer = new Printer($connector);
/* 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 = EscposImage::load("resources/escpos-php.png", false);
$printer = new Printer($connector);
/* Print top logo */
$printer -> setJustification(Printer::JUSTIFY_CENTER);
$printer -> graphics($logo);
/* Name of shop */
$printer -> selectPrintMode(Printer::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(Printer::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(Printer::MODE_DOUBLE_WIDTH);
$printer -> text($total);
$printer -> selectPrintMode();
/* Footer */
$printer -> feed(2);
$printer -> setJustification(Printer::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";
}
}