Skip to content

Instantly share code, notes, and snippets.

Last active March 24, 2023 04:54
Show Gist options
  • Save lacyrhoades/09d8a367125b6225df5038aec68ed9e7 to your computer and use it in GitHub Desktop.
Save lacyrhoades/09d8a367125b6225df5038aec68ed9e7 to your computer and use it in GitHub Desktop.
import UIKit
import MobileCoreServices
import ImageIO
let sourceOptions: [String: AnyObject] = [kCGImageSourceTypeIdentifierHint as String: kUTTypeJPEG]
let cfSourceOptions = sourceOptions as CFDictionary
let image = UIImage(named: "input.jpg")!
let data = UIImageJPEGRepresentation(image, 1.0)
let source: CGImageSource = CGImageSourceCreateWithData(data as! CFData, cfSourceOptions)!
let filepath = NSTemporaryDirectory().appending("out.jpg")
print("Output file:")
let fileURL: URL = URL(fileURLWithPath: filepath)
let destination: CGImageDestination = CGImageDestinationCreateWithURL(fileURL as CFURL, kUTTypeJPEG, 1, nil)!
var makeTag = CGImageMetadataTagCreate(
kCGImageMetadataNamespaceTIFF, kCGImageMetadataPrefixTIFF, kCGImagePropertyTIFFMake, .string, "Make" as CFString
var modelTag = CGImageMetadataTagCreate(
kCGImageMetadataNamespaceTIFF, kCGImageMetadataPrefixTIFF, kCGImagePropertyTIFFModel, .string, "Model" as CFString
var metaDatas = CGImageMetadataCreateMutable()
var tagPath = "tiff:Make" as CFString
var result = CGImageMetadataSetTagWithPath(metaDatas, nil, tagPath, makeTag)
tagPath = "tiff:Model" as CFString
result = CGImageMetadataSetTagWithPath(metaDatas, nil, tagPath, modelTag)
let destOptions: [String: AnyObject] = [
kCGImageDestinationMergeMetadata as String: NSNumber(value: 1),
kCGImageDestinationMetadata as String: metaDatas
let cfDestOptions = destOptions as CFDictionary
var error: Unmanaged<CFError>?
var errorPtr: UnsafeMutablePointer<CFError>
withUnsafeMutablePointer(to: &error, { ptr in
result = CGImageDestinationCopyImageSource(destination, source, cfDestOptions, ptr)
print(String(format: "Write image to file result: %@", result ? "Success" : "Failed"))
print(String(format: "With error: %@", error.debugDescription))
let writeResult = CGImageDestinationFinalize(destination)
// This is false, and you may see an error like:
// " ImageIO: finalize:2031: not allowed for image destination that was updated with CGImageDestinationCopyImageSource "
// But, in practice, it works. The file is there and the metadata is correct.
Copy link

maurymarkowitz commented Mar 15, 2017

What is the purpose of line 52:

var errorPtr: UnsafeMutablePointer

It is not used anywhere, and Xcode complains about that.

Copy link

maurymarkowitz commented Mar 15, 2017

And just a note to anyone trying this: you can only add data for tags that are "known". If you try to make your own tags they just disappear. Even the most minor errors in the strings, like the tagPath, will cause the data to disappear when it's saved. To add to the annoyance, Apple's documentation is wrong - most of the possible tags are shown as being CFString types, but there are many that are actually numbers and will fail to be saved if you don't provide a number. An example is TIFFOrientation, where it claims to be a CFString but you must provide a number using NSNumber(value:5) or it simply won't save.

Copy link

@maurymarkowitz no idea about errorPtr I ended up not having that line in production. Thanks for the tips too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment