@capawesome/capacitor-exif 0.0.1
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/CapawesomeCapacitorExif.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +28 -0
- package/README.md +322 -0
- package/android/build.gradle +60 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/Exif.java +289 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/ExifPlugin.java +120 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/classes/CustomException.java +20 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/classes/CustomExceptions.java +27 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/classes/options/ReadExifOptions.java +36 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/classes/options/RemoveExifOptions.java +43 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/classes/options/WriteExifOptions.java +185 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/classes/results/ReadExifResult.java +152 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/interfaces/Callback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/interfaces/EmptyCallback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/interfaces/NonEmptyResultCallback.java +7 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/interfaces/Result.java +7 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +746 -0
- package/dist/esm/definitions.d.ts +375 -0
- package/dist/esm/definitions.js +32 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +7 -0
- package/dist/esm/web.js +13 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +59 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +62 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/Classes/Options/ReadExifOptions.swift +20 -0
- package/ios/Plugin/Classes/Options/RemoveExifOptions.swift +12 -0
- package/ios/Plugin/Classes/Options/WriteExifOptions.swift +49 -0
- package/ios/Plugin/Classes/Results/ReadExifResult.swift +75 -0
- package/ios/Plugin/Enums/CustomError.swift +54 -0
- package/ios/Plugin/Exif.swift +219 -0
- package/ios/Plugin/ExifPlugin.swift +83 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/Protocols/Result.swift +5 -0
- package/package.json +97 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.exif;
|
|
2
|
+
|
|
3
|
+
import android.graphics.BitmapFactory;
|
|
4
|
+
import androidx.annotation.NonNull;
|
|
5
|
+
import androidx.annotation.Nullable;
|
|
6
|
+
import androidx.exifinterface.media.ExifInterface;
|
|
7
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.CustomExceptions;
|
|
8
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.options.ReadExifOptions;
|
|
9
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.options.RemoveExifOptions;
|
|
10
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.options.WriteExifOptions;
|
|
11
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.results.ReadExifResult;
|
|
12
|
+
import io.capawesome.capacitorjs.plugins.exif.interfaces.EmptyCallback;
|
|
13
|
+
import io.capawesome.capacitorjs.plugins.exif.interfaces.NonEmptyResultCallback;
|
|
14
|
+
import java.io.File;
|
|
15
|
+
import java.io.FileInputStream;
|
|
16
|
+
import java.io.InputStream;
|
|
17
|
+
|
|
18
|
+
public class Exif {
|
|
19
|
+
|
|
20
|
+
private static final String[] REMOVABLE_TAGS = {
|
|
21
|
+
ExifInterface.TAG_APERTURE_VALUE,
|
|
22
|
+
ExifInterface.TAG_ARTIST,
|
|
23
|
+
ExifInterface.TAG_BODY_SERIAL_NUMBER,
|
|
24
|
+
ExifInterface.TAG_BRIGHTNESS_VALUE,
|
|
25
|
+
ExifInterface.TAG_CAMERA_OWNER_NAME,
|
|
26
|
+
ExifInterface.TAG_CFA_PATTERN,
|
|
27
|
+
ExifInterface.TAG_COLOR_SPACE,
|
|
28
|
+
ExifInterface.TAG_COMPONENTS_CONFIGURATION,
|
|
29
|
+
ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL,
|
|
30
|
+
ExifInterface.TAG_CONTRAST,
|
|
31
|
+
ExifInterface.TAG_COPYRIGHT,
|
|
32
|
+
ExifInterface.TAG_CUSTOM_RENDERED,
|
|
33
|
+
ExifInterface.TAG_DATETIME,
|
|
34
|
+
ExifInterface.TAG_DATETIME_DIGITIZED,
|
|
35
|
+
ExifInterface.TAG_DATETIME_ORIGINAL,
|
|
36
|
+
ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION,
|
|
37
|
+
ExifInterface.TAG_DIGITAL_ZOOM_RATIO,
|
|
38
|
+
ExifInterface.TAG_EXIF_VERSION,
|
|
39
|
+
ExifInterface.TAG_EXPOSURE_BIAS_VALUE,
|
|
40
|
+
ExifInterface.TAG_EXPOSURE_INDEX,
|
|
41
|
+
ExifInterface.TAG_EXPOSURE_MODE,
|
|
42
|
+
ExifInterface.TAG_EXPOSURE_PROGRAM,
|
|
43
|
+
ExifInterface.TAG_EXPOSURE_TIME,
|
|
44
|
+
ExifInterface.TAG_FILE_SOURCE,
|
|
45
|
+
ExifInterface.TAG_FLASH,
|
|
46
|
+
ExifInterface.TAG_FLASHPIX_VERSION,
|
|
47
|
+
ExifInterface.TAG_FLASH_ENERGY,
|
|
48
|
+
ExifInterface.TAG_FOCAL_LENGTH,
|
|
49
|
+
ExifInterface.TAG_FOCAL_LENGTH_IN_35MM_FILM,
|
|
50
|
+
ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT,
|
|
51
|
+
ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION,
|
|
52
|
+
ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION,
|
|
53
|
+
ExifInterface.TAG_F_NUMBER,
|
|
54
|
+
ExifInterface.TAG_GAIN_CONTROL,
|
|
55
|
+
ExifInterface.TAG_GAMMA,
|
|
56
|
+
ExifInterface.TAG_GPS_ALTITUDE,
|
|
57
|
+
ExifInterface.TAG_GPS_ALTITUDE_REF,
|
|
58
|
+
ExifInterface.TAG_GPS_AREA_INFORMATION,
|
|
59
|
+
ExifInterface.TAG_GPS_DATESTAMP,
|
|
60
|
+
ExifInterface.TAG_GPS_DEST_BEARING,
|
|
61
|
+
ExifInterface.TAG_GPS_DEST_BEARING_REF,
|
|
62
|
+
ExifInterface.TAG_GPS_DEST_DISTANCE,
|
|
63
|
+
ExifInterface.TAG_GPS_DEST_DISTANCE_REF,
|
|
64
|
+
ExifInterface.TAG_GPS_DEST_LATITUDE,
|
|
65
|
+
ExifInterface.TAG_GPS_DEST_LATITUDE_REF,
|
|
66
|
+
ExifInterface.TAG_GPS_DEST_LONGITUDE,
|
|
67
|
+
ExifInterface.TAG_GPS_DEST_LONGITUDE_REF,
|
|
68
|
+
ExifInterface.TAG_GPS_DIFFERENTIAL,
|
|
69
|
+
ExifInterface.TAG_GPS_DOP,
|
|
70
|
+
ExifInterface.TAG_GPS_H_POSITIONING_ERROR,
|
|
71
|
+
ExifInterface.TAG_GPS_IMG_DIRECTION,
|
|
72
|
+
ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
|
|
73
|
+
ExifInterface.TAG_GPS_LATITUDE,
|
|
74
|
+
ExifInterface.TAG_GPS_LATITUDE_REF,
|
|
75
|
+
ExifInterface.TAG_GPS_LONGITUDE,
|
|
76
|
+
ExifInterface.TAG_GPS_LONGITUDE_REF,
|
|
77
|
+
ExifInterface.TAG_GPS_MAP_DATUM,
|
|
78
|
+
ExifInterface.TAG_GPS_MEASURE_MODE,
|
|
79
|
+
ExifInterface.TAG_GPS_PROCESSING_METHOD,
|
|
80
|
+
ExifInterface.TAG_GPS_SATELLITES,
|
|
81
|
+
ExifInterface.TAG_GPS_SPEED,
|
|
82
|
+
ExifInterface.TAG_GPS_SPEED_REF,
|
|
83
|
+
ExifInterface.TAG_GPS_STATUS,
|
|
84
|
+
ExifInterface.TAG_GPS_TIMESTAMP,
|
|
85
|
+
ExifInterface.TAG_GPS_TRACK,
|
|
86
|
+
ExifInterface.TAG_GPS_TRACK_REF,
|
|
87
|
+
ExifInterface.TAG_GPS_VERSION_ID,
|
|
88
|
+
ExifInterface.TAG_IMAGE_DESCRIPTION,
|
|
89
|
+
ExifInterface.TAG_IMAGE_UNIQUE_ID,
|
|
90
|
+
ExifInterface.TAG_INTEROPERABILITY_INDEX,
|
|
91
|
+
ExifInterface.TAG_ISO_SPEED,
|
|
92
|
+
ExifInterface.TAG_ISO_SPEED_LATITUDE_YYY,
|
|
93
|
+
ExifInterface.TAG_ISO_SPEED_LATITUDE_ZZZ,
|
|
94
|
+
ExifInterface.TAG_LENS_MAKE,
|
|
95
|
+
ExifInterface.TAG_LENS_MODEL,
|
|
96
|
+
ExifInterface.TAG_LENS_SERIAL_NUMBER,
|
|
97
|
+
ExifInterface.TAG_LENS_SPECIFICATION,
|
|
98
|
+
ExifInterface.TAG_LIGHT_SOURCE,
|
|
99
|
+
ExifInterface.TAG_MAKE,
|
|
100
|
+
ExifInterface.TAG_MAKER_NOTE,
|
|
101
|
+
ExifInterface.TAG_MAX_APERTURE_VALUE,
|
|
102
|
+
ExifInterface.TAG_METERING_MODE,
|
|
103
|
+
ExifInterface.TAG_MODEL,
|
|
104
|
+
ExifInterface.TAG_OECF,
|
|
105
|
+
ExifInterface.TAG_OFFSET_TIME,
|
|
106
|
+
ExifInterface.TAG_OFFSET_TIME_DIGITIZED,
|
|
107
|
+
ExifInterface.TAG_OFFSET_TIME_ORIGINAL,
|
|
108
|
+
ExifInterface.TAG_ORIENTATION,
|
|
109
|
+
ExifInterface.TAG_PHOTOGRAPHIC_SENSITIVITY,
|
|
110
|
+
ExifInterface.TAG_PIXEL_X_DIMENSION,
|
|
111
|
+
ExifInterface.TAG_PIXEL_Y_DIMENSION,
|
|
112
|
+
ExifInterface.TAG_RECOMMENDED_EXPOSURE_INDEX,
|
|
113
|
+
ExifInterface.TAG_RELATED_SOUND_FILE,
|
|
114
|
+
ExifInterface.TAG_RESOLUTION_UNIT,
|
|
115
|
+
ExifInterface.TAG_SATURATION,
|
|
116
|
+
ExifInterface.TAG_SCENE_CAPTURE_TYPE,
|
|
117
|
+
ExifInterface.TAG_SCENE_TYPE,
|
|
118
|
+
ExifInterface.TAG_SENSING_METHOD,
|
|
119
|
+
ExifInterface.TAG_SENSITIVITY_TYPE,
|
|
120
|
+
ExifInterface.TAG_SHARPNESS,
|
|
121
|
+
ExifInterface.TAG_SHUTTER_SPEED_VALUE,
|
|
122
|
+
ExifInterface.TAG_SOFTWARE,
|
|
123
|
+
ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE,
|
|
124
|
+
ExifInterface.TAG_SPECTRAL_SENSITIVITY,
|
|
125
|
+
ExifInterface.TAG_STANDARD_OUTPUT_SENSITIVITY,
|
|
126
|
+
ExifInterface.TAG_SUBJECT_AREA,
|
|
127
|
+
ExifInterface.TAG_SUBJECT_DISTANCE,
|
|
128
|
+
ExifInterface.TAG_SUBJECT_DISTANCE_RANGE,
|
|
129
|
+
ExifInterface.TAG_SUBJECT_LOCATION,
|
|
130
|
+
ExifInterface.TAG_SUBSEC_TIME,
|
|
131
|
+
ExifInterface.TAG_SUBSEC_TIME_DIGITIZED,
|
|
132
|
+
ExifInterface.TAG_SUBSEC_TIME_ORIGINAL,
|
|
133
|
+
ExifInterface.TAG_USER_COMMENT,
|
|
134
|
+
ExifInterface.TAG_WHITE_BALANCE,
|
|
135
|
+
ExifInterface.TAG_X_RESOLUTION,
|
|
136
|
+
ExifInterface.TAG_Y_RESOLUTION
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
@NonNull
|
|
140
|
+
private final ExifPlugin plugin;
|
|
141
|
+
|
|
142
|
+
public Exif(@NonNull ExifPlugin plugin) {
|
|
143
|
+
this.plugin = plugin;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public void readExif(@NonNull ReadExifOptions options, @NonNull NonEmptyResultCallback<ReadExifResult> callback) {
|
|
147
|
+
File file = new File(options.getPath());
|
|
148
|
+
if (!file.exists()) {
|
|
149
|
+
callback.error(CustomExceptions.FILE_NOT_FOUND);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
ExifInterface exifInterface = new ExifInterface(file);
|
|
154
|
+
BitmapFactory.Options boundsOptions = new BitmapFactory.Options();
|
|
155
|
+
boundsOptions.inJustDecodeBounds = true;
|
|
156
|
+
BitmapFactory.decodeFile(file.getPath(), boundsOptions);
|
|
157
|
+
Integer pixelWidth = boundsOptions.outWidth > 0 ? boundsOptions.outWidth : null;
|
|
158
|
+
Integer pixelHeight = boundsOptions.outHeight > 0 ? boundsOptions.outHeight : null;
|
|
159
|
+
callback.success(new ReadExifResult(exifInterface, pixelWidth, pixelHeight));
|
|
160
|
+
} catch (Exception exception) {
|
|
161
|
+
callback.error(CustomExceptions.READ_FAILED);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public void removeExif(@NonNull RemoveExifOptions options, @NonNull EmptyCallback callback) {
|
|
166
|
+
File file = new File(options.getPath());
|
|
167
|
+
if (!file.exists()) {
|
|
168
|
+
callback.error(CustomExceptions.FILE_NOT_FOUND);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
if (!isWritableFormat(file)) {
|
|
173
|
+
callback.error(CustomExceptions.UNSUPPORTED_FORMAT);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
} catch (Exception exception) {
|
|
177
|
+
callback.error(CustomExceptions.READ_FAILED);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
ExifInterface exifInterface = new ExifInterface(file);
|
|
182
|
+
String orientation = exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION);
|
|
183
|
+
for (String tag : REMOVABLE_TAGS) {
|
|
184
|
+
exifInterface.setAttribute(tag, null);
|
|
185
|
+
}
|
|
186
|
+
if (options.getKeepOrientation() && orientation != null) {
|
|
187
|
+
exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION, orientation);
|
|
188
|
+
}
|
|
189
|
+
exifInterface.saveAttributes();
|
|
190
|
+
callback.success();
|
|
191
|
+
} catch (Exception exception) {
|
|
192
|
+
callback.error(CustomExceptions.WRITE_FAILED);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public void writeExif(@NonNull WriteExifOptions options, @NonNull EmptyCallback callback) {
|
|
197
|
+
File file = new File(options.getPath());
|
|
198
|
+
if (!file.exists()) {
|
|
199
|
+
callback.error(CustomExceptions.FILE_NOT_FOUND);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
if (!isWritableFormat(file)) {
|
|
204
|
+
callback.error(CustomExceptions.UNSUPPORTED_FORMAT);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
} catch (Exception exception) {
|
|
208
|
+
callback.error(CustomExceptions.READ_FAILED);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
ExifInterface exifInterface = new ExifInterface(file);
|
|
213
|
+
applyTags(exifInterface, options);
|
|
214
|
+
exifInterface.saveAttributes();
|
|
215
|
+
callback.success();
|
|
216
|
+
} catch (Exception exception) {
|
|
217
|
+
callback.error(CustomExceptions.WRITE_FAILED);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private void applyTags(@NonNull ExifInterface exifInterface, @NonNull WriteExifOptions options) {
|
|
222
|
+
if (options.getDateTimeOriginal() != null) {
|
|
223
|
+
exifInterface.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, options.getDateTimeOriginal());
|
|
224
|
+
}
|
|
225
|
+
if (options.getExposureTime() != null) {
|
|
226
|
+
exifInterface.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, String.valueOf(options.getExposureTime()));
|
|
227
|
+
}
|
|
228
|
+
if (options.getFNumber() != null) {
|
|
229
|
+
exifInterface.setAttribute(ExifInterface.TAG_F_NUMBER, String.valueOf(options.getFNumber()));
|
|
230
|
+
}
|
|
231
|
+
if (options.getFlash() != null) {
|
|
232
|
+
exifInterface.setAttribute(ExifInterface.TAG_FLASH, options.getFlash() ? "1" : "0");
|
|
233
|
+
}
|
|
234
|
+
if (options.getFocalLength() != null) {
|
|
235
|
+
exifInterface.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, convertDoubleToRational(options.getFocalLength()));
|
|
236
|
+
}
|
|
237
|
+
if (options.getGpsAltitude() != null) {
|
|
238
|
+
exifInterface.setAltitude(options.getGpsAltitude());
|
|
239
|
+
}
|
|
240
|
+
if (options.getGpsLatitude() != null && options.getGpsLongitude() != null) {
|
|
241
|
+
exifInterface.setLatLong(options.getGpsLatitude(), options.getGpsLongitude());
|
|
242
|
+
}
|
|
243
|
+
if (options.getIso() != null) {
|
|
244
|
+
exifInterface.setAttribute(ExifInterface.TAG_PHOTOGRAPHIC_SENSITIVITY, String.valueOf(options.getIso()));
|
|
245
|
+
}
|
|
246
|
+
if (options.getLensModel() != null) {
|
|
247
|
+
exifInterface.setAttribute(ExifInterface.TAG_LENS_MODEL, options.getLensModel());
|
|
248
|
+
}
|
|
249
|
+
if (options.getMake() != null) {
|
|
250
|
+
exifInterface.setAttribute(ExifInterface.TAG_MAKE, options.getMake());
|
|
251
|
+
}
|
|
252
|
+
if (options.getModel() != null) {
|
|
253
|
+
exifInterface.setAttribute(ExifInterface.TAG_MODEL, options.getModel());
|
|
254
|
+
}
|
|
255
|
+
if (options.getOrientation() != null) {
|
|
256
|
+
exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(options.getOrientation()));
|
|
257
|
+
}
|
|
258
|
+
if (options.getSoftware() != null) {
|
|
259
|
+
exifInterface.setAttribute(ExifInterface.TAG_SOFTWARE, options.getSoftware());
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
@NonNull
|
|
264
|
+
private String convertDoubleToRational(double value) {
|
|
265
|
+
return Math.round(value * 1000) + "/1000";
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private boolean isWritableFormat(@NonNull File file) throws Exception {
|
|
269
|
+
byte[] header = new byte[12];
|
|
270
|
+
try (InputStream inputStream = new FileInputStream(file)) {
|
|
271
|
+
int bytesRead = inputStream.read(header);
|
|
272
|
+
if (bytesRead < 12) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
boolean isJpeg = (header[0] & 0xFF) == 0xFF && (header[1] & 0xFF) == 0xD8 && (header[2] & 0xFF) == 0xFF;
|
|
277
|
+
boolean isPng = (header[0] & 0xFF) == 0x89 && header[1] == 'P' && header[2] == 'N' && header[3] == 'G';
|
|
278
|
+
boolean isWebp =
|
|
279
|
+
header[0] == 'R' &&
|
|
280
|
+
header[1] == 'I' &&
|
|
281
|
+
header[2] == 'F' &&
|
|
282
|
+
header[3] == 'F' &&
|
|
283
|
+
header[8] == 'W' &&
|
|
284
|
+
header[9] == 'E' &&
|
|
285
|
+
header[10] == 'B' &&
|
|
286
|
+
header[11] == 'P';
|
|
287
|
+
return isJpeg || isPng || isWebp;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.exif;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
import com.getcapacitor.Logger;
|
|
6
|
+
import com.getcapacitor.Plugin;
|
|
7
|
+
import com.getcapacitor.PluginCall;
|
|
8
|
+
import com.getcapacitor.PluginMethod;
|
|
9
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
10
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.CustomException;
|
|
11
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.options.ReadExifOptions;
|
|
12
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.options.RemoveExifOptions;
|
|
13
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.options.WriteExifOptions;
|
|
14
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.results.ReadExifResult;
|
|
15
|
+
import io.capawesome.capacitorjs.plugins.exif.interfaces.EmptyCallback;
|
|
16
|
+
import io.capawesome.capacitorjs.plugins.exif.interfaces.NonEmptyResultCallback;
|
|
17
|
+
import io.capawesome.capacitorjs.plugins.exif.interfaces.Result;
|
|
18
|
+
|
|
19
|
+
@CapacitorPlugin(name = "Exif")
|
|
20
|
+
public class ExifPlugin extends Plugin {
|
|
21
|
+
|
|
22
|
+
public static final String ERROR_UNKNOWN_ERROR = "An unknown error has occurred.";
|
|
23
|
+
public static final String TAG = "ExifPlugin";
|
|
24
|
+
|
|
25
|
+
private Exif implementation;
|
|
26
|
+
|
|
27
|
+
@Override
|
|
28
|
+
public void load() {
|
|
29
|
+
super.load();
|
|
30
|
+
this.implementation = new Exif(this);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@PluginMethod
|
|
34
|
+
public void readExif(PluginCall call) {
|
|
35
|
+
try {
|
|
36
|
+
ReadExifOptions options = new ReadExifOptions(call);
|
|
37
|
+
NonEmptyResultCallback<ReadExifResult> callback = new NonEmptyResultCallback<>() {
|
|
38
|
+
@Override
|
|
39
|
+
public void success(@NonNull ReadExifResult result) {
|
|
40
|
+
resolveCall(call, result);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Override
|
|
44
|
+
public void error(Exception exception) {
|
|
45
|
+
rejectCall(call, exception);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
implementation.readExif(options, callback);
|
|
49
|
+
} catch (Exception exception) {
|
|
50
|
+
rejectCall(call, exception);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@PluginMethod
|
|
55
|
+
public void removeExif(PluginCall call) {
|
|
56
|
+
try {
|
|
57
|
+
RemoveExifOptions options = new RemoveExifOptions(call);
|
|
58
|
+
EmptyCallback callback = new EmptyCallback() {
|
|
59
|
+
@Override
|
|
60
|
+
public void success() {
|
|
61
|
+
resolveCall(call);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Override
|
|
65
|
+
public void error(Exception exception) {
|
|
66
|
+
rejectCall(call, exception);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
implementation.removeExif(options, callback);
|
|
70
|
+
} catch (Exception exception) {
|
|
71
|
+
rejectCall(call, exception);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@PluginMethod
|
|
76
|
+
public void writeExif(PluginCall call) {
|
|
77
|
+
try {
|
|
78
|
+
WriteExifOptions options = new WriteExifOptions(call);
|
|
79
|
+
EmptyCallback callback = new EmptyCallback() {
|
|
80
|
+
@Override
|
|
81
|
+
public void success() {
|
|
82
|
+
resolveCall(call);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@Override
|
|
86
|
+
public void error(Exception exception) {
|
|
87
|
+
rejectCall(call, exception);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
implementation.writeExif(options, callback);
|
|
91
|
+
} catch (Exception exception) {
|
|
92
|
+
rejectCall(call, exception);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private void rejectCall(@NonNull PluginCall call, @NonNull Exception exception) {
|
|
97
|
+
String message = exception.getMessage();
|
|
98
|
+
if (message == null) {
|
|
99
|
+
message = ERROR_UNKNOWN_ERROR;
|
|
100
|
+
}
|
|
101
|
+
String code = null;
|
|
102
|
+
if (exception instanceof CustomException) {
|
|
103
|
+
code = ((CustomException) exception).getCode();
|
|
104
|
+
}
|
|
105
|
+
Logger.error(TAG, message, exception);
|
|
106
|
+
call.reject(message, code);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private void resolveCall(@NonNull PluginCall call) {
|
|
110
|
+
call.resolve();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private void resolveCall(@NonNull PluginCall call, @Nullable Result result) {
|
|
114
|
+
if (result == null) {
|
|
115
|
+
call.resolve();
|
|
116
|
+
} else {
|
|
117
|
+
call.resolve(result.toJSObject());
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/classes/CustomException.java
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.exif.classes;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
|
|
6
|
+
public class CustomException extends Exception {
|
|
7
|
+
|
|
8
|
+
@Nullable
|
|
9
|
+
private final String code;
|
|
10
|
+
|
|
11
|
+
public CustomException(@Nullable String code, @NonNull String message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Nullable
|
|
17
|
+
public String getCode() {
|
|
18
|
+
return code;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/exif/classes/CustomExceptions.java
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.exif.classes;
|
|
2
|
+
|
|
3
|
+
public class CustomExceptions {
|
|
4
|
+
|
|
5
|
+
public static final CustomException FILE_NOT_FOUND = new CustomException(
|
|
6
|
+
"FILE_NOT_FOUND",
|
|
7
|
+
"The file was not found at the provided path."
|
|
8
|
+
);
|
|
9
|
+
public static final CustomException GPS_COORDINATES_INCOMPLETE = new CustomException(
|
|
10
|
+
null,
|
|
11
|
+
"gpsLatitude and gpsLongitude must be provided together."
|
|
12
|
+
);
|
|
13
|
+
public static final CustomException PATH_MISSING = new CustomException(null, "path must be provided.");
|
|
14
|
+
public static final CustomException READ_FAILED = new CustomException(
|
|
15
|
+
"READ_FAILED",
|
|
16
|
+
"The EXIF metadata could not be read from the file."
|
|
17
|
+
);
|
|
18
|
+
public static final CustomException TAGS_MISSING = new CustomException(null, "tags must be provided.");
|
|
19
|
+
public static final CustomException UNSUPPORTED_FORMAT = new CustomException(
|
|
20
|
+
"UNSUPPORTED_FORMAT",
|
|
21
|
+
"The file format does not support writing or removing EXIF metadata on this platform."
|
|
22
|
+
);
|
|
23
|
+
public static final CustomException WRITE_FAILED = new CustomException(
|
|
24
|
+
"WRITE_FAILED",
|
|
25
|
+
"The EXIF metadata could not be written to the file."
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.exif.classes.options;
|
|
2
|
+
|
|
3
|
+
import android.net.Uri;
|
|
4
|
+
import androidx.annotation.NonNull;
|
|
5
|
+
import com.getcapacitor.PluginCall;
|
|
6
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.CustomExceptions;
|
|
7
|
+
|
|
8
|
+
public class ReadExifOptions {
|
|
9
|
+
|
|
10
|
+
@NonNull
|
|
11
|
+
private final String path;
|
|
12
|
+
|
|
13
|
+
public ReadExifOptions(@NonNull PluginCall call) throws Exception {
|
|
14
|
+
this.path = ReadExifOptions.getPathFromCall(call);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@NonNull
|
|
18
|
+
public String getPath() {
|
|
19
|
+
return path;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@NonNull
|
|
23
|
+
private static String getPathFromCall(@NonNull PluginCall call) throws Exception {
|
|
24
|
+
String path = call.getString("path");
|
|
25
|
+
if (path == null || path.isEmpty()) {
|
|
26
|
+
throw CustomExceptions.PATH_MISSING;
|
|
27
|
+
}
|
|
28
|
+
if (path.startsWith("file://")) {
|
|
29
|
+
String uriPath = Uri.parse(path).getPath();
|
|
30
|
+
if (uriPath != null) {
|
|
31
|
+
return uriPath;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return path;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.exif.classes.options;
|
|
2
|
+
|
|
3
|
+
import android.net.Uri;
|
|
4
|
+
import androidx.annotation.NonNull;
|
|
5
|
+
import com.getcapacitor.PluginCall;
|
|
6
|
+
import io.capawesome.capacitorjs.plugins.exif.classes.CustomExceptions;
|
|
7
|
+
|
|
8
|
+
public class RemoveExifOptions {
|
|
9
|
+
|
|
10
|
+
private final boolean keepOrientation;
|
|
11
|
+
|
|
12
|
+
@NonNull
|
|
13
|
+
private final String path;
|
|
14
|
+
|
|
15
|
+
public RemoveExifOptions(@NonNull PluginCall call) throws Exception {
|
|
16
|
+
this.keepOrientation = call.getBoolean("keepOrientation", true);
|
|
17
|
+
this.path = RemoveExifOptions.getPathFromCall(call);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public boolean getKeepOrientation() {
|
|
21
|
+
return keepOrientation;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@NonNull
|
|
25
|
+
public String getPath() {
|
|
26
|
+
return path;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@NonNull
|
|
30
|
+
private static String getPathFromCall(@NonNull PluginCall call) throws Exception {
|
|
31
|
+
String path = call.getString("path");
|
|
32
|
+
if (path == null || path.isEmpty()) {
|
|
33
|
+
throw CustomExceptions.PATH_MISSING;
|
|
34
|
+
}
|
|
35
|
+
if (path.startsWith("file://")) {
|
|
36
|
+
String uriPath = Uri.parse(path).getPath();
|
|
37
|
+
if (uriPath != null) {
|
|
38
|
+
return uriPath;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return path;
|
|
42
|
+
}
|
|
43
|
+
}
|