Druckeransteuerung über ESC-Sequenz

temi

Top Contributor
Ich möchte einen Drucker ansteuern und benötige für die Statusabfrage ein (Drucker-)Kommando, dass mit einem Escape eingeleitet wird => "ESCs". Die Antwort des Druckers sollte ein kurzer String mit Informationen sein.

Meine aktuelle copy-and-paste Lösung sieht folgendermaßen aus:
Java:
public class Main {

    public static void main(String[] args)
    {
        if (args.length != 2) {
            System.err.println(
                    "Usage: java tcptest <host name> <port number>");
            System.exit(1);
        }

        String hostName = args[0];
        int portNumber = Integer.parseInt(args[1]);

        try (   Socket echoSocket = new Socket(hostName, portNumber);
                PrintWriter out =
                        new PrintWriter(echoSocket.getOutputStream(), true);
                BufferedReader in =
                        new BufferedReader(
                                new InputStreamReader(echoSocket.getInputStream()));
        {
            out.println("\u001bs");
            System.out.println("echo: " + in.readLine());

        }

        catch (UnknownHostException e)
        {
            System.err.println("Don't know about host " + hostName);
            System.exit(1);
        }

        catch (IOException e)
        {
            System.err.println("Couldn't get I/O for the connection to " +
                    hostName);
            System.exit(1);
        }
    }
}

Eine Verbindung zum Drucker wird anscheinend aufgebaut (ich hatte zuerst den falschen Port angegeben und darauf eine IOException erhalten), aber eine Antwort erhalte ich offenbar nicht. Leider sind meine Testmöglichkeiten hier etwas eingeschränkt.

Allerdings bin ich mir auch nicht so sicher, ob ich überhaupt sende, was ich senden möchte.
Falls nein, wie sende ich denn "ESCs"?
 
Was passiert denn wenn du einfach mal einen ganz normalen Text sendest. Druckt er den?
Es kommen auf jeden Fall Daten beim Drucker an. Es gibt am Drucker einen Monitormodus, in dem er alles was reinkommt, direkt ausgibt. Dort ist zu erkennen, dass zwischen jedem Zeichen ein "NUL" steht. Das hat vermutlich was mit Unicode zu tun, oder?

Damit habe ich mich noch nicht näher beschäftigt. Gibt es eine schnelle Lösung mit dem obigen Code, um das Problem zu beheben?
 
Zuletzt bearbeitet:
Ich komme leider nicht weiter. Folgendes ist der Stand:
Code:
try (Socket socket = new Socket(hostName, portNumber);
             PrintWriter out = new PrintWriter(
               new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.ISO_8859_1), true);)
        {
            System.out.println("Connected, sending data..");
         
              out.println(new String(label.getBytes(), StandardCharsets.ISO_8859_1));
         
            System.out.println("Done");

        }

Wenn ich beim out.println direkt einen String "irgendwas" angebe, dann funktioniert es, so wie oben gezeigt nicht. 'label' ist ein String, der aus einer Textdatei gelesen wird.
Ich steh jetzt auf dem Schlauch...🙁
 
Ich habe dein Programm mal etwas abgewandelt und PCL-Codes als ESC-Sequenz gedruckt. In der ersten Ausgabezeile wird das mittlere "Hallo Welt" fett gedruckt, in der zweiten Zeile kursiv:
Java:
public class PrtEsc {
    private static final String ESC = "\u001B";
    private static final String MEDIUM = ESC + "(s0B";
    private static final String BOLD = ESC + "(s3B";
    private static final String UPRIGHT = ESC + "(s0S";
    private static final String ITALIC = ESC + "(s1S";

    public static void main(String[] args) {
        String hostName = "127.0.0.1";
        int portNumber = 9100;
        try (Socket echoSocket = new Socket(hostName, portNumber);
                PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
                BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));)
        {
            out.println("Hallo Welt" + BOLD + "Hallo Welt" + MEDIUM + "Hallo Welt" );
            out.println("Hallo Welt" + ITALIC + "Hallo Welt" + UPRIGHT + "Hallo Welt" );
        }
        catch (UnknownHostException e) {
            System.err.println("Don't know about host " + hostName);
            System.exit(1);
        }
        catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to " + hostName);
            System.exit(1);
        }
    }
}
 
Aktuell habe ich das mit dem ESC etwas zur Seite geschoben und versuche die Etikettendaten an den Drucker zu senden. Diese liegen als Textdatei vor und sehen z.B. so aus:
Code:
m m
J
H 100,0,T
S l1;.0,.0,22.0,26.0,50.0
T:LORT;14.0,9.7,.0,3,3.0;9001
T:EXTGRP;34.0,19.3,.0,3,2.5;I2N NC
T:HST;2.0,19.3,.0,3,2.5;SICK
T:HTNUMMER;2.0,16.3,.0,3,2.5;6025574
T:LPLATZ;22.0,9.7,.0,3,3.0;002/032
T:ZIND;14.0,5.6,.0,5,5.0;2222370515
T:BEZ;2.0,13.3,.0,3,2.5,h1.6;Inductive Proximity Sensor IM08-03BPS-ZT
B:BC;2.0,2.0,.0,DATAMATRIX,.68;[ZIND]
A1
Eingelesen werden die Daten folgendermaßen:
Java:
        String line;
        String label = new String();
      
        try (BufferedReader in = new BufferedReader (new FileReader ("zind.lbl"));)
        {
            while( (line = in.readLine()) != null )
            {
                label += line;
            }
             in.close();
        }
Es werden auch Daten an den Drucker geschickt, aber zwischen jedem gesendeten Zeichen befindet sich ein NUL, darum kann der Drucker nichts mit anfangen.
 
Hm, ich glaube das Problem liegt entweder an der Datei oder beim Einlesen. Heute ist erst mal Schluss, morgen gehts weiter.
 
Die Etikettendaten kommen mir ja irgendwie bekannt vor. Das ist nicht zufällig ein cab-Drucker? Damit haben wir vor vielen Jahren eine Menge gemacht, aber niemals ESC-Sequenzen benötigt.

Ich habe mit dem Testprogramm oben mal einen Hex-Dump auf meinem Laserdrucker erstellt. Da kamen keine NUL-Zeichen. Ich vermute, es liegt am Format deiner Eingabedatei. Du kannst ja mal konstante Strings im Java-Code einbauen oder die Eingabedatei in einem anderen Format speichern. Wahrscheinlich hattest du mit deiner Unicode-Vermutung schon recht.
 
Ich tippe mal drauf, dass der Drucker kein UTF-16 kann und du die Daten in einem Encoding senden musst, was er versteht.
'NUL' ist das erste Byte von UTF-16 Zeichen, wenn man sie nicht als UTF-16 interpretiert

EDIT: dein zweites Codestück übersehen, da könnte das doppelte konvertieren das Problem sein.
Du interpretierst den UTF-16 String als ISO 8859-1, und schreibst das dann als ISO 8859-1. Für bspw 'y' ist das erst ein 0079 (UTF-16), wenn er das interpretiert als ISO 8859-1 wird intern zu 0000 0079(UTF-16), das wieder geschrieben als ISO 8859-1 wird 00 79
 
Zuletzt bearbeitet:
Das ist nicht zufällig ein cab-Drucker?
Richtig erkannt! 🙂

Ich tippe mal drauf, dass der Drucker kein UTF-16 kann und du die Daten in einem Encoding senden musst, was er versteht.
100% ACK. Leider haben meine verzweifelten Versuche alle nicht funktioniert...

So jetzt bin ich wieder daheim und habe die geballte Gewalt einer IDE hinter mir und nicht nur eine Krückenlösung, wie auf der Arbeit. Das Problem liegt beim Format der Datei, bzw. beim Einlesen. Hier die aktuelle Routine zum Einlesen:
Java:
        String label = null;

        try
        {
            byte[] encoded = Files.readAllBytes(Paths.get("zind.lbl"));
            label = new String(encoded, StandardCharsets.UTF_16);
        }

        catch (IOException e)
        {
            System.err.println("Error opening file.");
        }
