Android连接蓝牙并打印
- 蓝牙连接和打印数据发送
- 打印管理类
- 打印工具类
- 最后
蓝牙连接和打印数据发送
/**
* 保持蓝牙连接的线程
*/
public class BluetoothThread extends Thread {
// 固定不变,表示蓝牙通用串口服务
private static final UUID BLUETOOTH_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private BluetoothSocket mSocket; // 蓝牙连接的socket
private OutputStream mOutputStream; // 用于打印数据的输出流
private Handler mHandler;
private Callback mCallback;
private BluetoothDevice mDevice;
public BluetoothThread(BluetoothDevice bondedDevice) throws Exception {
mDevice = bondedDevice;
if (bondedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
throw new Exception("BluetoothDevice has not bonded.");
}
try {
mSocket = bondedDevice.createRfcommSocketToServiceRecord(BLUETOOTH_UUID); // 创建连接的Socket对象
mSocket.connect();
mOutputStream = mSocket.getOutputStream();
} catch (IOException e) {
if (mSocket != null) {
try {
mSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
throw new Exception("BluetoothDevice connect fail. " + e.getMessage());
}
}
public void quit() {
if (mHandler == null) {
return;
}
mHandler.sendEmptyMessage(-1);
}
/**
* 发送打印信息(文本或图片 字节码数值格式)
* @param bytes
*/
public void write(byte[] bytes) {
if (mHandler == null) {
return;
}
Message msg = mHandler.obtainMessage(0);
msg.obj = bytes;
mHandler.sendMessage(msg);
}
public boolean isInnerPrinter() {
return "00:11:22:33:44:55".equals(mDevice.getAddress());
}
@SuppressLint("HandlerLeak")
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == -1) {
Looper looper = Looper.myLooper();
if (looper != null) {
looper.quit();
}
removeCallbacksAndMessages(null);
mHandler = null;
} else {
byte[] bytes = (byte[]) msg.obj;
try {
mOutputStream.write(bytes);
if (mCallback != null) {
mCallback.onWriteFinished(mDevice);
}
} catch (IOException e) {
if (mCallback != null) {
mCallback.onWriteFail(mDevice);
}
}
}
}
};
Looper.loop();
// 线程结束,则关闭
try {
mOutputStream.close();
mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setCallback(Callback callback) {
mCallback = callback;
}
interface Callback {
void onWriteFinished(BluetoothDevice device);
void onWriteFail(BluetoothDevice device);
}
}
打印管理类
/**
* 负责蓝牙相关的业务逻辑
*/
public class BluetoothManager {
private static BluetoothManager sBluetoothManager; // 防止创建多次,设置为单例
private static Map<BluetoothDevice, BluetoothThread> mBluetoothThreadMap = new HashMap<>();
private int mPrintingThreadCount = 0;
private BluetoothManager() {
// 通过getInstance()方法获取实例
}
/**
* 获取当前类示例
*/
public synchronized static BluetoothManager getInstance() {
if (sBluetoothManager == null) {
sBluetoothManager = new BluetoothManager();
}
return sBluetoothManager;
}
/**
* 连接蓝牙设备
*/
public static boolean connect(BluetoothDevice device) {
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
BluetoothThread thread = mBluetoothThreadMap.get(device);
if (thread == null) {
try {
thread = new BluetoothThread(device);
thread.start();
mBluetoothThreadMap.put(device, thread);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} else {
return true;
}
}
private void preparePrint() {
int count;
do {
synchronized (BluetoothManager.class) {
count = mPrintingThreadCount;
if (count <= 0) {
mPrintingThreadCount = mBluetoothThreadMap.size();
}
}
} while (count > 0);
}
/**
* 断开当前正在连接的蓝牙设备
*/
public void disconnect(BluetoothDevice device) {
BluetoothThread thread = mBluetoothThreadMap.get(device);
if (thread != null) {
thread.quit();
mBluetoothThreadMap.remove(device);
}
}
/**
* 指定某个蓝牙设备打印文本内容
*
* @param text 打印的文本内容
*/
public void printText(BluetoothDevice device, String text, final OnPrintListener listener) {
if (TextUtils.isEmpty(text)) {
return;
}
byte[] bytes = new byte[0];
try {
bytes = text.getBytes("GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
addListenerAndPrint(device,bytes,listener);
}
/**
* 指定某个蓝牙设备打印图片
* @param device
* @param bitmap
*/
public void printBitmap(BluetoothDevice device, Bitmap bitmap, final OnPrintListener listener) {
if (null==bitmap) {
return;
}
byte[] bit = PrintUtil.draw2PxPoint(bitmap);
addListenerAndPrint(device,bit,listener);
}
private void addListenerAndPrint(BluetoothDevice device,byte[] bit,final OnPrintListener listener){
final BluetoothThread thread = mBluetoothThreadMap.get(device);
if (thread == null) {
throw new RuntimeException("蓝牙连接不存在!");
}
if (listener != null) {
thread.setCallback(new BluetoothThread.Callback() {
@Override
public void onWriteFinished(BluetoothDevice device) {
thread.setCallback(null);
listener.onPrintFinished();
}
@Override
public void onWriteFail(BluetoothDevice device) {
thread.setCallback(null);
listener.onPrintFail(device);
}
});
}
thread.write(bit);
}
public interface OnPrintListener {
void onPrintFinished();
void onPrintFail(BluetoothDevice device);
}
}
打印工具类
public class PrintUtil {
/**
* 对图片进行压缩(去除透明度)
*
* @param bitmap
*/
public static Bitmap compressPic(Bitmap bitmap) {
// 获取这个图片的宽和高
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// 指定调整后的宽度和高度
int newWidth = 240;
int newHeight = 240;
Bitmap targetBmp = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
Canvas targetCanvas = new Canvas(targetBmp);
targetCanvas.drawColor(0xffffffff);
targetCanvas.drawBitmap(bitmap, new Rect(0, 0, width, height), new Rect(0, 0, newWidth, newHeight), null);
return targetBmp;
}
/*************************************************************************
* 假设一个240*240的图片,分辨率设为24, 共分10行打印
* 每一行,是一个 240*24 的点阵, 每一列有24个点,存储在3个byte里面。
* 每个byte存储8个像素点信息。因为只有黑白两色,所以对应为1的位是黑色,对应为0的位是白色
**************************************************************************/
/**
* 把一张Bitmap图片转化为打印机可以打印的字节流
*
* @param bmp
* @return
*/
public static byte[] draw2PxPoint(Bitmap bmp) {
// bmp = compressPic(bmp);
//用来存储转换后的 bitmap 数据。为什么要再加1000,这是为了应对当图片高度无法
//整除24时的情况。比如bitmap 分辨率为 240 * 250,占用 7500 byte,
//但是实际上要存储11行数据,每一行需要 24 * 240 / 8 =720byte 的空间。再加上一些指令存储的开销,
//所以多申请 1000byte 的空间是稳妥的,不然运行时会抛出数组访问越界的异常。
int size = bmp.getWidth() * bmp.getHeight() / 8 + 5000;
byte[] data = new byte[size];
int k = 0;
//设置行距为0的指令
data[k++] = 0x1B;
data[k++] = 0x33;
data[k++] = 0x00;
// 逐行打印
for (int j = 0; j < bmp.getHeight() / 24f; j++) {
//打印图片的指令
data[k++] = 0x1B;
data[k++] = 0x2A;
data[k++] = 33;
data[k++] = (byte) (bmp.getWidth() % 256); //nL
data[k++] = (byte) (bmp.getWidth() / 256); //nH
//对于每一行,逐列打印
for (int i = 0; i < bmp.getWidth(); i++) {
//每一列24个像素点,分为3个字节存储
for (int m = 0; m < 3; m++) {
//每个字节表示8个像素点,0表示白色,1表示黑色
for (int n = 0; n < 8; n++) {
byte b = px2Byte(i, j * 24 + m * 8 + n, bmp);
data[k] += data[k] + b;
}
k++;
}
}
data[k++] = 10;//换行
}
return data;
}
/**
* 灰度图片黑白化,黑色是1,白色是0
*
* @param x 横坐标
* @param y 纵坐标
* @param bit 位图
* @return
*/
public static byte px2Byte(int x, int y, Bitmap bit) {
if (x < bit.getWidth() && y < bit.getHeight()) {
byte b;
int pixel = bit.getPixel(x, y);
int red = (pixel & 0x00ff0000) >> 16; // 取高两位
int green = (pixel & 0x0000ff00) >> 8; // 取中两位
int blue = pixel & 0x000000ff; // 取低两位
int gray = RGB2Gray(red, green, blue);
if (gray < 128) {
b = 1;
} else {
b = 0;
}
return b;
}
return 0;
}
/**
* 图片灰度的转化
*/
private static int RGB2Gray(int r, int g, int b) {
int gray = (int) (0.29900 * r + 0.58700 * g + 0.11400 * b); //灰度转化公式
return gray;
}
}
最后
代码整合了诸多大佬的博客,非原创。