57 votes

Comment imprimer une image sur une imprimante Bluetooth sous Android ?

Je dois imprimer des données sur une imprimante thermique bluetooth, c'est ce que je fais :

String message="abcdef any message 12345";
byte[] send;
send = message.getBytes();
mService.write(send);

Cela fonctionne bien pour le texte, mais pas pour les images. Je pense que je dois obtenir le byte[] des données de l'image. J'ai essayé de récupérer les données de l'image de cette façon :

Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.qrcode);
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
byte[] image=stream.toByteArray();

Malheureusement, l'imprimante imprime beaucoup de caractères étranges (environ 50 cm de papier). Je ne sais pas comment imprimer l'image.

J'aimerais essayer de récupérer les pixels de l'image bitmap et de la convertir ensuite en un fichier de type byte[] et l'envoyer, mais je ne sais pas comment faire.

Merci

UPDATE :

Après tant de temps, je fais ça : J'ai une méthode appelée print_image(String file), qui récupère le chemin de l'image que je veux imprimer :

private void print_image(String file) {
    File fl = new File(file);
    if (fl.exists()) {
        Bitmap bmp = BitmapFactory.decodeFile(file);
        convertBitmap(bmp);
        mService.write(PrinterCommands.SET_LINE_SPACING_24);

        int offset = 0;
        while (offset < bmp.getHeight()) {
            mService.write(PrinterCommands.SELECT_BIT_IMAGE_MODE);
            for (int x = 0; x < bmp.getWidth(); ++x) {

                for (int k = 0; k < 3; ++k) {

                    byte slice = 0;
                    for (int b = 0; b < 8; ++b) {
                        int y = (((offset / 8) + k) * 8) + b;
                        int i = (y * bmp.getWidth()) + x;
                        boolean v = false;
                        if (i < dots.length()) {
                            v = dots.get(i);
                        }
                        slice |= (byte) ((v ? 1 : 0) << (7 - b));
                    }
                    mService.write(slice);
                }
            }
            offset += 24;
            mService.write(PrinterCommands.FEED_LINE);
            mService.write(PrinterCommands.FEED_LINE);          
            mService.write(PrinterCommands.FEED_LINE);
            mService.write(PrinterCommands.FEED_LINE);
            mService.write(PrinterCommands.FEED_LINE);
            mService.write(PrinterCommands.FEED_LINE);
        }
        mService.write(PrinterCommands.SET_LINE_SPACING_30);

    } else {
        Toast.makeText(this, "file doesn't exists", Toast.LENGTH_SHORT)
                .show();
    }
}

Je l'ai fait en me basant sur ceci poste

Voici la classe PrinterCommands :

public class PrinterCommands {
public static final byte[] INIT = {27, 64};
public static byte[] FEED_LINE = {10};

public static byte[] SELECT_FONT_A = {27, 33, 0};

public static byte[] SET_BAR_CODE_HEIGHT = {29, 104, 100};
public static byte[] PRINT_BAR_CODE_1 = {29, 107, 2};
public static byte[] SEND_NULL_BYTE = {0x00};

public static byte[] SELECT_PRINT_SHEET = {0x1B, 0x63, 0x30, 0x02};
public static byte[] FEED_PAPER_AND_CUT = {0x1D, 0x56, 66, 0x00};

public static byte[] SELECT_CYRILLIC_CHARACTER_CODE_TABLE = {0x1B, 0x74, 0x11};

public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};
public static byte[] SET_LINE_SPACING_24 = {0x1B, 0x33, 24};
public static byte[] SET_LINE_SPACING_30 = {0x1B, 0x33, 30};

public static byte[] TRANSMIT_DLE_PRINTER_STATUS = {0x10, 0x04, 0x01};
public static byte[] TRANSMIT_DLE_OFFLINE_PRINTER_STATUS = {0x10, 0x04, 0x02};
public static byte[] TRANSMIT_DLE_ERROR_STATUS = {0x10, 0x04, 0x03};
public static byte[] TRANSMIT_DLE_ROLL_PAPER_SENSOR_STATUS = {0x10, 0x04, 0x04};
}

