PDF文档存储依赖于分辨率的向量图形、文本和位图,并用于程序的一系列指令中。一个PDF文档可以包含多页的图形和文本。PDF可用于创建跨平台、只读的文档,也可用于绘制依赖于分辨率的图形。
         Quartz为所有应用程序创建高保真的PDF文档,这些文档保留应用的绘制操作,如图13-1所示。PDF文档的结果将通过系统的其它部分或第三方法的产品来有针对性地进行优化。Quartz创建的PDF文档在Preview和Acrobat中都能正确的显示。

Quartz不仅仅只使用PDF作为它的数字页,它同样包含一些API来显示和生成PDF文件,及完成一些其它PDF相关的工作。

打开和查看PDF
         Quartz提供了CGPDFDocumentRef数据类型来表示PDF文档。我们可以使用CGPDFDocumentCreateWithProvider或CGPDFDocumentCreateWithURL来创建CGPDFDocument对象。在创建CGPDFDocument对象后,我们可以将其绘制到图形上下文中。图13-2显示了在一个窗体中绘制PDF文档。

代码清单13-1显示了如何创建一个CGPDFDocument对象及获取文档的页数。

 

复制代码

  1. CGPDFDocumentRefMyGetPDFDocumentRef (const char *filename)
  2. {
  3. CFStringRef path;
  4. CFURLRef url;
  5. CGPDFDocumentRef document;
  6. size_t count;
  7. path = CFStringCreateWithCString (NULL, filename, kCFStringEncodingUTF8);
  8. url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle,0);  // 1 创建CFURL对象
  9. CFRelease (path);
  10. document = CGPDFDocumentCreateWithURL (url);                 // 2 创建CFPDFDocument对象
  11. CFRelease(url);
  12. count = CGPDFDocumentGetNumberOfPages (document);    // 3 获取文档页数
  13. if (count == 0) {
  14. printf("`%s' needs at least onepage!", filename);
  15. return NULL;
  16. }
  17. return document;
  18. }

代码清单显示了如何将一个PDF页绘制到图形上下文中。

 

复制代码

  1. void MyDisplayPDFPage (CGContextRefmyContext, size_t pageNumber, const char *filename)
  2. {
  3. CGPDFDocumentRef document;
  4. CGPDFPageRef page;
  5. document = MyGetPDFDocumentRef (filename);                                   // 1 创建PDFDocument对象
  6. page = CGPDFDocumentGetPage (document, pageNumber);           // 2 获取指定页的PDF文档
  7. CGContextDrawPDFPage (myContext, page);                                       // 3 将PDF绘制到图形上下文中
  8. CGPDFDocumentRelease (document);
  9. }

为PDF页创建一个转换
     Quartz提供了函数CGPDFPageGetDrawingTransform来创建一个仿射变换,该变换基于将PDF页的BOX映射到指定的矩形中。函数原型是:

 

复制代码

  1. CGAffineTransformCGPDFPageGetDrawingTransform (
  2. CGPPageRef page,
  3. CGPDFBox box,
  4. CGRect rect,
  5. int rotate,
  6. bool preserveAspectRatio
  7. );

该函数通过如下算法来返回一个仿射变换:
· 将在box参数中指定的PDF box的类型相关的矩形(media, crop, bleed, trim, art)与指定的PDF页的/MediaBox入口求交集。相交的部分即为一个有效的矩形(effectiverectangle)。
· 将effective rectangle旋转参数/Rotate入口指定的角度。
· 将得到的矩形放到rect参数指定的中间。
· 如果rotate参数是一个非零且是90的倍数,函数将effective rectangel旋转该值指定的角度。正值往右旋转;负值往左旋转。需要注意的是我们传入的是角度,而不是弧度。记住PDF页的/Rotate入口也包含一个旋转,我们提供的rotate参数是与/Rotate入口接合在一起的。
· 如果需要,可以缩放矩形,从而与我们提供的矩形保持一致。
· 如果我们通过传递true值给preserveAspectRadio参数以指定保持长宽比,则最后的矩形将与rect参数的矩形的边一致。

【注:上面这段翻译得不是很好】

例如,我们可以使用这个函数来创建一个与图13-3类似的PDF浏览程序。如果我们提供一个Rotate Left/Rotate Right属性,则可以调用CGPDFPageGetDrawingTransform来根据当前的窗体大小和旋转设置计算出适当的转换。

程序清单13-3显示了为一个PDF页创建及应用仿射变换,然后绘制PDF。

 