Zwei Möglichkeiten der Lösung; entweder die Datei anders speichern, dann funktioniert es (zumindest auf meinem Computer) ohne Angabe der Kodierung oder die Datei als UTF-16 laden.

Jetzt habe ich allerdings trotzdem noch Fragen. Welche Codierung hat denn der String 'label' den jetzt im Speicher?

Muss ich jetzt beim Senden noch einmal nach ISO_8859_1 kodieren?

Leider habe ich hier keinen Drucker zum Ausprobieren.
 
Zwei Möglichkeiten der Lösung; entweder die Datei anders speichern, dann funktioniert es (zumindest auf meinem Computer) ohne Angabe der Kodierung oder die Datei als UTF-16 laden.
Welches Encoding hat denn die Datei?

Jetzt habe ich allerdings trotzdem noch Fragen. Welche Codierung hat denn der String 'label' den jetzt im Speicher?
Strings sind immer UTF-16.

Muss ich jetzt beim Senden noch einmal nach ISO_8859_1 kodieren?
Ja, wenn der Drucker ISO_8859_1 erwartet.
 
Damit haben wir vor vielen Jahren eine Menge gemacht, aber niemals ESC-Sequenzen benötigt.
Es gibt einige ESC-Sequenzen und die Statusabfrage ist ganz sinnvoll, wenn man die Entnahme des gespendeten Etiketts abfragen möchte, weil die Anzahl der offenen Druckjobs zurück gemeldet wird und der Job offen ist, solange das Etikett noch da ist. Das ist mir aber gerade nicht ganz so wichtig, weil ich erst mal überhaupt drucken möchte...
 
Ja, hört sich sinnvoll an. Das hätten wir seinerzeit nur schwer über die Statusabfrage realisieren können, weil wir die Druckaufträge von einer AS/400 über deren Warteschlangensystem an die Drucker geschickt haben. Es wäre also kein eigenes Programm im Spiel gewesen, dass direkt mit dem Drucker kommuniziert und die Rückinfos verarbeiten könnte. Man konnte aber die Druckjobs in der Warteschlange einsehen und hätte sie auch automatisiert abfragen können, so dass ein ähnliches Resultat auf anderem Weg möglich gewesen wäre.
 
Welches Encoding hat denn die Datei?
Keine Ahnung. Wie kann ich das feststellen? Anscheinend UTF-16, wenn meine nächste Frage zutrifft.
Strings sind immer UTF-16.
Das hatte ich vermutet. Bezogen auf das letzte Codebeispiel; es werden zuerst alle Bytes der Datei eingelesen und dann entsprechend des angegebenen Encodings für den String interpretiert. Ist das richtig so?
Ja, wenn der Drucker ISO_8859_1 erwartet.
Wo ist dann die korrekte Stelle dafür?
Java:
        try (Socket socket = new Socket(hostName, portNumber);
             PrintWriter out = new PrintWriter(
               new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.ISO_8859_1), true);) // A
        {
            System.out.println("Connected, sending data..");
        
              out.println(new String(label.getBytes(), StandardCharsets.ISO_8859_1)); // B
        
            System.out.println("Done");

        }
Bei (B) wird ja wieder nur ein UTF-16 String erzeugt, also müsste (A) richtig sein, oder?
 
Keine Ahnung. Wie kann ich das feststellen?
Den fragen, der sie erstellt hat 😛
Oder mit nem vernünftigen Editor öffnen, die meisten erkennen das (oder versuchen es)

Das hatte ich vermutet. Bezogen auf das letzte Codebeispiel; es werden zuerst alle Bytes der Datei eingelesen und dann entsprechend des angegebenen Encodings für den String interpretiert. Ist das richtig so?
Ja.

Bei (B) wird ja wieder nur ein UTF-16 String erzeugt, also müsste (A) richtig sein, oder?
Ja.
 
