java 从 Android 应用程序使用蓝牙热敏打印机打印图像?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16982485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:37:09  来源:igfitidea点击:

Printing an Image using a Bluetooth Thermal Printer From an Android App?

javaandroidbitmapbytearraybitmapfactory

提问by beerBear


I have been trying to get a print of an Image but I have not been successful so far.

The printer is a locally manufactured 2" thermal printer having a printing resolution of 8dots/mm, 384dots/line, 203 dpi.
The printer is based of a board having the "NXP 2388 ARM v7 Microproc." having a Memory FLASH size of 512 KB, RAM: 128 KB & a Receive Buffer Size of 16KB.

I followed this questiontill now.


我一直在尝试打印图像,但到目前为止我还没有成功。

该打印机是本地制造的 2" 热敏打印机,打印分辨率为 8 点/毫米,384 点/线,203 dpi。
该打印机基于具有“NXP 2388 ARM v7 Microproc”的板,具有 512 的内存闪存大小KB, RAM: 128 KB & a Receive Buffer Size of 16KB.

我一直关注这个问题直到现在。

Problem:The image I tried printing is of 576x95 res. enter image description here

问题:我尝试打印的图像为 576x95 分辨率。 在此处输入图片说明

The image got printed(with some error LED lighting up and debug buzzer noise :D) but the orientation of the image was vertical instead of getting horizontally printed; that too at the very left side of the page and the top part of the image was cut-off

图像被打印(有一些错误 LED 亮起和调试蜂鸣器噪音:D)但图像的方向是垂直而不是水平打印;页面的最左侧和图像的顶部也被剪掉了

Assuming here that I din't passed some of the flags(while making the "packet") compatible with the printer that I have.

在这里假设我没有通过一些标志(同时使“数据包”)与我拥有的打印机兼容。

I have not worked on bluetooth printing before so any help is appreciable :)

我之前没有做过蓝牙打印,所以任何帮助都是可观的:)

My Existing Main Activity:

我现有的主要活动:

