Quartz 2D編程指南 (十六) —— PDF文檔創(chuàng)建对供,查看和轉(zhuǎn)換(一)

版本記錄

版本號 時間
V1.0 2018.09.08

前言

Quartz 2D框架相信大家都知道,也都一直在使用。Quartz 2D的API是純C語言的产场,它是一個二維繪圖引擎鹅髓,同時支持iOS和Mac系統(tǒng)。Quartz 2D的API來自于Core Graphics框架京景,數(shù)據(jù)類型和函數(shù)基本都以CG作為前綴窿冯,接下來幾篇我們就一起來看一下這個框架。感興趣可以看上面幾篇文章确徙。
1. Quartz 2D編程指南 (一) —— 簡介(一)
2. Quartz 2D編程指南 (二) —— Quartz 2D概覽(二)
3. Quartz 2D編程指南 (三) —— 圖形上下文(三)
4. Quartz 2D編程指南 (四) —— Paths路徑(一)
5. Quartz 2D編程指南 (五) —— Paths路徑(二)
6. Quartz 2D編程指南 (六) —— 顏色和顏色空間(一)
7. Quartz 2D編程指南 (七) —— 變換(一)
8. Quartz 2D編程指南 (八) —— Patterns圖案樣式(一)
9. Quartz 2D編程指南 (九) —— 陰影(一)
10. Quartz 2D編程指南 (十) —— 漸變(一)
11. Quartz 2D編程指南 (十一) —— 透明層(一)
12. Quartz 2D編程指南 (十二) —— Quartz 2D中的數(shù)據(jù)管理(一)
13. Quartz 2D編程指南 (十三) —— 位圖圖像和圖像蒙版(一)
14. Quartz 2D編程指南 (十四) —— 位圖圖像和圖像蒙版(二)
15. Quartz 2D編程指南 (十五) —— Core Graphics圖層繪制(一)

PDF Document Creation, Viewing, and Transforming - PDF文檔創(chuàng)建醒串,查看和轉(zhuǎn)換

PDF文檔將與分辨率無關(guān)的矢量圖形,文本和圖像存儲為以緊湊編程語言編寫的一系列命令鄙皇。 PDF文檔可以包含多頁圖像和文本芜赌。 PDF對于創(chuàng)建跨平臺,只讀文檔和繪制與分辨率無關(guān)的圖形非常有用伴逸。

對于所有應(yīng)用程序缠沈,Quartz為保留應(yīng)用程序繪圖操作創(chuàng)建高保真PDF文檔,如圖13-1所示错蝴。 生成的PDF可以針對特定用途(例如特定打印機或Web)針對系統(tǒng)的其他部分或第三方產(chǎn)品進行優(yōu)化洲愤。 Quartz產(chǎn)生的PDF文檔可以在PreviewAcrobat中正確顯示。

Figure 13-1 Quartz creates high-quality PDF documents

Quartz不僅使用PDF作為其“數(shù)字紙”顷锰,還包括作為其API的一部分柬赐,可用于顯示和生成PDF文件以及完成許多其他PDF相關(guān)任務(wù)的許多功能。

有關(guān)PDF的詳細信息官紫,包括PDF語言和語法肛宋,請參閱PDF Reference, Fourth Edition, Version 1.5


Opening and Viewing a PDF - 打開和顯示一個PDF

Quartz提供數(shù)據(jù)類型CGPDFDocumentRef來表示PDF文檔万矾。 使用函數(shù)CGPDFDocumentCreateWithProvider或函數(shù)CGPDFDocumentCreateWithURL創(chuàng)建CGPDFDocument對象悼吱。 創(chuàng)建CGPDFDocument對象后慎框,可以將其繪制到圖形上下文良狈。 圖13-2顯示了窗口內(nèi)顯示的PDF文檔。

Figure 13-2 A PDF document

Listing 13-1顯示了如何創(chuàng)建CGPDFDocument對象并獲取文檔中的頁數(shù)笨枯。 列表后面會顯示每個編號行代碼的詳細說明薪丁。

// Listing 13-1  Creating a CGPDFDocument object from a PDF file

