diff --git a/PhotosExporter/exporter/PhotosExporter.swift b/PhotosExporter/exporter/PhotosExporter.swift index 3401166..51b25f9 100644 --- a/PhotosExporter/exporter/PhotosExporter.swift +++ b/PhotosExporter/exporter/PhotosExporter.swift @@ -8,6 +8,9 @@ import Foundation import MediaLibrary +import CoreImage +import AppKit +import Photos enum PhotosExporterError: Error { @@ -82,6 +85,8 @@ class PhotosExporter { var exportCurrent = true // set to true if original photos should be exported var exportOriginals = true + // set to true if HEIC photos should be converted to JPG + var convertHeic2Jpg = false let fileManager = FileManager.default @@ -436,6 +441,36 @@ class PhotosExporter { } statistics.countLinkedFiles += 1 stopWatchFileManagerLinkItem.stop() + + if sourceUrl.pathExtension.lowercased() == "heic" && convertHeic2Jpg { + + if let image = CIImage(contentsOf: sourceUrl) { + let context = CIContext() + let data = context.jpegRepresentation(of: image, colorSpace: CGColorSpaceCreateDeviceRGB(), options: [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption:0.8]) + var targetJPEGUrl = URL.init(fileURLWithPath: "\(targetPath)/\(fotoName).jpg") + logger.debug("Convert HEIC foto: \(fotoName) to \(targetJPEGUrl)") + var i = 1 + while fileManager.fileExists(atPath: targetJPEGUrl.path) { + targetJPEGUrl = URL(fileURLWithPath: "\(targetJPEGUrl)/\(fotoName) (\(i)).jpg") + i += 1 + } + logger.debug("convert jpg image: \(targetJPEGUrl.lastPathComponent)") + do { + try data?.write(to: targetJPEGUrl) + } catch { + logger.error("\(String(describing: index)): Unable to convert heic to jpg : \(fotoName) to \(targetJPEGUrl). Error: \(error)") + } + + do { + if let creationDate = try fileManager.attributesOfItem(atPath: sourceUrl.path)[FileAttributeKey.creationDate] as? Date { + try fileManager.setAttributes([FileAttributeKey.creationDate:creationDate], ofItemAtPath: targetJPEGUrl.path) + } + } catch { + logger.error("\(String(describing: index)): Unable to set creationDate to jpg : \(fotoName) to \(targetJPEGUrl). Error: \(error)") + } + } + } + } else { logger.warn("Source URL of mediaObject unknown: \(mediaObject)") } diff --git a/PhotosExporter/exporter/PhotosExporterFactory.swift b/PhotosExporter/exporter/PhotosExporterFactory.swift index a250be1..ec19872 100644 --- a/PhotosExporter/exporter/PhotosExporterFactory.swift +++ b/PhotosExporter/exporter/PhotosExporterFactory.swift @@ -85,6 +85,9 @@ class PhotosExporterFactory { if let exportOriginals = plan.exportOriginals { photosExporter.exportOriginals = exportOriginals } + if let convertHeic2Jpg = plan.convertHeic2Jpg { + photosExporter.convertHeic2Jpg = convertHeic2Jpg + } return photosExporter } diff --git a/PhotosExporter/preferences/PreferencesReader.swift b/PhotosExporter/preferences/PreferencesReader.swift index eeaeeb0..5ee6478 100644 --- a/PhotosExporter/preferences/PreferencesReader.swift +++ b/PhotosExporter/preferences/PreferencesReader.swift @@ -90,6 +90,7 @@ class PreferencesReader { } plan.exportCurrent = planDict["exportCurrent"]?.bool plan.exportOriginals = planDict["exportOriginals"]?.bool + plan.convertHeic2Jpg = planDict["convertHeic2Jpg"]?.bool if let plan = plan as? FileSystemExportPlan { plan.targetFolder = planDict["targetFolder"]?.string diff --git a/PhotosExporter/preferences/model/Plan.swift b/PhotosExporter/preferences/model/Plan.swift index bdcc0ab..5f28d6e 100644 --- a/PhotosExporter/preferences/model/Plan.swift +++ b/PhotosExporter/preferences/model/Plan.swift @@ -21,6 +21,9 @@ class Plan { // exports the original assets public var exportOriginals: Bool? + // convert heic to jpg + public var convertHeic2Jpg: Bool? + public var mediaObjectFilter = MediaObjectFilter() @@ -49,6 +52,9 @@ class Plan { if let exportOriginals = exportOriginals { result += "exportOriginals: \(exportOriginals)\n".indent(indent) } + if let convertHeic2Jpg = convertHeic2Jpg { + result += "convertHeic2Jpg: \(convertHeic2Jpg)\n".indent(indent) + } result += mediaObjectFilter.toYaml(indent: indent) return result