前段时间做了一个收银的项目,里面要用到链接小票打印机打印小票的功能,牵涉到ios的蓝牙链接,打印指令等方面内容,这里总结一些使用心得。

关于ios系统的蓝牙,现在的ios支持的是蓝牙4.0,一般意义的蓝牙教程也都是关于蓝牙4.0的了。常规的操作这里不进行介绍,给大家推荐一个开源的iOS蓝牙项目,BabyBluetooth ,BabyBluetooth极好的封装了CoreBluetooth,可以使你更简单的使用CoreBluetooth的API,另外BabyBluetooth采用链式编程,是代码更加简洁优雅。有兴趣的同学可以研究下。

   至于打印这块是采用的ESC/POS指令来控制打印机的行为。当然如果你就是使用的EPSON打印机,那么肯定会有相应的SDK的,就省去了使用最原始ESC/POS指令打印的繁琐。ESC/POS指令集网上有很多,自己搜索一些就好了。不过可能有的朋友看了指令集之后仍然不会使用,这里贴一下常用的控制指令:

/***  重置打印机*/
- (void)resetPrinter
{Byte reset[] = {0x1B,0X40};[self writeData:[NSData dataWithBytes:reset length:2]];
}/***  唤醒打印机*/
- (void)wakeUpPrinter
{Byte wake[] = {0x00};[self writeData:[NSData dataWithBytes:wake length:1]];
}/***  打印并换行*/
- (void)printAndGoToNextLine
{Byte next[] = {0x0A};[self writeData:[NSData dataWithBytes:next length:1]];
}- (void)printAndEnter
{Byte enter[] = {0x0D};[self writeData:[NSData dataWithBytes:enter length:1]];
}/***  加大字体**  @param n 位宽,位高*/
- (void)enlargeFont:(int )n
{Byte font[] = {0x1D,0X21,n};[self writeData:[NSData dataWithBytes:font length:3]];
}/***  设置对齐方式**  @param n 0左对齐,1中对齐,2右对齐*/
- (void)setAlignment:(int)n
{Byte align[] = {0x1B,0x61,n};[self writeData:[NSData dataWithBytes:align length:3]];
}/***  打印缓冲区数据并进纸n个垂直点距,0<= n <= 255,一个垂直点距为0.125mm**  @param n*/
- (void)printAndGoNLine:(int)n
{Byte line[] = {0x1B,0X64,n};[self writeData:[NSData dataWithBytes:line length:3]];
}/***  结束打印*/
- (void)printEnd
{Byte end[] = {0x1d, 0x4c, 0x1f, 0x00};[self writeData:[NSData dataWithBytes:end length:4]];
}/***  写入数据**  @param param 可以是NSData,也可以是NSString*/
- (void)writeData:(id )param
{NSData *data = nil;if ([param isKindOfClass:[NSString class]]) {NSString *str = (NSString *)param;data = [str dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)];}else if ([param isKindOfClass:[NSData class]]){data = (NSData *)param;}if ([self setUp]) {[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];}
}

具体的打印效果和格式就使用这些基本指令来组合就好了。这里提醒大家一下,一定要看好你的打印机支持的语言,以便于在打印的时候进行相应的encode。当然你可以根据指令来进行其他效果的组合,上面贴出的是打印文字时候常用的指令组合。如果是做的收银小票的打印,那么在商品列表那里应该是两端对齐的格式。在博主的试验中实时动态的对打印机设置对齐方式是不起作用的,或许是方法不对,如果有大神可以实现请千万不吝赐教。博主采用的方法是在两端文字中间动态的拼接空格来达到两端对齐的目的,那么这里的知识点就来了,那就是计算字符串的长度,有同学可能觉得字符串长度ios不是提供了length了吗?如果你的打印效果是同一种类型的文字当然可以,但如果同时包含字母,汉子,数字等,那么用length计算的长度就不准确了,因为字母,汉子的编码不同,字节数是不同的,所以要转换成Unicode编码统一的计算。下面是博主使用的计算方法:

//判断中英混合的的字符串长度
- (int)convertToInt:(NSString*)strtemp
{int strlength = 0;char* p = (char*)[strtemp cStringUsingEncoding:NSUnicodeStringEncoding];for (int i=0 ; i<[strtemp lengthOfBytesUsingEncoding:NSUnicodeStringEncoding] ;i++) {if (*p) {p++;strlength++;}else {p++;}}return strlength;
}

