NCUtility+Exif.swift 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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. // This program is free software: you can redistribute it and/or modify
  9. // it under the terms of the GNU General Public License as published by
  10. // the Free Software Foundation, either version 3 of the License, or
  11. // (at your option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU General Public License
  19. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. //
  21. import Foundation
  22. public struct ExifData {
  23. var colorModel: String?
  24. var width: Int?
  25. var height: Int?
  26. var dpiWidth: Int?
  27. var dpiHeight: Int?
  28. var depth: Int?
  29. var orientation: Int?
  30. var apertureValue: Double?
  31. var exposureValue: Int?
  32. var shutterSpeedApex: Double?
  33. var iso: Int?
  34. var lensLength: Int?
  35. var brightnessValue: String?
  36. var dateTimeDigitized: String?
  37. var dateTimeOriginal: String?
  38. var offsetTime: String?
  39. var offsetTimeDigitized: String?
  40. var offsetTimeOriginal: String?
  41. var make: String?
  42. var model: String?
  43. var software: String?
  44. var tileLength: Double?
  45. var tileWidth: Double?
  46. var xResolution: Double?
  47. var yResolution: Double?
  48. var altitude: String?
  49. var destBearing: String?
  50. var hPositioningError: String?
  51. var imgDirection: String?
  52. var latitude: Double?
  53. var longitude: Double?
  54. var speed: Double?
  55. var location: String?
  56. var lensModel: String?
  57. var date: Date?
  58. }
  59. extension NCUtility {
  60. func getExif(metadata: tableMetadata, completion: @escaping (ExifData) -> Void) {
  61. var data = ExifData()
  62. writeExifFromMetadata(metadata: metadata, data: &data)
  63. if let latitude = data.latitude, let longitude = data.longitude {
  64. getLocation(latitude: latitude, longitude: longitude) { location in
  65. data.location = location
  66. completion(data)
  67. }
  68. }
  69. if metadata.classFile != "image" || !utilityFileSystem.fileProviderStorageExists(metadata) {
  70. print("Storage exists or file is not an image")
  71. }
  72. let url = URL(fileURLWithPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))
  73. guard let originalSource = CGImageSourceCreateWithURL(url as CFURL, nil),
  74. let imageProperties = CGImageSourceCopyPropertiesAtIndex(originalSource, 0, nil) as NSDictionary? else {
  75. print("Could not get image properties")
  76. completion(data)
  77. return
  78. }
  79. data.colorModel = imageProperties[kCGImagePropertyColorModel] as? String
  80. data.height = imageProperties[kCGImagePropertyPixelWidth] as? Int
  81. data.width = imageProperties[kCGImagePropertyPixelHeight] as? Int
  82. data.dpiWidth = imageProperties[kCGImagePropertyDPIWidth] as? Int
  83. data.dpiHeight = imageProperties[kCGImagePropertyDPIHeight] as? Int
  84. data.depth = imageProperties[kCGImagePropertyDepth] as? Int
  85. data.orientation = imageProperties[kCGImagePropertyOrientation] as? Int
  86. if let tiffData = imageProperties[kCGImagePropertyTIFFDictionary] as? NSDictionary {
  87. data.make = tiffData[kCGImagePropertyTIFFMake] as? String
  88. data.model = tiffData[kCGImagePropertyTIFFModel] as? String
  89. data.software = tiffData[kCGImagePropertyTIFFSoftware] as? String
  90. data.tileLength = tiffData[kCGImagePropertyTIFFTileLength] as? Double
  91. data.tileWidth = tiffData[kCGImagePropertyTIFFTileWidth] as? Double
  92. data.xResolution = tiffData[kCGImagePropertyTIFFXResolution] as? Double
  93. data.yResolution = tiffData[kCGImagePropertyTIFFYResolution] as? Double
  94. let dateTime = tiffData[kCGImagePropertyTIFFDateTime] as? String
  95. let dateFormatter = DateFormatter()
  96. dateFormatter.dateFormat = "yyyy:MM:dd HH:mm:ss"
  97. data.date = dateFormatter.date(from: dateTime ?? "")
  98. }
  99. if let exifData = imageProperties[kCGImagePropertyExifDictionary] as? NSDictionary {
  100. data.apertureValue = exifData[kCGImagePropertyExifFNumber] as? Double
  101. data.exposureValue = exifData[kCGImagePropertyExifExposureBiasValue] as? Int
  102. data.shutterSpeedApex = exifData[kCGImagePropertyExifShutterSpeedValue] as? Double
  103. data.iso = (exifData[kCGImagePropertyExifISOSpeedRatings] as? [Int])?[0]
  104. data.lensLength = exifData[kCGImagePropertyExifFocalLenIn35mmFilm] as? Int
  105. data.brightnessValue = exifData[kCGImagePropertyExifBrightnessValue] as? String
  106. data.dateTimeDigitized = exifData[kCGImagePropertyExifDateTimeDigitized] as? String
  107. data.dateTimeOriginal = exifData[kCGImagePropertyExifDateTimeOriginal] as? String
  108. data.offsetTime = exifData[kCGImagePropertyExifOffsetTime] as? String
  109. data.offsetTimeDigitized = exifData[kCGImagePropertyExifOffsetTimeDigitized] as? String
  110. data.offsetTimeOriginal = exifData[kCGImagePropertyExifOffsetTimeOriginal] as? String
  111. data.lensModel = exifData[kCGImagePropertyExifLensModel] as? String
  112. }
  113. if let gpsData = imageProperties[kCGImagePropertyGPSDictionary] as? NSDictionary {
  114. data.altitude = gpsData[kCGImagePropertyGPSAltitude] as? String
  115. data.destBearing = gpsData[kCGImagePropertyGPSDestBearing] as? String
  116. data.hPositioningError = gpsData[kCGImagePropertyGPSHPositioningError] as? String
  117. data.imgDirection = gpsData[kCGImagePropertyGPSImgDirection] as? String
  118. data.latitude = gpsData[kCGImagePropertyGPSLatitude] as? Double
  119. data.longitude = gpsData[kCGImagePropertyGPSLongitude] as? Double
  120. data.speed = gpsData[kCGImagePropertyGPSSpeed] as? Double
  121. }
  122. writeExifFromMetadata(metadata: metadata, data: &data)
  123. if let latitude = data.latitude, let longitude = data.longitude {
  124. getLocation(latitude: latitude, longitude: longitude) { location in
  125. data.location = location
  126. completion(data)
  127. }
  128. }
  129. completion(data)
  130. }
  131. /**
  132. 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.
  133. */
  134. private func writeExifFromMetadata(metadata: tableMetadata, data: inout ExifData) {
  135. if metadata.latitude != 0, metadata.longitude != 0 {
  136. if data.latitude == nil { data.latitude = metadata.latitude }
  137. if data.longitude == nil { data.longitude = metadata.longitude }
  138. }
  139. if metadata.height != 0, metadata.width != 0 {
  140. if data.height == nil { data.height = metadata.height }
  141. if data.width == nil { data.width = metadata.width }
  142. }
  143. }
  144. }