Wednesday, September 17, 2014

Image Dump using Swift

目前大多的工作是設計方面的,
對於了解視覺方面的事情平時自然也很有興趣,
所以用 Swift 寫寫圖片相關的東西了解運作也是很正常的。

回到主題,之前是因為看到有人用 Objective-C 寫了一個 Image Dump,
而最近因為寫一個簡報,就順手改寫了個 Swift 的版本,
也把一些筆記整理進來。

先來看一下程式碼,如下:
func imageDump(img:UIImage){
        
        let imageRef = img.CGImage
        
        let width = CGImageGetWidth(imageRef)
        let height = CGImageGetHeight(imageRef)
        let bytesPerRow = CGImageGetBytesPerRow(imageRef)
        let bitsPerPixel = CGImageGetBitsPerPixel(imageRef)
        let colorSpace = CGImageGetColorSpace(imageRef)
        let bitPerComponent = CGImageGetBitsPerComponent(imageRef);
        let bytesPerPixel = bitsPerPixel / bitPerComponent;
        
        let provider:CGDataProviderRef = CGImageGetDataProvider(imageRef)
        let data:NSData = CGDataProviderCopyData(provider)
        let bytes = data.bytes // Needs to be changed to ConstUnsafePointer<()> in xCode beta3
        let bytePointer = UnsafePointer(bytes)
        
        println("\n")
        println("Pixel Data:\n")
        
        var printString:String = ""
        
        for var row:Int = 0; row < Int(height); row++ {
            for var col:Int = 0; col < Int(width); col++ {
                
                printString += "("
                
                for var x = 0; x < Int(bytesPerPixel); x++ {
                    var channel:UInt8 = bytePointer[row * Int(bytesPerRow) + col * Int(bytesPerPixel) + x]
                    printString += NSString(format:"%.2X, ", channel)
                }
                
                printString += ")"
                
                if col < Int(width) - 1 {
                    printString += ","
                }
                
            }
            printString += "\n"
        }
        
        println(printString)
        
    }


關於 CGImage 參數


這邊使用的是一張 4 x 3 像素的 png 圖片,
一開始先把 UIImage 轉為 CGImage,
藉由 CGImage 取得一些需要的數據,
println("bytesPerRow",bytesPerRow) //16
println("bitsPerPixel",bitsPerPixel) //32
println("bitPerComponent",bitPerComponent) //8
println("bytesPerPixel",bytesPerPixel) //4
bitPerComponent 為 8, 是因為圖片為 ARGB8888。
  *關於ARGB8888參考連結


bytesPerPixel 為 4 bytes 是由 bitPerComponent 而來,
R、G、B、A 每個 Channel 都使用 8 bits,
所以每個像素的 R、G、B、A 加起來是 32 bits = 4 bytes。 (1 bit = 8 bytes)
 因此 bitsPerPixel 從 bytesPerPixel 換算來就是 32 bits。


bytesPerRow 為 16 是跟圖片的寬度有關,
前面說一個像素是 4 bytes,乘上圖片寬度 4 像素, 就為 16 啦!
  *別處對於CGImageRef的參數解釋

 println(data) 的話,可以直接看到 4 x 3 的圖片 RGBA 數據
39b64eff fcee09ff 0005e8ff ed1b2eff 00bbf7ff e90189ff fc9512ff fcf006ff ee352bff c9e3daff 3ab84aff 02abecff


關於 row 跟 col 的迴圈
for迴圈那是利用 row(height) 跟 col(width) 來取得每個像素位置,如下圖


關於每個像素 channel 的值
最內層的迴圈for var x = 0; x < Int(bytesPerPixel); x++
 x會為0~3,也就是像素的寬度。
在 bytePointer[row * Int(bytesPerRow) + col * Int(bytesPerPixel) + x] 得到的數值可以這樣看

 另外,不知道為什麼下面這些程式碼開專案寫可以,但寫在Playground就不行。
let imageRef = img.CGImage
let provider:CGDataProviderRef = CGImageGetDataProvider(imageRef)
let data:NSData = CGDataProviderCopyData(provider)

其他相關資料:
ROMAIN GUY講位圖質量
關於轉換位圖陣列ARGB8888到RGB565


No comments:

Post a Comment