复制代码

  1. Listing 13-3  Creating an affine transform for aPDF page
  2. void MyDrawPDFPageInRect(CGContextRef context, CGPDFPageRef page, CGPDFBox box, CGRect rect, int rotation, bool preserveAspectRatio)
  3. {
  4. CGAffineTransform m;
  5. m = CGPDFPageGetDrawingTransform (page, box, rect, rotation, preserveAspectRato);
  6. CGContextSaveGState (context);
  7. CGContextConcatCTM (context, m);
  8. CGContextClipToRect (context,CGPDFPageGetBoxRect (page, box));
  9. CGContextDrawPDFPage (context, page);
  10. CGContextRestoreGState (context);

创建PDF文件
使用Quartz创建PDF与绘制其它图形上下文一下简单。我们指定一个PDF文件地址,设置一个PDF图形上下文,并使用与其它图形上下文一样的绘制程序。如代码清单13-4所示的MyCreatePDFFile函数,显示了创建一个PDF的所有工作。
注意,代码在CGPDFContextBeginPage和CGPDFContextEndPage中来绘制PDF。我们可以传递一个CFDictionary对象来指定页属性,包括media, crop, bleed,trim和art boxes。
Listing 13-4  Creating a PDF file

 

复制代码

  1. void MyCreatePDFFile (CGRectpageRect, const char *filename)
  2. {
  3. CGContextRef pdfContext;
  4. CFStringRef path;
  5. CFURLRef url;
  6. CFData boxData = NULL;
  7. CFMutableDictionaryRef myDictionary = NULL;
  8. CFMutableDictionaryRef pageDictionary = NULL;
  9. path = CFStringCreateWithCString (NULL, filename, kCFStringEncodingUTF8);
  10. url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, 0);
  11. CFRelease (path);
  12. myDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  13. CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("MyPDF File"));
  14. CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("MyName"));
  15. pdfContext = CGPDFContextCreateWithURL (url, &pageRect,myDictionary);
  16. CFRelease(myDictionary);
  17. CFRelease(url);
  18. pageDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  19. boxData = CFDataCreate(NULL,(const UInt8 *)&pageRect, sizeof(CGRect));
  20. CFDictionarySetValue(pageDictionary, kCGPDFContextMediaBox, boxData);
  21. CGPDFContextBeginPage (pdfContext, &pageRect);
  22. myDrawContent (pdfContext);
  23. CGPDFContextEndPage (pdfContext);
  24. CGContextRelease (pdfContext);
  25. CFRelease(pageDictionary);
  26. CFRelease(boxData);
  27. }

添加链接
我们可以在PDF上下文中添加链接和锚点。Quartz提供了三个函数,每个函数都以PDF图形上下文作为参数,还有链接的信息:
· CGPDFContextSetURLForRect可以让我们指定在点击当前PDF页中的矩形时打开一个URL。
· CGPDFContextSetDestinationForRect指定在点击当前PDF页中的矩形区域时设置目标以进行跳转。我们需要提供一个目标名。
· CGPDFContextAddDestinationAtPoint指定在点击当前PDF页中的一个点时设置目标以进行跳转。我们需要提供一个目标名。

保护PDF内容
为了保护PDF内容,我们可以在辅助字典中指定一些安全选项并传递给CGPDFContextCreate。我们可以通过包含如下关键字来设置所有者密码、用户密码、PDF是否可以被打印或拷贝:
· kCGPDFContextOwnerPassword: 定义PDF文档的所有者密码。如果指定该值,则文档使用所有者密码来加密;否则文档不加密。该关键字的值必须是ASCII编码的CFString对象。只有前32位是用于密码的。该值没有默认值。如果该值不能表示成ASCII,则无法创建文档并返回NULL。Quartz使用40-bit加密。
· kCGPDFContextUserPassword: 定义PDF文档的用户密码。如果文档加密了,则该值是文档的用户密码。如果没有指定,则用户密码为空。该关键字的值必须是ASCII编码的CFString对象。只有前32位是用于密码的。如果该值不能表示成ASCII,则无法创建文档并返回NULL。
· kCGPDFContextAllowsPrinting:指定当使用用户密码锁定时文档是否可以打印。该值必须是CFBoolean对象。默认值是kCGBooleanTrue。
· kCGPDFContextAllowsCopying: 指定当使用用户密码锁定时文档是否可以拷贝。该值必须是CFBoolean对象。默认值是kCGBooleanTrue。
代码清单14-4(下一章)显示了确认PDF文档是否被锁定,及用密码打开文档。

原文链接:http://www.cocoachina.com/bbs/read.php?tid=83761

