Loading and Processing RAW image in iOS

Updated
Apr 5, 2021 3:52 PM
Created
Apr 5, 2021 3:48 PM
Tags
CoreImage
Keywords
Date

Approach.1 - Use CIImage.init(data:)

let rawImageData: Data = ...

let image: CIImage? = CIImage(data: rawImageData)

💡

This approach won't fix image orientation. To fix it needs to get the image orientation from EXIF using ImageIO. Then, using CIImage.oriented fixes the orientation issue.

⚠️ Caution

As this tweet says, this initializer might create a CIImage that uses a pre-rendered image in the RAW image file. which means, you might get a low-resolution image. If the preview image is not there, I suspect CoreImage renders at the time.

Approach.2 - Use CIFilter(data: options:)

let rawImageData: Data = ...

let filter = CIFilter(imageData: rawImageData, options: [:])!
let ciImage: CIImage = filter.outputImage

⚠️

This approach won't work on iOS Simulator. CIFilter.outputImage returns nil.

This approach renders bitmap image from RAW data with options. Actually that CIFilter is CIRawFilter implicitly. To convert to UIImage:

UIImage(ciImage: ciImage)

However, this approach might take a cost of processing in displaying UI. e.g UIScrollView's zooming. And, that UIImage instance won't return cgImage. Then, to get better performance in UIKit, creating UIImage from CGImage rendered by CIContext.

let ciContext = CIContext()
let cgImage = ciContext.createCGImage(image, from: image.extent)!
let image = UIImage(cgImage: cgImage)

Write to file as JPEG

let ciContext = CIContext()

let target = URL(fileURLWithPath: NSTemporaryDirectory() + "/raw_image.jpeg")
try! ciContext.writeJPEGRepresentation(of: image, to: target, colorSpace: image.colorSpace ?? CGColorSpaceCreateDeviceRGB(), options: [:])

How to get image-orientation

As well as

let rawImageData: Data = ...

let source = CGImageSourceCreateWithURL(data as CFData, nil)!

func readOrientation(from imageSource: CGImageSource) -> CGImagePropertyOrientation? {
    let propertiesOptions = [kCGImageSourceShouldCache: false] as CFDictionary

    guard
      let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, propertiesOptions)
        as? [CFString: Any]
    else {
      return nil
    }

    let _orientation: CGImagePropertyOrientation? =
      (properties[kCGImagePropertyTIFFOrientation] as? UInt32).flatMap {
        CGImagePropertyOrientation(rawValue: $0)
      }

    guard
      let orientation = _orientation
    else {
      return nil
    }

    return orientation
  }

Resources