Search code examples
iosswiftxcode6pixel

How to read and log the raw pixels of image in swift iOS


I need to read pixel values of an image and iterate to print in swift output, I have written this so far and used a RGBAImage class to read out pixels. I'm getting lost from CGContextRef to Iteration. I tried to write from CGImage, getting pixel data from objective C language to swift since I wanted to work in swift.

func createRGBAPixel(inImage: CGImageRef) -> CGContextRef {
//Image width, height

let pixelWidth = CGImageGetWidth(inImage)
let pixelHeight = CGImageGetHeight(inImage)

//Declaring number of bytes 

let bytesPerRow = Int(pixelWidth) * 4
let byteCount = bytesPerRow * Int(pixelHeight)

//RGB color space

let colorSpace = CGColorSpaceCreateDeviceRGB()

//Allocating image data

let mapData = malloc(byteCount)
let mapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)

//Create bitmap context

let context = CGBitmapContextCreate(mapData, pixelWidth, pixelHeight, Int(8), Int(bytesPerRow), colorSpace, mapInfo.rawValue)

let pixelImage = CGBitmapContextCreate(pixels, pixelWidth, pixelHeight, bitsPerComponent, bytesPerRow, colorSpace, mapInfo)
let CGContextRef = pixelImage
let CGContextDrawImage(context, CGRectMake(0, 0, pixelWidth, pixelHeight), inImage)

//Iterating and logging
print("Logging pixel counts")
let pixels = calloc(pixelHeight * pixelWidth, sizeof(UInt32))

let myImage = CGImageRef: inImage
let myRGBA = RGBAImage(image: myImage)! //RGBAImage class to read pixels.

var number = 0
var currentPixel:Int32 = 0
currentPixel = pixels * UInt32
for number in 0..<pixelHeight {
  for number in 0..<pixelWidth {
    var color = color * currentPixel
    print((pixel.red + pixel.green + pixel.blue) / 3.0)
    currentPixel++
  }
}
return context!
}

Solution

  • I created small class for this:

    class ImagePixelReader {
    
        enum Component:Int {
            case r = 0
            case g = 1
            case b = 2
            case alpha = 3
        }
    
        struct Color {
            var r:UInt8
            var g:UInt8
            var b:UInt8
            var a:UInt8
    
            var uiColor:UIColor {
                return UIColor(red:CGFloat(r)/255.0,green:CGFloat(g)/255.0,blue:CGFloat(b)/255.0,alpha:CGFloat(alpha)/255.0)
            }
    
        }
    
        let image:UIImage
    
        private var data:CFData
        private let pointer:UnsafePointer<UInt8>
        private let scale:Int
    
        init?(image:UIImage){
    
            self.image = image
            guard let cfdata = self.image.cgImage?.dataProvider?.data,
                  let pointer = CFDataGetBytePtr(cfdata) else {
                return nil
            }
            self.scale = Int(image.scale)
            self.data = cfdata
            self.pointer = pointer
        }
    
        func componentAt(_ component:Component,x:Int,y:Int)->UInt8{
    
            assert(CGFloat(x) < image.size.width)
            assert(CGFloat(y) < image.size.height)
    
            let pixelPosition = (Int(image.size.width) * y * scale + x) * 4 * scale
    
            return pointer[pixelPosition + component.rawValue]
        }
    
        func colorAt(x:Int,y:Int)->Color{
    
            assert(CGFloat(x) < image.size.width)
            assert(CGFloat(y) < image.size.height)
    
            let pixelPosition = (Int(image.size.width) * y * scale + x) * 4 * scale
    
            return Color(r: pointer[pixelPosition + Component.r.rawValue],
                         g: pointer[pixelPosition + Component.g.rawValue],
                         b: pointer[pixelPosition + Component.b.rawValue],
                         a: pointer[pixelPosition + Component.alpha.rawValue])
        }
    }
    

    How to use:

    if let reader = ImagePixelReader(image: yourImage) {
    
       //get alpha or color
       let alpha = reader.componentAt(.alpha, x: 10, y:10)
       let color = reader.colorAt(x:10, y: 10).uiColor
    
       //getting all the pixels you need
    
       var values = ""
    
       //iterate over all pixels
       for x in 0 ..< Int(image.size.width){
         for y in 0 ..< Int(image.size.height){
    
            let color = reader.colorAt(x: x, y: y)
            values += "[\(x):\(y):\(color)] "
    
         }
         //add new line for every new row
         values += "\n"
       }
    
       print(values)
    }