title: Consistent binary data from images in Swift
body: <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>