CGPDFDocumentRef MyGetPDFDocumentRef (const char *filename)
{
    CFStringRef path;
    CFURLRef url;
    CGPDFDocumentRef document;
    size_t count;
 
    path = CFStringCreateWithCString (NULL, filename,
                         kCFStringEncodingUTF8);
    url = CFURLCreateWithFileSystemPath (NULL, path, // 1
                        kCFURLPOSIXPathStyle, 0);
    CFRelease (path);
    document = CGPDFDocumentCreateWithURL (url);// 2
    CFRelease(url);
    count = CGPDFDocumentGetNumberOfPages (document);// 3
    if (count == 0) {
        printf("`%s' needs at least one page!", filename);
        return NULL;
    }
    return document;
}

這是代碼的作用:

  • 1) 調(diào)用Core Foundation函數(shù)從CFString對象創(chuàng)建CFURL對象,該對象表示要顯示的PDF文件的文件名馅精。
  • 2) 從CFURL對象創(chuàng)建CGPDFDocument對象严嗜。
  • 3) 獲取PDF中的頁數(shù),以便代碼中的下一個語句可以確保文檔至少有一個頁面洲敢。

通過查看Listing 13-2中的代碼漫玄,您可以了解如何將PDF頁面繪制到圖形上下文。 列表后面會顯示每個編號行代碼的詳細說明。

// Listing 13-2  Drawing a PDF page

void MyDisplayPDFPage (CGContextRef myContext,
                    size_t pageNumber,
                    const char *filename)
{
    CGPDFDocumentRef document;
    CGPDFPageRef page;
 
    document = MyGetPDFDocumentRef (filename);// 1
    page = CGPDFDocumentGetPage (document, pageNumber);// 2
    CGContextDrawPDFPage (myContext, page);// 3
    CGPDFDocumentRelease (document);// 4
}

這是代碼的作用:

  • 1) 調(diào)用您的函數(shù)(參見Listing 13-1)從您提供的文件名創(chuàng)建CGPDFDocument對象睦优。
  • 2) 從PDF文檔中獲取指定頁碼的頁面渗常。
  • 3) 通過調(diào)用函數(shù)CGContextDrawPDFPage從PDF文件中繪制指定的頁面。 您需要提供圖形上下文和要繪制的頁面汗盘。
  • 4) 釋放CGPDFDocument對象皱碘。

Creating a Transform for a PDF Page - 為PDF頁面創(chuàng)建轉(zhuǎn)換

Quartz提供了一個函數(shù)-CGPDFPageGetDrawingTransform,它通過將PDF頁面中的框映射到您指定的矩形來創(chuàng)建仿射變換隐孽。 該函數(shù)的原型是:

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

該函數(shù)使用以下算法返回仿射變換:

  • 將與您在box參數(shù)(media癌椿,crop,bleed菱阵,trim或art)中指定的PDF框類型相關(guān)聯(lián)的矩形與指定PDF頁面的/ MediaBox條目相交踢俄。交叉點產(chǎn)生有效的矩形。
  • 按照PDF頁面的/ Rotate條目指定的量旋轉(zhuǎn)有效矩形晴及。
  • 將生成的矩形居中放在您在rect參數(shù)中提供的矩形上褪贵。
  • 如果您提供的rotate參數(shù)的值為非零且為90的倍數(shù),則該函數(shù)會將有效矩形旋轉(zhuǎn)您提供的度數(shù)抗俄。正值將矩形向右旋轉(zhuǎn)脆丁,負值將矩形向左旋轉(zhuǎn)。請注意动雹,您傳遞度數(shù)槽卫,而不是弧度。請記住胰蝠,PDF頁面的/ Rotate條目也包含旋轉(zhuǎn)歼培,您提供的rotate參數(shù)與/ Rotate條目組合在一起。
  • 如有必要茸塞,縮放有效矩形躲庄,使其與您提供的矩形的邊緣重合。
  • 如果通過在preserveAspectRatio參數(shù)中傳遞true來指定保留縱橫比钾虐,則最終矩形與您在rect參數(shù)中提供的矩形的限制性更大的維度的邊緣重合噪窘。