既然已经计算出了字符串的长度,那么动态的拼接空格的操作就简单了:

/***  动态拼接空格使所有字符串长度一致,比如:(辣条x2     ¥100)**  @param leader 字符串的左边部分,比如:辣条x2*  @param tail   字符串的右边部分,比如:¥100**  @return 拼接空格之后的字符串*/
- (NSString *)getPrintString:(NSString *)leader tail:(NSString *)tail
{static int TOTAL = 30;//这里是根据你的纸张宽度试验出来的一个合适的总字数NSMutableString *printString = [NSMutableString new];[printString appendString:leader];int lenderLen = [self convertToInt:leader];if (tail) {int tailLen = [self convertToInt:tail];int detal = (int)(TOTAL - lenderLen - tailLen);for (int i = 0; i < detal; i ++) {[printString appendString:@" "];}[printString appendString:tail];}else{int detal = (int)(TOTAL - lenderLen);for (int i = 0; i < detal; i ++) {[printString appendString:@" "];}}return printString;
}

但是大家在现实中一定有这样的需求,那就是在票据的最下方需要打印二维码。这里就涉及到了图片的打印,说来这里有一个小插曲,本人在做这个项目的时候对于图片的打印百般调试都达不到预定效果,而网上也没找到理想的材料,后来论坛发现有人做过,就抱着求教的心态去请教,人家是爽快人,果断说2000块钱,代码卖你。当时博主什么都没说,默默的删掉了他的联系方式。但是其实内心对这种没有分享精神的人是比较鄙视的。这里说一下自己的研究成果。如果你研究了ESC/POS指令集的话会发现其中有图片的打印指令,而图片的打印也没有那么神秘,只不过是把你的图片转换一下点阵图,然后按照指令打印就OK了:

-(DXImage *)getBitmapImageData{CGImageRef cgImage = [m_image CGImage];int32_t width = CGImageGetWidth(cgImage);int32_t height = CGImageGetHeight(cgImage);NSInteger psize = sizeof(ARGBPixel);ARGBPixel * pixels = malloc(width * height * psize);NSMutableData* data = [[NSMutableData alloc] init];[self ManipulateImagePixelDataWithCGImageRef:cgImage imageData:pixels];for (int h = 0; h < height; h++) {for (int w = 0; w < width; w++) {int pIndex = [self PixelIndexWithX:w y:h width:width];ARGBPixel pixel = pixels[pIndex];if ([self PixelBrightnessWithRed:pixel.red green:pixel.green blue:pixel.blue] <= 127) {u_int8_t ch = 0x01;[data appendBytes:&ch length:1];}else{u_int8_t ch = 0x00;[data appendBytes:&ch length:1];}}}DXImage* bi = [[DXImage alloc] init];bi.bitmap = data;bi.width = width;bi.height = height;return bi;
}-(NSData *)getDataForPrint{DXImage* bi = [self getBitmapImageData];const char* bytes = bi.bitmap.bytes;NSMutableData* dd = [[NSMutableData alloc] init];//横向点数计算需要除以8NSInteger w8 = bi.width / 8;//如果有余数,点数+1NSInteger remain8 = bi.width % 8;if (remain8 > 0) {w8 = w8 + 1;}/**根据公式计算出 打印指令需要的参数指令:十六进制码 1D 76 30 m xL xH yL yH d1...dkm为模式,如果是58毫秒打印机,m=1即可xL 为宽度/256的余数,由于横向点数计算为像素数/8,因此需要 xL = width/(8*256)xH 为宽度/256的整数yL 为高度/256的余数yH 为高度/256的整数**/NSInteger xL = w8 % 256;NSInteger xH = bi.width / (8 * 256);NSInteger yL = bi.height % 256;NSInteger yH = bi.height / 256;const char cmd[] = {0x1d,0x76,0x30,0,xL,xH,yL,yH};[dd appendBytes:cmd length:8];for (int h = 0; h < bi.height; h++) {for (int w = 0; w < w8; w++) {u_int8_t n = 0;for (int i=0; i<8; i++) {int x = i + w * 8;u_int8_t ch;if (x < bi.width) {int pindex = h * bi.width + x;ch = bytes[pindex];}else{ch = 0x00;}n = n << 1;n = n | ch;}[dd appendBytes:&n length:1];}}return dd;
}
</pre><pre name="code" class="objc"><pre name="code" class="objc">-(void)ManipulateImagePixelDataWithCGImageRef:(CGImageRef)inImage imageData:(void*)oimageData
{// Create the bitmap contextCGContextRef cgctx = [self CreateARGBBitmapContextWithCGImageRef:inImage];if (cgctx == NULL){// error creating contextreturn;}// Get image width, height. We'll use the entire image.size_t w = CGImageGetWidth(inImage);size_t h = CGImageGetHeight(inImage);CGRect rect = {{0,0},{w,h}};// Draw the image to the bitmap context. Once we draw, the memory// allocated for the context for rendering will then contain the// raw image data in the specified color space.CGContextDrawImage(cgctx, rect, inImage);// Now we can get a pointer to the image data associated with the bitmap// context.void *data = CGBitmapContextGetData(cgctx);if (data != NULL){CGContextRelease(cgctx);memcpy(oimageData, data, w * h * sizeof(u_int8_t) * 4);free(data);return;}// When finished, release the contextCGContextRelease(cgctx);// Free image data memory for the contextif (data){free(data);}return;
}// 参考 http://developer.apple.com/library/mac/#qa/qa1509/_index.html
-(CGContextRef)CreateARGBBitmapContextWithCGImageRef:(CGImageRef)inImage
{CGContextRef    context = NULL;CGColorSpaceRef colorSpace;void *          bitmapData;int             bitmapByteCount;int             bitmapBytesPerRow;// Get image width, height. We'll use the entire image.size_t pixelsWide = CGImageGetWidth(inImage);size_t pixelsHigh = CGImageGetHeight(inImage);// Declare the number of bytes per row. Each pixel in the bitmap in this// example is represented by 4 bytes; 8 bits each of red, green, blue, and// alpha.bitmapBytesPerRow   = (pixelsWide * 4);bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);// Use the generic RGB color space.colorSpace =CGColorSpaceCreateDeviceRGB();if (colorSpace == NULL){return NULL;}// Allocate memory for image data. This is the destination in memory// where any drawing to the bitmap context will be rendered.bitmapData = malloc( bitmapByteCount );if (bitmapData == NULL){CGColorSpaceRelease( colorSpace );return NULL;}// Create the bitmap context. We want pre-multiplied ARGB, 8-bits// per component. Regardless of what the source image format is// (CMYK, Grayscale, and so on) it will be converted over to the format// specified here by CGBitmapContextCreate.context = CGBitmapContextCreate (bitmapData,pixelsWide,pixelsHigh,8,      // bits per componentbitmapBytesPerRow,colorSpace,kCGImageAlphaPremultipliedFirst);if (context == NULL){free (bitmapData);}// Make sure and release colorspace before returningCGColorSpaceRelease( colorSpace );return context;
}-(u_int8_t)PixelBrightnessWithRed:(u_int8_t)red green:(u_int8_t)green blue:(u_int8_t)blue
{int level = ((int)red + (int)green + (int)blue)/3;return level;
}-(u_int32_t)PixelIndexWithX:(u_int32_t)x y:(u_int32_t)y width:(u_int32_t)width
{return (x + (y * width));
}-(UIImage*)ScaleImageWithImage:(UIImage*)image width:(NSInteger)width height:(NSInteger)height
{CGSize size;size.width = width;size.height = height;UIGraphicsBeginImageContext(size);[image drawInRect:CGRectMake(0, 0, width, height)];UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return scaledImage;
}-(NSInteger)GetGreyLevelWithARGBPixel:(ARGBPixel)source intensity:(float)intensity
{if (source.alpha == 0){return 255;}int32_t gray = (int)(((source.red + source.green +  source.blue) / 3) * intensity);if (gray > 255)gray = 255;return (u_int8_t)gray;
}

把你的图片转换之后就可以使用上面的writeData方法来打印图片了。

