-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathExify.swift
134 lines (115 loc) · 4 KB
/
Exify.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
*
* Created by Jovanni Lo (@lodev09)
* Copyright 2024
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import PhotosUI
@objc(Exify)
class Exify: NSObject {
func readExif(uri: String, resolve: @escaping RCTPromiseResolveBlock) {
guard let url = URL(string: uri) else {
resolve(nil)
return
}
readExifTags(from: url) { tags in
resolve(tags)
}
}
func readExif(assetId: String, resolve: @escaping RCTPromiseResolveBlock) {
guard let asset = getAssetBy(id: assetId) else {
resolve(nil)
return
}
let imageOptions = PHContentEditingInputRequestOptions()
imageOptions.isNetworkAccessAllowed = true
asset.requestContentEditingInput(with: imageOptions) { contentInput, _ in
guard let url = contentInput?.fullSizeImageURL else {
resolve(nil)
return
}
readExifTags(from: url) { tags in
resolve(tags)
}
}
}
func writeExif(assetId: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
guard let asset = getAssetBy(id: assetId) else {
reject("Error", "Cannot retrieve asset.", nil)
return
}
let imageOptions = PHContentEditingInputRequestOptions()
imageOptions.isNetworkAccessAllowed = true
asset.requestContentEditingInput(with: imageOptions) { contentInput, _ in
guard let contentInput, let url = contentInput.fullSizeImageURL else {
reject("Error", "Unable to read metadata from asset", nil)
return
}
updateMetadata(url: url, with: tags) { metadata, data in
guard let metadata, let data else {
reject("Error", "Could not update metadata", nil)
return
}
do {
try PHPhotoLibrary.shared().performChangesAndWait {
let request = PHAssetCreationRequest.forAsset()
request.addResource(with: .photo, data: data, options: nil)
request.creationDate = Date()
let newAssetId = request.placeholderForCreatedAsset!.localIdentifier
resolve([
"uri": "ph://\(newAssetId)",
"assetId": newAssetId,
"tags": getExifTags(from: metadata),
])
}
} catch {
reject("Error", "Could not save to image file", nil)
print(error)
}
}
}
}
func writeExif(uri: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
guard let url = URL(string: uri) else {
reject("Error", "Invalid URL", nil)
return
}
updateMetadata(url: url, with: tags) { metadata, data in
guard let metadata, let data else {
reject("Error", "Could not update metadata", nil)
return
}
do {
// Write to the current file
try data.write(to: url, options: .atomic)
resolve([
"uri": uri,
"tags": getExifTags(from: metadata),
])
} catch {
reject("Error", "Could not save to image file", nil)
print(error)
}
}
}
@objc(readAsync:withResolver:withRejecter:)
func readAsync(uri: String, resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
if uri.starts(with: "ph://") {
let assetId = String(uri[uri.index(uri.startIndex, offsetBy: 5)...])
readExif(assetId: assetId, resolve: resolve)
} else {
readExif(uri: uri, resolve: resolve)
}
}
@objc(writeAsync:withExif:withResolver:withRejecter:)
func writeAsync(uri: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
if uri.starts(with: "ph://") {
let assetId = String(uri[uri.index(uri.startIndex, offsetBy: 5)...])
writeExif(assetId: assetId, tags: tags, resolve: resolve, reject: reject)
} else {
writeExif(uri: uri, tags: tags, resolve: resolve, reject: reject)
}
}
}