例如,如果您正在編寫類似于圖13-3中所示的PDF查看應(yīng)用程序效扫,則可以使用此函數(shù)倔监。如果要提供“向左旋轉(zhuǎn)/向右旋轉(zhuǎn)”功能,則可以調(diào)用CGPDFPageGetDrawingTransform來計算當(dāng)前窗口大小和旋轉(zhuǎn)設(shè)置的相應(yīng)變換菌仁。

Figure 13-3 A PDF page rotated 90 degrees to the right

Listing 13-3顯示了一個函數(shù)浩习,該函數(shù)使用傳遞給函數(shù)的參數(shù)為PDF頁面創(chuàng)建仿射變換,應(yīng)用變換济丘,然后繪制PDF頁面谱秽。 列表后面會顯示每個編號行代碼的詳細說明。

// Listing 13-3  Creating an affine transform for a PDF page

void MyDrawPDFPageInRect (CGContextRef context,
                    CGPDFPageRef page,
                    CGPDFBox box,
                    CGRect rect,
                    int rotation,
                    bool preserveAspectRatio)
{
    CGAffineTransform m;
 
    m = CGPDFPageGetDrawingTransform (page, box, rect, rotation,// 1
                                    preserveAspectRato);
    CGContextSaveGState (context);// 2
    CGContextConcatCTM (context, m);// 3
    CGContextClipToRect (context,CGPDFPageGetBoxRect (page, box));// 4
    CGContextDrawPDFPage (context, page);// 5
    CGContextRestoreGState (context);// 6
}

這是代碼的作用:

  • 1)根據(jù)提供給函數(shù)的參數(shù)創(chuàng)建仿射變換。
  • 2)保存圖形狀態(tài)疟赊。
  • 3)將CTM與仿射變換連接起來辱士。
  • 4)將圖形上下文剪切為box參數(shù)指定的矩形。 函數(shù)CGPDFPageGetBoxRect獲取與您提供的常量相關(guān)聯(lián)的頁面邊界框(media, crop, bleed, trim, and art boxes) - kCGPDFMediaBox听绳,kCGPDFCropBox颂碘,kCGPDFBleedBoxkCGPDFTrimBoxkCGPDFArtBox椅挣。
  • 5)將PDF頁面繪制到已變換和剪切的上下文中头岔。
  • 6)恢復(fù)圖形狀態(tài)。

Creating a PDF File - 創(chuàng)建PDF文件

使用Quartz 2D創(chuàng)建PDF文件非常容易鼠证,因為它可以繪制到任何圖形上下文峡竣。 您可以指定PDF文件的位置,設(shè)置PDF圖形上下文量九,并使用與任何圖形上下文相同的繪圖例程适掰。 Listing 13-4中顯示的函數(shù)MyCreatePDFFile顯示了代碼為創(chuàng)建PDF文件而執(zhí)行的所有任務(wù)。 列表后面會顯示每個編號行代碼的詳細說明荠列。

請注意类浪,代碼通過調(diào)用函數(shù)CGPDFContextBeginPageCGPDFContextEndPage來描述PDF頁面。 您可以傳遞CFDictionary對象以指定頁面屬性肌似,包括media, crop, bleed, trim, and art boxes费就。 有關(guān)字典鍵常量的列表以及每個常量的更詳細說明,請參閱CGPDFContext Reference川队。

// Listing 13-4  Creating a PDF file

void MyCreatePDFFile (CGRect pageRect, const char *filename)// 1
{
    CGContextRef pdfContext;
    CFStringRef path;
    CFURLRef url;
    CFDataRef boxData = NULL;
    CFMutableDictionaryRef myDictionary = NULL;
    CFMutableDictionaryRef pageDictionary = NULL;
 
    path = CFStringCreateWithCString (NULL, filename, // 2
                                kCFStringEncodingUTF8);
    url = CFURLCreateWithFileSystemPath (NULL, path, // 3
                     kCFURLPOSIXPathStyle, 0);
    CFRelease (path);
    myDictionary = CFDictionaryCreateMutable(NULL, 0,
                        &kCFTypeDictionaryKeyCallBacks,
                        &kCFTypeDictionaryValueCallBacks); // 4
    CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("My PDF File"));
    CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name"));
    pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary); // 5
    CFRelease(myDictionary);
    CFRelease(url);
    pageDictionary = CFDictionaryCreateMutable(NULL, 0,
                        &kCFTypeDictionaryKeyCallBacks,
                        &kCFTypeDictionaryValueCallBacks); // 6
    boxData = CFDataCreate(NULL,(const UInt8 *)&pageRect, sizeof (CGRect));
    CFDictionarySetValue(pageDictionary, kCGPDFContextMediaBox, boxData);
    CGPDFContextBeginPage (pdfContext, pageDictionary); // 7
    myDrawContent (pdfContext);// 8
    CGPDFContextEndPage (pdfContext);// 9
    CGContextRelease (pdfContext);// 10
    CFRelease(pageDictionary); // 11
    CFRelease(boxData);
}

