From 09069f1c3a1b6a1f5b52207f0ea96e3f55b49350 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Wed, 22 Sep 2021 11:59:10 +0300 Subject: [PATCH] Signed-off-by: Guy Cohen First Commit --- Sources/ExifModifier/ExifData.swift | 127 ++++++++++++++++++++++++ Sources/ExifModifier/ExifModifier.swift | 3 - Sources/ExifModifier/Extensions.swift | 56 +++++++++++ 3 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 Sources/ExifModifier/ExifData.swift delete mode 100644 Sources/ExifModifier/ExifModifier.swift create mode 100644 Sources/ExifModifier/Extensions.swift diff --git a/Sources/ExifModifier/ExifData.swift b/Sources/ExifModifier/ExifData.swift new file mode 100644 index 0000000..7ceeb00 --- /dev/null +++ b/Sources/ExifModifier/ExifData.swift @@ -0,0 +1,127 @@ +// +// File.swift +// +// +// Created by Guy Cohen on 20/09/2021. +// + +import Foundation +import ImageIO +import CoreLocation + +public class ExifData { + + var imageMetaData = [String: Any]() + + public func exifData() -> [String: Any] { imageMetaData } + + public func addDescripton(_ description: String) { tiffDictionary[kCGImagePropertyTIFFImageDescription as String] = description } + + public func addProjection(_ projection: String) { exifDictionary[Self.kCGImagePropertyProjection as String] = projection } + + public func addCreationDate(_ date: Date?) { + guard let dateStr = getUTCFormattedDate(date) else { return } + exifDictionary[kCGImagePropertyExifDateTimeOriginal as String] = dateStr + } + + public func addUserComment(_ comment: String){ exifDictionary[kCGImagePropertyExifUserComment as String] = comment } + + public func add(_ currentLocation: CLLocation?) { + + var latitude = currentLocation?.coordinate.latitude ?? 0 + var longitude = currentLocation?.coordinate.longitude ?? 0 + + var latitudeRef: String? = nil + var longitudeRef: String? = nil + + if latitude < 0.0 { + latitude *= CLLocationDegrees(-1) + latitudeRef = "S" + } else { + latitudeRef = "N" + } + + if longitude < 0.0 { + longitude *= CLLocationDegrees(-1) + longitudeRef = "W" + } else { + longitudeRef = "E" + } + + gpsDictionary[kCGImagePropertyGPSTimeStamp as String] = getUTCFormattedDate(currentLocation?.timestamp) + + gpsDictionary[kCGImagePropertyGPSLatitudeRef as String] = latitudeRef ?? "" + gpsDictionary[kCGImagePropertyGPSLatitude as String] = NSNumber(value: Float(latitude)) + + gpsDictionary[kCGImagePropertyGPSLongitudeRef as String] = longitudeRef ?? "" + gpsDictionary[kCGImagePropertyGPSLongitude as String] = NSNumber(value: Float(longitude)) + + gpsDictionary[kCGImagePropertyGPSDOP as String] = NSNumber(value: Float(currentLocation?.horizontalAccuracy ?? 0.0)) + gpsDictionary[kCGImagePropertyGPSAltitude as String] = NSNumber(value: Float(currentLocation?.altitude ?? 0.0)) + } + +} + +fileprivate extension ExifData { + + func dictionaryForKey(key: String) -> [String: Any] { + if let existedDict = imageMetaData[key] as? [String: Any] { + return existedDict + } + let dic = [String: Any]() + imageMetaData[key] = dic + return dic + } + + func getUTCFormattedDate(_ localDate: Date?) -> String? { + if let localDate = localDate { + return Self.getUTCDateFormatter?.string(from: localDate) + } + return nil + } + + var exifDictionary: [AnyHashable : Any] { + get { + if let existedDict = imageMetaData[kCGImagePropertyExifDictionary as String] as? [String: Any] { + return existedDict + } + let dic = [String: Any]() + imageMetaData[kCGImagePropertyExifDictionary as String] = dic + return dic + } + set { imageMetaData[kCGImagePropertyExifDictionary as String] = newValue } + } + + var tiffDictionary: [AnyHashable : Any] { + get { + if let existedDict = imageMetaData[kCGImagePropertyTIFFDictionary as String] as? [String: Any] { + return existedDict + } + let dic = [String: Any]() + imageMetaData[kCGImagePropertyTIFFDictionary as String] = dic + return dic + } + set { imageMetaData[kCGImagePropertyTIFFDictionary as String] = newValue } + } + + var gpsDictionary: [AnyHashable : Any] { + get { + if let existedDict = imageMetaData[kCGImagePropertyGPSDictionary as String] as? [String: Any] { + return existedDict + } + let dic = [String: Any]() + imageMetaData[kCGImagePropertyGPSDictionary as String] = dic + return dic + } + set { imageMetaData[kCGImagePropertyGPSDictionary as String] = newValue } + } + + static let getUTCDateFormatter: DateFormatter? = { + var dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy:MM:dd HH:mm:ss" + return dateFormatter + }() + + static let kCGImagePropertyProjection = "ProjectionType" + +} diff --git a/Sources/ExifModifier/ExifModifier.swift b/Sources/ExifModifier/ExifModifier.swift deleted file mode 100644 index f18ba96..0000000 --- a/Sources/ExifModifier/ExifModifier.swift +++ /dev/null @@ -1,3 +0,0 @@ -struct ExifModifier { - var text = "Hello, World!" -} diff --git a/Sources/ExifModifier/Extensions.swift b/Sources/ExifModifier/Extensions.swift new file mode 100644 index 0000000..cb4c00c --- /dev/null +++ b/Sources/ExifModifier/Extensions.swift @@ -0,0 +1,56 @@ +// +// File.swift +// +// +// Created by Guy Cohen on 20/09/2021. +// + +import UIKit + +public extension UIImage { + + func addExif(_ container: ExifData) -> Data? { + + let imageData = self.jpegData(compressionQuality: 1.0) + + // create an imagesourceref + var source: CGImageSource? = nil + if let data = imageData as CFData? { + source = CGImageSourceCreateWithData(data, nil) + } + + // this is the type of image (e.g., public.jpeg) + var UTI: CFString? = nil + if let source = source { + UTI = CGImageSourceGetType(source) + } + + // create a new data object and write the new image into it + let dest_data = Data() + var destination: CGImageDestination? = nil + if let UTI = UTI { + destination = CGImageDestinationCreateWithData(dest_data as! CFMutableData, UTI, 1, nil) + } + + if destination == nil { + print("Error: Could not create image destination") + } + + // add the image contained in the image source to the destination, overidding the old metadata with our modified metadata + if let destination = destination, let source = source { + CGImageDestinationAddImageFromSource(destination, source, 0, container.exifData as! CFDictionary?) + } + var success = false + if let destination = destination { + success = CGImageDestinationFinalize(destination) + } + + if !success { + print("Error: Could not create data from image destination") + } + + + return dest_data + } + +}