Printing Receipts in Android
<p>Hello I am new to android I have spent so much time on trying to print a receipt in my app.  I use a <strong>Zicox XT4131</strong> thermal printer which <strong>connects via bluetooth</strong> to my tablet running the <strong>Android 4.4 OS</strong>.</p>

<p>SO far I have successfully been able to print only text on my receipt, now my next hurdle is trying to print barcodes, qrcodes and logos on my receipt, I have spent many hours on the internet trying to find a solution for this but nothing seems to work.</p>

<p>What I have learned however is that to print a bitmap image, i first need to convert it to a byte array (which I did) and write it to the output stream (which I also did), all I got after that was either a long blank space on the printer or some weird characters.</p>

<p>Right now I'm refusing to believe in 2016 printing from a tablet to a printer has no simple solution so I only assume I am going about all this the wrong way.</p>

<p>The way my app works is simple, in my activity where I have a preview of the purchase there is a button which upon being clicked sends a command to the bluetooth printer to print.  That is all, no converting to pdf and what not and having to select a printer.</p>

<p>So what I would like to know is what exactly is the way for me to correctly print a receipt from my tablet to my bluetooth printer and how exactly would I use such method to print a barcode, qrcode or logo along with the text on the receipt?</p>

<p>I do not want this to be voted as off topic as that may require me abandon this project (all because of printing) I just want one workable efficient solution that can help me do what I want to do.</p>

<p>This is my code for printing right now:</p>

<pre><code>import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Handler;
import android.view.View;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.nio.ByteBuffer;

import java.util.EnumMap;
import java.util.GregorianCalendar;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
</code></pre>

<p>These are the functions for it:</p>

<pre><code>// this will find a bluetooth printer device
void findBT() {

    try {
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        if(mBluetoothAdapter == null) {
            Toast.makeText(PurchaseSummaryActivity.this, "No bluetooth adapter available", Toast.LENGTH_SHORT).show();
        }

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

        Set&lt;BluetoothDevice&gt; pairedDevices = mBluetoothAdapter.getBondedDevices();

        if(pairedDevices.size() &gt; 0) {
            for (BluetoothDevice device : pairedDevices) {

                // RPP300 is the name of the bluetooth printer device
                // we got this name from the list of paired devices
                if (device.getName().equals("XT4131A")) {
                    mDevice = device;
                    break;
                }
            }
        }

        Toast.makeText(PurchaseSummaryActivity.this, "Bluetooth device found.", Toast.LENGTH_SHORT).show();

    }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");
        mSocket = mDevice.createRfcommSocketToServiceRecord(uuid);
        mSocket.connect();
        mOutputStream = mSocket.getOutputStream();
        mInputStream = mSocket.getInputStream();

        beginListenForData();

        Toast.makeText(PurchaseSummaryActivity.this, "Bluetooth Connection Opened", Toast.LENGTH_SHORT).show();

    } 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() &amp;&amp; !stopWorker) {

                    try {

                        int bytesAvailable = mInputStream.available();

                        if (bytesAvailable &gt; 0) {

                            byte[] packetBytes = new byte[bytesAvailable];
                            mInputStream.read(packetBytes);

                            for (int i = 0; i &lt; bytesAvailable; i++) {

                                byte b = packetBytes[i];
                                if (b == delimiter) {

                                    byte[] encodedBytes = new byte[readBufferPosition];
                                    System.arraycopy(
                                            readBuffer, 0,
                                            encodedBytes, 0,
                                            encodedBytes.length
                                    );

                                    // specify US-ASCII encoding
                                    final String data = new String(encodedBytes, "US-ASCII");
                                    readBufferPosition = 0;

                                    // tell the user data were sent to bluetooth printer device
                                    handler.post(new Runnable() {
                                        public void run() {
                                            Toast.makeText(PurchaseSummaryActivity.this, data, Toast.LENGTH_SHORT).show();
                                        }
                                    });

                                } else {
                                    readBuffer[readBufferPosition++] = b;
                                }
                            }
                        }

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

                }
            }
        });

        workerThread.start();

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