public class MainActivity extends Activity 
    {
    // will show the statuses
    TextView myLabel;
    // will enable user to enter any text to be printed
    EditText myTextbox;
    EditText devName;
    public TableLayout tl2; 
    String devid;
    String[] pName;
    String[] LODQTY;
    String[] rte;
    String[] stk;
    String[] oQty;
    String[] oVal;
    String[] fQty;

    BitSet dots;
    int mWidth;
    int mHeight;
    String mStatus;
    String TAG = "TAG";

    public String msg;

    // android built in classes for bluetooth operations
    BluetoothAdapter mBluetoothAdapter;
    BluetoothSocket mmSocket;
    BluetoothDevice mmDevice;

    OutputStream mmOutputStream;
    InputStream mmInputStream;
    Thread workerThread;

    byte[] readBuffer;
    int readBufferPosition;
    int counter;
    volatile boolean stopWorker;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        devName = (EditText) findViewById(R.id.etdevice);

        devName.setText("BTprinter0377");

        String[] product_info = new String[6];
        product_info[0] = "CPL400^10^1^0^4^0.4^0";
        product_info[1] = "CPL400^10^1^0^4^0.4^0";
        product_info[2] = "CPL400^10^1^0^4^0.4^0";
        product_info[3] = "CPL400^10^1^0^4^0.4^0";
        product_info[4] = "CPL400^10^1^0^4^0.4^0";
        product_info[5] = "CPL400^10^1^0^4^0.4^0";


        tl2 = (TableLayout) findViewById(R.id.dynSummary);
        LayoutInflater inflater = getLayoutInflater();
    for (int current = 0; current <= (product_info.length - 1); current++) {


            final TableRow row = (TableRow)inflater.inflate(R.layout.table_summary_row, tl2 , false);

            TextView tv1 = (TextView)row.findViewById(R.id.tvSkuName);
            TextView tv2 = (TextView)row.findViewById(R.id.tvOrderQty);
            TextView tv3 = (TextView)row.findViewById(R.id.tvFreeQty);

            TextView tv4 = (TextView)row.findViewById(R.id.tvSampleQty);
            TextView tv5 = (TextView)row.findViewById(R.id.tvTotalOrderKg);
            TextView tv6 = (TextView)row.findViewById(R.id.tvTotalFreeKg);
           TextView tv7 = (TextView)row.findViewById(R.id.tvTotalSampleKg);

            StringTokenizer tokens = new StringTokenizer(String.valueOf(product_info[current]), "^");
            //System.out.println("tokens.nextToken().trim()"+tokens.nextToken().trim());
            tv1.setText(tokens.nextToken().trim());
            tv2.setText(tokens.nextToken().trim());
            tv3.setText(tokens.nextToken().trim());
            tv4.setText(tokens.nextToken().trim());
            tv5.setText(tokens.nextToken().trim());
            tv6.setText(tokens.nextToken().trim());
            tv7.setText(tokens.nextToken().trim());

            tl2.addView(row);

    }

        try {

            // we have three buttons for specific functions
            Button openButton = (Button) findViewById(R.id.open);
            Button sendButton = (Button) findViewById(R.id.send);
            Button closeButton = (Button) findViewById(R.id.close);

            myLabel = (TextView) findViewById(R.id.label);

            // open bluetooth connection
            openButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {

                    devid = devName.getText().toString().trim();

                    try {
                        findBT();
                        openBT();
                    } catch (IOException ex) {
                    }

                }
            });

            // send data typed by the user to be printed
            sendButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    try {
                        sendData();
                    } catch (IOException ex) {
                    }
                }
            });

            // close bluetooth connection
            closeButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    try {
                        closeBT();
                    } catch (IOException ex) {
                    }
                }
            });

        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * This will find a bluetooth printer device
     */
    void findBT() {

        try {
            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

            if (mBluetoothAdapter == null) {
                myLabel.setText("No bluetooth adapter available");
            }

            if (!mBluetoothAdapter.isEnabled()) {
                Intent enableBluetooth = new Intent(
                        BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBluetooth, 0);
            }

            Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
                    .getBondedDevices();
            if (pairedDevices.size() > 0) {
                for (BluetoothDevice device : pairedDevices) {

                System.out.println("device.getName(): "+device.getName().toString());

                    if (device.getName().equals("BTprinter0377")) {
                        mmDevice = device;
                        break;
                    }
                }
            }
            myLabel.setText("Bluetooth Device Found");
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * Tries to open a connection to the bluetooth printer device
     */
    void openBT() throws IOException {
        try {
            // Standard SerialPortService ID
            UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); 

            mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
            mmSocket.connect();
            mmOutputStream = mmSocket.getOutputStream();
            mmInputStream = mmSocket.getInputStream();

            beginListenForData();

            myLabel.setText("Bluetooth Opened");
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * After opening a connection to bluetooth printer device, 
     * we have to listen and check if a data were sent to be printed.
     */
    void beginListenForData() {
        try {
            final Handler handler = new Handler();

            // This is the ASCII code for a newline character
            final byte delimiter = 10;

            stopWorker = false;
            readBufferPosition = 0;
            readBuffer = new byte[1024];

            workerThread = new Thread(new Runnable() {
                public void run() {
                    while (!Thread.currentThread().isInterrupted()
                            && !stopWorker) {

                        try {

                            int bytesAvailable = mmInputStream.available();
                            if (bytesAvailable > 0) {
                                byte[] packetBytes = new byte[bytesAvailable];
                                mmInputStream.read(packetBytes);
                                for (int i = 0; i < bytesAvailable; i++) {
                                    byte b = packetBytes[i];
                                    if (b == delimiter) {
                                        byte[] encodedBytes = new byte[readBufferPosition];
                                        System.arraycopy(readBuffer, 0,
                                                encodedBytes, 0,
                                                encodedBytes.length);
                                        final String data = new String(
                                                encodedBytes, "US-ASCII");
                                        readBufferPosition = 0;

                                        handler.post(new Runnable() {
                                            public void run() {
                                                myLabel.setText(data);
                                            }
                                        });
                                    } else {
                                        readBuffer[readBufferPosition++] = b;
                                    }
                                }
                            }

                        } catch (IOException ex) {
                            stopWorker = true;
                        }

                    }
                }
            });

            workerThread.start();
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * This will send data to be printed by the bluetooth printer
     */
    void sendData() throws IOException {
        System.out.println("tl2.getChildCount(): "+tl2.getChildCount());
        try {

            print_image("/sdcard/tryimg.png");

            String msg22;
            msg22 = "\n";
            msg22 += "PN     Or Fr Sa TOKg TFKg TSKg";
            msg22 += "\n";

            //mmOutputStream.write(msg22.getBytes());

            // tell the user data were sent
            myLabel.setText("Data Sent");

        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * Close the connection to bluetooth printer.
     */
    void closeBT() throws IOException {
        try {
            stopWorker = true;
            mmOutputStream.close();
            mmInputStream.close();
            mmSocket.close();
            myLabel.setText("Bluetooth Closed");
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


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


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

            int offset = 0;
            while (offset < bmp.getHeight()) {
                mmOutputStream.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));
                        }
                        mmOutputStream.write(slice);
                    }
                }
                offset += 24;
                mmOutputStream.write(PrinterCommands.FEED_LINE);
                mmOutputStream.write(PrinterCommands.FEED_LINE);          
                mmOutputStream.write(PrinterCommands.FEED_LINE);
                mmOutputStream.write(PrinterCommands.FEED_LINE);
                mmOutputStream.write(PrinterCommands.FEED_LINE);
                mmOutputStream.write(PrinterCommands.FEED_LINE);
            }
            mmOutputStream.write(PrinterCommands.SET_LINE_SPACING_30);


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

}

The PrinterCommands Class:

打印机命令类:

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, (byte) 255, 3};
//public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 0x64, 0x63, 48, (byte) 255};

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};
}

