NCUtility+Exif.swift 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. //
  2. // NCUtility+Exif.swift
  3. // Nextcloud
  4. //
  5. // Created by Milen on 04.08.23.
  6. // Copyright © 2023 Marino Faggiana. All rights reserved.
  7. //
  8. import Foundation
  9. public struct ExifData {
  10. var colorModel: String?
  11. var width: Int?
  12. var height: Int?
  13. var dpiWidth: Int?
  14. var dpiHeight: Int?
  15. var depth: Int?
  16. var orientation: Int?
  17. var apertureValue: Double?
  18. var exposureValue: Int?
  19. var shutterSpeedApex: Double?
  20. var iso: Int?
  21. var lensLength: Int?
  22. var brightnessValue: String?
  23. var dateTimeDigitized: String?
  24. var dateTimeOriginal: String?
  25. var offsetTime: String?
  26. var offsetTimeDigitized: String?
  27. var offsetTimeOriginal: String?
  28. var make: String?
  29. var model: String?
  30. var software: String?
  31. var tileLength: Double?
  32. var tileWidth: Double?
  33. var xResolution: Double?
  34. var yResolution: Double?
  35. var altitude: String?
  36. var destBearing: String?
  37. var hPositioningError: String?
  38. var imgDirection: String?
  39. var latitude: Double?
  40. var longitude: Double?
  41. var speed: Double?
  42. var location: String?
  43. var lensModel: String?
  44. var date: Date?
  45. }
  46. extension NCUtility {
  47. func getExif(metadata: tableMetadata, completion: @escaping (ExifData) -> Void) {
  48. var data = ExifData()
  49. writeExifFromMetadata(metadata: metadata, data: &data)
  50. if let latitude = data.latitude, let longitude = data.longitude {
  51. getLocation(latitude: latitude, longitude: longitude) { location in
  52. data.location = location
  53. completion(data)
  54. }
  55. }
  56. if metadata.classFile != "image" || !CCUtility.fileProviderStorageExists(metadata) {
  57. print("Storage exists or file is not an image")
  58. }
  59. let url = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))
  60. guard let originalSource = CGImageSourceCreateWithURL(url as CFURL, nil),
  61. let imageProperties = CGImageSourceCopyPropertiesAtIndex(originalSource, 0, nil) as NSDictionary? else {
  62. print("Could not get image properties")
  63. completion(data)
  64. return
  65. }
  66. data.colorModel = imageProperties[kCGImagePropertyColorModel] as? String
  67. data.height = imageProperties[kCGImagePropertyPixelWidth] as? Int
  68. data.width = imageProperties[kCGImagePropertyPixelHeight] as? Int
  69. data.dpiWidth = imageProperties[kCGImagePropertyDPIWidth] as? Int
  70. data.dpiHeight = imageProperties[kCGImagePropertyDPIHeight] as? Int
  71. data.depth = imageProperties[kCGImagePropertyDepth] as? Int
  72. data.orientation = imageProperties[kCGImagePropertyOrientation] as? Int
  73. if let tiffData = imageProperties[kCGImagePropertyTIFFDictionary] as? NSDictionary {
  74. data.make = tiffData[kCGImagePropertyTIFFMake] as? String
  75. data.model = tiffData[kCGImagePropertyTIFFModel] as? String
  76. data.software = tiffData[kCGImagePropertyTIFFSoftware] as? String
  77. data.tileLength = tiffData[kCGImagePropertyTIFFTileLength] as? Double
  78. data.tileWidth = tiffData[kCGImagePropertyTIFFTileWidth] as? Double
  79. data.xResolution = tiffData[kCGImagePropertyTIFFXResolution] as? Double
  80. data.yResolution = tiffData[kCGImagePropertyTIFFYResolution] as? Double
  81. let dateTime = tiffData[kCGImagePropertyTIFFDateTime] as? String
  82. let dateFormatter = DateFormatter()
  83. dateFormatter.dateFormat = "yyyy:MM:dd HH:mm:ss"
  84. data.date = dateFormatter.date(from: dateTime ?? "")
  85. }
  86. if let exifData = imageProperties[kCGImagePropertyExifDictionary] as? NSDictionary {
  87. data.apertureValue = exifData[kCGImagePropertyExifFNumber] as? Double
  88. data.exposureValue = exifData[kCGImagePropertyExifExposureBiasValue] as? Int
  89. data.shutterSpeedApex = exifData[kCGImagePropertyExifShutterSpeedValue] as? Double
  90. data.iso = (exifData[kCGImagePropertyExifISOSpeedRatings] as? [Int])?[0]
  91. data.lensLength = exifData[kCGImagePropertyExifFocalLenIn35mmFilm] as? Int
  92. data.brightnessValue = exifData[kCGImagePropertyExifBrightnessValue] as? String
  93. data.dateTimeDigitized = exifData[kCGImagePropertyExifDateTimeDigitized] as? String
  94. data.dateTimeOriginal = exifData[kCGImagePropertyExifDateTimeOriginal] as? String
  95. data.offsetTime = exifData[kCGImagePropertyExifOffsetTime] as? String
  96. data.offsetTimeDigitized = exifData[kCGImagePropertyExifOffsetTimeDigitized] as? String
  97. data.offsetTimeOriginal = exifData[kCGImagePropertyExifOffsetTimeOriginal] as? String
  98. data.lensModel = exifData[kCGImagePropertyExifLensModel] as? String
  99. }
  100. if let gpsData = imageProperties[kCGImagePropertyGPSDictionary] as? NSDictionary {
  101. data.altitude = gpsData[kCGImagePropertyGPSAltitude] as? String
  102. data.destBearing = gpsData[kCGImagePropertyGPSDestBearing] as? String
  103. data.hPositioningError = gpsData[kCGImagePropertyGPSHPositioningError] as? String
  104. data.imgDirection = gpsData[kCGImagePropertyGPSImgDirection] as? String
  105. data.latitude = gpsData[kCGImagePropertyGPSLatitude] as? Double
  106. data.longitude = gpsData[kCGImagePropertyGPSLongitude] as? Double
  107. data.speed = gpsData[kCGImagePropertyGPSSpeed] as? Double
  108. }
  109. writeExifFromMetadata(metadata: metadata, data: &data)
  110. if let latitude = data.latitude, let longitude = data.longitude {
  111. getLocation(latitude: latitude, longitude: longitude) { location in
  112. data.location = location
  113. completion(data)
  114. }
  115. }
  116. completion(data)
  117. }
  118. /**
  119. Since non-downloaded images are usually thumbnails, the server sends some exif metadata of the real image. This function writes that data to the local exif object, if that data doesn't exist already.
  120. */
  121. private func writeExifFromMetadata(metadata: tableMetadata, data: inout ExifData) {
  122. if metadata.latitude != 0, metadata.longitude != 0 {
  123. if data.latitude == nil { data.latitude = metadata.latitude }
  124. if data.longitude == nil { data.longitude = metadata.longitude }
  125. }
  126. if metadata.height != 0, metadata.width != 0 {
  127. if data.height == nil { data.height = metadata.height }
  128. if data.width == nil { data.width = metadata.width }
  129. }
  130. }
  131. }