蓝牙打印小票排版&&图片打印优化
去年七八月份做的一个小功能,过了有点久,现在抽个时间整理下以备后用。本文主要是针对蓝牙打印小票做的处理以及优化打印,连接蓝牙那些就不说,这边就讲一些针对文字打印排版,图片打印排版以及优化打印速度的处理。
蓝牙打印小票,分两种打印方式:文字打印、图片打印,当然图文混合的也是有的哈,图文混合就不多说了自己结合处理就行。
文字打印
先上调用部分的代码,至于HLPrinter,可以直接通过这个Github上获取得到,这边就不在赘述了。
- (NSData *)getBluetoothPrintWith {
HLPrinter *printer = [[HLPrinter alloc] init];
// 账单名称
[printer appendText:_printEnvelop.billName alignment:HLTextAlignmentCenter fontSize:HLFontSizeTitleSmalle];
// 收费金额
[printer appendText:_printEnvelop.amount alignment:HLTextAlignmentCenter fontSize:HLFontSizeTitleMiddle];
// 缴费状态
[printer appendText:_printEnvelop.payStatus alignment:HLTextAlignmentCenter fontSize:HLFontSizeTitleSmalle];
// 收费项目
for (ZTGResponseTuitionBillFeaturesEnvelop *envelop in _printEnvelop.features) {
if (envelop.value.length >= 15) {
[printer appendTitle:envelop.name value:envelop.value valueOffset:145];
} else [printer appendTitle:envelop.name value:envelop.value];
}
// 空行方便用户查看
[printer appendTitle:@" " value:@" " fontSize:HLFontSizeTitleBig];
NSData *mainData = [printer getFinalData];
return mainData;
}
文字打印的数据还是非常快的,但是一些打印机的问题会导致国际通用编码kCFStringEncodingGB_18030_2000
打印出来的一些比较不常见的文字出现乱码,本文总结的时候小票已经丢光了没法上图请见谅。只能考虑通过数据请求获取到数据然后排版,排版完成后转为图片...
图片打印
文字转为图片
百度了半天只有一些参考的,最后只能自己造轮子上代码,SZYPrinterManager.h
文件
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class ZTGResponseTuitionBillFeaturesEnvelop;
typedef NS_ENUM(NSInteger, SZYPrinterFontSize) {
SZYFontSizeTitleSmalle = 12,
SZYFontSizeTitleMiddle = 24,
SZYFontSizeTitleBig = 40
};
typedef NS_ENUM(NSInteger, SZYPrinterLogoAligment) {
SZYPrinterLogoAligmentTop,
SZYPrinterLogoAligmentCenter,
SZYPrinterLogoAligmentBottom,
SZYPrinterLogoAligmentTopLeft,
SZYPrinterLogoAligmentTopRight,
};
@interface SZYPrinterManager : NSObject
- (UIImage *)convertToImage;
- (UIImage *)convertToImageAppendLogo:(UIImage *)logoImage agliment:(SZYPrinterLogoAligment)agliment;
- (void)appendTitle:(NSString *)title fontSize:(SZYPrinterFontSize)fontSize;
- (void)appendTitle:(NSString *)title textAlignment:(NSTextAlignment)textAlignment fontSize:(SZYPrinterFontSize)fontSize;
- (void)appendTitle:(NSString *)title value:(NSString *)value;
- (void)appendTitleWithArray:(NSArray<ZTGResponseTuitionBillFeaturesEnvelop *> *)array textAlignment:(NSTextAlignment)textAlignment fontSize:(SZYPrinterFontSize)fontSize;
- (void)appendTitle:(NSString *)title value:(NSString *)value textAlignment:(NSTextAlignment)textAlignment fontSize:(SZYPrinterFontSize)fontSize;
- (void)appendSpacingLine;
@end
这边的ZTGResponseTuitionBillFeaturesEnvelop
,是服务器返回的数据模型,键值对哈,如下所示:
@interface ZTGResponseTuitionBillFeaturesEnvelop : SZYJsonModel
/**
金额(分)
*/
@property (nonatomic, copy) NSString *name;
/**
收费项目
*/
@property (nonatomic, copy) NSString *value;
@end
下面的是实现SZYPrinterManager.m
文件
#import "SZYPrinterManager.h"
#import "ZTGResponseTuitionBillPrintEnvelop.h"
static const CGFloat kPrinterMaxWidth = 384.0f;
static const CGFloat kPrinterTextSpecing = 30.0f;// 一个汉字可以当20pt来计算,一个字母可以当10pt计算
static const CGFloat kPrinterLineSpacing = 5.0f;
static const CGFloat kPrinterLogoWidth = 125.0f;
static const CGFloat kPrinterLogoMargin = 0.0f;
static const CGFloat kPrinterPrintMargin = 80.0f;
static const CGFloat kPrinterSpacingMargin = 15.0f;
static const CGFloat kPrinterCompress = 0.1f;
@interface SZYPrinterManager ()
@property (nonatomic, strong) NSMutableAttributedString *attributed;
@property (nonatomic, assign) CGFloat textHeight;
@end
@implementation SZYPrinterManager
- (instancetype)init {
self = [super init];
if (self) {
_attributed = [[NSMutableAttributedString alloc] init];
_textHeight = 0;
}
return self;
}
- (void)appendTitle:(NSString *)title fontSize:(SZYPrinterFontSize)fontSize {
[self appendTitle:title value:nil textAlignment:NSTextAlignmentLeft fontSize:fontSize];
}
- (void)appendTitle:(NSString *)title value:(NSString *)value {
[self appendTitle:title value:value textAlignment:NSTextAlignmentLeft fontSize:SZYFontSizeTitleMiddle];
}
- (void)appendTitleWithArray:(NSArray<ZTGResponseTuitionBillFeaturesEnvelop *> *)array textAlignment:(NSTextAlignment)textAlignment fontSize:(SZYPrinterFontSize)fontSize {
[array enumerateObjectsUsingBlock:^(ZTGResponseTuitionBillFeaturesEnvelop * envelop, NSUInteger idx, BOOL * _Nonnull stop) {
[self appendTitle:envelop.name value:envelop.value textAlignment:textAlignment fontSize:fontSize];
}];
}
- (void)appendTitle:(NSString *)title textAlignment:(NSTextAlignment)textAlignment fontSize:(SZYPrinterFontSize)fontSize {
if (![title isNotBlank]) {
return;
}
// 段落
NSMutableAttributedString *attribute = [[NSMutableAttributedString alloc] initWithString:title];
[attribute addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:fontSize] range:NSMakeRange(0, title.length)];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
paragraphStyle.alignment = textAlignment;
[paragraphStyle setLineSpacing:kPrinterLineSpacing];
[attribute addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, title.length)];
[_attributed appendAttributedString:attribute];
// 高度
_textHeight += [self HeightForString:attribute fontSize:fontSize];
// 换行
[_attributed appendAttributedString:[self newLine]];
// 换行高度
_textHeight += kPrinterLineSpacing;
}
- (void)appendTitle:(NSString *)title value:(NSString *)value textAlignment:(NSTextAlignment)textAlignment fontSize:(SZYPrinterFontSize)fontSize {
if (![title isNotBlank] && ![value isNotBlank]) {
return;
}
title = [title isNotBlank] ? title : @" ";
value = [value isNotBlank] ? value : @"";
NSString *string = [title stringByAppendingString:value];
// 段落
NSMutableAttributedString *attribute = [[NSMutableAttributedString alloc] initWithString:string];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
paragraphStyle.alignment = textAlignment;
[paragraphStyle setLineSpacing:kPrinterLineSpacing];
[attribute addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, string.length)];
// 获取真实间距
CGFloat spacing = [self getSpacingWithTitle:title content:value fontSize:fontSize];
[attribute addAttribute:NSKernAttributeName value:@(spacing) range:NSMakeRange(title.length - 1, 1)];
[attribute addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:fontSize] range:NSMakeRange(0, string.length)];
[_attributed appendAttributedString:attribute];
// 高度
_textHeight += [self HeightForString:attribute fontSize:fontSize];
// 换行
[_attributed appendAttributedString:[self newLine]];
// 换行高度
_textHeight += kPrinterLineSpacing;
}
- (UIImage *)convertToImage {
UIImage *image = [self convertToImageAppendLogo:nil agliment:0];
return image;
}
- (UIImage *)convertToImageAppendLogo:(UIImage *)logoImage agliment:(SZYPrinterLogoAligment)agliment {
// 比原本高度多出 80提高用户体验
CGSize size = CGSizeMake(kPrinterMaxWidth, _textHeight + kPrinterPrintMargin);
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor whiteColor] set];
CGRect rect = CGRectMake(0, 0, size.width + 1, size.height + 1);
CGContextFillRect(context, rect);
[_attributed drawInRect:rect];
if (!logoImage) {
UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *tempData = UIImageJPEGRepresentation(resultImg, kPrinterCompress);
resultImg = [[UIImage alloc] initWithData:tempData];
return resultImg;
}
// 水印
CGFloat logoHeight = (logoImage.size.height / logoImage.size.width) * kPrinterLogoWidth;
CGFloat logoLeft = (kPrinterMaxWidth - kPrinterLogoWidth) / 2;
CGFloat logoTop = 0;
switch (agliment) {
case SZYPrinterLogoAligmentTop:
logoTop = 0;
break;
case SZYPrinterLogoAligmentCenter:
logoTop = (_textHeight - logoHeight) / 2;
break;
case SZYPrinterLogoAligmentBottom:
logoTop = _textHeight - logoHeight;
break;
case SZYPrinterLogoAligmentTopLeft:
{
logoLeft = kPrinterLogoMargin;
logoTop = kPrinterLogoMargin;
}
break;
case SZYPrinterLogoAligmentTopRight:
{
logoLeft = kPrinterMaxWidth - kPrinterLogoWidth - kPrinterLogoMargin;
logoTop = kPrinterLogoMargin;
}
break;
default:
break;
}
[logoImage drawInRect:CGRectMake(logoLeft, logoTop, kPrinterLogoWidth, logoHeight)];
UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();//关闭上下文
// 压缩图片
NSData *tempData = UIImageJPEGRepresentation(resultImg, kPrinterCompress);
resultImg = [[UIImage alloc] initWithData:tempData];
return resultImg;
}
- (void)appendSpacingLine {
NSString *string = @" \n";
NSAttributedString *newline = [[NSAttributedString alloc] initWithString:string];
NSMutableAttributedString *attribute = [[NSMutableAttributedString alloc] initWithString:string];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
[paragraphStyle setLineSpacing:kPrinterSpacingMargin];
[attribute addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, string.length)];
[_attributed appendAttributedString:attribute];
// 高度
_textHeight += kPrinterSpacingMargin * 2;
}
#pragma mark private
// 换行
- (NSAttributedString *)newLine {
NSAttributedString *newline = [[NSAttributedString alloc] initWithString:@"\n"];
return newline;
}
// 获取间距
- (CGFloat)getSpacingWithTitle:(NSString *)title content:(NSString *)content fontSize:(SZYPrinterFontSize)fontSize {
CGFloat spacing = 0;
NSString *string = [title stringByAppendingString:content];
UIFont *font = [UIFont systemFontOfSize:fontSize];
CGFloat allWidth = [self widthForString:string fontSize:font] + kPrinterTextSpecing;
if (allWidth > kPrinterMaxWidth) {
// 超过部分,默认间距
spacing = kPrinterTextSpecing;
} else {
// 未超过部分,用间距补足
CGFloat titleWidth = [self widthForString:title fontSize:font];
CGFloat contentWidth = [self widthForString:content fontSize:font];
spacing = kPrinterMaxWidth - titleWidth - contentWidth;
}
return spacing;
}
// 获取文本宽度
- (CGFloat)widthForString:(NSString *)string fontSize:(UIFont *)font {
NSDictionary * detailDic = [NSDictionary dictionaryWithObjectsAndKeys:font,