Swift 蓝牙打印机数据排版

蓝牙打印机打印排版
本次使用的是 Swift 5构建,蓝牙连接打印机打印

[TOC]

  • 功能包含:
  • 两列排版
  • 两列左右侧标题自动换行
  • 三列排版
  • 四列排版
  • 四列排版自动换行
  • 根据打印纸的大小(50mm、80mm)自动排版
  • 对齐方式(两列左对齐、有对齐)
  • 单列左对齐、居中对齐、右对齐
  • 字体大小设置

先上效果图 80MM打印 50MM 打印

备注两列自动换行、四列商品自动换行

80.jpeg
50.jpeg

使用方法

把BaseManager.swift 文件导入项目 (文件内容在下面)

在需要使用的VC中

    // 变量生命
    var manager:BaseManager?


    // 初始化
    if manager == nil{
        manager = BaseManager()
        manager?.delegate = self
        manager?.successBlock = {
            self.printerBtn.isEnabled = true
            print("连接成功")
            self.tableView.reloadData()
        }
    }
    
    // 接收搜索到打印机的回调
    extension ViewController: BaseManagerDelegate {
        func discoverPeripheral(_ peripheral: CBPeripheral) {
            peripheralArr.append(peripheral)
            tableView.reloadData()
        }
    }
    
    // 打印测试数据
    @objc func printTextAction() {
        manager?.testPrint()
    }

    

