RawExposeEmbedded/ImageViewController.swift
/*  | 
Copyright (C) 2016 Apple Inc. All Rights Reserved.  | 
See LICENSE.txt for this sample’s licensing information  | 
Abstract:  | 
Application Image view controller.  | 
*/  | 
import UIKit  | 
import GLKit  | 
import ImageIO  | 
import Photos  | 
import CoreImage  | 
/**  | 
This UIViewController displays an image processed using  | 
the CoreImage CIRawFilter in a GLKView.  | 
It also allows the user to perform simple edit, like  | 
adjusting exposure, temperature and tint.  | 
*/  | 
class ImageViewController: UIViewController, GLKViewDelegate { | 
// MARK: Properties  | 
/// Outlet to sliders used to edit the image.  | 
@IBOutlet weak var exposureSlider : UISlider!  | 
@IBOutlet weak var tempSlider : UISlider!  | 
@IBOutlet weak var tintSlider : UISlider!  | 
/**  | 
View used to display the CoreImage output produced by the  | 
CIRawFilter.  | 
*/  | 
@IBOutlet weak var imageView : GLKView!  | 
// Asset containing the image to render.  | 
var asset : PHAsset?  | 
// Original values of temperature and tint from the image.  | 
var originalTemp : Float = 0.0  | 
var originalTint : Float = 0.0  | 
// CIRawFilter used to process the Raw image  | 
var ciRawFilter : CIFilter?  | 
// Size of the processed image.  | 
var imageNativeSize : CGSize?  | 
// Context used to render the CIImage to display.  | 
var ciContext : CIContext?  | 
// MARK: Image load  | 
/// On load, construct the CIRawFilter  | 
    override func viewDidLoad() { | 
super.viewDidLoad()  | 
        guard let asset = asset else { return } | 
// Setup options to request original image.  | 
let options = PHImageRequestOptions()  | 
options.version = .original  | 
options.isSynchronous = true  | 
// Request the image data and UTI type for the image.  | 
        PHImageManager.default().requestImageData(for: asset, options: options) { imageData, dataUTI, _, _ in | 
            guard let imageData = imageData, let dataUTI = dataUTI else { return } | 
/**  | 
Create a CIRawFilter from original image data.  | 
UTI type is passed in to provide the CIRawFilter with  | 
a hint about the UTI type of the Raw file.  | 
*/  | 
let rawOptions = [ String(kCGImageSourceTypeIdentifierHint) : dataUTI ]  | 
self.ciRawFilter = CIFilter(imageData: imageData as Data, options: rawOptions)  | 
            guard let ciRawFilter = self.ciRawFilter else { return } | 
// Get the native size of the image produced by the CIRawFilter.  | 
            if let value = ciRawFilter.value(forKey: kCIOutputNativeSizeKey) as? CIVector { | 
self.imageNativeSize = CGSize(width: value.x, height: value.y)  | 
}  | 
// Record the original value of the temperature, and setup the editing slider.  | 
            if let value = ciRawFilter.value(forKey: kCIInputNeutralTemperatureKey) { | 
self.originalTemp = (value as AnyObject).floatValue  | 
self.tempSlider.setValue((value as AnyObject).floatValue, animated: false)  | 
}  | 
// Record the original value of the tint, and setup the editing slider.  | 
            if let value = ciRawFilter.value(forKey: kCIInputNeutralTintKey) { | 
self.originalTint = (value as AnyObject).floatValue  | 
self.tintSlider.setValue((value as AnyObject).floatValue, animated: false)  | 
}  | 
}  | 
// Create EAGL context used to render the CIImage produced by the CIRawFilter to display.  | 
imageView.context = EAGLContext(api : .openGLES3)  | 
ciContext = CIContext(eaglContext: imageView.context, options:[ kCIContextWorkingFormat : Int(kCIFormatRGBAh) ])  | 
}  | 
// MARK: Image edit actions  | 
/// Resets the CIRawFilter to the original values.  | 
    @IBAction func resetSettings(_ sender: UIBarButtonItem) { | 
        guard let ciRawFilter = ciRawFilter else { return } | 
ciRawFilter.setValue(0.0, forKey: kCIInputEVKey)  | 
exposureSlider.setValue(0.0, animated: false)  | 
ciRawFilter.setValue(originalTemp, forKey: kCIInputNeutralTemperatureKey)  | 
tempSlider.setValue(originalTemp, animated: false)  | 
ciRawFilter.setValue(originalTint, forKey: kCIInputNeutralTintKey)  | 
tintSlider.setValue(originalTint, animated: false)  | 
imageView.setNeedsDisplay()  | 
}  | 
/// Adjust the exposure of the image  | 
    @IBAction func exposureAdjusted(sender: UISlider) { | 
        guard let ciRawFilter = ciRawFilter else { return } | 
ciRawFilter.setValue(sender.value, forKey: kCIInputEVKey)  | 
imageView.setNeedsDisplay()  | 
}  | 
/// Adjust the temperature of the image  | 
    @IBAction func temperatureAdjusted(sender: UISlider) { | 
        guard let ciRawFilter = ciRawFilter else { return } | 
ciRawFilter.setValue(sender.value, forKey: kCIInputNeutralTemperatureKey)  | 
imageView.setNeedsDisplay()  | 
}  | 
/// Adjust the tint of the image  | 
    @IBAction func tintAdjusted(sender: UISlider) { | 
        guard let ciRawFilter = ciRawFilter else { return } | 
ciRawFilter.setValue(sender.value, forKey: kCIInputNeutralTintKey)  | 
imageView.setNeedsDisplay()  | 
}  | 
/// Update the image when the device is rotated.  | 
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { | 
self.imageView.setNeedsDisplay()  | 
}  | 
/// Render image to display.  | 
    func glkView(_ view: GLKView, drawIn rect: CGRect) { | 
        guard let context = ciContext, let ciRawFilter = ciRawFilter, let imageNativeSize = imageNativeSize else { return } | 
// OpenGLES drawing setup.  | 
glClearColor(0.0, 0.0, 0.0, 1.0)  | 
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))  | 
// Set the blend mode to "source over" so that CI will use that.  | 
glEnable(GLenum(GL_BLEND))  | 
glBlendFunc(GLenum(GL_ONE), GLenum(GL_ONE_MINUS_SRC_ALPHA))  | 
// Calculate scale to show the image at.  | 
let contentScaledRect = rect.applying(CGAffineTransform(scaleX: view.contentScaleFactor, y: view.contentScaleFactor))  | 
let scale = min(contentScaledRect.width / imageNativeSize.width, contentScaledRect.height / imageNativeSize.height)  | 
// Set scale factor of the CIRawFilter to size it correctly for display.  | 
ciRawFilter.setValue(scale, forKey: kCIInputScaleFactorKey)  | 
// Calculate rectangle to display image in.  | 
var displayRect = CGRect(x:0, y:0, width:imageNativeSize.width, height:imageNativeSize.height).applying(CGAffineTransform(scaleX: scale, y: scale))  | 
// Ensure the image is centered.  | 
displayRect.origin.x = (contentScaledRect.width - displayRect.width) / 2.0  | 
displayRect.origin.y = (contentScaledRect.height - displayRect.height) / 2.0  | 
        guard let image = ciRawFilter.outputImage else { return } | 
// Display the image scaled to fit.  | 
context.draw(image, in:displayRect, from:image.extent)  | 
}  | 
}  | 
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-10-04