Quartz 2D编程指南- PDF文档的创建、显示及转换的更多相关文章

  1. Quartz 2D编程指南(1) - 概览

    Quartz 2D编程指南是论坛会员德鲁伊翻译的国外的Quartz 2D一系列学习资料,供大家参考 Quartz 2D是一个二维图形绘制引擎,支持iOS环境和Mac OS X环境.我们可以使用Quar ...

  2. C# 如何在PDF文档中创建表格

    表格能够直观的传达数据信息,使信息显得条理化,便于阅读同时也利于管理.那在PDF类型的文档中如何来添加表格并且对表格进行格式化操作呢?使用常规方法直接在PDF中添加表格行不通,那我们可以在借助第三方组 ...

  3. qt 利用 HTML 生成PDF文档,不能显示jpg图片

    利用 QPrinter 和html 生成 pdf文档 其中用html语句有显示图片的语句 但只能显示png格式的图片,不能显示jpg格式图片. 经过排查:语法,文件路径等都正确,最终在stack ov ...

  4. [.NET开发] C# 如何在PDF文档中创建表格

    表格能够直观的传达数据信息,使信息显得条理化,便于阅读同时也利于管理.那在PDF类型的文档中如何来添加表格并且对表格进行格式化操作呢?使用常规方法直接在PDF中添加表格行不通,那我们可以在借助第三方组 ...

  5. Quartz 2D编程指南(4) - 颜色和颜色空间

    不同的设备(显示器.打印机.扫描仪.摄像头)处理颜色的方式是不同的.每种设备都有其所能支持的颜色值范围.一种设备能支持的颜色可能在其它设备中无法支持.为了有效的使用颜色及理解Quartz 2D中用于颜 ...

  6. Quartz 2D编程指南(5) - 变换(Transforms)

    Quartz 2D 绘制模型定义了两种独立的坐标空间:用户空间(用于表现文档页)和设备空间(用于表现设备的本地分辨率).用户坐标空间用浮点数表示坐标,与设备空间的像素分辨率没有关系.当我们需要一个点或 ...

  7. Quartz 2D编程指南(7) - 阴影(Shadows)

    阴影是绘制在一个图形对象下的且有一定偏移的图片,它用于模拟光源照射到图形对象上所形成的阴影效果,如果7-1所示.文本也可以有阴影.阴影可以让一幅图像看上去是立体的或者是浮动的. 阴影有三个属性: 1. ...

  8. Quartz 2D编程指南(2) - 图形上下文

    一个Graphics Context表示一个绘制目标.它包含绘制系统用于完成绘制指令的绘制参数和设备相关信息.Graphics Context定义了基本的绘制属性,如颜色.裁减区域.线条宽度和样式信息 ...

  9. Quartz 2D编程指南(2)图形上下文(Graphics Contexts)

    Graphics Contexts       一个Graphics Context表示一个绘制目标(也能够理解为图形上下文).它包括绘制系统用于完毕绘制指令的绘制參数和设备相关信息.Graphics ...

随机推荐

  1. PHP数据库链接类(PDO+Access)

    PHP PDO Access链接 class DbHelpClass { private $conn; private $qxId; private $ret; function __construc ...

  2. Java_SQL_类型对应_资料

    1.http://argel-lj.iteye.com/blog/1183123 2.http://www.fx114.net/qa-119-110105.aspx JDBC 的"类型&qu ...

  3. Spring事物原理完全解析

    事务是什么?了解事务的原理吗?说下Spring的事务原理,能自己实现Spring事务原理吗?先自我检测下这些知识掌握了吗.那么接下来一起看下与Spring相关的事务 概念 事务具有ACID特性. 是指 ...

  4. 动态延迟加载网页元素jQuery插件scrollLoading

    如果一个网页很长,那么该页面的加载时间也会相应的较长.而这里给大家介绍的这个jQuery插件scrollLoading的作用则是,对页面元素进行动态加载,通俗的说就是滚到哪就加载到哪,屏幕以下看不见的 ...

  5. HTML5 history API,创造更好的浏览体验

    HTML5 history API有什么用呢? 从Ajax翻页的问题说起 请想象你正在看一个视频下面的评论,在翻到十几页的时候,你发现一个写得稍长,但非常有趣的评论.正当你想要停下滚轮细看的时候,手残 ...

  6. [Vue]Vue语法糖v-bind、v-on

    语法糖 :是指在不影响功能的情况下,添加某种方法实现同样的效果,从而方便程序开发,简化代码是书写. Vue.js的v-bind和v-on指令都提供了语法糖,也可以说是缩写. 1.v-bind可以省略, ...

  7. C# - Generics泛型,一图话c#泛型

    一.一篇好文 https://www.cnblogs.com/yueyue184/p/5032156.html 二.一幅好图

  8. 【LeetCode 67_字符串_算术运算】Add Binary

    string addBinary(string a, string b) { int alen = a.size(); int blen = b.size(); ) return b; ) retur ...

  9. 通过ping 主机名,或者主机名对应的IP地址

    通过ping 主机名,或者主机名对应的IP地址: 如下图: 懵了吧? 但是你用 ping 主机名 -4

  10. Python基础学习----元组

    # 元组和列表的区别: # 相同点: # 1.表示多个元素的序列 # 2.数据之间用 , 分开 # 3.索引都是[0]开始 # # 不同点: # 1.列表创建是[],元组是()表示 # 2.元组元素一 ...