一、打印的效果图,打印照片+二维码+文字
二、蓝牙相关组件介绍
/**
* 代表本地蓝牙适配器(蓝牙无线电)。BluetoothAdapter是所有蓝牙交互的入口。
* 使用这个你可以发现其他蓝牙设备,查询已配对的设备列表,
* 使用一个已知的MAC地址来实例化一个BluetoothDevice,
* 以及创建一个BluetoothServerSocket来为监听与其他设备的通信。
*/
private BluetoothAdapter mBluetoothAdapter = null;
/**
* 代表一个远程蓝牙设备,使用这个来请求一个与远程设备的BluetoothSocket连接,
* 或者查询关于设备名称、地址、类和连接状态等设备信息。
*/
private BluetoothDevice mBluetoothDevice = null;
/**
* 代表一个蓝牙socket的接口(和TCP Socket类似)。这是一个连接点,
* 它允许一个应用与其他蓝牙设备通过InputStream和OutputStream交换数据。
*/
private BluetoothSocket mBluetoothSocket = null;
三、搜索蓝牙设备
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_device);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//注册设备被发现时的广播
IntentFilter filter1=new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver,filter1);
//注册一个搜索结束时的广播
IntentFilter filter2=new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver,filter2);
IntentFilter filter3=new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
registerReceiver(mReceiver,filter3);
IntentFilter filter4=new IntentFilter(BluetoothAdapter.ACTION_REQUEST_ENABLE); // 开关变化的广播
registerReceiver(mReceiver,filter4);
Button btn = (Button)findViewById(R.id.btnV1); // 设备搜索
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mBluetoothAdapter != null){
if(!mBluetoothAdapter.isEnabled()){ // 蓝牙开关是否打开
mBluetoothAdapter.enable();
}else{
Log.d(TAG,"mBluetoothAdapter.isEnabled() == true");
}
mBluetoothAdapter.startDiscovery(); // 开始搜索蓝牙设备,通过监听广播接收搜索到的设备
}else{
Toast.makeText(SearchBlueToothActivity.this,"该设备没有蓝牙模块",Toast.LENGTH_SHORT).show();
}
}
});
}
/**
* 接收搜索蓝牙设备结果的信息
*/
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
BluetoothDevice device=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG,"device = " + device);
if(device.getBondState()==BluetoothDevice.BOND_BONDED){ //显示已配对设备
Log.d(TAG,"已配对设备 : " + device.getName() + ", " + device.getName());
}else{
Log.d(TAG,"未配对设备 : " + device.getName() + ", " + device.getName());
}
}else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
Log.d(TAG,"搜索完成...");
}else if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
Log.d(TAG,"搜索开始...");
}else if(BluetoothAdapter.ACTION_REQUEST_ENABLE.equals(action)){
Log.d(TAG,"蓝牙打开...");
}
}
};
四、蓝牙打印 // 这里写死了,要修改获取蓝牙设备的方式
public class BtPrint {
private static BtPrint instance;
public static String TAG = BtPrint.class.getSimpleName();
private List<String> mpairedDeviceList = new ArrayList<String>();
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothDevice mBluetoothDevice = null;
private BluetoothSocket mBluetoothSocket = null;
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private OutputStream mOutputStream = null;
Set<BluetoothDevice> pairedDevices = null;
/**
* @return
* @throws
* @Title: getInstance
*/
public static BtPrint getInstance() {
if (instance == null) {
synchronized (BtPrint.class) {
if (instance == null) {
instance = new BtPrint();
}
}
}
return instance;
}
public void releasePrint(){
mBluetoothAdapter = null;
if(mBluetoothSocket != null){
try {
mBluetoothSocket.close();
mBluetoothSocket = null;
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG,"releasePrint(),IOException :",e);
mBluetoothSocket = null;
}
}
}
/**
* 连接打印机设备
*/
public void connectPrinter(){
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null){ // 蓝牙功能没有打开,UI界面弹出打开蓝牙功能
Log.d(TAG,"connectPrinter(),mBluetoothAdapter = null");
}else if(mBluetoothAdapter.isEnabled()){ // 蓝牙已经打开
// 列出已经配对过的设备
String getName = mBluetoothAdapter.getName();
Log.d(TAG, "getName = " + getName);
pairedDevices = mBluetoothAdapter.getBondedDevices(); // 已经配对了的设备?
while (mpairedDeviceList.size() > 1) {
mpairedDeviceList.remove(1);
}
if (pairedDevices.size() == 0) {
Log.d(TAG,"connectPrinter(),pairedDevices.size == 0");
return; // 没有配对过的设备
}
for (BluetoothDevice device : pairedDevices) {
getName = device.getAddress();
mpairedDeviceList.add(getName);//蓝牙名
}
String temString = mpairedDeviceList.get(0);
Log.d(TAG,"temString = " + temString + ", mBluetoothDevice = " + mBluetoothDevice);
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(temString);
try {
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(SPP_UUID);
mBluetoothSocket.connect();
Log.d(TAG,"mBluetoothDevice = " + mBluetoothDevice +", mBluetoothSocket = " + mBluetoothSocket);
} catch (IOException e) {
Log.d(TAG,"connectPrinter(),IOException :",e);
}
}else { // 蓝牙未打开
Log.d(TAG,"connectPrinter(),bluetooth isnot open");
}
}
private static int printTimes = 0; // 出错时重试打印的次数
/**
* 打印小条
*/
public void printVerifyData(String tmpName,
String tmpIdNo,
String curName,
String idcardNo,
String headerPic) {
if(mBluetoothSocket == null){
connectPrinter();
}else{
if(!mBluetoothSocket.isConnected()){
try {
mBluetoothSocket.connect();
} catch (IOException e) {
e.printStackTrace();
}
}else{
Log.d(TAG,"printVerifyData(),mBluetoothSocket.isConnected.");
}
}
// 打印图片
// 打印标题
String title = Const.VALUE.TITLE;
String line = ".......................................";
try {
mOutputStream = mBluetoothSocket.getOutputStream();
PrintUtils PrintUtils = new PrintUtils();
PrintUtils.setOutputStream(mOutputStream);
PrintUtils.selectCommand(PrintUtils.RESET);
PrintUtils.selectCommand(PrintUtils.LINE_SPACING_DEFAULT);
PrintUtils.selectCommand(PrintUtils.LINE_SPACING);
PrintUtils.selectCommand(PrintUtils.ALIGN_CENTER);
PrintUtils.selectCommand(PrintUtils.BOLD);
PrintUtils.selectCommand(PrintUtils.DOUBLE_HEIGHT_WIDTH); //宽高加倍
PrintUtils.printText(title + "\n");
PrintUtils.selectCommand(PrintUtils.BOLD_CANCEL);
PrintUtils.selectCommand(PrintUtils.NORMAL);
PrintUtils.printText(line + "\n");
// 打印照片
Bitmap image = ImageUtils.getBitmap(headerPic);
image = convertGreyImgByFloyd(image);
byte[]imageData = PrinterUtils.decodeBitmap(image);
PrintUtils.selectCommand(imageData);
PrintUtils.printText(line + "\n");
PrintUtils.selectCommand(PrintUtils.ALIGN_CENTER);
PrintUtils.selectCommand(PrintUtils.BOLD);
Log.d(TAG,"BtPrint # tmpName = " + tmpName + ",tmpIdNo = " + tmpIdNo);
PrintUtils.printText(PrintUtils.printTwoData("姓名:", tmpName +"\n"));
PrintUtils.printText(PrintUtils.printTwoData("身份证号码:", tmpIdNo+"\n"));
PrintUtils.printText(PrintUtils.printTwoData("凭证有效期:", TimeUtils.date2String(new Date(),new SimpleDateFormat("yyyy年MM月dd日"))+"\n"));
PrintUtils.selectCommand(PrintUtils.BOLD_CANCEL);
PrintUtils.printText(line + "\n");
String oriString = curName+"|" +idcardNo;
Log.d(TAG,"BtPrint # oriString = " + oriString);
String qrString = Base64.encodeToString(oriString.getBytes("UTF-8"),Base64.NO_WRAP);
Log.d(TAG,"qrString = " + qrString);
Bitmap qrCodeImage = QRCodeUtil.createQRCodeBitmap(qrString, 300, "0");
byte[] qrData = PrinterUtils.decodeBitmap(qrCodeImage);
PrintUtils.selectCommand(qrData);
PrintUtils.printText(line + "\n");
PrintUtils.selectCommand(PrintUtils.NORMAL);
PrintUtils.selectCommand(PrintUtils.ALIGN_LEFT);
PrintUtils.selectCommand(PrintUtils.BOLD);
PrintUtils.selectCommand(PrintUtils.COLUMN_SPACING);
String tips1 = " lajdflajdfl,"+ "\n";
String tips2 = " lasdjflkajsdlfjalksdjflajsdflja"+"\n";
PrintUtils.printText(tips1);
PrintUtils.printText(tips2);
PrintUtils.selectCommand(PrintUtils.BOLD_CANCEL);
PrintUtils.selectCommand(PrintUtils.COLUMN_SPACING_CANCEL);
PrintUtils.printText("\n\n");
// 切纸
mOutputStream = mBluetoothSocket.getOutputStream();
mOutputStream.write(new byte[]{0x0a, 0x0a, 0x1d, 0x56, 0x01});
mOutputStream.flush();
BusEvent busEvent = new BusEvent();
busEvent.action = "printer_completed";
busEvent.data = "ok";
EventBus.getDefault().post(busEvent);
} catch (Exception e) {
Log.d(TAG, "print error printTimes = " + printTimes);
if(printTimes < 5){
printTimes ++;
printVerifyData(tmpName,tmpIdNo,curName,idcardNo,headerPic);
}else{
Log.d(TAG, "print error :", e);
LogUtils.file(e.getCause() + "--" + e.getMessage());
sendPrintErr();
}
}
}
/**
* 发送打印错误的信息
*/
private void sendPrintErr(){
BusEvent busEvent = new BusEvent();
busEvent.action = "printer_completed";
busEvent.data = "error";
EventBus.getDefault().post(busEvent);
BtPrint.getInstance().releasePrint();
}
public Bitmap convertGreyImgByFloyd(Bitmap img) {
int width = img.getWidth();
//获取位图的宽
int height = img.getHeight();
//获取位图的高 \
int[] pixels = new int[width * height];
//通过位图的大小创建像素点数组
img.getPixels(pixels, 0, width, 0, 0, width, height);
int[] gray = new int[height * width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int grey = pixels[width * i + j];
int red = ((grey & 0x00FF0000) >> 16);
gray[width * i + j] = red;
}
}
int e = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int g = gray[width * i + j];
if (g >= 128) {
pixels[width * i + j] = 0xffffffff;
e = g - 255;
} else {
pixels[width * i + j] = 0xff000000;
e = g - 0;
}
if (j < width - 1 && i < height - 1) {
//右边像素处理
gray[width * i + j + 1] += 3 * e / 8;
//下
gray[width * (i + 1) + j] += 3 * e / 8;
//右下
gray[width * (i + 1) + j + 1] += e / 4;
} else if (j == width - 1 && i < height - 1) {
//靠右或靠下边的像素的情况
//下方像素处理
gray[width * (i + 1) + j] += 3 * e / 8;
} else if (j < width - 1 && i == height - 1) {
//右边像素处理
gray[width * (i) + j + 1] += e / 4;
}
}
}
Bitmap mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
mBitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return mBitmap;
}
}
PrintUtils
import android.annotation.SuppressLint;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
public class PrintUtils {
private static final int LINE_BYTE_SIZE = 32;
private static OutputStream outputStream = null;
public static void setOutputStream(OutputStream outputStream) {
PrintUtils.outputStream = outputStream;
}
/**
* 打印文字
*
* @param text 要打印的文字
*/
public static void printText(String text) {
try {
byte[] data = text.getBytes("gbk");
outputStream.write(data, 0, data.length);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 设置打印格式
*
* @param command 格式指令
*/
public static void selectCommand(byte[] command) {
try {
outputStream.write(command);
outputStream.flush();
} catch (IOException e) {
//Toast.makeText(this.context, "发送失败!", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
/**
* 复位打印机
*/
public static final byte[] RESET = {0x1b, 0x40};
/**
* 左对齐
*/
public static final byte[] ALIGN_LEFT = {0x1b, 0x61, 0x00};
/**
* 中间对齐
*/
public static final byte[] ALIGN_CENTER = {0x1b, 0x61, 0x01};
/**
* 选择加粗模式
*/
public static final byte[] BOLD = {0x1b, 0x45, 0x01};
/**
* 取消加粗模式
*/
public static final byte[] BOLD_CANCEL = {0x1b, 0x45, 0x00};
/**
* 宽高加倍
*/
public static final byte[] DOUBLE_HEIGHT_WIDTH = {0x1d, 0x21, 0x11};
/**
* 字体不放大
*/
public static final byte[] NORMAL = {0x1d, 0x21, 0x00};
/**
* 设置默认行间距
*/
public static final byte[] LINE_SPACING_DEFAULT = {0x1b, 0x32};
// /**
// * 设置行间距
// */
public static final byte[] LINE_SPACING = {0x1b, 0x33, 0x50}; // 20的行间距(0,255)
/**
* 设置字符间距
*/
public static final byte[] COLUMN_SPACING = {0x1b, 0x20, 0x25};
/**
* 取消设置字符间距
*/
public static final byte[] COLUMN_SPACING_CANCEL = {0x1b, 0x20, 0x00};
/**
* 打印两列
*
* @param leftText 左侧文字
* @param rightText 右侧文字
* @return
*/
@SuppressLint("NewApi")
public static String printTwoData(String leftText, String rightText) {
StringBuilder sb = new StringBuilder();
int leftTextLength = getBytesLength(leftText);
int rightTextLength = getBytesLength(rightText);
sb.append(leftText);
// 计算两侧文字中间的空格
int marginBetweenMiddleAndRight = LINE_BYTE_SIZE - leftTextLength - rightTextLength;
for (int i = 0; i < marginBetweenMiddleAndRight; i++) {
sb.append(" ");
}
sb.append(rightText);
return sb.toString();
}
/**
* 获取数据长度
*
* @param msg
* @return
*/
@SuppressLint("NewApi")
private static int getBytesLength(String msg) {
return msg.getBytes(Charset.forName("GB2312")).length;
}
}