CoreGraphics之浏览和生成PDF文件详解

文章结构

  • 加载并浏览PDF文件
  • 图片生成PDF文件
  • demo代码解释
  • 总结

加载并浏览PDF文件

  • 思路:加载pdf文件,一页一页绘制到自己的自定义控件中,然后可以把这些控件放到网格或者UIPageViewController中进行滑动显示。

第一步:获取表示pdf文件的CGPDFDocumentRef对象。

为了能够读取pdf文件的信息,我们需要把pdf加载到一个CGPDFDocumentRef对象中,可以通过两个方法生成该对象,如下代码:

CGPDFDocumentRef __nullable CGPDFDocumentCreateWithProvider(
    CGDataProviderRef cg_nullable provider);
CGPDFDocumentRef __nullable CGPDFDocumentCreateWithURL(
    CFURLRef cg_nullable url);

第二步:检查pdf文件是否加密。

使用以下接口检查是否加密

bool CGPDFDocumentIsEncrypted(CGPDFDocumentRef cg_nullable document);

如果是加密的pdf文件则需要通过以下接口解密

 bool CGPDFDocumentUnlockWithPassword(
    CGPDFDocumentRef cg_nullable document, const char *  password);

否则无法进行下一步。

第三步:获取表示一页pdf的对象CGPDFPageRef。

通过以下代码获取CGPDFPageRef对象

CGPDFPageRef __nullable CGPDFDocumentGetPage(
    CGPDFDocumentRef cg_nullable document, size_t pageNumber);

注意:该接口最后一个参数表示第几页,并且从1开始。

第四步:创建一个映射变换,映射pdf的box到你指定的矩形区域内。

通过如下接口创建一个映射变换

CGAffineTransform CGPDFPageGetDrawingTransform(
    CGPDFPageRef cg_nullable page, CGPDFBox box, CGRect rect, int rotate,
    bool preserveAspectRatio);

以上接口的第三个参数表示你想要绘制的pdf在什么区域内,一般设置self.bounds表示布满整个绘制上下文,可以修改该参数看看相对应的效果;第四个参数表示旋转角度,第五个参数表示是否等比例绘制你的pdf文件。
如果少了这一步,则文件过大情况下,文件内容显示会超出屏幕导致 显示不全。

注意:CGPDFPageGetDrawingTransform方法的官方文档原文如下:

creates an affine transform by mapping a box in a PDF page to a rectangle you specify.

通过

void CGContextConcatCTM(CGContextRef cg_nullable c,
    CGAffineTransform transform);

把映射变换合成到上下文中。

第五部:绘制pdf文件。

通过以下接口绘制pdf文件到自己的控件中

void CGContextDrawPDFPage(CGContextRef cg_nullable c,
    CGPDFPageRef cg_nullable page);

其实核心代码就是CGContextDrawPDFPage该API,通过该API所需的参数一步步逆向往上推导,就不会感到迷茫。


第六步:使用网格或者UIPageViewController浏览pdf。

怎么使用这两个就不多说了,不会的自学。
这里说下不同点,使用网格的话,如果每个网格之间有间隔,则越往后滑动UI就越难看,效果如下:


如果每页之间不使用间隔的话,可以使用网格,如果每页之间有间隔的话,使用网格浏览到目前为止我没有想到解决以上问题的方法,要是有解决方法可以给我留言。

图片生成PDF文件

  • 思路:给pdf设置附加信息,如作者、是否加密等信息;设置页面信息,如pdf的box信息等,在API文档里都有说明;获取pdf上下文环境,绘制pdf。

第一步:生成pdf上下文环境。

通过以下API创建pdf的上下文环境

CGContextRef __nullable CGPDFContextCreateWithURL(CFURLRef cg_nullable url,
  const CGRect * __nullable mediaBox, CFDictionaryRef __nullable auxiliaryInfo);

注意:还有另外一个方法CGPDFContextCreate创建。
第一个参数表示生成完成后保存pdf文件的路径,第二个参数表示绘制pdf区域,第三个参数表示pdf的附件信息,是一个字典,相关的key在接口文档里说明。

第二步:绘制pdf。

通过以下两个接口开始绘制和结束pdf。

void CGPDFContextBeginPage(CGContextRef cg_nullable context,
  CFDictionaryRef __nullable pageInfo);
void CGPDFContextEndPage(CGContextRef cg_nullable context);

这两个api表示开始和结束,并且必须是成对搭配使用的,在这两个api之间绘制想要的内容。

这里说明的是把图片转换成pdf文件,所以使用到以下API

void CGContextDrawImage(CGContextRef cg_nullable c, CGRect rect,
    CGImageRef cg_nullable image);

注意:在生成CGImageRef对象的时候,如果是通过以下两个接口生成的话,必须根据图片的格式类型使用正确的API,否则绘制不出来。

CGImageRef __nullable CGImageCreateWithJPEGDataProvider(
    CGDataProviderRef cg_nullable source, const CGFloat * __nullable decode,
    bool shouldInterpolate,
    CGColorRenderingIntent intent);
CGImageRef __nullable CGImageCreateWithPNGDataProvider(
    CGDataProviderRef cg_nullable source, const CGFloat * __nullable decode,
    bool shouldInterpolate,
    CGColorRenderingIntent intent);

也可以使用ImageIO框架创建CGImageRef对象,不需要关心图片的格式类型,代码如下:

- (CGImageRef)CGImageWithName:(NSString *)imageName{
    
    NSURL *url = [[NSBundle mainBundle] URLForResource:imageName withExtension:nil];
    CFURLRef cfImageURL = (__bridge_retained CFURLRef)url;
    CGImageSourceRef imageSource = CGImageSourceCreateWithURL(cfImageURL, NULL);
    CGImageRef cgimge = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
    CFRelease(cfImageURL);
    CFRelease(imageSource);
    return cgimge;
}

demo代码解释

网格浏览demo文件夹路径:PDF->CollectionViewWay。
UIPageViewController demo文件夹路径:PDF->PageVC。
图片生成pdf文件demo文件夹路径:PDF->ConvertToPDF。
猛戳Demo,谢谢你的阅读,如发现错误请给我留言,谢谢!
如果喜欢就给个赞👍吧!

总结

在把图片转化成PDF时候(工程里的PDF->ConvertToPDF),出现CFDictionary的内存泄漏,如下图:


看代码没看出哪里没有不正确使用的内存管理,希望看到的朋友给我指出来,万分感谢!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335