美文网首页iOS开发技能集锦iOS Developer程序员
CoreGraphics之浏览和生成PDF文件详解

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

作者: LotusLee | 来源:发表于2018-01-11 18:11 被阅读382次

    文章结构

    • 加载并浏览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的内存泄漏,如下图:


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

    相关文章

      网友评论

        本文标题:CoreGraphics之浏览和生成PDF文件详解

        本文链接:https://www.haomeiwen.com/subject/qkqtoxtx.html