创建分页 PDF—Mac OS X
Create a paginated PDF—Mac OS X
我正在制作一个 Mac 应用程序(在 Swift 3 中使用 Xcode 8,Beta 5),用户可以使用它做一个长笔记并将其导出为 PDF。
要创建此 PDF,我使用 Cocoa 的 dataWithPDF:
方法和以下代码:
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
}
这完全有效,但有一个问题:PDF 只在一页上,这意味着当笔记中有很多文本时,页面会变得很长。如何在我的应用程序正在导出 PDF 时或之后立即强制 PDF 进入所需数量的信纸大小的页面?
经过几周的挫折,我想出了在 Swift 应用程序中创建分页 PDF 的最终方法。而且它并没有看起来那么复杂(以下是根据Swift 2):
注意:在阅读更多内容之前,您应该知道我在 Github 上制作了一个简单的工具,因此您可以这在更少的步骤中(并且在 Swift 3 中,不再需要任何 Objective-C)。 Check that out here.
第 1 步:正确设置应用程序沙盒。每个提交的 Mac 应用程序都需要应用程序沙盒正确设置,因此最好立即花 30 秒设置它。如果它还没有打开,请转到您的 Target 的设置,然后转到 Capabilities header。打开 App Sandboxing,在顶部。您应该会看到许多 sub-capabilities,启用您的应用需要的任何一个,并确保将 User Selected File
设置为 Read/Write
。
第 2 步:将此函数添加到您的代码中,这将创建一个不可见的 webview 并将您的文本添加到其中。
func createPDF(fromHTMLString: String) {
self.webView.mainFrame.loadHTMLString(htmlString, baseURL: nil)
self.delay(1) {
MyCreatePDFFile(self.webView)
}
}
第 3 步: 创建 delay()
函数以允许 Xcode 等待一秒钟,以便将 HTML 加载到网络中看法。
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
(注:对于Swift3版本的这个函数,go here。)
第 4 步:在第 2 步中添加的函数上方添加 WebView 的声明。
var webView = WebView()
第 5 步: 您可能会注意到我们还没有创建 MyCreatePDFFile()
函数。原来用Swift是没办法把这个WebView转成PDF的,所以我们只好求助于Objective-C(唉)。是的,您将不得不在 Swift 应用程序中 运行 一些 Objective-C。
第 6 步: 通过转到 File
-> New
-> File
创建一个 .m
文件(或通过点击 CMD + N) 然后在 Objective-C File
上点击 double-clicking。将其命名为 CreatePDF.m
并将其保留为空文件。
第 7 步: 添加 .m
文件时,系统会提示您添加桥接 header:
单击 Yes
。
如果您没有看到提示,或者不小心删除了您的桥接 header,请将新的 .h
文件添加到您的项目并将其命名为 <#YourProjectName#>-Bridging-Header.h
在某些情况下,尤其是在使用 ObjC 框架时,您不会显式添加 Objective-C class 并且 Xcode 找不到 linker .在这种情况下,创建如上所述命名的桥接 Header .h
文件,然后确保 link 它在目标项目设置中的路径如下:
步骤 8: 通过转到 File
-> New
-> File
创建一个 .h
文件(或通过点击 CMD + N) 然后在 Header File
上点击 double-clicking。将其命名为 CreatePDF.h
.
第 9 步: 在您的 CreatePDF.h
文件中,添加以下代码,导入 Cocoa 和 WebKit 并设置您的 PDF 创建功能:
#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 */
第 10 步: 是时候为 PDF 创建功能设置 .m
文件了。首先将其添加到空的 .m
文件中:
#import "CreatePDF.h"
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
@implementation Thing
void MyCreatePDFFile(WebView *thewebview) {
}
@end
第 11 步: 现在您可以将代码添加到 MyCreatePDFFile(..)
函数中。这是函数本身(它在 currently-empty void
函数中):
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];
第 12 步: 现在将其添加到您的桥接 header 以允许您的 Swift 文件看到您刚刚创建的 Objective-C 函数.
#import "CreatePDF.h"
第 13 步:这段代码应该没有任何错误,但如果有,请在下方评论。
第 14 步:要从 Swift 文件的任何位置调用 createPDF
函数,请执行以下操作:
createPDF("<h1>Title!</h1><p>\(textview.text!)</p>")
您在 createPDF
中看到的字符串是 HTML,可以编辑为任何内容 HTML。如果你不知道HTML,你可以看一些非常基础的知识right here。
应该是这样!您现在应该可以在 Cocoa/Mac 应用程序上直接从 Swift 创建分页 PDF。
学分
How to write a PDF from a WebView in Obj-C,感谢一些随机的网络论坛。
- How to create a bridging header manually,感谢 Logan。
- Delay function in Swift,感谢马特
- Images,感谢 Logan。
注意:这个答案已经过测试,可以与 Xcode 7、Swift 2 和 OS X El Captian 一起使用。如果您在使用 Xcode 8/Swift 3/macOS Sierra 时遇到任何问题,请告诉我。
我正在制作一个 Mac 应用程序(在 Swift 3 中使用 Xcode 8,Beta 5),用户可以使用它做一个长笔记并将其导出为 PDF。
要创建此 PDF,我使用 Cocoa 的 dataWithPDF:
方法和以下代码:
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
}
这完全有效,但有一个问题:PDF 只在一页上,这意味着当笔记中有很多文本时,页面会变得很长。如何在我的应用程序正在导出 PDF 时或之后立即强制 PDF 进入所需数量的信纸大小的页面?
经过几周的挫折,我想出了在 Swift 应用程序中创建分页 PDF 的最终方法。而且它并没有看起来那么复杂(以下是根据Swift 2):
注意:在阅读更多内容之前,您应该知道我在 Github 上制作了一个简单的工具,因此您可以这在更少的步骤中(并且在 Swift 3 中,不再需要任何 Objective-C)。 Check that out here.
第 1 步:正确设置应用程序沙盒。每个提交的 Mac 应用程序都需要应用程序沙盒正确设置,因此最好立即花 30 秒设置它。如果它还没有打开,请转到您的 Target 的设置,然后转到 Capabilities header。打开 App Sandboxing,在顶部。您应该会看到许多 sub-capabilities,启用您的应用需要的任何一个,并确保将 User Selected File
设置为 Read/Write
。
第 2 步:将此函数添加到您的代码中,这将创建一个不可见的 webview 并将您的文本添加到其中。
func createPDF(fromHTMLString: String) {
self.webView.mainFrame.loadHTMLString(htmlString, baseURL: nil)
self.delay(1) {
MyCreatePDFFile(self.webView)
}
}
第 3 步: 创建 delay()
函数以允许 Xcode 等待一秒钟,以便将 HTML 加载到网络中看法。
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
(注:对于Swift3版本的这个函数,go here。)
第 4 步:在第 2 步中添加的函数上方添加 WebView 的声明。
var webView = WebView()
第 5 步: 您可能会注意到我们还没有创建 MyCreatePDFFile()
函数。原来用Swift是没办法把这个WebView转成PDF的,所以我们只好求助于Objective-C(唉)。是的,您将不得不在 Swift 应用程序中 运行 一些 Objective-C。
第 6 步: 通过转到 File
-> New
-> File
创建一个 .m
文件(或通过点击 CMD + N) 然后在 Objective-C File
上点击 double-clicking。将其命名为 CreatePDF.m
并将其保留为空文件。
第 7 步: 添加 .m
文件时,系统会提示您添加桥接 header:
单击 Yes
。
如果您没有看到提示,或者不小心删除了您的桥接 header,请将新的 .h
文件添加到您的项目并将其命名为 <#YourProjectName#>-Bridging-Header.h
在某些情况下,尤其是在使用 ObjC 框架时,您不会显式添加 Objective-C class 并且 Xcode 找不到 linker .在这种情况下,创建如上所述命名的桥接 Header .h
文件,然后确保 link 它在目标项目设置中的路径如下:
步骤 8: 通过转到 File
-> New
-> File
创建一个 .h
文件(或通过点击 CMD + N) 然后在 Header File
上点击 double-clicking。将其命名为 CreatePDF.h
.
第 9 步: 在您的 CreatePDF.h
文件中,添加以下代码,导入 Cocoa 和 WebKit 并设置您的 PDF 创建功能:
#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 */
第 10 步: 是时候为 PDF 创建功能设置 .m
文件了。首先将其添加到空的 .m
文件中:
#import "CreatePDF.h"
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
@implementation Thing
void MyCreatePDFFile(WebView *thewebview) {
}
@end
第 11 步: 现在您可以将代码添加到 MyCreatePDFFile(..)
函数中。这是函数本身(它在 currently-empty void
函数中):
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];
第 12 步: 现在将其添加到您的桥接 header 以允许您的 Swift 文件看到您刚刚创建的 Objective-C 函数.
#import "CreatePDF.h"
第 13 步:这段代码应该没有任何错误,但如果有,请在下方评论。
第 14 步:要从 Swift 文件的任何位置调用 createPDF
函数,请执行以下操作:
createPDF("<h1>Title!</h1><p>\(textview.text!)</p>")
您在 createPDF
中看到的字符串是 HTML,可以编辑为任何内容 HTML。如果你不知道HTML,你可以看一些非常基础的知识right here。
应该是这样!您现在应该可以在 Cocoa/Mac 应用程序上直接从 Swift 创建分页 PDF。
学分
How to write a PDF from a WebView in Obj-C,感谢一些随机的网络论坛。
- How to create a bridging header manually,感谢 Logan。
- Delay function in Swift,感谢马特
- Images,感谢 Logan。
注意:这个答案已经过测试,可以与 Xcode 7、Swift 2 和 OS X El Captian 一起使用。如果您在使用 Xcode 8/Swift 3/macOS Sierra 时遇到任何问题,请告诉我。