iOS PDF之旅(一)创建PDF文件
来源:互联网 发布:视频裁切软件 编辑:程序博客网 时间:2024/05/02 02:53
最近要写关于PDF读取和涂鸦编辑的应用,这段时间在看PDF的相关资料,顺便写下Demo做下短篇笔记。
直接上代码吧:
- (void)viewDidLoad{ [super viewDidLoad]; // 1.创建media box CGFloat myPageWidth = self.view.bounds.size.width; CGFloat myPageHeight = self.view.bounds.size.height; CGRect mediaBox = CGRectMake (0, 0, myPageWidth, myPageHeight); // 2.设置pdf文档存储的路径 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = paths[0]; NSString *filePath = [documentsDirectory stringByAppendingString:@"/test.pdf"]; // NSLog(@"%@", filePath); const char *cfilePath = [filePath UTF8String]; CFStringRef pathRef = CFStringCreateWithCString(NULL, cfilePath, kCFStringEncodingUTF8); // 3.设置当前pdf页面的属性 CFStringRef myKeys[3]; CFTypeRef myValues[3]; myKeys[0] = kCGPDFContextMediaBox; myValues[0] = (CFTypeRef) CFDataCreate(NULL,(const UInt8 *)&mediaBox, sizeof (CGRect)); myKeys[1] = kCGPDFContextTitle; myValues[1] = CFSTR("我的PDF"); myKeys[2] = kCGPDFContextCreator; myValues[2] = CFSTR("Creator Name"); CFDictionaryRef pageDictionary = CFDictionaryCreate(NULL, (const void **) myKeys, (const void **) myValues, 3, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks); // 4.获取pdf绘图上下文 CGContextRef myPDFContext = MyPDFContextCreate (&mediaBox, pathRef); // 5.开始描绘第一页页面 CGPDFContextBeginPage(myPDFContext, pageDictionary); CGContextSetRGBFillColor (myPDFContext, 1, 0, 0, 1); CGContextFillRect (myPDFContext, CGRectMake (0, 0, 200, 100 )); CGContextSetRGBFillColor (myPDFContext, 0, 0, 1, .5); CGContextFillRect (myPDFContext, CGRectMake (0, 0, 100, 200 )); // 为一个矩形设置URL链接www.baidu.com CFURLRef baiduURL = CFURLCreateWithString(NULL, CFSTR("http://www.baidu.com"), NULL); CGContextSetRGBFillColor (myPDFContext, 0, 0, 0, 1); CGContextFillRect (myPDFContext, CGRectMake (200, 200, 100, 200 )); CGPDFContextSetURLForRect(myPDFContext, baiduURL, CGRectMake (200, 200, 100, 200 )); CGPDFContextEndPage(myPDFContext); // 6.开始描绘第二页页面 // 注意要另外创建一个page dictionary CFDictionaryRef page2Dictionary = CFDictionaryCreate(NULL, (const void **) myKeys, (const void **) myValues, 3, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks); CGPDFContextBeginPage(myPDFContext, page2Dictionary); // 在左下角画两个矩形 CGContextSetRGBFillColor (myPDFContext, 1, 0, 0, 1); CGContextFillRect (myPDFContext, CGRectMake (0, 0, 200, 100 )); CGContextSetRGBFillColor (myPDFContext, 0, 0, 1, .5); CGContextFillRect (myPDFContext, CGRectMake (0, 0, 100, 200 )); // 在右下角写一段文字:"Hello world" CGContextSelectFont(myPDFContext, "Helvetica", 30, kCGEncodingMacRoman); CGContextSetTextDrawingMode (myPDFContext, kCGTextFill); CGContextSetRGBFillColor (myPDFContext, 0, 0, 0, 1); const char *text = [@"Hello world" UTF8String]; CGContextShowTextAtPoint (myPDFContext, 120, 120, text, strlen(text)); /* // 为某一个矩形设置destination,这里destination的作用还不是很明白,保留 CGPDFContextSetDestinationForRect(myPDFContext, CFSTR("Hello world"), CGRectMake(50.0, 300.0, 100.0, 100.0)); CGContextSetRGBFillColor(myPDFContext, 1, 0, 1, 0.5); CGContextFillEllipseInRect(myPDFContext, CGRectMake(50.0, 300.0, 100.0, 100.0)); */ // 为右上角的矩形设置一段file URL链接,打开本地文件 NSURL *furl = [NSURL fileURLWithPath:@"/Users/one/Library/Application Support/iPhone Simulator/7.0/Applications/3E7CB341-693A-4FE4-8FE5-A827A5210F0A/Documents/test1.pdf"]; CFURLRef fileURL = (__bridge CFURLRef)furl; CGContextSetRGBFillColor (myPDFContext, 0, 0, 0, 1); CGContextFillRect (myPDFContext, CGRectMake (200, 200, 100, 200 )); CGPDFContextSetURLForRect(myPDFContext, fileURL, CGRectMake (200, 200, 100, 200 )); CGPDFContextEndPage(myPDFContext); // 7.释放创建的对象 CFRelease(page2Dictionary); CFRelease(pageDictionary); CFRelease(myValues[0]); CGContextRelease(myPDFContext);}/* * 获取pdf绘图上下文 * inMediaBox指定pdf页面大小 * path指定pdf文件保存的路径 */CGContextRef MyPDFContextCreate (const CGRect *inMediaBox, CFStringRef path){ CGContextRef myOutContext = NULL; CFURLRef url; CGDataConsumerRef dataConsumer; url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, false); if (url != NULL) { dataConsumer = CGDataConsumerCreateWithURL(url); if (dataConsumer != NULL) { myOutContext = CGPDFContextCreate (dataConsumer, inMediaBox, NULL); CGDataConsumerRelease (dataConsumer); } CFRelease(url); } return myOutContext;}
代码注释基本说明了所有问题,这里要注意的就是如果要创建多页的pdf文件,就必须设置多个page dictionary从而获取不同的pdf绘图上下文。
打开文件保存的路径,可以找到我们创建的pdf文档,打开来看看:
其中test.pdf是我们创建的目标文件,test1.pdf是我放到该路径的一个文件,用于测试本地URL。
打开test.pdf:
将鼠标放到第一页右上角的黑色矩形上,可以见到www.baidu.com的链接,点击该矩形可以打开百度的主页。
再看看第二页:
将鼠标放到第二页右上角黑色矩形的范围,可以看到test.pdf链接提示,点击该矩形可以打开该目录下的test.pdf(当然这个是之前代码设定好的本地文件的地址)。
但是直接用iOS程序打开,是无法响应链接的,这个还要继续修正,PDF之旅将持续更新。
后续更新:
上次留了个坑给大家,现在填一下,参考网址:Drawing and Printing Guide for iOS
上次写完该博客的时候留了一段僵尸代码:
/* // 为某一个矩形设置destination,这里destination的作用还不是很明白,保留 CGPDFContextSetDestinationForRect(myPDFContext, CFSTR("Hello world"), CGRectMake(50.0, 300.0, 100.0, 100.0)); CGContextSetRGBFillColor(myPDFContext, 1, 0, 1, 0.5); CGContextFillEllipseInRect(myPDFContext, CGRectMake(50.0, 300.0, 100.0, 100.0)); */也就是关于set destination的问题,这几天偶然看到了上面的guide,今天找到了理解方法并写了代码验证,现在填一下这个坑吧。
看看SDK中的该方法:
/* Create a PDF destination named `name' at `point' in the current page of the PDF context `context'. */CG_EXTERN void CGPDFContextAddDestinationAtPoint(CGContextRef context, CFStringRef name, CGPoint point) CG_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0);
该方法创建了一个跳转的终点,name指定了该跳转点的名字,起到标识该点以及和下面的rect配对的作用,point则指定跳转的位置,对应的参考坐标系为左下角为原点。
以及:
/* Specify a destination named `name' to jump to when clicking in `rect' of the current page of the PDF context `context'. */CG_EXTERN void CGPDFContextSetDestinationForRect(CGContextRef context, CFStringRef name, CGRect rect) CG_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0);
name指定了跳转点的名字,必须和上面的destination name配对,否则点击该矩形无效,rect为接受点击的矩形范围。
示意图如下:
(1)在rect上设置的跳转点的name为:"Chapter_1"。
(2)在某一个page上设置了跳转点point,其name为"Chapter_1",和rect上设置的跳转点配对。
(3)点击rect,页面将跳转到point对应的位置。
下面代码测试一下:
在PDF第一页中设置如下:
// 为一个矩形设置一个跳转终点 CGPDFContextSetDestinationForRect(myPDFContext, CFSTR("page2"), CGRectMake(50.0, 300.0, 100.0, 100.0)); CGContextSetRGBFillColor(myPDFContext, 1, 0, 1, 0.5); CGContextFillEllipseInRect(myPDFContext, CGRectMake(50.0, 300.0, 100.0, 100.0));
在第二页中设置如下:
// 在右下角写一段文字:"Page 2" CGContextSelectFont(myPDFContext, "Helvetica", 30, kCGEncodingMacRoman); CGContextSetTextDrawingMode (myPDFContext, kCGTextFill); CGContextSetRGBFillColor (myPDFContext, 0, 0, 0, 1); const char *text = [@"Page 2" UTF8String]; CGContextShowTextAtPoint (myPDFContext, 120, 80, text, strlen(text)); CGPDFContextAddDestinationAtPoint(myPDFContext, CFSTR("page2"), CGPointMake(120.0, 120.0));
跑起来看看(直接在Mac上打开):
点击后跳转到我们预先设置好的目的地:
在这里要注意的是:
destination point的设置的坐标系是左下角为(0, 0),x轴向右增长,y轴向上增长。而不是左上角为(0, 0),x轴向右增长,y轴向下增长。
如果出现了多个desination name相同的情况呢?经测试是跳转到最后一个设定的同名的destination point上,因为该点覆盖了以上所有点,例如在第一页中加上:
// 为一个矩形设置一个跳转终点 CGPDFContextAddDestinationAtPoint(myPDFContext, CFSTR("page"), CGPointMake(120.0, 400.0)); CGPDFContextSetDestinationForRect(myPDFContext, CFSTR("page"), CGRectMake(50.0, 300.0, 100.0, 100.0)); CGContextSetRGBFillColor(myPDFContext, 1, 0, 1, 0.5); CGContextFillEllipseInRect(myPDFContext, CGRectMake(50.0, 300.0, 100.0, 100.0));
跑起来的话还是跳转到第二页的point上。
说得比较乱,贴上完整代码,有兴趣的可以自己测试看看:
- (void)viewDidLoad{ [super viewDidLoad]; // 1.创建media box CGFloat myPageWidth = self.view.bounds.size.width; CGFloat myPageHeight = self.view.bounds.size.height; CGRect mediaBox = CGRectMake (0, 0, myPageWidth, myPageHeight); // 2.设置pdf文档存储的路径 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = paths[0]; NSString *filePath = [documentsDirectory stringByAppendingString:@"/test.pdf"]; // NSLog(@"%@", filePath); const char *cfilePath = [filePath UTF8String]; CFStringRef pathRef = CFStringCreateWithCString(NULL, cfilePath, kCFStringEncodingUTF8); // 3.设置当前pdf页面的属性 CFStringRef myKeys[3]; CFTypeRef myValues[3]; myKeys[0] = kCGPDFContextMediaBox; myValues[0] = (CFTypeRef) CFDataCreate(NULL,(const UInt8 *)&mediaBox, sizeof (CGRect)); myKeys[1] = kCGPDFContextTitle; myValues[1] = CFSTR("我的PDF"); myKeys[2] = kCGPDFContextCreator; myValues[2] = CFSTR("Jymn_Chen"); CFDictionaryRef pageDictionary = CFDictionaryCreate(NULL, (const void **) myKeys, (const void **) myValues, 3, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks); // 4.获取pdf绘图上下文 CGContextRef myPDFContext = MyPDFContextCreate (&mediaBox, pathRef); // 5.开始描绘第一页页面 CGPDFContextBeginPage(myPDFContext, pageDictionary); CGContextSetRGBFillColor (myPDFContext, 1, 0, 0, 1); CGContextFillRect (myPDFContext, CGRectMake (0, 0, 200, 100 )); CGContextSetRGBFillColor (myPDFContext, 0, 0, 1, .5); CGContextFillRect (myPDFContext, CGRectMake (0, 0, 100, 200 )); // 为一个矩形设置URL链接www.baidu.com CFURLRef baiduURL = CFURLCreateWithString(NULL, CFSTR("http://www.baidu.com"), NULL); CGContextSetRGBFillColor (myPDFContext, 0, 0, 0, 1); CGContextFillRect (myPDFContext, CGRectMake (200, 200, 100, 200 )); CGPDFContextSetURLForRect(myPDFContext, baiduURL, CGRectMake (200, 200, 100, 200 )); // 为一个矩形设置一个跳转终点 CGPDFContextAddDestinationAtPoint(myPDFContext, CFSTR("page"), CGPointMake(120.0, 400.0)); CGPDFContextSetDestinationForRect(myPDFContext, CFSTR("page"), CGRectMake(50.0, 300.0, 100.0, 100.0)); // 跳转点的name为page// CGPDFContextSetDestinationForRect(myPDFContext, CFSTR("page2"), CGRectMake(50.0, 300.0, 100.0, 100.0)); // 跳转点的name为page2 CGContextSetRGBFillColor(myPDFContext, 1, 0, 1, 0.5); CGContextFillEllipseInRect(myPDFContext, CGRectMake(50.0, 300.0, 100.0, 100.0)); CGPDFContextEndPage(myPDFContext); // 6.开始描绘第二页页面 // 注意要另外创建一个page dictionary CFDictionaryRef page2Dictionary = CFDictionaryCreate(NULL, (const void **) myKeys, (const void **) myValues, 3, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks); CGPDFContextBeginPage(myPDFContext, page2Dictionary); // 在左下角画两个矩形 CGContextSetRGBFillColor (myPDFContext, 1, 0, 0, 1); CGContextFillRect (myPDFContext, CGRectMake (0, 0, 200, 100 )); CGContextSetRGBFillColor (myPDFContext, 0, 0, 1, .5); CGContextFillRect (myPDFContext, CGRectMake (0, 0, 100, 200 )); // 在右下角写一段文字:"Page 2" CGContextSelectFont(myPDFContext, "Helvetica", 30, kCGEncodingMacRoman); CGContextSetTextDrawingMode (myPDFContext, kCGTextFill); CGContextSetRGBFillColor (myPDFContext, 0, 0, 0, 1); const char *text = [@"Page 2" UTF8String]; CGContextShowTextAtPoint (myPDFContext, 120, 80, text, strlen(text));// CGPDFContextAddDestinationAtPoint(myPDFContext, CFSTR("page2"), CGPointMake(120.0, 120.0)); // 跳转点的name为page2// CGPDFContextAddDestinationAtPoint(myPDFContext, CFSTR("page"), CGPointMake(120.0, 120.0)); // 跳转点的name为page // 为右上角的矩形设置一段file URL链接,打开本地文件 NSURL *furl = [NSURL fileURLWithPath:@"/Users/one/Library/Application Support/iPhone Simulator/7.0/Applications/3E7CB341-693A-4FE4-8FE5-A827A5210F0A/Documents/test1.pdf"]; CFURLRef fileURL = (__bridge CFURLRef)furl; CGContextSetRGBFillColor (myPDFContext, 0, 0, 0, 1); CGContextFillRect (myPDFContext, CGRectMake (200, 200, 100, 200 )); CGPDFContextSetURLForRect(myPDFContext, fileURL, CGRectMake (200, 200, 100, 200 )); CGPDFContextEndPage(myPDFContext); // 7.创建第三页内容 CFDictionaryRef page3Dictionary = CFDictionaryCreate(NULL, (const void **) myKeys, (const void **) myValues, 3, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks); CGPDFContextBeginPage(myPDFContext, page3Dictionary); CGContextSetRGBFillColor (myPDFContext, 0, 0, 0, 1); CGPDFContextEndPage(myPDFContext); // 8.释放创建的对象 CFRelease(page3Dictionary); CFRelease(page2Dictionary); CFRelease(pageDictionary); CFRelease(myValues[0]); CGContextRelease(myPDFContext);}
- iOS PDF之旅(一)创建PDF文件
- (一) 创建PDF
- (一) 创建PDF
- 创建PDF文件 - iOS开发
- iOS PDF之旅(二)将PDF文件Open In MyApp
- ios 创建和绘画pdf文件
- PDF文件结构(一)
- PDF文件结构(一)
- 创建pdf文件
- PDFBox创建PDF文件
- word创建PDF文件
- 基于iTextSharp(C#)创建PDF文件
- itext poi 学习之旅 (1)创建pdf
- Excel,Pdf,Xml 文件操作(一)
- Java操作文件一(pdf)
- PDF文件结构(一) 物理结构
- Pdf之C#直接打印pdf文件
- PDF文件在线预览之pdf.js
- VC++连接SQL Server2005 数据库
- MongoDB 单机
- Android之Inflate()方法用途+setContentView和inflate区别
- Java 正则表达式(二)
- 四件在我步入职业软件开发生涯那天起就该知道的事情
- iOS PDF之旅(一)创建PDF文件
- 关于产品的一些思考——CSDN博客
- 创新式开发探索(四) —— 探索式学习
- (2)啊哈!算法
- 设计模式笔记
- 线段树_懒标记
- vim 缩进、禁用鼠标、高亮、从上次编辑位置打开
- IOS 图片上传处理 图片压缩 图片处理
- MongoDB 双机集群配置与管理