NCUtility+Exif.swift 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. import UIKit
  23. public struct ExifData {
  24. var colorModel: String?
  25. var width: Int?
  26. var height: Int?
  27. var dpiWidth: Int?
  28. var dpiHeight: Int?
  29. var depth: Int?
  30. var orientation: Int?
  31. var apertureValue: Double?
  32. var exposureValue: Int?
  33. var shutterSpeedApex: Double?
  34. var iso: Int?
  35. var lensLength: Int?
  36. var brightnessValue: String?
  37. var dateTimeDigitized: String?
  38. var dateTimeOriginal: String?
  39. var offsetTime: String?
  40. var offsetTimeDigitized: String?
  41. var offsetTimeOriginal: String?
  42. var make: String?
  43. var model: String?
  44. var software: String?
  45. var tileLength: Double?
  46. var tileWidth: Double?
  47. var xResolution: Double?
  48. var yResolution: Double?
  49. var altitude: String?
  50. var destBearing: String?
  51. var hPositioningError: String?
  52. var imgDirection: String?
  53. var latitude: Double?
  54. var longitude: Double?
  55. var speed: Double?
  56. var location: String?
  57. var lensModel: String?
  58. var date: Date?
  59. }
  60. extension NCUtility {
  61. func getExif(metadata: tableMetadata, completion: @escaping (ExifData) -> Void) {
  62. var data = ExifData()
  63. writeExifFromMetadata(metadata: metadata, data: &data)
  64. if let latitude = data.latitude, let longitude = data.longitude {
  65. getLocation(latitude: latitude, longitude: longitude) { location in
  66. data.location = location
  67. completion(data)
  68. }
  69. }
  70. if metadata.classFile != "image" || !utilityFileSystem.fileProviderStorageExists(metadata) {
  71. print("Storage exists or file is not an image")
  72. }
  73. let url = URL(fileURLWithPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))
  74. guard let originalSource = CGImageSourceCreateWithURL(url as CFURL, nil),
  75. let imageProperties = CGImageSourceCopyPropertiesAtIndex(originalSource, 0, nil) as NSDictionary? else {
  76. print("Could not get image properties")
  77. completion(data)
  78. return
  79. }
  80. data.colorModel = imageProperties[kCGImagePropertyColorModel] as? String
  81. data.height = imageProperties[kCGImagePropertyPixelWidth] as? Int
  82. data.width = imageProperties[kCGImagePropertyPixelHeight] as? Int
  83. data.dpiWidth = imageProperties[kCGImagePropertyDPIWidth] as? Int
  84. data.dpiHeight = imageProperties[kCGImagePropertyDPIHeight] as? Int
  85. data.depth = imageProperties[kCGImagePropertyDepth] as? Int
  86. data.orientation = imageProperties[kCGImagePropertyOrientation] as? Int
  87. if let tiffData = imageProperties[kCGImagePropertyTIFFDictionary] as? NSDictionary {
  88. data.make = tiffData[kCGImagePropertyTIFFMake] as? String
  89. data.model = tiffData[kCGImagePropertyTIFFModel] as? String
  90. data.software = tiffData[kCGImagePropertyTIFFSoftware] as? String
  91. data.tileLength = tiffData[kCGImagePropertyTIFFTileLength] as? Double
  92. data.tileWidth = tiffData[kCGImagePropertyTIFFTileWidth] as? Double
  93. data.xResolution = tiffData[kCGImagePropertyTIFFXResolution] as? Double
  94. data.yResolution = tiffData[kCGImagePropertyTIFFYResolution] as? Double
  95. let dateTime = tiffData[kCGImagePropertyTIFFDateTime] as? String
  96. let dateFormatter = DateFormatter()
  97. dateFormatter.dateFormat = "yyyy:MM:dd HH:mm:ss"
  98. data.date = dateFormatter.date(from: dateTime ?? "")
  99. }
  100. if let exifData = imageProperties[kCGImagePropertyExifDictionary] as? NSDictionary {
  101. data.apertureValue = exifData[kCGImagePropertyExifFNumber] as? Double
  102. data.exposureValue = exifData[kCGImagePropertyExifExposureBiasValue] as? Int
  103. data.shutterSpeedApex = exifData[kCGImagePropertyExifShutterSpeedValue] as? Double
  104. data.iso = (exifData[kCGImagePropertyExifISOSpeedRatings] as? [Int])?[0]
  105. data.lensLength = exifData[kCGImagePropertyExifFocalLenIn35mmFilm] as? Int
  106. data.brightnessValue = exifData[kCGImagePropertyExifBrightnessValue] as? String
  107. data.dateTimeDigitized = exifData[kCGImagePropertyExifDateTimeDigitized] as? String
  108. data.dateTimeOriginal = exifData[kCGImagePropertyExifDateTimeOriginal] as? String
  109. data.offsetTime = exifData[kCGImagePropertyExifOffsetTime] as? String
  110. data.offsetTimeDigitized = exifData[kCGImagePropertyExifOffsetTimeDigitized] as? String
  111. data.offsetTimeOriginal = exifData[kCGImagePropertyExifOffsetTimeOriginal] as? String
  112. data.lensModel = exifData[kCGImagePropertyExifLensModel] as? String
  113. }
  114. if let gpsData = imageProperties[kCGImagePropertyGPSDictionary] as? NSDictionary {
  115. data.altitude = gpsData[kCGImagePropertyGPSAltitude] as? String
  116. data.destBearing = gpsData[kCGImagePropertyGPSDestBearing] as? String
  117. data.hPositioningError = gpsData[kCGImagePropertyGPSHPositioningError] as? String
  118. data.imgDirection = gpsData[kCGImagePropertyGPSImgDirection] as? String
  119. data.latitude = gpsData[kCGImagePropertyGPSLatitude] as? Double
  120. data.longitude = gpsData[kCGImagePropertyGPSLongitude] as? Double
  121. data.speed = gpsData[kCGImagePropertyGPSSpeed] as? Double
  122. }
  123. writeExifFromMetadata(metadata: metadata, data: &data)
  124. if let latitude = data.latitude, let longitude = data.longitude {
  125. getLocation(latitude: latitude, longitude: longitude) { location in
  126. data.location = location
  127. completion(data)
  128. }
  129. }
  130. completion(data)
  131. }
  132. /**
  133. 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.
  134. */
  135. private func writeExifFromMetadata(metadata: tableMetadata, data: inout ExifData) {
  136. if metadata.latitude != 0, metadata.longitude != 0 {
  137. if data.latitude == nil { data.latitude = metadata.latitude }
  138. if data.longitude == nil { data.longitude = metadata.longitude }
  139. }
  140. if metadata.height != 0, metadata.width != 0 {
  141. if data.height == nil { data.height = metadata.height }
  142. if data.width == nil { data.width = metadata.width }
  143. }
  144. }
  145. }