创建分页 PDF—Mac OS X [英] Create a paginated PDF—Mac OS X

查看:18
本文介绍了创建分页 PDF—Mac OS X的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个 Mac 应用程序(在 Swift 3 中使用 Xcode 8、Beta 5),用户可以使用它制作长笔记并将其导出为 PDF.

要创建此 PDF,我使用 Cocoa 的 dataWithPDF: 方法和以下代码:

做{//将 PDF 的边界定义为注释文本视图让矩形:NSRect = self.noteTextView.bounds//创建 PDF 的文件路径if let dir = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true).first {//将笔记标题添加到路径让路径 = NSURL(fileURLWithPath: dir).appendingPathComponent("ExportedNote.pdf")//创建noteTextView 的PDF 并将其写入创建的文件路径尝试 self.noteTextView.dataWithPDF(inside: rect).write(to: path!)} 别的 {打印(路径格式不正确.")//从来没有发生在我身上}} 抓住 _ {打印(出了点问题.")//从来没有发生在我身上}

这完全有效,但有一个问题:PDF 只出现在一页上,这意味着当笔记中有很多文本时,页面会变得很长.在我的应用程序正在导出 PDF 时或之后,我如何强制将 PDF 放到尽可能多的信纸大小的页面上?

解决方案

经过数周的挫折之后,我想出了在 Swift 应用程序中创建分页 PDF 的最终方法.而且它并不像看起来那么复杂(以下内容基于 Swift 2):

<小时>

注意:在您阅读更多内容之前,您应该知道我在 Github 上制作了一个简单的工具,因此您可以通过更少的步骤完成此操作(在 Swift 3 中,不再需要任何 Objective-C).查看一些非常基础的内容.

应该就是这样!您现在应该能够在 Cocoa/Mac 应用程序上直接从 Swift 创建分页 PDF.

<小时>

学分

注意:此答案经过测试可与 Xcode 7、Swift 2 和 OS X El Captian 一起使用.如果您在 Xcode 8/Swift 3/macOS Sierra 上使用它时遇到任何问题,请告诉我.

I am making a Mac app (in Swift 3 using Xcode 8, Beta 5) with which the user can make a long note and export it as a PDF.

To create this PDF, I am using Cocoa's dataWithPDF: method with the following code:

do {
   // define bounds of PDF as the note text view
   let rect: NSRect = self.noteTextView.bounds
   // create the file path for the PDF
   if let dir = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true).first {
        // add the note title to path
        let path = NSURL(fileURLWithPath: dir).appendingPathComponent("ExportedNote.pdf")
        // Create a PDF of the noteTextView and write it to the created filepath
        try self.noteTextView.dataWithPDF(inside: rect).write(to: path!)  
   } else {
        print("Path format incorrect.") // never happens to me
   }

} catch _ {
    print("something went wrong.") // never happens to me
}

This completely works, but there's one problem: the PDF goes only on one page, which means the page gets really long when there's a lot of text in the note. How can I force the PDF to go onto as many letter-size pages as it needs, either while my app is exporting the PDF or right after?

解决方案

After weeks of frustration, I have come up with the definitive way of creating a paginated PDF in a Swift app. And it's not as complicated as it seems (the following is based on Swift 2):


Note: Before you read more, you should know I made an easy tool on Github so you can do this in many fewer steps (and in Swift 3, which no longer needs any Objective-C). Check that out here.


Step 1: Set up your App Sandboxing correctly. Every submitted Mac app requires App Sandboxing correctly, so it's best to just take 30 seconds to set it up right now. If it's not on already, go to your Target's settings and then the Capabilities header. Turn on App Sandboxing, up at the top. You should see many sub-capabilities, enable any one of these your app needs, and make sure to have User Selected File set to Read/Write.

Step 2: Add this function to your code, which will create an invisible webview and add your text into it.

