如何在Android中的蓝牙打印机上打印图像?

Leo*_*puy 49 java android bytearray bitmap bitmapfactory

我必须在热蓝牙打印机上打印一些数据,我正在这样做:

String message="abcdef any message 12345";
byte[] send;
send = message.getBytes();
mService.write(send);
Run Code Online (Sandbox Code Playgroud)

它适用于文本,但不适用于图像.我想我需要获取byte[]图像数据.我尝试以这种方式获取图像的数据:

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

不幸的是,打印机会打印出许多奇怪的字符(大约50厘米的纸张).我不知道如何打印图像.

我想尝试获取位图的像素,然后将其转换为a byte[]并发送它,但我不知道该怎么做.

谢谢

更新:

经过这么多时间,我这样做:我有一个名为print_image(String file)的方法,它获取我想要打印的图像的路径:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我是根据这篇文章做到

这是类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};
}
Run Code Online (Sandbox Code Playgroud)

正如在print_image方法中看到的,我正在调用一个名为convertBitmap的方法,并且即时发送一个位图,这是代码:

   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());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我正在使用的打印机,分辨率:8点/ mm,576点/线

这就是我喜欢做的事情(我使用相同的打印机,但从Play商店下载的应用程序) 我要打印的图像

这就是我现在要做的 我的打印尝试

言归正传: 更接近的部分

Closer2: 在此输入图像描述

可以看到图像的一小部分,所以我认为我更接近可以打印图像...

我正在使用的图像是这个(576x95):在此输入图像描述

这是转换后的图像(我用上面的代码转换它): 转换后的图像

倒

所以,答案是:我做错了什么?,我认为错误在这个命令中:

  public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};
Run Code Online (Sandbox Code Playgroud)

但是,我怎样才能为我的图像计算正确的值?谢谢

Md *_*ury 18

我解决了将Bitmap转换为Byte数组的问题.请记住,您的图片必须是黑白格式.

完整源代码:https: //github.com/imrankst1221/Thermal-Printer-in-Android

在此输入图像描述

 public void printPhoto() {
        try {
            Bitmap bmp = BitmapFactory.decodeResource(getResources(),
                    R.drawable.img);
            if(bmp!=null){
                byte[] command = Utils.decodeBitmap(bmp);
                printText(command);
            }else{
                Log.e("Print Photo error", "the file isn't exists");
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("PrintTools", "the file isn't exists");
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 为什么宽度和高度有限制? (2认同)
  • 是否可以打印宽度超过 255 像素的图像? (2认同)

Leo*_*puy 10

解决了!,我正在做一个错误的打印机初始化...核心方式是:

 public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3};
Run Code Online (Sandbox Code Playgroud)

因此,通过这种方式,图像被完全打印出来


Raz*_*riz 9

我也尝试了这个,我得到了自己的解决方案,我想我弄清楚SELECT_BIT_IMAGE_MODE命令是如何工作的.

该命令public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, 255, 3};在类PrinterCommands是POS命令图像打印.

前两个是非常标准的,接下来的三个确定要打印的图像的模式和尺寸.为了解决这个问题,我们假设第二个元素(33,我们索引为零)总是33.

该字节[]的最后两个元素是指要打印的图像的宽度(以像素为单位)属性,元素3有时称为nL,元素4有时称为nH.他们实际上都指的宽度,nLLow Byte同时nHHigh Byte.这意味着我们最多可以拥有宽度为1111 1111 1111 1111b(二进制)的图像,即65535d(十进制),尽管我还没有尝试过.如果nL或nH未设置为正确的值,则将随图像一起打印垃圾字符.

不知何故,Android文档告诉我们字节数组中字节值的限制是-128和+127,当我试图输入255时,Eclipse要求我将其转换为Byte.

无论如何,回到nL和nW,对于你的情况,你有一个宽度为576的图像,如果我们将576转换为二进制,我们得到两个字节,如下所示:

0000 0010 0100 0000

在这种情况下,低字节是0100 0000高字节0000 0010.将它转换回十进制,我们得到nL = 64nH = 2.

在我的情况下,我打印了一个宽度为330px的图像,将330转换为二进制,我们得到:

0000 0001 0100 1010

现在在这种情况下,低字节0100 1010和高字节是0000 0001.转换为十进制,我们得到nL = 74nH = 1.

有关更多信息,请查看以下文档/教程:

Star Asia移动打印机文档

ECS-POS编程指南 - 非常广泛

另一份文件

上面代码的扩展版本,有更多解释

上面代码的解释

希望这些有帮助.

  • 感谢您的回答,我使用此代码来初始化我的 priter:`public static byte[] SELECT_BIT_IMAGE_MODE = { 0x1B, 0x2A, 33, (byte) 255, 3 };` 并且它对我来说很好用 (2认同)

And*_*ock 8

编辑:根据您的问题更新:https://stackoverflow.com/questions/16597789/print-bitmap-on-esc-pos-printer-java

我将假设您要打印的打印机与上面相同,即Rego热敏打印机.正如您所说,这支持ESC/POS页面描述语言.


打印机将流式传输的数据解释为标记文档(与浏览器解释HTML的方式类似).在某些情况下,打印机将文档作为程序(例如PostScript)运行.链接:页面描述语言.

常用语言有:

您需要阅读打印机的规格以确定使用哪种语言 - 如果您需要支持任何打印机,那么您前面的工作量非常大:(

在ESC/POS中,您需要使用GS v 0命令(在p33中记录).您可以通过0x1D7630串行链接发送字符,然后是一组参数来完成此操作:

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 
Run Code Online (Sandbox Code Playgroud)

参数定义:

  • L:
    • 0,48:正常模式(1:1比例)
    • 1,49:双倍宽度
    • 2,50:双倍高度
    • 3,51:双宽+双高
  • xL,xH指定位图的水平方向上的(xL + xH×256)字节.
  • yL,yH指定位图的垂直方向上的(yL + yH×256)个点.
  • [d] k指定位图数据(光栅格式).
  • k表示位图数据的数量.k是解释参数; 因此,它不需要传输.

笔记:

  • 当数据[d] k为1时,指定打印为1的位而不打印为0.
  • 如果光栅位图像超过一行打印区域,则不会打印多余的数据.
  • 无论ESC 2或ESC 3的设置如何,该命令都会执行打印位图所需的进纸量.
  • 打印位图后,此命令将打印位置设置为行的开头,并清除缓冲区.
  • 执行此命令时,将同步传输和打印数据.因此不需要其他打印命令.

还有几个更广泛的阐述:


不幸的是,Android中没有打印机API.如果您对此有强烈的感受,请遵循以下问题:

  • 我要上床睡觉,但是如果您可以更全面地描述正在发生的事情和没有发生的事情,那将非常有用。例如,产生了多少行输出?是否在每行上打印了全角?线条打印的像素是完美还是错误?您可以显示发送到打印机的数据的十六进制转储吗? (2认同)