关于 iOS 输出 PDF 文档
iOS 开发中难免会遇到生成文件的需求,生成文件还是很简单的,直接将字符串写入文件不就好了吗? 但是又难免会遇到刁钻的用户,不禁要生成文件,还要生成好看的文件。这样的需求说实话,有点过分了,但是项目经理却同意了这样无理的要求,来压榨我们这些开发人员,非要给生成个带各种样式的文件。
既然要生成文件,那首先便是想要生成什么格式的文件了,最简单的txt,集简单、粗暴、好用等优点于一身,可惜不带样式。 Word ? word格式太复杂了,又没有能用的第三方库,考虑了半天决定还是用 PDF.
先看下这个刁钻的需求:
这样的一个东西,输出成 PDF 真的是报了警了,网上找了一堆资料,大多都是自己画简直就是开玩笑吧,这个东西要画出来直接爆炸,终于在简书上看到了一篇文章,大概思路将数据先转成网页再由网页转成 PDF 觉得此思路可行,终于能用现成的了,进去一看,是 swift 的,网上搜了半天居然没有个 OC 的,只好自己弄了。
想必对于直接在 PDF 上画,这种先转网页的方式还是要舒服很多的。首先你需要一个网页模版,并且把格式都设置好。将需要填写字段的位置都用标示字符串替换掉,这样大概可以得到一个这样的模版,并将它丢到工程目录中:
再看下数据段的模版:
<tr>
<td td colspan="2">#TIME#</td>
<td td colspan="2">#DEVICE#</td>
<td>#TEMP#</td>
<td>#SHIDU#</td>
</tr>
关于html的模版,还是有点坑的,特别是 table 的边线问题。table 有边框 tb 也有边框,从好友那里搞了个 CSS. 拉进来才解决。
有了模版,首先要从文件中得到模版内容:
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *filePath =[resourcePath stringByAppendingPathComponent:@"PDFtemplet.html"];
NSString *HTMLContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
得到内容后,将标记字符替换掉:
temp = [temp stringByReplacingOccurrencesOfString:@"#DEVICE_DESC#" withString:model.stringDevice];
temp = [temp stringByReplacingOccurrencesOfString:@"#START_TIME#" withString:model.stringStartTime];
...
...
标记全部替换完成后,剩下的就是把这个网页的源码转成 PDF 了,这里会用到 UIPrintPageRenderer 类,自定义一个 CustomPrintPageRenderer 类继承于 UIPrintPageRenderer 并添加初始化函数:
- (instancetype)init
{
self = [super init];
if (self) {
CGRect page;
page.origin.x=0;
page.origin.y=0;
page.size.width=595.2;
page.size.height=612;
CGRect printable=CGRectInset(page, 40, 60 );
[self setValue:[NSValue valueWithCGRect:page] forKey:@"paperRect"];
[self setValue:[NSValue valueWithCGRect:printable] forKey:@"printableRect"];
}
return self;
}
在这里可以调整页边距什么的。
接下来将 HTML 转成 PDF :
CustomPrintPageRenderer *printPageRenderer = [[CustomPrintPageRenderer alloc] init];
UIMarkupTextPrintFormatter *printFormatter = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:HTMLContent];
[printPageRenderer addPrintFormatter:printFormatter startingAtPageAtIndex:0];
NSMutableData *PDFData = [NSMutableData data];
UIGraphicsBeginPDFContextToData(PDFData, CGRectZero, nil );
for (NSInteger i=0; i < [printPageRenderer numberOfPages]; i++) {
UIGraphicsBeginPDFPage();
CGRect bounds = UIGraphicsGetPDFContextBounds();
[printPageRenderer drawPageAtIndex:i inRect:bounds];
}
UIGraphicsEndPDFContext();
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString * pdfFile = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"info.pdf"]];
[PDFData writeToFile:pdfFile atomically:YES];
[SVProgressHUD showSuccessWithStatus:@"生成文件成功"];
文件生成成功,看看转成的 PDF 效果:
没毛病!这样的话不管生成什么样子的 PDF 都把它先转成网页,让前端把模版做好,数据填上去,要多炫酷有多炫酷,要什么样式有什么样式!
网友评论