func createPDF(fromHTMLString: String) {
            self.webView.mainFrame.loadHTMLString(htmlString, baseURL: nil)
            self.delay(1) {
            MyCreatePDFFile(self.webView)
    }
}

Step 3: Create the delay() function to allow Xcode to wait a second for the HTML to be loaded into the web view.

 func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

(Note: For the Swift 3 version of this function, go here.)

Step 4: Add the declaration of our WebView above the function you added in step 2.

var webView = WebView()

Step 5: You may notice that we haven't created the MyCreatePDFFile() function yet. Turns out that there is no way to convert this WebView to a PDF with Swift, so we're going to have to turn to Objective-C (groan). Yep, you're going to have to run some Objective-C in your Swift app.

Step 6: Create a .m file by going to File -> New -> File (or by hitting CMD + N) then double-clicking on Objective-C File. Name it CreatePDF.m and leave it as an Empty File.

Step 7: When adding your .m file, you should get a prompt to add a bridging header:

Click Yes.

If you did not see the prompt, or accidentally deleted your bridging header, add a new .h file to your project and name it <#YourProjectName#>-Bridging-Header.h

In some situations, particularly when working with ObjC frameworks, you don't add an Objective-C class explicitly and Xcode can't find the linker. In this case, create your Bridging Header .h file named as mentioned above, then make sure you link its path in your target's project settings like this:

Step 8: Create a .h file by going to File -> New -> File (or by hitting CMD + N) then double-clicking on Header File. Name it CreatePDF.h.

Step 9: In your CreatePDF.h file, add the following code, which imports Cocoa and WebKit and sets up for your PDF creation function:

#ifndef CreatePDF_h
#define CreatePDF_h

#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>

@interface Thing : NSObject

void MyCreatePDFFile(WebView *thewebview);

@end


#endif /* CreatePDF_h */

Step 10: Time to setup the .m file for the PDF creation function. Start by adding this to the empty .m file:

#import "CreatePDF.h"
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>

@implementation Thing

void MyCreatePDFFile(WebView *thewebview) {

}
@end

Step 11: Now you can add the code to the MyCreatePDFFile(..) function. Here's the function itself (this goes inside the currently-empty void function):

NSDictionary *printOpts = @{
    NSPrintJobDisposition: NSPrintSaveJob // sets the print job to save the PDF instead of print it.
};
NSPrintInfo *printInfo = [[NSPrintInfo alloc] initWithDictionary:printOpts];    
[printInfo setPaperSize:NSMakeSize(595.22, 841.85)]; // sets the paper size to a nice size that works, you can mess around with it
[printInfo setTopMargin:10.0];
[printInfo setLeftMargin:10.0];
[printInfo setRightMargin:10.0];
[printInfo setBottomMargin:10.0];
NSPrintOperation *printOp = [NSPrintOperation printOperationWithView:[[[thewebview mainFrame] frameView] documentView] printInfo:printInfo]; // sets the print operation to printing the WebView as a document with the print info set above
printOp.showsPrintPanel = NO; // skip the print question and go straight to saving pdf
printOp.showsProgressPanel = NO; 
[printOp runOperation];

Step 12: Now add this to your bridging header to allow your Swift file to see that Objective-C function you just made.

#import "CreatePDF.h"

Step 13: There shouldn't be any errors from this code left, but if there are please comment below about them.

Step 14: To call the createPDF function from anywhere your Swift file, do the following:

createPDF("<h1>Title!</h1><p>(textview.text!)</p>")

The string you see inside createPDF is HTML, and can be edited to anything HTML. If you don't know HTML, you can see some of the very basics right here.

That should be it! You should now be able to create paginated PDFs right from Swift, on Cocoa/Mac apps.


Credits

Note: This answer was tested to work with Xcode 7, Swift 2, and OS X El Captian. If you have any problems using it with Xcode 8/Swift 3/macOS Sierra, let me know.

这篇关于创建分页 PDF—Mac OS X的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