Consistent binary data from images in Swift
<p>For a small project, I'm making an iOS app which should do two things:</p>

<ol>
<li>take a picture</li>
<li>take a hash from the picture data (and print it to the xcode console)</li>
</ol>

<p>Then, I want to export the picture to my laptop and confirm the hash. I tried exporting via AirDrop, Photos.app, email and iCloud (Photos.app compresses the photo and iCloud transforms it into an <code>.png</code>). </p>

<p>Problem is, I can't repodruce the hash. This means that the exported picture differs from the picture in the app. There are some variables I tried to rule out one by one. To get <code>NSData</code> from a picture, one can use the <code>UIImagePNGRepresentation</code> and <code>UIImageJPEGRepresentation</code> functions, forcing the image in a format representation before extracting the data. To be honest, I'm not completely sure what these functions do (other than transforming to <code>NSData</code>), but they do something different from the other because they give a different result compared to each other and compared to the exported data (which is <code>.jpg</code>).</p>

<p>There are some things unclear to me what Swift/Apple is doing to my (picture)data upon exporting. I read in several places that Apple transforms (or deletes) the EXIF but to me it is unclear what part. I tried to anticipate this by explicitly removing the EXIF data myself before hashing in both the app (via function <code>ImageHelper.removeExifData</code> (found <a href="https://stackoverflow.com/questions/32788736/swift-how-to-delete-exif-data-from-picture-taken-with-avfoundation?noredirect=1&amp;lq=1">here</a>) and via <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/" rel="nofollow noreferrer">exiftools</a> on the command line), but to no avail.</p>

<p>I tried hashing an existing photo on my phone. I had a photo send to me by mail but hashing this in my app and on the command line gave different results. A <code>string</code> gave similar results in the app and on command line so the hash function(s) are not the problem.</p>

<p>So my questions are:</p>

<ol>
<li>Is there a way to prevent transformation when exporting a photo</li>
<li>Are there alternatives to <code>UIImagePNGRepresentation / UIImageJPEGRepresentation</code> functions</li>
</ol>

<p>(3. Is this at all possible or is iOS/Apple too much of a black box?)</p>

<p><strong>Any help or pointers to more documentation is greatly appreciated!</strong></p>

<hr>

<p>Here is my code</p>

<pre><code>//
//  ViewController.swift
//  camera test

import UIKit
import ImageIO

// extension on NSData format, to enable conversion to String type
extension NSData {    
    func toHexString() -&gt; String {
        var hexString: String = ""
        let dataBytes =  UnsafePointer&lt;CUnsignedChar&gt;(self.bytes)
        for (var i: Int=0; i&lt;self.length; ++i) {
            hexString +=  String(format: "%02X", dataBytes[i])
            }
        return hexString
    }
}

// function to remove EXIF data from image
class ImageHelper {
    static func removeExifData(data: NSData) -&gt; NSData? {
        guard let source = CGImageSourceCreateWithData(data, nil) else {
            return nil
        }
        guard let type = CGImageSourceGetType(source) else {
            return nil
        }
        let count = CGImageSourceGetCount(source)
        let mutableData = NSMutableData(data: data)
        guard let destination = CGImageDestinationCreateWithData(mutableData, type, count, nil) else {
            return nil
        }
        // Check the keys for what you need to remove
        // As per documentation, if you need a key removed, assign it kCFNull
        let removeExifProperties: CFDictionary = [String(kCGImagePropertyExifDictionary) : kCFNull, String(CGImagePropertyOrientation): kCFNull]

        for i in 0..&lt;count {
            CGImageDestinationAddImageFromSource(destination, source, i, removeExifProperties)
        }

        guard CGImageDestinationFinalize(destination) else {
            return nil
        }

        return mutableData;
    }
}



class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, MFMailComposeViewControllerDelegate {

    @IBOutlet weak var imageView: UIImageView!

    // creats var for picture
    var imagePicker: UIImagePickerController!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // calls Camera function and outputs picture to imagePicker
    @IBAction func cameraAction(sender: UIButton) {
        imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = .Camera

        presentViewController(imagePicker, animated: true, completion: nil)
    }

    // calls camera app, based on cameraAction
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        imagePicker.dismissViewControllerAnimated(true, completion: nil)
        imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
    }

    // calls photoHash function based on button hashAction
    @IBAction func hashAction(sender: AnyObject) {
        photoHash()
    }


    // converts latest picture to binary to sha256 hash and outputs to console 
    func photoHash(){
        let img = ImageHelper.removeExifData(UIImagePNGRepresentation(imageView.image!)!)
        let img2 = ImageHelper.removeExifData(UIImageJPEGRepresentation(imageView.image!, 1.0)!)
        let imgHash = sha256_bin(img!)
        let imgHash2 = sha256_bin(img2!)
        print(imgHash)
        print(imgHash2)

        // write image to photo library
        UIImageWriteToSavedPhotosAlbum(imageView.image!, nil, nil, nil)
    }

    // Digests binary data from picture into sha256 hash, output: hex string
    func sha256_bin(data : NSData) -&gt; String {
        var hash = [UInt8](count: Int(CC_SHA256_DIGEST_LENGTH), repeatedValue: 0)
        CC_SHA256(data.bytes, CC_LONG(data.length), &amp;hash)
        let res = NSData(bytes: hash, length: Int(CC_SHA256_DIGEST_LENGTH))

        let resString = res.toHexString() 
        return resString
    }



}
</code></pre>

<p>Specifications:</p>

<p>MacBook Pro retina 2013, OS X 10.11.5<br>
xcode version 7.3.1<br>
swift 2<br>
iphone 5S<br>
hash on command line via <code>shasum -a 256 filename.jpg</code><br></p>