【问题标题】:Generate scaled image from off-screen NSView从屏幕外 NSView 生成缩放图像
【发布时间】:2012-07-07 17:45:42
【问题描述】:

我在 Cocoa 应用程序中有一系列离屏 NSView,它们用于编写 PDF 以进行打印。视图不在 NSWindow 中,或以任何方式可见。

我希望能够生成该视图的缩略图,与 PDF 的外观完全相同,但要按比例缩小以适应特定的像素大小(限制为宽度或高度)。这需要尽可能快,所以我想避免渲染为 PDF,然后转换为光栅和缩放 - 我想直接转到光栅。

目前我正在做:

NSBitmapImageRep *bitmapImageRep = [pageView bitmapImageRepForCachingDisplayInRect:pageView.bounds];
[pageView cacheDisplayInRect:pageView.bounds toBitmapImageRep:bitmapImageRep];
NSImage *image = [[NSImage alloc] initWithSize:bitmapImageRep.size];
[image addRepresentation:bitmapImageRep];

这种方法效果很好,但我不知道如何在渲染 bitmapImageRep 之前对 NSView 应用缩放。我想避免使用scaleUnitSquareToSize,因为据我了解,它只会改变边界,而不是 NSView 的框架。

对最好的方法有什么建议吗?

【问题讨论】:

    标签: objective-c macos cocoa nsview


    【解决方案1】:

    这就是我最终做的,效果很好。我们直接绘制到NSBitmapImageRep,但事先使用CGContextScaleCTM 显式缩放上下文。 graphicsContext.graphicsPort 为您提供 CGContextRef 上的句柄 NSGraphicsContext

    NSView *pageView = [self viewForPageIndex:pageIndex];
    
    float scale = width / pageView.bounds.size.width;
    float height = scale * pageView.bounds.size.height;
    
    NSRect targetRect = NSMakeRect(0.0, 0.0, width, height);
    NSBitmapImageRep *bitmapRep;
    
    bitmapRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
                                                        pixelsWide:targetRect.size.width
                                                        pixelsHigh:targetRect.size.height
                                                     bitsPerSample:8
                                                   samplesPerPixel:4
                                                          hasAlpha:YES
                                                          isPlanar:NO
                                                    colorSpaceName:NSCalibratedRGBColorSpace
                                                      bitmapFormat:0
                                                       bytesPerRow:(4 * targetRect.size.width)
                                                      bitsPerPixel:32];
    
    [NSGraphicsContext saveGraphicsState];
    
    NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmapRep];
    [NSGraphicsContext setCurrentContext:graphicsContext];
    CGContextScaleCTM(graphicsContext.graphicsPort, scale, scale);
    
    [pageView displayRectIgnoringOpacity:pageView.bounds inContext:graphicsContext];
    
    [NSGraphicsContext restoreGraphicsState];
    
    NSImage *image = [[NSImage alloc] initWithSize:bitmapRep.size];
    [image addRepresentation:bitmapRep];
    
    return image;
    

    【讨论】:

    • 我使用bitmapImageRepForCacheDisplayInRect:cacheDisplayInRect:toBitmapImageRep: 在启动时为笔记本应用程序动态生成缩略图。超过 40 个页面(层托管的 NSView)包含大量视觉内容,生成缩略图需要接近 90 秒。在以前的 macOS 版本中,情况并非如此。我用上面@tomtaylor 的方法替换了这个方法,使用了 1.0 的比例(因为我需要缩略图来流畅地向上缩放到全尺寸)并且缩略图生成下降到 20 秒(背景),使用了大约一半的虚拟内存!跨度>
    【解决方案2】:

    使用scaleUnitSquareToSize: 然后将一个较小的矩形传递给bitmapImageRepForCachingDisplayInRect:cacheDisplayInRect:toBitmapImageRep: 怎么样?

    因此,如果您将其缩小 2 倍,您将传递一个带有边界和高度的半边矩形。

    【讨论】:

    • 我正在使用 Cocoa 文本布局系统以及 NSTextContainer。据我了解,这只能在 NSView 级别实现。
    • 啊,对不起,我误会了。我以为您正在显示 PDF,但您正在从现有视图创建 PDF。
    • 我提出了一些新的建议;我认为你的计划是有道理的。您也可以尝试使用支持图层的视图并在该图层上使用变换。 (我更习惯于 iOS,这是很自然的事情。)
    猜你喜欢
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    • 2018-03-02
    • 1970-01-01
    • 2012-05-10
    • 2011-12-24
    相关资源
    最近更新 更多