Get pixel data as array from UIImage/CGImage in swift

后端 未结 3 1569
梦毁少年i
梦毁少年i 2020-12-01 12:14

I have an app so far that allows the user to free draw (like a sketch pad) on a UIImageView element.

I want to get the raw RGB pixel data (as <

相关标签:
3条回答
  • 2020-12-01 12:58

    Converting a CGImage to an array of intensity values

    My function takes a CGImage and returns an array of unsigned 8-bit integers as well as the width and height of the image. I wrote this code for use with grayscale images. Extending this to color should be a matter of changing Gray to RGB and changing the bytes per pixel to 3 assuming no alpha channel.

    func pixelValues(fromCGImage imageRef: CGImage?) -> (pixelValues: [UInt8]?, width: Int, height: Int)
    {
        var width = 0
        var height = 0
        var pixelValues: [UInt8]?
        if let imageRef = imageRef {
            width = imageRef.width
            height = imageRef.height
            let bitsPerComponent = imageRef.bitsPerComponent
            let bytesPerRow = imageRef.bytesPerRow
            let totalBytes = height * bytesPerRow
    
            let colorSpace = CGColorSpaceCreateDeviceGray()
            var intensities = [UInt8](repeating: 0, count: totalBytes)
    
            let contextRef = CGContext(data: &intensities, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: 0)
            contextRef?.draw(imageRef, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(width), height: CGFloat(height)))
    
            pixelValues = intensities
        }
    
        return (pixelValues, width, height)
    }
    
    func image(fromPixelValues pixelValues: [UInt8]?, width: Int, height: Int) -> CGImage?
    {
        var imageRef: CGImage?
        if var pixelValues = pixelValues {
            let bitsPerComponent = 8
            let bytesPerPixel = 1
            let bitsPerPixel = bytesPerPixel * bitsPerComponent
            let bytesPerRow = bytesPerPixel * width
            let totalBytes = height * bytesPerRow
    
            imageRef = withUnsafePointer(to: &pixelValues, {
                ptr -> CGImage? in
                var imageRef: CGImage?
                let colorSpaceRef = CGColorSpaceCreateDeviceGray()
                let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(CGBitmapInfo())
                let data = UnsafeRawPointer(ptr.pointee).assumingMemoryBound(to: UInt8.self)
                let releaseData: CGDataProviderReleaseDataCallback = {
                    (info: UnsafeMutableRawPointer?, data: UnsafeRawPointer, size: Int) -> () in
                }
    
                if let providerRef = CGDataProvider(dataInfo: nil, data: data, size: totalBytes, releaseData: releaseData) {
                    imageRef = CGImage(width: width,
                                       height: height,
                                       bitsPerComponent: bitsPerComponent,
                                       bitsPerPixel: bitsPerPixel,
                                       bytesPerRow: bytesPerRow,
                                       space: colorSpaceRef,
                                       bitmapInfo: bitmapInfo,
                                       provider: providerRef,
                                       decode: nil,
                                       shouldInterpolate: false,
                                       intent: CGColorRenderingIntent.defaultIntent)
                }
    
                return imageRef
            })
        }
    
        return imageRef
    }
    
    0 讨论(0)
  • 2020-12-01 13:08

    In Swift 3 and Swift 4, using Core Graphics, it is quite easy to do what you want:

    extension UIImage {
        func pixelData() -> [UInt8]? {
            let size = self.size
            let dataSize = size.width * size.height * 4
            var pixelData = [UInt8](repeating: 0, count: Int(dataSize))
            let colorSpace = CGColorSpaceCreateDeviceRGB()
            let context = CGContext(data: &pixelData,
                                    width: Int(size.width),
                                    height: Int(size.height),
                                    bitsPerComponent: 8,
                                    bytesPerRow: 4 * Int(size.width),
                                    space: colorSpace,
                                    bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue)
            guard let cgImage = self.cgImage else { return nil }
            context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    
            return pixelData
        }
     }
    
    0 讨论(0)
  • 2020-12-01 13:15

    Please try this. This worked right for me.

    func pixelValues(fromCGImage imageRef: CGImage?) -> [UInt8]?
        {
            var width = 0
            var height = 0
            var pixelValues: [UInt8]?
    
            if let imageRef = imageRef {
                width = imageRef.width
                height = imageRef.height
                let bitsPerComponent = imageRef.bitsPerComponent
                let bytesPerRow = imageRef.bytesPerRow
                let totalBytes = height * bytesPerRow
                let bitmapInfo = imageRef.bitmapInfo
    
                let colorSpace = CGColorSpaceCreateDeviceRGB()
                var intensities = [UInt8](repeating: 0, count: totalBytes)
    
                let contextRef = CGContext(data: &intensities,
                                          width: width,
                                         height: height,
                               bitsPerComponent: bitsPerComponent,
                                    bytesPerRow: bytesPerRow,
                                          space: colorSpace,
                                     bitmapInfo: bitmapInfo.rawValue)
                contextRef?.draw(imageRef, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(width), height: CGFloat(height)))
    
                pixelValues = intensities
            }
    
            return pixelValues
    }
    
    0 讨论(0)
提交回复
热议问题