【问题标题】:Sample NSImage and retain quality (swift 3)采样 NSImage 并保持质量(swift 3)
【发布时间】:2016-12-21 17:33:31
【问题描述】:

我编写了一个 NSImage 扩展来允许我对图像进行随机采样。我希望这些样本保持与原始图像相同的质量。但是,它们似乎混叠或略微模糊。这是一个示例 - 右侧绘制的原始样本和左侧的随机样本:

我现在在 SpriteKit 中玩这个。以下是我创建原始图像的方法:

    let bg = NSImage(imageLiteralResourceName: "ref")
    let tex = SKTexture(image: bg)
    let sprite = SKSpriteNode(texture: tex)
    sprite.position = CGPoint(x: size.width/2, y:size.height/2)
    addChild(sprite)

这是我创建示例的方式:

    let sample = bg.sample(size: NSSize(width: 100, height: 100))
    let sampletex = SKTexture(image:sample!)
    let samplesprite = SKSpriteNode(texture:sampletex)
    samplesprite.position = CGPoint(x: 60, y:size.height/2)
    addChild(samplesprite)

这是创建示例的 NSImage 扩展(和 randomNumber 函数):

extension NSImage {

    /// Returns the height of the current image.
    var height: CGFloat {
        return self.size.height
    }

    /// Returns the width of the current image.
    var width: CGFloat {
        return self.size.width
    }

    func sample(size: NSSize) -> NSImage? {
        // Resize the current image, while preserving the aspect ratio.
        let source = self

        // Make sure that we are within a suitable range
        var checkedSize    = size
        checkedSize.width  = floor(min(checkedSize.width,source.size.width * 0.9))
        checkedSize.height = floor(min(checkedSize.height, source.size.height * 0.9))

        // Get random points for the crop.
        let x = randomNumber(range: 0...(Int(source.width) - Int(checkedSize.width)))
        let y = randomNumber(range: 0...(Int(source.height) - Int(checkedSize.height)))

        // Create the cropping frame.
        var frame = NSRect(x: x, y: y, width: Int(checkedSize.width), height: Int(checkedSize.height))

        // let ref = source.cgImage.cropping(to:frame)
        let ref = source.cgImage(forProposedRect: &frame, context: nil, hints: nil)
        let rep = NSBitmapImageRep(cgImage: ref!)

        // Create a new image with the new size
        let img = NSImage(size: checkedSize)

        // Set a graphics context
        img.lockFocus()
        defer { img.unlockFocus() }

        // Fill in the sample image
        if rep.draw(in: NSMakeRect(0, 0, checkedSize.width, checkedSize.height),
                    from: frame,
                    operation: NSCompositingOperation.copy,
                    fraction: 1.0,
                    respectFlipped: false,
                    hints: [NSImageHintInterpolation:NSImageInterpolation.high.rawValue]) {
            // Return the cropped image.
            return img
        }

        // Return nil in case anything fails.
        return nil
    }

}

func randomNumber(range: ClosedRange<Int> = 0...100) -> Int {
    let min = range.lowerBound
    let max = range.upperBound
    return Int(arc4random_uniform(UInt32(1 + max - min))) + min
}

我已经尝试了大约 10 种不同的方法,但结果似乎总是有点模糊。我什至检查了屏幕上的污迹。 :)

如何创建一个 NSImage 样本,以保留原始源图像部分的确切质量?

【问题讨论】:

  • 试试NSImageInterpolation.none。此外,如果cgImage(forProposedRect:...) 更改了框架,那么您应该更改您绘制的in: 矩形。您基本上应该使用由 (-x, -y) 偏移的 frame 的副本,因此它相对于 (0, 0) 而不是 (x, y)。
  • 感谢@KenThomases! NSImageInterpolation.none 成功了。我想我已经尝试了除此之外的所有价值观。如果您想添加答案,我会将其标记为正确。

标签: swift macos appkit


【解决方案1】:

在这种情况下,将插值模式切换为 NSImageInterpolation.none 显然就足够了。

正确处理绘制目标矩形也很重要。由于cgImage(forProposedRect:...) 可能会更改建议的矩形,因此您应该使用基于它的目标矩形。您基本上应该使用由 (-x, -y) 偏移的 frame 的副本,因此它相对于 (0, 0) 而不是 (x, y)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 2019-12-27
    • 1970-01-01
    相关资源
    最近更新 更多