iOS蓝牙链接打印机的使用心得相关推荐

  1. uni-app(android、ios) 使用蓝牙便携式打印机(热敏打印机)

    机型等参数 HSPOS 点密度:576点/行(8dots/mm,203dpi) 接口类型: 蓝牙(Bluetooth2.0,4.0双模,支持Android,IOS) 打印方式:图形打印(位图) 打印指 ...

  2. iOS蓝牙开发---CoreBluetooth[BLE 4.0] 初级篇[内附Demo地址]

    一.蓝牙基础知识 (一)常见简称 1.MFI  make for ipad ,iphone, itouch 专们为苹果设备制作的设备,开发使用ExternalAccessory 框架(认证流程貌似挺复 ...

  3. 今日分享-ios蓝牙

    1. ios蓝牙库的基本介绍-CoreBluetooth 2. CoreBluetooth使用详解 3. 相关问题 1. ios蓝牙库的基本介绍-CoreBluetooth 首先熟悉相关名词:Cent ...

  4. iOS 蓝牙4.0开发使用(内附Demo)

    一: 介绍 近几年,智能设备越来越火,这些智能设备中,有很大一部分是通过手机来控制硬件设备,来达到预期的效果,这中间少不了要使用到蓝牙功能,通过蓝牙来通信来控制设备. 蓝牙分为蓝牙2.0和蓝牙4.0. ...

  5. 微信小程序蓝牙连接打印机

    需求:蓝牙搜索打印机并打印信息 微信小程序中需要打印订单信息 1.搜索打印机蓝牙,并链接 2.发送打印 微信小程序连接蓝牙 1.初始化蓝牙 1.1 wx.openBluetoothAdapter(Ob ...

  6. iOS蓝牙学习(一)

    最近在学蓝牙开发,就去网上收集了一些文章看,自己做了一个总结,下面就分享出来. 前提: iOS蓝牙开发使用的API是:Core Bluetooth 正常情况下需要两台真实的蓝牙4.0设备(当然也可以使 ...

  7. 小米手环iOS开发实战(一):iOS蓝牙框架CoreBluetooth

    小米手环iOS开发实战(一):iOS蓝牙框架CoreBluetooth 本项目为对小米手环进行二次开发,利用了小米手环蓝牙连接并不安全的特性,连接后可以获取手环数据,并可修改数据. 本实例使用Swif ...

  8. Xcode中的iOS模拟器(iOS Simulator)的介绍和使用心得

    [整理]Xcode中的iOS模拟器(iOS Simulator)的介绍和使用心得 2012-12-12 10:45:40|  分类: Apple|字号 订阅 原文链接: http://www.crif ...

  9. iOS 蓝牙方案预研

    iOS蓝牙方案预研 经过前段时间的工作,现将研究结论总结如下: 一般的IOS蓝牙开发有以下三种目的: 一.IOS设备和IOS设备之间交互 用到两个框架:GameKit(iOS6)和Multipeer ...

  10. iOS通用链接(Universal Links)突然点击无效的解决方案

    接上文<微信中通过页面(H5)直接打开本地app的解决方案>已经把iOS搞定并且已经正常能跑了,突然就再也用不了了... 问题描述 测试告诉我,如果从微信打开App之后,点击App右上角的 ...

最新文章

  1. Shell test命令(Shell [])详解,附带所有选项及说明
  2. mongodb简单的函数
  3. Java集合Set,List和Map等
  4. python随机发红包_python 微信红包随机金额
  5. 研究生,怎么经济独立?
  6. “123456”连续七年霸榜,2019最糟糕密码榜单出炉
  7. 计算机系统结构 02325_计算机系统的组成硬件系统1
  8. PHP中cookies跨目录无法调用解决办法
  9. 告别码公式的痛苦,公式OCR终于来了!
  10. Jackson的JSON转对象,忽略不需要的字段
  11. STM32LCD显示汉字
  12. oracle恢复表数据
  13. 最新聚合支付系统+农信易扫/飞行模式+附APP
  14. 【读书笔记】--少有人走的路①:心智成熟的旅程
  15. Word2vec简单整理
  16. HTTP 十分钟教程
  17. 微商城模式适合什么规模企业?新商云,满足多种行业需求!
  18. 01 KVM虚拟化简介
  19. UVA 1471 Defense Lines (LIS变形)
  20. soso地图api接口poi检索示例----并在信息框显示经纬度

热门文章

  1. 中文依存句法结构分析
  2. 土方测量-挖方填方量的计算思路
  3. pack文件如何安装
  4. 简单线性相关案例-求相关系数
  5. Java网络爬虫(七)--实现定时爬取与IP代理池
  6. python爬取谷歌学术_对于python抓取google搜索结果的一些了解
  7. python docx文档内容提取与写入(汇总)
  8. 数据流-移动超平面(HyperPlane)构造
  9. 测试微信好友是否删除软件,如何测试微信好友是否删了你?
  10. 统计学常用概念:T检验、F检验、卡方检验、P值、自由度