web-dev-qa-db-fra.com

Impression sur une imprimante POS à partir de PHP

Nous cherchons à imprimer sur une imprimante POS connectée sur laquelle Apache fonctionne. En raison de la conception de l'application et du déploiement, l'impression doit être effectuée à partir du serveur (il doit détecter la commande et l'envoyer à différentes imprimantes et différents formats d'impression ... facture, commandes de cuisine, etc.). Pour cette raison et d'autres (comme l'accès à une application depuis un iPad par exemple), nous rejetons les options comme l'applet QZ-Print et nous devons imprimer directement côté serveur.

Nous avons beaucoup cherché et constaté qu'il existe une extension appelée php-printer mais qui semble obsolète et qui fonctionne uniquement sous Windows.

Nous avons suivi ce code: ( 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);

Et cela fonctionne, mais cela envoie du texte brut, et nous devons envoyer une image (logo) et formater une facture plus mignonne. Nous avons essayé de créer un PDF et "envoyer" à l'imprimante de la même manière, mais nous imprimons simplement en blanc.

J'ai trouvé une bibliothèque pour travailler avec des imprimantes réseau (escpos-php sur github), mais nous devons aussi travailler avec des imprimantes USB, pour éviter à nos clients de changer de matériel.

Quelques idées pour y parvenir?

Merci d'avance.

17
Giu

Auteur de escpos-php ici.

Si vos imprimantes prennent en charge ESC/POS (la plupart des imprimantes de reçus thermiques semblent en utiliser un sous-ensemble), je pense que le pilote s'adaptera à votre cas d'utilisation: impression USB ou réseau, logo, certains formats. Certains d'entre eux sont des ajouts assez récents.

Impression USB

escpos-php imprime sur un pointeur de fichier. Sous Linux, vous pouvez rendre l'imprimante USB visible sous forme de fichier en utilisant le pilote usblp, puis simplement fopen() it ( exemple de reçu USB , article de blog sur l'installation d'une imprimante USB sous Linux ).

L'impression de "Hello world" sur une imprimante USB n'est donc que légèrement différente de l'impression sur une imprimante en réseau:

<?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();

Ou, plus comme le code que vous utilisez actuellement avec succès, vous pouvez écrire dans un fichier temporaire et le copier:

<?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);

Ainsi, dans votre système de point de vente, vous auriez besoin d'une fonction qui renvoie un pointeur de fichier en fonction de votre configuration client et de votre destination préférée. Les imprimantes de reçus répondent assez rapidement, mais si vous avez quelques iPads en train de passer des commandes, vous devez encapsuler les opérations sur chaque imprimante avec un verrou de fichier ( flock () ) pour éviter les problèmes liés à la concurrence.

Notez également que la prise en charge USB sous Windows n'est pas testée.

Logo et formatage

Une fois que vous avez compris comment vous prévoyez de parler à l'imprimante, vous pouvez utiliser la suite complète des commandes de formatage et d'image.

Un logo peut être imprimé à partir d'un fichier PNG comme suit:

use Mike42\Escpos\EscposImage;
$logo = EscposImage::load("foo.png");
$printer -> graphics($logo);

Et pour le formatage, le README.md et l'exemple ci-dessous devraient vous aider à démarrer. Pour la plupart des reçus, vous n'avez vraiment besoin que:

  • selectPrintMode() pour modifier les tailles de police.
  • setEmphasis() pour basculer en gras.
  • setJustification() pour aligner à gauche ou centrer du texte ou des images.
  • cut() après chaque reçu.

Je suggérerais également que là où vous utilisez actuellement un exemple qui dessine des boîtes comme ceci:

=========
|       |
=========

Vous pouvez utiliser les caractères d'IBM page de code 437 qui sont conçus pour dessiner des boîtes prises en charge par de nombreuses imprimantes - incluez simplement les caractères 0xB3 à 0xDA dans la sortie. Ils ne sont pas parfaits, mais il semble beaucoup moins "texte" -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);

Exemple complet

L'exemple ci-dessous est également maintenant inclus avec le pilote. Je pense que cela ressemble à un reçu de magasin assez typique, au niveau du formatage, et pourrait être facilement adapté à votre scénario de cuisine.

Sortie numérisée:

Example formatted receipt including logo

Code source PHP pour le générer:

<?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";
    }
}
48
mike42