【问题标题】:Mac OS X: How to draw multiple NSViews into a new, multi-page PDF?Mac OS X:如何将多个 NSView 绘制成一个新的多页 PDF?
【发布时间】:2012-05-03 19:27:40
【问题描述】:

我有一个与图形相关的基于文档的 Mac 应用程序。我的应用程序的文档可能有多个“页面”。每个页面都有一个NSView“canvas”对象。

我的应用有几个导出选项,这些选项被实现为返回 NSData 对象(然后将其写入磁盘)的方法。

我想以以下方法实现 PDF 导出选项:

  1. 创建内存中的 PDF
  2. 循环遍历我文档的画布视图,并在内存 PDF 的新页面中呈现每个视图
  3. NSData 形式返回内存中的多页 PDF

下面的代码是我目前正在尝试的。

我文档中的每一页都是 800 x 600 像素。

当我将生成的NSData 对象写入磁盘时,写入操作成功,但磁盘上的文件以某种方式损坏。该文件无法在 Preview 或我尝试过的任何其他应用中打开。

我做错了什么?

NSMutableData *data = [NSMutableData data];
CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)data);

CGRect mediaBox = CGRectMake(0.0, 0.0, 800.0, 600.0);
CGContextRef ctx = CGPDFContextCreate(consumer, &mediaBox, NULL);
CFRelease(consumer);

NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:NO];

for (NSView *canvas in myCanvases) {
    CGContextBeginPage(ctx, &mediaBox);
    CGContextSaveGState(ctx);

    [canvas displayRectIgnoringOpacity:mediaBox inContext:gc];

    CGContextRestoreGState(ctx);
    CGContextEndPage(ctx);
}

CGPDFContextClose(ctx); // UPDATE: this line was originally missing. see answer below
CGContextRelease(ctx);

...

NSError *err = nil;
if (![data writeToFile:s options:NSDataWritingAtomic error:&err]) {
    if (err) {
        NSLog(@"%@", err);
    }
}

【问题讨论】:

  • 你能发布一个十六进制转储,可能是第一千字节的数据吗?
  • 为什么要导出到内存中的数据对象?为什么不直接导出到文件?
  • 我想知道你能否给我一些意见:stackoverflow.com/questions/10621858/… 谢谢!

标签: macos cocoa core-graphics quartz-2d


【解决方案1】:

在这里。我已经解决了这个问题。我错过了对CGPDFContextClose() 的最后一次通话。

所以在释放上下文之前...

CGPDFContextClose(ctx);
CGContextRelease(ctx);

【讨论】:

  • 我不敢相信它这么简单,谢谢!我在这上面浪费了几个小时,因为这个错误只是在我开始在 OS 10.10 上混合 NSString 绘图(通过 AppKit 扩展)时才发生,而不是在 OS 10.9 上,所以我正在寻找更复杂的东西。并且它之前在没有关闭上下文的情况下工作了几个月!
【解决方案2】:

我发现这是一个最有用的答案(并且必须在问题和答案上都对 OP 投赞成票!)。将它翻译成 Swift 3 时遇到了一些小问题,但这就像一个魅力,它可以在 iOS 上运行......

let data = NSMutableData()
guard let consumer = CGDataConsumer(data: data) else { Swift.print("Aargh - no CGDataConsumer"); return }
var mediaBox = CGRect(x: 0, y: 0, width: 800, height: 600)
guard let ctx = CGContext(consumer: consumer, mediaBox: &mediaBox, nil) else { Swift.print("Aargh - no CGContext"); return }

//let gc = NSGraphicsContext(cgContext: ctx, flipped: false) 
//I don't need the NS context, as my drawing routines just use CGContext

for page in self.pages { // Array of page models
    ctx.beginPage(mediaBox: &mediaBox)
    ctx.saveGState()
    myDraw(page, context: ctx, options: []) // My routine
    ctx.restoreGState()
    ctx.endPage()
}
ctx.closePDF()
do {
    try data.write(toFile: "/Users/grimxn/Test.pdf", options: .atomic)
} catch {
    Swift.print("Aargh - failed to write output file")
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-19
    • 2016-12-03
    • 2012-03-22
    • 2014-12-02
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多