@lodev09/react-native-exify 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # React Native Exify
2
2
 
3
+ [![CI](https://github.com/lodev09/react-native-exify/actions/workflows/ci.yml/badge.svg)](https://github.com/lodev09/react-native-exify/actions/workflows/ci.yml)
4
+ ![GitHub Release](https://img.shields.io/github/v/release/lodev09/react-native-exify)
5
+ ![NPM Downloads](https://img.shields.io/npm/dw/%40lodev09%2Freact-native-exify)
6
+
3
7
  A simple library to read and write image Exif metadata in React Native. Inspired from [this thread](https://github.com/mrousavy/react-native-vision-camera/issues/780).
4
8
 
5
9
  ## Features
@@ -44,7 +44,7 @@ def supportsNamespace() {
44
44
 
45
45
  android {
46
46
  if (supportsNamespace()) {
47
- namespace "com.exify"
47
+ namespace "com.lodev09.exify"
48
48
 
49
49
  sourceSets {
50
50
  main {
@@ -1,3 +1,3 @@
1
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
- package="com.exify">
2
+ package="com.lodev09.exify">
3
3
  </manifest>
@@ -1,9 +1,9 @@
1
- package com.exify
1
+ package com.lodev09.exify
2
2
 
3
3
  import android.content.Context
4
4
  import android.net.Uri
5
5
  import androidx.exifinterface.media.ExifInterface
6
- import com.exify.ExifyUtils.formatTags
6
+ import com.lodev09.exify.ExifyUtils.formatTags
7
7
  import com.facebook.react.bridge.Arguments
8
8
  import com.facebook.react.bridge.Promise
9
9
  import com.facebook.react.bridge.ReactApplicationContext
@@ -1,4 +1,4 @@
1
- package com.exify
1
+ package com.lodev09.exify
2
2
 
3
3
  import com.facebook.react.ReactPackage
4
4
  import com.facebook.react.bridge.NativeModule
@@ -1,4 +1,4 @@
1
- package com.exify
1
+ package com.lodev09.exify
2
2
  import androidx.exifinterface.media.ExifInterface
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- package com.exify
1
+ package com.lodev09.exify
2
2
 
3
3
  import androidx.exifinterface.media.ExifInterface
4
4
  import com.facebook.react.bridge.Arguments
package/ios/Exify.swift CHANGED
@@ -11,19 +11,18 @@ import PhotosUI
11
11
 
12
12
  @objc(Exify)
13
13
  class Exify: NSObject {
14
-
15
- func readExif(uri: String, resolve: @escaping RCTPromiseResolveBlock) -> Void {
14
+ func readExif(uri: String, resolve: @escaping RCTPromiseResolveBlock) {
16
15
  guard let url = URL(string: uri) else {
17
16
  resolve(nil)
18
17
  return
19
18
  }
20
-
19
+
21
20
  readExifTags(from: url) { tags in
22
21
  resolve(tags)
23
22
  }
24
23
  }
25
24
 
26
- func readExif(assetId: String, resolve: @escaping RCTPromiseResolveBlock) -> Void {
25
+ func readExif(assetId: String, resolve: @escaping RCTPromiseResolveBlock) {
27
26
  guard let asset = getAssetBy(id: assetId) else {
28
27
  resolve(nil)
29
28
  return
@@ -32,62 +31,61 @@ class Exify: NSObject {
32
31
  let imageOptions = PHContentEditingInputRequestOptions()
33
32
  imageOptions.isNetworkAccessAllowed = true
34
33
 
35
- asset.requestContentEditingInput(with: imageOptions) { contentInput, info in
34
+ asset.requestContentEditingInput(with: imageOptions) { contentInput, _ in
36
35
  guard let url = contentInput?.fullSizeImageURL else {
37
36
  resolve(nil)
38
37
  return
39
38
  }
40
-
39
+
41
40
  readExifTags(from: url) { tags in
42
41
  resolve(tags)
43
42
  }
44
43
  }
45
44
  }
46
-
47
- func writeExif(assetId: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
45
+
46
+ func writeExif(assetId: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
48
47
  guard let asset = getAssetBy(id: assetId) else {
49
48
  reject("Error", "Cannot retrieve asset.", nil)
50
49
  return
51
50
  }
52
-
51
+
53
52
  let imageOptions = PHContentEditingInputRequestOptions()
54
53
  imageOptions.isNetworkAccessAllowed = true
55
-
54
+
56
55
  asset.requestContentEditingInput(with: imageOptions) { contentInput, _ in
57
56
  guard let contentInput, let url = contentInput.fullSizeImageURL else {
58
57
  reject("Error", "Unable to read metadata from asset", nil)
59
58
  return
60
59
  }
61
-
60
+
62
61
  updateMetadata(url: url, with: tags) { metadata, data in
63
62
  guard let metadata, let data else {
64
63
  reject("Error", "Could not update metadata", nil)
65
64
  return
66
65
  }
67
-
66
+
68
67
  do {
69
- try PHPhotoLibrary.shared().performChangesAndWait{
68
+ try PHPhotoLibrary.shared().performChangesAndWait {
70
69
  let request = PHAssetCreationRequest.forAsset()
71
70
  request.addResource(with: .photo, data: data, options: nil)
72
71
  request.creationDate = Date()
73
-
72
+
74
73
  let newAssetId = request.placeholderForCreatedAsset!.localIdentifier
75
74
  resolve([
76
75
  "uri": "ph://\(newAssetId)",
77
76
  "assetId": newAssetId,
78
77
  "tags": getExifTags(from: metadata),
79
78
  ])
80
-
81
79
  }
82
- } catch let error {
80
+ } catch {
83
81
  reject("Error", "Could not save to image file", nil)
84
82
  print(error)
85
83
  }
86
84
  }
87
85
  }
88
86
  }
89
-
90
- func writeExif(uri: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
87
+
88
+ func writeExif(uri: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
91
89
  guard let url = URL(string: uri) else {
92
90
  reject("Error", "Invalid URL", nil)
93
91
  return
@@ -98,7 +96,7 @@ class Exify: NSObject {
98
96
  reject("Error", "Could not update metadata", nil)
99
97
  return
100
98
  }
101
-
99
+
102
100
  do {
103
101
  // Write to the current file
104
102
  try data.write(to: url, options: .atomic)
@@ -107,8 +105,7 @@ class Exify: NSObject {
107
105
  "uri": uri,
108
106
  "tags": getExifTags(from: metadata),
109
107
  ])
110
-
111
- } catch let error {
108
+ } catch {
112
109
  reject("Error", "Could not save to image file", nil)
113
110
  print(error)
114
111
  }
@@ -116,7 +113,7 @@ class Exify: NSObject {
116
113
  }
117
114
 
118
115
  @objc(readAsync:withResolver:withRejecter:)
119
- func readAsync(uri: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
116
+ func readAsync(uri: String, resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
120
117
  if uri.starts(with: "ph://") {
121
118
  let assetId = String(uri[uri.index(uri.startIndex, offsetBy: 5)...])
122
119
  readExif(assetId: assetId, resolve: resolve)
@@ -126,7 +123,7 @@ class Exify: NSObject {
126
123
  }
127
124
 
128
125
  @objc(writeAsync:withExif:withResolver:withRejecter:)
129
- func writeAsync(uri: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
126
+ func writeAsync(uri: String, tags: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
130
127
  if uri.starts(with: "ph://") {
131
128
  let assetId = String(uri[uri.index(uri.startIndex, offsetBy: 5)...])
132
129
  writeExif(assetId: assetId, tags: tags, resolve: resolve, reject: reject)
@@ -27,7 +27,7 @@ func getAssetsBy(assetIds: [String]) -> PHFetchResult<PHAsset> {
27
27
  return PHAsset.fetchAssets(withLocalIdentifiers: assetIds, options: options)
28
28
  }
29
29
 
30
- func addTagEntries(from dictionary: CFString, metadata: NSDictionary, to tags: NSMutableDictionary) -> Void {
30
+ func addTagEntries(from dictionary: CFString, metadata: NSDictionary, to tags: NSMutableDictionary) {
31
31
  if let entries = metadata[dictionary] as? [String: Any] {
32
32
  tags.addEntries(from: entries)
33
33
  }
@@ -35,56 +35,56 @@ func addTagEntries(from dictionary: CFString, metadata: NSDictionary, to tags: N
35
35
 
36
36
  func getExifTags(from metadata: NSDictionary) -> [String: Any] {
37
37
  let tags: NSMutableDictionary = [:]
38
-
38
+
39
39
  // Add root non-dictionary properties
40
40
  for (key, value) in metadata {
41
41
  if value as? [String: Any] == nil {
42
42
  tags[key] = value
43
43
  }
44
44
  }
45
-
45
+
46
46
  // Append all {Exif} properties
47
47
  addTagEntries(from: kCGImagePropertyExifDictionary, metadata: metadata, to: tags)
48
-
48
+
49
49
  // Prefix {GPS} dictionary with "GPS"
50
50
  if let gps = metadata[kCGImagePropertyGPSDictionary as String] as? [String: Any] {
51
51
  for (key, value) in gps {
52
52
  tags["GPS" + key] = value
53
53
  }
54
54
  }
55
-
55
+
56
56
  // Include tags from formats
57
57
  addTagEntries(from: kCGImagePropertyTIFFDictionary, metadata: metadata, to: tags)
58
58
  addTagEntries(from: kCGImagePropertyPNGDictionary, metadata: metadata, to: tags)
59
59
  addTagEntries(from: kCGImagePropertyHEICSDictionary, metadata: metadata, to: tags)
60
-
61
- return tags as! [String: Any]
60
+
61
+ return tags as? [String: Any] ?? [:]
62
62
  }
63
63
 
64
- func readExifTags(from url: URL?, completionHandler: ([String: Any]?) -> Void) -> Void {
64
+ func readExifTags(from url: URL?, completionHandler: ([String: Any]?) -> Void) {
65
65
  guard let url, let sourceImage = CGImageSourceCreateWithURL(url as CFURL, nil),
66
66
  let metadataDict = CGImageSourceCopyPropertiesAtIndex(sourceImage, 0, nil) else {
67
67
  completionHandler(nil)
68
68
  return
69
69
  }
70
-
70
+
71
71
  let tags = getExifTags(from: metadataDict)
72
72
  completionHandler(tags)
73
73
  }
74
74
 
75
- func updateMetadata(url: URL, with tags: [String: Any], completionHanlder: (NSDictionary?, Data?) -> Void) -> Void {
75
+ func updateMetadata(url: URL, with tags: [String: Any], completionHanlder: (NSDictionary?, Data?) -> Void) {
76
76
  guard let cgImageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else {
77
77
  completionHanlder(nil, nil)
78
78
  return
79
79
  }
80
-
80
+
81
81
  let metadataDict = CGImageSourceCopyPropertiesAtIndex(cgImageSource, 0, nil) ?? [:] as CFDictionary
82
82
  let metadata = NSMutableDictionary(dictionary: metadataDict)
83
83
 
84
84
  // Append additional Exif data
85
85
  let exifDict = metadata[kCGImagePropertyExifDictionary as String] as? NSMutableDictionary
86
86
  exifDict?.addEntries(from: tags)
87
-
87
+
88
88
  // Handle GPS Tags
89
89
  var gpsDict = [String: Any]()
90
90
 
@@ -102,15 +102,14 @@ func updateMetadata(url: URL, with tags: [String: Any], completionHanlder: (NSDi
102
102
  gpsDict[kCGImagePropertyGPSAltitude as String] = abs(altitude)
103
103
  gpsDict[kCGImagePropertyGPSAltitudeRef as String] = altitude >= 0 ? 0 : 1
104
104
  }
105
-
105
+
106
106
  if let gpsDate = tags["GPSDateStamp"] as? String {
107
107
  gpsDict[kCGImagePropertyGPSDateStamp as String] = gpsDate
108
108
  }
109
-
109
+
110
110
  if let gpsTime = tags["GPSTimeStamp"] as? String {
111
111
  gpsDict[kCGImagePropertyGPSTimeStamp as String] = gpsTime
112
112
  }
113
-
114
113
 
115
114
  if metadata[kCGImagePropertyGPSDictionary as String] == nil {
116
115
  metadata[kCGImagePropertyGPSDictionary as String] = gpsDict
@@ -119,20 +118,20 @@ func updateMetadata(url: URL, with tags: [String: Any], completionHanlder: (NSDi
119
118
  metadataGpsDict.addEntries(from: gpsDict)
120
119
  }
121
120
  }
122
-
121
+
123
122
  metadata.setObject(NSNumber(value: 1), forKey: kCGImageDestinationLossyCompressionQuality as NSString)
124
-
123
+
125
124
  let destinationData = NSMutableData()
126
125
 
127
126
  guard let uiImage = UIImage(contentsOfFile: url.path),
128
- let sourceType = CGImageSourceGetType(cgImageSource),
129
- let destination = CGImageDestinationCreateWithData(destinationData, sourceType, 1, nil) else {
127
+ let sourceType = CGImageSourceGetType(cgImageSource),
128
+ let destination = CGImageDestinationCreateWithData(destinationData, sourceType, 1, nil) else {
130
129
  completionHanlder(nil, nil)
131
130
  return
132
131
  }
133
132
 
134
133
  CGImageDestinationAddImage(destination, uiImage.cgImage!, metadata)
135
134
  CGImageDestinationFinalize(destination)
136
-
135
+
137
136
  completionHanlder(metadata, destinationData as Data)
138
137
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lodev09/react-native-exify",
3
- "version": "0.2.3",
4
- "description": "Read and write exif data into an image.",
3
+ "version": "0.2.4",
4
+ "description": "Read and write exif data into an image 🏷️",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
7
7
  "types": "lib/typescript/src/index.d.ts",
@@ -31,7 +31,7 @@
31
31
  "typecheck": "tsc --noEmit",
32
32
  "lint": "eslint --fix \"**/*.{js,ts,tsx}\"",
33
33
  "format": "prettier --write \"**/*.{js,ts,tsx}\"",
34
- "tidy": "yarn typecheck && yarn lint && yarn format",
34
+ "tidy": "yarn typecheck && yarn lint && yarn format && scripts/swiftlint.sh && scripts/swiftformat.sh",
35
35
  "clean": "del-cli android/build lib && yarn workspace exify-example clean",
36
36
  "prepare": "bob build",
37
37
  "release": "release-it"
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <Workspace
3
- version = "1.0">
4
- <FileRef
5
- location = "self:">
6
- </FileRef>
7
- </Workspace>
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>IDEDidComputeMac32BitWarning</key>
6
- <true/>
7
- </dict>
8
- </plist>
@@ -1,14 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>SchemeUserState</key>
6
- <dict>
7
- <key>Exify.xcscheme_^#shared#^_</key>
8
- <dict>
9
- <key>orderHint</key>
10
- <integer>0</integer>
11
- </dict>
12
- </dict>
13
- </dict>
14
- </plist>