As mentioned in the dev manual of the printer(pdf):

如打印机的开发手册(pdf)中所述:

Bit Map Image Print
1. Select the image either from PC or from mobile's SD card.
2. Convert the image into monochrome bmp.
3. Resize the image to fit into the printer paper area if it is exceeding
4. Now read the processed image through fileinputstream and save it into byte array.
5. Make the packet of image and then send it to printer over outputstream.

The required packet structure: enter image description here

The packet fields chart: enter image description here

所需的数据包结构: 在此处输入图片说明

数据包字段图表: 在此处输入图片说明

Alignment table & other info: enter image description here

对齐表和其他信息: 在此处输入图片说明

回答by mjosh

private byte[] printbyte = {(byte)0x1B,(byte)0x2A,(byte)0x6F,(byte)0x63} 

File file = new File(Environment.getExternalStorageDirectory + File.seprator()+"file_name");
FileInputStream fin = new FileInputStream(file);
byte imageContent[] = new byte[(int)file.length()];
fin.read(imageContent);

byte [] width  = hexToBuffer(Integer.toHexString(your_width));
byte [] height = hexToBuffer(Integer.toHexString(your_height));

byte[] imageToPrint = new byte[printbyte.lenght()+imageContent.lenght()+width.lenght()+height.lenght()];

  System.arraycopy(imagetoprint,0,printbyte,0,printbyte.lenght());
  System.arraycopy(imagetoprint,printbyte.lenght(),width ,0,width.lenght());
  System.arraycopy(imagetoprint,width.lenght(),height,0,height.lenght());  
  System.arraycopy(imagetoprint,height.lenght(),imageContent,0,imageContent.lenght()); 

  mmOutputStream.write(imagetoprint);  

Hex to Buffer method -

十六进制到缓冲区方法 -

public static byte[] hexToBuffer(String hexString)
    throws NumberFormatException {
    int length = hexString.length();
    byte[] buffer = new byte[(length + 1) / 2];
    boolean evenByte = true;
    byte nextByte = 0;
    int bufferOffset = 0;

    if ((length % 2) == 1) {
        evenByte = false;
    }

    for (int i = 0; i < length; i++) {
        char c = hexString.charAt(i);
        int nibble; // A "nibble" is 4 bits: a decimal 0..15

        if ((c >= '0') && (c <= '9')) {
            nibble = c - '0';
        } else if ((c >= 'A') && (c <= 'F')) {
            nibble = c - 'A' + 0x0A;
        } else if ((c >= 'a') && (c <= 'f')) {
            nibble = c - 'a' + 0x0A;
        } else {
            throw new NumberFormatException("Invalid hex digit '" + c +
                "'.");
        }

        if (evenByte) {
            nextByte = (byte) (nibble << 4);
        } else {
            nextByte += (byte) nibble;
            buffer[bufferOffset++] = nextByte;
        }

        evenByte = !evenByte;
    }

    return buffer;
}

回答by Mneckoee

I have a thermal printer with bluetooth and Usb connection, if your printer support ESC/POS command search for its commands on internet, for print raster image you should send this:

我有一台带蓝牙和 USB 连接的热敏打印机,如果您的打印机支持 ESC/POS 命令,请在互联网上搜索其命令,对于打印光栅图像,您应该发送:

[Name] Print raster bit image
[Format] ASCII GS v 0 m xL xH yL yH d1...dk
         Hex 1D 76 30 m xL xH yL yH d1...dk
         Decimal 29 118 48 m xL xH yL yH d1...dk
[Range] 0£ m£ 3, 48£ m £ 51
0£ xL£ 255
0£ xH£ 255
0£ yL£ 255
0£ d£ 255
k=(xL+ xH*256)*(yL+yH*256)

Follow your printer guidelines, it is may be different from others.

遵循您的打印机指南,它可能与其他指南不同。