文章结构
- 加载并浏览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的内存泄漏,如下图:
看代码没看出哪里没有不正确使用的内存管理,希望看到的朋友给我指出来,万分感谢!!!