核心代码


    /**
     * 打印四列 自动换行
     * max 最大4字
     * @param leftText   左侧文字
     * @param middleLeftText 中间左文字
     * @param middleRIghtText 中间右文字
     * @param rightText  右侧文字
     * @return
     */
    func printFourDataAutoLine(leftText: String, middleLeftText: String, middleRIghtText: String, rightText: String) ->[Data]{
        // 存放打印的数据(data)
        var printerAllDataArr: [Data] = []
        // 每一列可显示汉子的个数
        let maxTextCount = LINE_BYTE_SIZE/4
        maxLine = 0
        let leftStrArr = printStrArrWithText(text: leftText, maxTextCount: maxTextCount)
        var middleLeftStrArr = printStrArrWithText(text: middleLeftText, maxTextCount: maxTextCount)
        var middleRightStrArr = printStrArrWithText(text: middleRIghtText, maxTextCount: maxTextCount)
        var rightStrArr = printStrArrWithText(text: rightText, maxTextCount: maxTextCount)
        for i in 0.. [String] {
        let enc = CFStringConvertEncodingToNSStringEncoding(UInt32(CFStringEncodings.GB_18030_2000.rawValue))

        var textArr:[String] = []
        let textData = setTitle(text: text) as NSData
        let textLength = textData.length
        if textLength > maxTextCount {
            // 需要几行
            let lines = textLength / maxTextCount
            // 余数
            let remainder = textLength % maxTextCount
            // 设置最大支持7行
            for i in 0..String{
        var strText = ""

        let leftTextLength = (setTitle(text: leftText) as NSData).length
        let middleTextLength = (setTitle(text: middleText)  as NSData).length
        let rightTextLength = (setTitle(text: rightText)  as NSData).length

        strText = strText + leftText

        // 计算左侧文字和中间文字的空格长度
        let marginBetweenLeftAndMiddle = LEFT_LENGTH - leftTextLength - middleTextLength / 2;
        for _ in 0..Data {
        var strText = ""
        let leftTextLength = (setTitle(text: leftText) as NSData).length
        let rightTextLength = (setTitle(text: rightText)  as NSData).length
        strText = strText + leftText

        // 计算文字中间的空格
        let marginBetweenMiddleAndRight = LINE_BYTE_SIZE - leftTextLength - rightTextLength;
        for _ in 0..Data {

        // 存放打印的数据(data)
        let printerData: NSMutableData = NSMutableData.init()

        let valueCount = right.count
        if valueCount > maxText {
            // 需要几行
            let lines = valueCount / maxText
            // 余数
            let remainder = valueCount % maxText
            for i in 0..Data {
        let data = text.data(using: String.Encoding(rawValue: enc))! as NSData

        if (data.length > maxChar) {
            let lines = data.length / maxChar
            let remainder = data.length % maxChar
            var tempData: NSMutableData = NSMutableData.init()
            for i in 0..

代码中使用的的数字含义

    // 这些数字都是10进制的 ASCII码 
    let ESC:UInt8   = 27    //换码
    let FS:UInt8    = 28    //文本分隔符
    let GS:UInt8    = 29    //组分隔符
    let DLE:UInt8   = 16    //数据连接换码
    let EOT:UInt8   = 4     //传输结束
    let ENQ:UInt8   = 5     //询问字符
    let SP:UInt8    = 32    //空格
    let HT:UInt8    = 9     //横向列表
    let LF:UInt8    = 10    //打印并换行(水平定位)
    let ER:UInt8    = 13    //归位键
    let FF:UInt8    = 12    //走纸控制(打印并回到标准模式(在页模式下) )

如何知道打印机支持的指令

本项目中有一个 <<58MM热敏打印机编程手册>> 这里面记录了,打印机支持的所有格式,可以自行查看

2019年12月5日 补充一下 BaseManager这个类文件内容

//
//  BaseManager.swift
//  WorldDoctor
//
//  Created by Max on 2019/7.20
//  Copyright © 2019年 xiangguohe. All rights reserved.
//

// 蓝牙打印机

import UIKit
import CoreBluetooth


protocol BaseManagerDelegate {
    // 设备发现回调 刷新页面
    func discoverPeripheral(_ peripheral: CBPeripheral)
}

class BaseManager: NSObject {
    var successBlock:(()->Void)?
    var delegate: BaseManagerDelegate?
    var command = BTPrinter()
    var manager: CBCentralManager!
    var currentPeripheral: CBPeripheral?
    var writeCharacteristic: CBCharacteristic!
    var currentServiceUUID: String?
    var currentWriteUUID: String?
    var currentScanName: String?
    let serviceId = "49535343-FE7D-4AE5-8FA9-9FAFD205E455"
    let WriteUUID = "49535343-8841-43F4-A8D4-ECBE34729BB3"
    
    override init() {
        super.init()
        self.manager = CBCentralManager(delegate: nil, queue: nil)
        self.manager.delegate = self;
        currentServiceUUID = serviceId
        currentWriteUUID = WriteUUID
        currentScanName = "Printer"
        updatePrinter()
    }

    //  刷新设备
    func updatePrinter() {
        // 发现设备 调用之后 中心管理者会为他的委托对象调用
        manager.scanForPeripherals(withServices: nil, options: nil)
    }
    //  链接设备
    func connectPrinter(peripheral: CBPeripheral) {
        if peripheral.name != currentPeripheral?.name  {
            if currentPeripheral != nil {
                manager.cancelPeripheralConnection(currentPeripheral!)
            }
        }else if peripheral.name == currentPeripheral?.name {

        }
        currentPeripheral = peripheral
        manager.connect(peripheral, options: nil)
    }
    
}
//MARK: - 蓝牙中心设备代理方法
extension BaseManager: CBCentralManagerDelegate {
    //    1.
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        
        var message = "";
        switch central.state {
        case .unknown:
            message = "蓝牙系统错误"
        case .resetting:
            message = "请重新开启手机蓝牙"
        case .unsupported:
            message = "该手机不支持蓝牙"
        case .unauthorized:
            message = "蓝牙验证失败"
        case .poweredOff://蓝牙没开启,直接到设置
            message = "蓝牙没有开启"
            
        case .poweredOn:
            central.scanForPeripherals(withServices: nil, options: nil)
        @unknown default:
            break
        }
        print(message)
    }
    
    //    2
    public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        
        print("设备名-->"+(peripheral.name ?? ""))
        let peripheralName = peripheral.name ?? ""
        let contains = (self.currentScanName != nil) && peripheralName.contains(self.currentScanName!)

        if contains {
            self.delegate?.discoverPeripheral(peripheral)
        }
    }
    //    3
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        //        链接成功之后 停止扫描
        central.stopScan()
        //蓝牙连接成功
        if currentPeripheral != nil {
            currentPeripheral!.delegate = self
            currentPeripheral!.discoverServices([CBUUID(string: self.currentServiceUUID!)])
        }
        successBlock?()

    }

    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
        print("断开链接 设备 =\(peripheral.name ?? "")")
    }
}
//MARK: - 蓝牙外围设备代理方法
extension BaseManager: CBPeripheralDelegate {
    //发现服务
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        print("当前currentServiceUUID-->"+(self.currentServiceUUID ?? ""))
        for service in peripheral.services! {
            print("寻找服务,服务有:\(service)"+"   id-->"+service.uuid.uuidString)
            if service.uuid.uuidString == self.currentServiceUUID {
                peripheral.discoverCharacteristics(nil, for: service)
                print("找到当前服务了。。。。")
                break
            }
        }
    }
    
    //发现特征
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        for characteristic in service.characteristics! {
            print("特征有\(characteristic)")
            if characteristic.uuid.uuidString == self.currentWriteUUID {
                self.writeCharacteristic = characteristic
                print("-找到了写服务----\(characteristic)")
            }
        }
    }
    
    ///发送指令给打印机
    private func send(value:Data) {
        currentPeripheral!.writeValue(value, for: writeCharacteristic, type: CBCharacteristicWriteType.withResponse)
    }
    ///发送指令
    func sendCommand(_ data:Data) {
        send(value: data)
    }
}

// MARK: 打印机封装方法
class BTPrinter
{
    ///一行最多打印字符个数
    let kRowMaxLength = 32
    let ESC:UInt8   = 27    //换码 0x1B
    let FS:UInt8    = 28    //文本分隔符 0x1c
    let GS:UInt8    = 29    //组分隔符
    let DLE:UInt8   = 16    //数据连接换码
    let EOT:UInt8   = 4     //传输结束
    let ENQ:UInt8   = 5     //询问字符
    let SP:UInt8    = 32    //空格
    let HT:UInt8    = 9     //横向列表
    let LF:UInt8    = 10    //打印并换行(水平定位)
    let CR:UInt8    = 13    //归位键
    let FF:UInt8    = 12    //走纸控制(打印并回到标准模式(在页模式下) )
    
    /*------------------------------------------------------------------------------------------------*/
    //    2019.7.24 新增方法
    /*------------------------------------------------------------------------------------------------*/

    let enc = CFStringConvertEncodingToNSStringEncoding(UInt32(CFStringEncodings.GB_18030_2000.rawValue))

    //   text 内容。value 右侧内容 左侧列 支持的最大显示 超过四字自动换行
    func setText(text: String,value: String,maxChar:Int)->Data {
        let data = text.data(using: String.Encoding(rawValue: enc))! as NSData

        if (data.length > maxChar) {
            let lines = data.length / maxChar
            let remainder = data.length % maxChar
            var tempData: NSMutableData = NSMutableData.init()
            for i in 0.. Data {
        let enc = CFStringConvertEncodingToNSStringEncoding(UInt32(CFStringEncodings.GB_18030_2000.rawValue))
        ///这里一定要GB_18030_2000,测试过用utf-系列是乱码,踩坑了。
        let data = text.data(using: String.Encoding(rawValue: enc), allowLossyConversion: false)
        if data != nil{
            return data!
        }
        return Data()
    }
    /**
     *  设置偏移文字
     *
     *  @param value 右侧内容
     */
    func setOffsetText(value: String) -> NSData {
        let attributes = [NSAttributedString.Key.font:UIFont.systemFont(ofSize: 22.0)] //设置字体大小
        let option = NSStringDrawingOptions.usesLineFragmentOrigin
        //获取字符串的frame
        let rect:CGRect = value.boundingRect(with: CGSize.init(width: 320.0, height: 999.9), options: option, attributes: attributes, context: nil)
        let valueWidth: Int = Int(rect.size.width)
        let preNum = (UserDefaults.standard.value(forKey: "printerNum") ?? 0) as! Int
        let offset = (preNum == 0 ? 384 : 566) - valueWidth
        let remainder = offset % 256
        let consult = offset / 256;
        var foo:[UInt8] = [0x1B, 0x24]
        foo.append(UInt8(remainder))
        foo.append(UInt8(consult))
        let data = Data.init(bytes: foo) as NSData
        let mutData = NSMutableData.init()
        mutData.append(data.bytes, length: data.length)
        let titleData = setTitle(text: value) as NSData
        mutData.append(titleData.bytes, length: titleData.length)
        return mutData as NSData
    }
    /*------------------------------------------------------------------------------------------------*/

    ///初始化打印机
    func clear() -> Data {
        return Data.init([ESC, 64])
    }
    
    ///打印空格
    func printBlank(number:Int) -> Data {
        var foo:[UInt8] = []
        for _ in 0.. Data {
        var foo:[UInt8] = []
        for _ in 0.. Data {
        var foo:[UInt8] = []
        foo.append(ESC)
        foo.append(45)
        foo.append(1)//一个像素
        return Data.init(foo)
    }
    
    ///取消绘制下划线
    func cancelUnderline() -> Data {
        var foo:[UInt8] = []
        foo.append(ESC)
        foo.append(45)
        foo.append(0)
        return Data.init(foo)
    }
    
    ///加粗文字
    func boldOn() -> Data {
        var foo:[UInt8] = []
        foo.append(ESC)
        foo.append(69)
        foo.append(0xF)
        return Data.init(foo)
    }
    
    ///取消加粗
    func boldOff() -> Data {
        var foo:[UInt8] = []
        foo.append(ESC)
        foo.append(69)
        foo.append(0)
        return Data.init(foo)
    }
    
    ///左对齐
    func alignLeft() -> Data {
        return Data.init([ESC,97,0])
    }
    
    ///居中对齐
    func alignCenter() -> Data {
        return Data.init([ESC,97,1])
    }
    
    ///右对齐
    func alignRight() -> Data {
        return Data.init([ESC,97,2])
    }
    
    ///水平方向向右移动col列
    func alignRight(col:UInt8) -> Data {
        var foo:[UInt8] = []
        foo.append(ESC)
        foo.append(68)
        foo.append(col)
        foo.append(0)
        return Data.init(foo)
    }

    ///字体变大为标准的n倍
    func fontSize(font:Int8) -> Data {
        var realSize:UInt8 = 0
        switch font {
        case 1:
            realSize = 0
        case 2:
            realSize = 17
        case 3:
            realSize = 34
        case 4:
            realSize = 51
        case 5:
            realSize = 68
        case 6:
            realSize = 85
        case 7:
            realSize = 102
        case 8:
            realSize = 119
        default:
            break
        }
        var foo:[UInt8] = []
        foo.append(29)
        foo.append(33)
        foo.append(realSize)
        return Data.init(foo)
    }
    
    ///进纸并全部切割
    func feedPaperCutAll() -> Data {
        var foo:[UInt8] = []
        foo.append(GS)
        foo.append(86)
        foo.append(65)
        foo.append(0)
        return Data.init(foo)
    }
    
    ///进纸并切割(左边留一点不切)
    func feedPaperCutPartial() -> Data {
        var foo:[UInt8] = []
        foo.append(GS)
        foo.append(86)
        foo.append(66)
        foo.append(0)
        return Data.init(foo)
    }
    
    ///设置纸张间距为默认
    func mergerPaper() -> Data {
        return Data.init([ESC,109])
    }
}

你可能感兴趣的:(Swift 蓝牙打印机数据排版)