酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

OSXアプリのSwiftのNSImageで扱う

iOSでいうところのUIImageはOS XですとNSImageに該当します(たぶん)。

iOSアプリを作っているとUIImageはよく使うのでなんとなく扱えるようになりますが、Macアプリを使ったことがないためNSImageの方はよく分からず……調べながら実装したものをメモっておきます。普段から使わないのでいざという時に忘れがちですね。

ファイルからNSImageを読み出す

let sourcePath = "/hoge/piyo.png"
let image = NSImage(contentsOfFile: sourcePath)

NSImageをPNGフォーマットで保存する

フォーマットを変更するとJPEGやJEPG200形式にエンコードさせることもできるようです。

private func saveAsPng(srcImage: NSImage?, _ distPath: String?) -> Bool {
    guard let srcImage = srcImage, distPath = distPath else {
        return false
    }
    guard let tiff = srcImage.TIFFRepresentation, imgRep = NSBitmapImageRep(data: tiff) else {
        return false
    }
    
    // PNGで保存する
    guard let data = imgRep.representationUsingType(.NSPNGFileType, properties: [:]) else {
        return false
    }
    
    data.writeToFile(distPath, atomically: true)
    
    return true
}

リサイズする

リサイズ時にはUIImageでも同じかな。白紙の領域を用意してそこに対して元画像を指定サイズで書き込む感じです。

func resize(newSize: NSSize) -> NSImage? {
    let sourceImage = self
    if !sourceImage.valid {
        return nil
    }
    
    let newImage = NSImage(size: newSize)
    newImage.lockFocus()
    
    sourceImage.size = newSize
    
    NSGraphicsContext.currentContext()?.imageInterpolation = .High
    sourceImage.drawAtPoint(NSPoint.zero, fromRect: CGRectMake(0,0,newSize.width,newSize.height), operation: .CompositeCopy, fraction: 1.0)
    newImage.unlockFocus()
    
    return newImage
}

すべてのピクセルの平均値を求める

全ピクセルを取得してreduceで畳み込みます。あまり使いどころがないように思えます。

private func avarageColor(srcImage: NSImage?) -> NSColor? {
    guard let srcImage = srcImage else {
        return nil
    }
    
    // すべてのピクセルの画素の色を取得する
    var colors = [NSColor]()
    if let d = srcImage.TIFFRepresentation, imageRep = NSBitmapImageRep(data: d) {
        for x in 0 ..< Int(srcImage.size.width) {
            for y in 0 ..< Int(srcImage.size.height) {
                if let c = imageRep.colorAtX(x, y: y) {
                    colors.append(c)
                }
            }
        }
    }
    
    // 平均を求めるマン
    class Color {
        var R: CGFloat = 0
        var G: CGFloat = 0
        var B: CGFloat = 0
    }
    
    let color = colors.map { (color) -> (CGFloat, CGFloat, CGFloat) in
        return (color.redComponent, color.redComponent, color.redComponent)
    }.reduce(Color(), combine: { (color: Color, c) -> Color in
        color.R = (color.R + c.0) / 2
        color.G = (color.G + c.1) / 2
        color.B = (color.B + c.2) / 2
        return color
    })
    
    return NSColor(calibratedRed: color.R, green: color.G, blue: color.B, alpha: 1.0)
}