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所需的参数一步步逆向往上推导,就不会感到迷茫。


CoreGraphics之浏览和生成PDF文件详解_第1张图片

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

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


CoreGraphics之浏览和生成PDF文件详解_第2张图片

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

图片生成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的内存泄漏,如下图:


CoreGraphics之浏览和生成PDF文件详解_第3张图片

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

你可能感兴趣的:(CoreGraphics之浏览和生成PDF文件详解)