這是代碼的作用:

  • 1) 將參數(shù)設(shè)置為指定PDF頁面大小的矩形和指定文件名的字符串力细。
  • 2) 從傳遞給函數(shù)MyCreatePDFFile的文件名創(chuàng)建CFString對象。
  • 3) 從CFString對象創(chuàng)建CFURL對象固额。
  • 4) 創(chuàng)建一個空的CFDictionary對象來保存元數(shù)據(jù)眠蚂。接下來的兩行添加標(biāo)題和創(chuàng)建者。您可以使用函數(shù)CFDictionarySetValue添加任意數(shù)量的鍵值對斗躏。有關(guān)創(chuàng)建字典的更多信息逝慧,請參閱CFDictionary Reference
  • 5) 創(chuàng)建PDF圖形上下文瑟捣,傳遞三個參數(shù):
    • CFURL對象馋艺,用于指定PDF數(shù)據(jù)的位置。
    • 指向矩形的指針迈套,用于定義PDF頁面的默認大小和位置。矩形的原點通常為(0,0)碱鳞。 Quartz使用此矩形作為頁面媒體框的默認邊界桑李。如果傳遞NULL,Quartz使用的默認頁面大小為8.5 x 11英寸(612 x 792點)
    • 包含PDF元數(shù)據(jù)的CFDictionary對象贵白。如果您沒有要添加的元數(shù)據(jù)率拒,請傳遞NULL。您可以使用CFDictionary對象指定輸出方法選項 - 意圖子類型禁荒,條件猬膨,條件標(biāo)識符,注冊表名稱呛伴,目標(biāo)輸出配置文件以及包含有關(guān)預(yù)期目標(biāo)設(shè)備或生產(chǎn)條件的其他信息或注釋的人類可讀文本字符串勃痴。有關(guān)輸出方法選項的更多信息,請參閱CGPDFContext Reference热康。
  • 6) 創(chuàng)建CFDictionary對象以保存PDF頁面的頁面框沛申。此示例設(shè)置media box
  • 7) 表示頁面的開頭姐军。當(dāng)您使用支持多個頁面(例如PDF)的圖形上下文時铁材,可以使用CGPDFContextBeginPageCGPDFContextEndPage調(diào)用函數(shù)來描述輸出中的頁面邊界。每個頁面必須通過調(diào)用CGPDFContextBeginPageCGPDFContextEndPage進行括號奕锌。 Quartz忽略在基于頁面的上下文中在頁邊界外執(zhí)行的所有繪制操作著觉。
  • 8) 調(diào)用應(yīng)用程序定義的函數(shù)以將內(nèi)容繪制到PDF上下文。您可以在此處提供繪圖程序惊暴。
  • 9) 在基于頁面的圖形上下文中指示頁面的結(jié)尾固惯。
  • 10) 釋放PDF上下文。
  • 11) 釋放頁面詞典缴守。

Adding Links - 添加鏈接

您可以為您創(chuàng)建的PDF上下文添加鏈接和錨點葬毫。 Quartz提供了三個函數(shù),每個函數(shù)都將PDF圖形上下文以及有關(guān)鏈接的信息作為參數(shù):

  • CGPDFContextSetURLForRect允許您指定在用戶單擊當(dāng)前PDF頁面中的矩形時打開的URL屡穗。
  • CGPDFContextSetDestinationForRect允許您設(shè)置當(dāng)用戶單擊當(dāng)前PDF頁面中的矩形時跳轉(zhuǎn)到的目標(biāo)贴捡。 您必須提供目的地名稱。
  • CGPDFContextAddDestinationAtPoint允許您設(shè)置當(dāng)用戶單擊當(dāng)前PDF頁面中的點時跳轉(zhuǎn)到的目標(biāo)村砂。 您必須提供目的地名稱烂斋。