Comme on le voit dans la méthode print_image, j'appelle une méthode, appelée convertBitmap, et j'envoie un bitmap, voici le code :

   public String convertBitmap(Bitmap inputBitmap) {

    mWidth = inputBitmap.getWidth();
    mHeight = inputBitmap.getHeight();

    convertArgbToGrayscale(inputBitmap, mWidth, mHeight);
    mStatus = "ok";
    return mStatus;

}

private void convertArgbToGrayscale(Bitmap bmpOriginal, int width,
        int height) {
    int pixel;
    int k = 0;
    int B = 0, G = 0, R = 0;
    dots = new BitSet();
    try {

        for (int x = 0; x < height; x++) {
            for (int y = 0; y < width; y++) {
                // get one pixel color
                pixel = bmpOriginal.getPixel(y, x);

                // retrieve color of all channels
                R = Color.red(pixel);
                G = Color.green(pixel);
                B = Color.blue(pixel);
                // take conversion up to one single value by calculating
                // pixel intensity.
                R = G = B = (int) (0.299 * R + 0.587 * G + 0.114 * B);
                // set bit into bitset, by calculating the pixel's luma
                if (R < 55) {                       
                    dots.set(k);//this is the bitset that i'm printing
                }
                k++;

            }

        }

    } catch (Exception e) {
        // TODO: handle exception
        Log.e(TAG, e.toString());
    }
}

C'est le imprimante que j'utilise, résolution : 8 points/mm, 576 points/ligne.

Et voici ce que j'aime faire (je l'ai fait avec la même imprimante, mais avec une application téléchargée sur play store) Image that I want to print

Voici ce que j'obtiens maintenant My printing trying

Plus près : A closer part

Closer2 : enter image description here

Une petite partie de l'image peut être vue, donc je pense que je suis plus proche de pouvoir imprimer l'image...

L'image que j'utilise est la suivante (576x95) : enter image description here

Et voici l'image convertie (je la convertis avec le code supérieur) : converted image

Inverted

Donc, la réponse est : qu'est-ce que je fais de mal ? Je pense que l'erreur se trouve dans cette commande :

  public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};

Mais, comment puis-je calculer les valeurs correctes pour mon image ? merci.

0 votes

Oui, je l'ai envoyé de la même façon que le premier extrait. mService.write(image) L'imprimante a un SDK mais il ne compile pas, donc je ne sais pas comment le faire.

0 votes

Si vous avez les sources du SDK, vous pouvez voir comment ils procèdent.

0 votes

Maintenant, je l'ai décompilé, ils utilisent une méthode pour retourner le tableau byte[], mais cela ne fonctionne pas, j'ai implémenté cette méthode mais quand je lance l'application sur la tablette, elle meurt, générant une erreur de fermeture forcée.... ``

13voto

Razgriz Points 1054

J'ai également essayé ceci et j'ai trouvé ma propre solution et je pense que j'ai compris comment la SELECT_BIT_IMAGE_MODE fonctionne.

La commande public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3}; dans la classe PrinterCommands est la commande POS pour l'impression d'images.

Les deux premières sont assez standard, les trois suivantes déterminent le mode et les dimensions de l'image à imprimer. Pour les besoins de cette solution, supposons simplement que le deuxième élément (33, nous sommes indexés zéro) est toujours 33.

Les deux derniers éléments de cet octet[] font référence à l'élément Largeur (en pixels) de l'image que vous voulez imprimer, l'élément 3 est parfois appelé nL et l'élément 4 est parfois appelé nH . En fait, les deux font référence à la largeur, nL est le Low Byte tandis que nH est le High Byte . Cela signifie que nous pouvons avoir au maximum une image d'une largeur de 1111 1111 1111 1111b (binaire) qui est 65535d (décimal), bien que je ne l'ai pas encore essayé. Si nL ou nH ne sont pas réglés sur les bonnes valeurs, alors il y aura des caractères trash imprimés avec l'image.