Noch eine Frage: Bei meiner gestrigen Recherche bin ich mehrfach auf die Aussage gestoßen, dass 'PrintWriter" nicht so gut sei (warum auch immer). Ist das so? Was wäre die (eine) Alternative?

Edit: Ist das eine "bessere" Alternative?
Java:
        try (Socket socket = new Socket(hostName, portNumber);
             Writer out = new OutputStreamWriter(socket.getOutputStream(), PRINTER_CHARSET))
        {
            out.write(label, 0, label.length());
            out.flush();
        }

out.flush(); ist doch eigentlich unnötig, da durch den try-with-resources Block 'out' automatisch geschlossen und damit geflusht wird, oder?
 
Zuletzt bearbeitet:
Muss ich jetzt beim Senden noch einmal nach ISO_8859_1 kodieren?
Zumindest auf deinem Rechner scheint das nicht zwingend nötig zu sein, denn du hattest ja offenbar bereits erfolgreiche Tests (auf meinem Rechner geht es auch so). Demzufolge müsste der Drucker den Standardzeichensatz deiner Umgebung also direkt verstehen (vermutlich UTF-8?). Kann natürlich trotzdem nicht schaden, den richtigen Zeichensatz anzugeben, falls es in anderen Umgebungen nicht passt.

Ich denke, das Problem ensteht derzeit nicht beim Senden, sondern beim Einlesen wie @mrBrown es in #12 beschrieben hat. Wahrscheinlich genügt es, readAllLines() mit dem korrekten Zeichensatz anstelle von readAllBytes() zu verwenden.
 
Zumindest auf deinem Rechner scheint das nicht zwingend nötig zu sein, denn du hattest ja offenbar bereits erfolgreiche Tests (auf meinem Rechner geht es auch so). Demzufolge müsste der Drucker den Standardzeichensatz deiner Umgebung also direkt verstehen (vermutlich UTF-8?). Kann natürlich trotzdem nicht schaden, den richtigen Zeichensatz anzugeben, falls es in anderen Umgebungen nicht passt.

Ich denke, das Problem ensteht derzeit nicht beim Senden, sondern beim Einlesen wie @mrBrown es in #12 beschrieben hat. Wahrscheinlich genügt es, readAllLines() mit dem korrekten Zeichensatz anstelle von readAllBytes() zu verwenden.
Stimmt, du hast Recht. Wenn ich bei der Ausgabe über den Socket direkt einen String angebe, dann funktioniert es. Ich lass es jetzt mal so und werde es heute Nachmittag mal probieren, wenn ich wieder einen Drucker zur Verfügung habe.
 
Soeben getestet, es funktioniert wie gewünscht. Danke für die Unterstützung.
Java:
public class Main {

    private static final Charset FILE_CHARSET = StandardCharsets.UTF_16;
    private static final Charset PRINTER_CHARSET = StandardCharsets.ISO_8859_1;

    public static void main(String[] args)
    {
        if (args.length != 2) {
            System.err.println(
                    "Usage: java Main <host name> <port number>");
            System.exit(1);
        }


        System.out.println("Reading label file..");

        String label = null;

        try
        {
            byte[] encoded = Files.readAllBytes(Paths.get("zind.lbl"));
            label = new String(encoded, FILE_CHARSET);
        }

        catch (IOException e)
        {
            System.err.println("Error opening file.");
        }

        System.out.println("Done");

        String hostName = args[0];
        int portNumber = Integer.parseInt(args[1]);

        System.out.println("Connecting to printer..");

        try (Socket socket = new Socket(hostName, portNumber);
             Writer out = new OutputStreamWriter(socket.getOutputStream(), PRINTER_CHARSET))
        {
            System.out.println("Connected");

            System.out.println("Sending to printer..");

            out.write(label, 0, label.length());

            System.out.println("Done");

        }

        catch (UnknownHostException e)
        {
            System.err.println("Unknown host " + hostName);
            System.exit(1);
        }

        catch (IOException e)
        {
            System.err.println("IO Error " + hostName);
            System.exit(1);
        }
    }
}
 

Zurück
Oben