2016-12-21 9 views
1

画像の無作為なサンプルを取れるようにNSImage拡張を書きました。私はこれらのサンプルが元の画像と同じ品質を保持したいと思います。しかし、それらはエイリアスまたはわずかにぼやけているように見えます。ここでは一例だ - 右と左のランダムなサンプルに描かれたオリジナル:サンプルNSImageと品質保持(スイフト3)

sample

私は、現時点では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では拡張子(と乱数funcが)です:

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のサンプルを作成するにはどうすればよいですか?

+0

'NSImageInterpolation.none'を試してください。また、 'cgImage(forProposedRect:...)'がフレームを変更した場合は描画する 'in:' rectを変更する必要があります。基本的に、(-x、-y)でオフセットされた 'frame'のコピーを使用して、(x、y)の代わりに(0、0)を基準にしてください。 –

+0

ありがとう@KenThomases! 'NSImageInterpolation.none'はそのトリックを行いました。私はそれ以外のすべての価値を試したと思う。回答を追加したい場合は、正しいとマークします。 – Clay

答えて

1

この場合、内挿モードをNSImageInterpolation.noneに切り替えるだけで十分です。

描画先の四角形を正しく処理することも重要です。 cgImage(forProposedRect:...)は、提案された矩形を変更する可能性があるので、それに基づいた宛先矩形を使用する必要があります。基本的には、(x、y)ではなく(0、0)に相対的になるように、(-x、-y)でオフセットされたframeのコピーを使用してください。

関連する問題