D'une certaine manière, la documentation Android nous dit que les limites de la valeur d'un octet dans un tableau d'octets sont -128 et +127, lorsque j'ai essayé de mettre 255, Eclipse m'a demandé de le convertir en octet.

Quoi qu'il en soit, pour revenir à nL et nW, dans votre cas, vous avez une image de largeur 576, si nous convertissons 576 en binaire, nous obtenons deux octets qui se présentent comme suit :

0000 0010 0100 0000

Dans ce cas, l'octet de poids faible est 0100 0000 tandis que l'octet supérieur est 0000 0010 . Convertissez-le en décimal et nous obtenons nL = 64 et nH = 2 .

Dans mon cas, j'ai imprimé une image qui a une largeur de 330px, en convertissant 330 en binaire on obtient :

0000 0001 0100 1010

Dans ce cas maintenant, l'octet de poids faible est 0100 1010 et l'octet de poids fort est 0000 0001 . En convertissant en décimal, on obtient nL = 74 et nH = 1 .

Pour plus d'informations, consultez ces documents/tutoriels :

Documentation sur l'imprimante mobile Star Asia

Guide de programmation ECS-POS - très complet

Une autre documentation

La version étendue du code ci-dessus, avec plus d'explications

Explication du code ci-dessus

J'espère que cela vous aidera.

2 votes

Merci pour votre réponse, j'utilise ce code pour initialiser mon priter : public static byte[] SELECT_BIT_IMAGE_MODE = { 0x1B, 0x2A, 33, (byte) 255, 3 }; et cela fonctionne bien pour moi

0 votes

Cette réponse m'aide également. J'ai imprimé en bluetooth le QRcode 150x150 sur le reçu et au moins ça marche. Il est imprimé sur le côté gauche. Ma question est de savoir comment centrer l'image imprimée si c'est possible ?

0 votes

{0x1B,0x33,0x00} charger cette commande avant d'imprimer le bitmap pour centrer l'image @Vranilac

12voto

Leonardo Sapuy Points 460

Résolu, je faisais une mauvaise initialisation de l'imprimante... La bonne méthode est :

 public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3};

Ainsi, de cette façon, l'image est imprimée complètement fine.

0 votes

Bonjour, j'ai implémenté le code ci-dessus et l'ai remplacé par votre solution également mais j'obtiens toujours des caractères étranges imprimés sur le papier. Merci de m'aider. Merci d'avance.

0 votes

Ce serait formidable, si vous pouviez m'aider.

0 votes

Désolé, j'ai mal écrit mon mail, est le suivant : leonardo.sapuy@hotmail.com

9voto

Andrew Alcock Points 10536

EDIT : Mise à jour en fonction de la lecture de votre question : https://stackoverflow.com/questions/16597789/print-bitmap-on-esc-pos-printer-java

Je suppose que l'imprimante sur laquelle vous imprimez est la même que ci-dessus, c'est-à-dire l'imprimante thermique Rego. Celle-ci, comme vous le notez, supporte le ESC/POS Page Description Language .


Les imprimantes interprètent les données qui leur sont transmises comme un document balisé (de la même manière que les navigateurs interprètent le HTML). Dans certains cas, l'imprimante exécute littéralement le document comme un programme (par exemple, PostScript). Lien : Description de la page Langues .

Les langues courantes sont :