Protecting PDF Content - 保護PDF內(nèi)容

為了保護PDF內(nèi)容,您可以在輔助字典中指定許多安全選項础废,并將其傳遞給函數(shù)CGPDFContextCreate汛骂。您可以通過在輔助字典中包含以下鍵來設(shè)置所有者密碼,用戶密碼以及是否可以打印或復(fù)制PDF:

  • kCGPDFContextOwnerPassword评腺,用于定義PDF文檔的所有者密碼帘瞭。如果指定了此key,則使用值作為所有者密碼對文檔進行加密蒿讥;否則蝶念,文檔未加密抛腕。此鍵的值必須是可以ASCII編碼表示的CFString對象。只有前32個字節(jié)用于密碼媒殉。此key沒有默認值担敌。如果此鍵的值無法用ASCII表示,則不會創(chuàng)建文檔廷蓉,并且創(chuàng)建函數(shù)將返回NULL全封。 Quartz使用40位加密。
  • kCGPDFContextUserPassword桃犬,用于定義PDF文檔的用戶密碼刹悴。如果文檔已加密,則此鍵的值是文檔的用戶密碼疫萤。如果未指定颂跨,則用戶密碼為空字符串。此鍵的值必須是可以ASCII編碼表示的CFString對象扯饶;只有前32個字節(jié)用于密碼恒削。如果此鍵的值無法用ASCII表示,則不會創(chuàng)建文檔尾序,并且創(chuàng)建函數(shù)將返回NULL钓丰。
  • kCGPDFContextAllowsPrinting指定在使用用戶密碼解鎖文檔時是否可以打印文檔。此鍵的值必須是CFBoolean對象每币。此鍵的默認值為kCFBooleanTrue携丁。
  • kCGPDFContextAllowsCopying指定在使用用戶密碼解鎖文檔時是否可以復(fù)制文檔。此鍵的值必須是CFBoolean對象兰怠。此鍵的默認值為kCFBooleanTrue梦鉴。

Listing 14-4(在下一章中)顯示了檢查PDF文檔是否被鎖定的代碼,如果是揭保,則嘗試使用密碼打開文檔肥橙。

后記

本篇主要講述了PDF文檔創(chuàng)建,查看和轉(zhuǎn)換秸侣,感興趣的給個贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末存筏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子味榛,更是在濱河造成了極大的恐慌椭坚,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搏色,死亡現(xiàn)場離奇詭異善茎,居然都是意外死亡,警方通過查閱死者的電腦和手機继榆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門巾表,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汁掠,“玉大人略吨,你說我怎么就攤上這事集币。” “怎么了翠忠?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵鞠苟,是天一觀的道長。 經(jīng)常有香客問我秽之,道長当娱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任考榨,我火速辦了婚禮跨细,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘河质。我一直安慰自己冀惭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布掀鹅。 她就那樣靜靜地躺著散休,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乐尊。 梳的紋絲不亂的頭發(fā)上戚丸,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音扔嵌,去河邊找鬼限府。 笑死,一個胖子當(dāng)著我的面吹牛痢缎,可吹牛的內(nèi)容都是我干的胁勺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼牺弄,長吁一口氣:“原來是場噩夢啊……” “哼姻几!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起势告,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤蛇捌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咱台,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體络拌,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年回溺,在試婚紗的時候發(fā)現(xiàn)自己被綠了春贸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片混萝。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖萍恕,靈堂內(nèi)的尸體忽然破棺而出逸嘀,到底是詐尸還是另有隱情,我是刑警寧澤允粤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布崭倘,位于F島的核電站,受9級特大地震影響类垫,放射性物質(zhì)發(fā)生泄漏司光。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一悉患、第九天 我趴在偏房一處隱蔽的房頂上張望残家。 院中可真熱鬧,春花似錦售躁、人聲如沸坞淮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽碾盐。三九已至,卻和暖如春揩局,著一層夾襖步出監(jiān)牢的瞬間毫玖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工凌盯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留付枫,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓驰怎,卻偏偏與公主長得像阐滩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子县忌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容