// this will send text data to be printed by the bluetooth printer
void printTickets(Event eo, Cart.Ticket to) throws IOException {
    try {
        byte[] arrayOfByte1 = { 27, 33, 0 };
        byte[] format = { 27, 33, 0 };
        // Bold
        format[2] = ((byte)(0x8 | arrayOfByte1[2]));
        // Height
        format[2] = ((byte)(0x10 | arrayOfByte1[2]));
        // Width
        format[2] = ((byte) (0x20 | arrayOfByte1[2]));
        byte[] center = new byte[]{ 0x1b, 0x61, 0x01 };
        // the text typed by the user
        StringBuilder msg = new StringBuilder();
        msg.append("\n");
        msg.append("\n");
        msg.append("\n myTicketGH");
        mOutputStream.write(center);
        mOutputStream.write(format);
        mOutputStream.write(msg.toString().getBytes());

        // Bold
        format[2] = ((byte)(0x8 | arrayOfByte1[2]));
        msg = new StringBuilder();
        msg.append("\n Address: No 10, Otublohum street");
        msg.append("\n North Industrial Area");
        msg.append("\n Tel.: 0266 8888 64");
        msg.append("\n");
        msg.append("\n");
        msg.append("\n");
        mOutputStream.write(center);
        mOutputStream.write(format);
        mOutputStream.write(msg.toString().getBytes());

        // Bold
        format[2] = ((byte)(0x8 | arrayOfByte1[2]));
        byte[] left = new byte[]{ 0x1b, 0x61, 0x00 };
        msg = new StringBuilder();
        msg.append("\n Event");
        mOutputStream.write(format);
        mOutputStream.write(left);
        mOutputStream.write(msg.toString().getBytes());

        mOutputStream.write(arrayOfByte1);

        left = new byte[]{ 0x1b, 0x61, 0x00 };
        msg = new StringBuilder();
        msg.append("\n  Name  : " + eo.getName());
        msg.append("\n  Date  : " + eo.getDate());
        msg.append("\n  Time  : " + eo.getTime());
        msg.append("\n  Venue : " + eo.getVenue());
        msg.append("\n");
        msg.append("\n");
        mOutputStream.write(arrayOfByte1);
        mOutputStream.write(left);
        mOutputStream.write(msg.toString().getBytes());

        // Bold
        format[2] = ((byte)(0x8 | arrayOfByte1[2]));
        msg = new StringBuilder();
        msg.append("\n Ticket");
        mOutputStream.write(format);
        mOutputStream.write(left);
        mOutputStream.write(msg.toString().getBytes());

        mOutputStream.write(arrayOfByte1);

        left = new byte[]{ 0x1b, 0x61, 0x00 };
        msg = new StringBuilder();
        msg.append("\n  Code              : " + to.getCode());
        msg.append("\n  Class             : " + to.getTclass() );
        msg.append("\n  Fee               : " + to.getPrice());
        msg.append("\n  Seat              : " + "N / A");
        msg.append("\n  Date of Purchase  : " + Calendar.getInstance().getTime().toString());
        msg.append("\n");
        msg.append("\n");
        msg.append("\n");
        msg.append("\n");
        msg.append("\n");
        mOutputStream.write(arrayOfByte1);
        mOutputStream.write(left);
        mOutputStream.write(msg.toString().getBytes());

        // barcode data
        String barcode_data = "123456";

        // barcode image
        byte[] barCodeBytes;
        String barCodeHex = "";

        try {
            barCode = encodeAsBitmap(barcode_data, BarcodeFormat.CODE_128, 300, 40);
            barCode = bitmapToGrayscale(barCode);
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            barCodeBytes = stream.toByteArray();
            mOutputStream.write(barCodeBytes);


        } catch (WriterException e) {
             e.printStackTrace();
        }



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

// close the connection to bluetooth printer.
void closeBT() throws IOException {
    try {
        stopWorker = true;
        mOutputStream.close();
        mInputStream.close();
        mSocket.close();
        // myLabel.setText("Bluetooth Closed");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
</code></pre>

<p>This is my onClickEvent handler:</p>

<pre><code>this.buttonNextView.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        try {
            findBT();
            openBT();

            for (int i = 0; i &lt; ta.length(); i++)
            {
                try {
                    printTickets(eo, new Cart(). new Ticket(
                            ta.getJSONObject(i).getInt("id"),
                            ta.getJSONObject(i).getString("code"),
                            ta.getJSONObject(i).getString("class"),
                            ta.getJSONObject(i).getString("description"),
                            Float.parseFloat(ta.getJSONObject(i).getString("price")),
                            ta.getJSONObject(i).getInt("quantity")

                    ));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            closeBT();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
});
</code></pre>

<p>And yes the printer I use is capable of printing barcodes and qr codes.</p>