Vous devez lire les spécifications de votre imprimante afin de déterminer la langue à utiliser. tout imprimante, alors vous avez un très gros travail devant vous :(

Dans ESC/POS, vous devrez utiliser la touche GS v 0 (documenté à la p33). Pour ce faire, envoyez les caractères 0x1D7630 à travers la liaison série, suivi d'un ensemble d'arguments :

ASCII:       Gs   v  0 
Decimal:     29 118 48 m xL xH yL yH [d]k 
Hexadecimal: 1D  76 30 m xL xH yL yH [d]k 

Définition des paramètres :

  • m :
    • 0,48 : mode normal (échelle 1:1)
    • 1,49 : double largeur
    • 2,50 : double hauteur
    • 3,51 : double largeur + double hauteur
  • xL, xH spécifie (xL + xH × 256) octets dans la direction horizontale pour l'image binaire.
  • yL, yH spécifie (yL + yH × 256) points dans la direction verticale pour l'image binaire.
  • [d]k spécifie les données d'image binaire (format raster).
  • k indique le nombre de données binaires de l'image. k est un paramètre d'explication ; il n'a donc pas besoin d'être transmis.

Notes :

  • Lorsque la donnée [d]k est 1, cela indique un bit imprimé à 1 et non imprimé à 0.
  • Si une image bitmap dépasse une ligne de la zone d'impression, les données excédentaires ne sont pas imprimées.
  • Cette commande exécute l'alimentation en papier pour la quantité nécessaire à l'impression de l'image binaire, quels que soient les réglages effectués par ESC 2 ou ESC 3.
  • Après avoir imprimé l'image binaire, cette commande place la position d'impression au début de la ligne et vide le tampon.
  • Lorsque cette commande est exécutée, les données sont transmises et imprimées de manière synchrone. Aucune autre commande d'impression n'est donc nécessaire.

Il existe plusieurs expositions plus complètes :


Malheureusement, il n'existe pas d'API d'imprimante dans Android. Si cela vous tient à cœur, suivez ces questions :

0 votes

Merci pour votre réponse... Je suis en train d'imprimer une petite partie de l'image, mon imprimante est compatible avec les commandes ESC/POS, et a une résolution de 576 dost/ligne... J'ai trouvé ce est une traduction en java du post de Nicholas Piasecki... J'ai implémenté cette source dans mon projet, et maintenant j'imprime une petite partie de mon image... Mais de toute façon, il ne peut pas imprimer l'image complète. Je pense que c'est une commande mal utilisée, j'utilise cette commande pour initialiser l'imprimante en mode graphique : 0x1B, 0x2A, 33, -128, 0

0 votes

Mais je crois que je m'y prends mal... Mon image a une résolution de 576 x 96 pixels, pouvez-vous me dire si je fais bien l'init imprimante, ou ce que je dois changer dans le code ?

2 votes

Je suis sur le point d'aller me coucher, mais il serait très utile que vous donniez une description plus complète de ce qui se passe et ne se passe pas. Par exemple, combien de lignes de sortie sont produites ? La largeur totale est-elle imprimée sur chaque ligne ? Les lignes imprimées sont-elles parfaites en pixels ou fausses ? Pouvez-vous montrer un vidage hexadécimal des données envoyées à l'imprimante ?

3voto

just some guy Points 124

Je suis nouveau dans l'ESC/POS et j'ai du mal à m'y retrouver. Je suis tombé sur cette page qui semble contenir quelques fonctions utiles : http://code.taobao.org/p/printer/src/trunk/prtest/src/com/enjar/plugins/PrintTools_58mm.java C'est en chinois, mais ça peut valoir la peine de le lire. Si quelqu'un trouve la solution, j'aimerais aussi être éclairé...

0 votes

Merci, ces codes pourraient être utiles pour imprimer des images dans une imprimante BT, j'ai amélioré mon code pour l'impression d'images, donc si vous avez besoin de quelques astuces je pourrais vous aider.

2voto

mjosh Points 4015

Je sais que pour les imprimantes bluetooth evolute et AMDL, il faut d'abord lire le document de définition du protocole de l'imprimante qui indique les octets spécifiques dont vous avez besoin pour le périphérique.

public void connect() throws Exception 
{

    BluetoothDevice printer = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(connParams);

    Method m = printer.getClass().getMethod("createInsecureRfcommSocket",new Class[] { int.class });
    sock = (BluetoothSocket)m.invoke(printer, Integer.valueOf(1));
    sock.connect();
    os=sock.getOutputStream();
    in=sock.getInputStream();

}

Après la connexion via le code ci-dessus, vous obtenez le flux de sortie du socket, puis convertissez votre image en octet correspondant via l'outil fourni avec l'imprimante.

public byte[] Packet1={
        (byte)0X8A,(byte)0XC6,(byte)0X94,(byte)0XF4,(byte)0X0B,(byte)0X5E,(byte)0X30,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X04,(byte)0X24,(byte)0X01,(byte)0X0C,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X01,(byte)0X08,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X04,(byte)0X24,(byte)0X05,(byte)0X0C,(byte)0X00,(byte)0X60,(byte)0X00,(byte)0X18,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X30,(byte)0X1E,(byte)0X10,(byte)0X60,(byte)0X00,(byte)0X18,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X70,(byte)0X3F,(byte)0X18,(byte)0XF0,(byte)0X00,(byte)0X3E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X70,(byte)0X3C,(byte)0X39,(byte)0XF1,(byte)0X80,(byte)0X3E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XF8,(byte)0X7C,(byte)0X9F,(byte)0XF1,(byte)0X80,(byte)0X7F,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XF9,(byte)0X9E,(byte)0X1C,(byte)0XFF,(byte)0XC2,(byte)0X7E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XF9,(byte)0X9E,(byte)0X1C,(byte)0XE7,(byte)0XE2,(byte)0X7E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XFB,(byte)0X1E,(byte)0X1C,(byte)0XFF,(byte)0XE7,(byte)0XBE,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X7B,(byte)0X16,(byte)0X1C,(byte)0XFF,(byte)0XDF,(byte)0X3E,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X71,(byte)0X12,(byte)0X1C,(byte)0XE7,(byte)0XF7,(byte)0X34,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X51,(byte)0X12,(byte)0X1C,(byte)0XF7,(byte)0XF7,(byte)0X24,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X49,(byte)0X12,(byte)0X1C,(byte)0XFF,(byte)0XF3,(byte)0X24,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X49,(byte)0X12,(byte)0X3F,(byte)0XFD,(byte)0XF3,(byte)0X24,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0X49,(byte)0X96,(byte)0X3F,(byte)0XFC,(byte)0XF3,(byte)0X24,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X05,(byte)0X49,(byte)0X80,(byte)0X00,(byte)0X08,(byte)0X10,(byte)0X5E,(byte)0X28,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X30,(byte)0X25,(byte)
        0X01,(byte)0X5E,(byte)0X03,(byte)0X24,(byte)0X06,(byte)0XE0,(byte)0X74,(byte)0XA9,(byte)0X33,(byte)0X23,(byte)0X26,(byte)0X5E,(byte)0X27,(byte)0X25,(byte)0X04
        };

où 8A est l'octet de départ C6 est l'octet de mode (différent pour la carte à puce, le lecteur et l'empreinte digitale), 94 est l'octet de police et le dernier octet 04 est l'octet de fin indiquant au matériel que c'est la fin du paquet. Selon la taille de l'image, vous obtenez plusieurs de ces paquets de 256 octets (la plupart des imprimantes).

os.write(Packet1)

0 votes

Je suis en train de convertir l'image en un bitmap monochrome, donc je crée un bitset qui contient des 1 et des 0 (cela représente le noir ou le blanc), mais l'image ne s'imprime pas correctement, elle n'imprime qu'une petite partie de l'image...

0 votes

Vous devez convertir l'image en sa représentation hexagonale, puis convertir ces données hexagonales en octets. L'appareil ne comprend que le format octet. Donnez-moi également le lien de l'application Market par laquelle vous obtenez l'impression. Voyez si je peux en tirer quelque chose.

0 votes

@mjosh Salut, pouvez-vous s'il vous plaît jeter un coup d'œil à ma question : stackoverflow.com/questions/16982485/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X