Mercurial > cgi-bin > hgweb.cgi > JpegWasher
comparison src/name/blackcap/exifwasher/exiv2/native.cpp @ 13:a59d84674fb0
Make it seamlessly work on IPTC and XMP metadata, too.
author | David Barts <davidb@stashtea.com> |
---|---|
date | Sat, 11 Apr 2020 09:14:31 -0700 |
parents | efd9fe2d70d7 |
children | cd2ca4727b7f |
comparison
equal
deleted
inserted
replaced
12:9ac6136c710c | 13:a59d84674fb0 |
---|---|
1 #include <jni.h> | 1 #include <jni.h> |
2 #include <string.h> | |
2 #include <exiv2/exiv2.hpp> | 3 #include <exiv2/exiv2.hpp> |
3 #include <exception> | 4 #include <exception> |
4 #include <iostream> | 5 #include <iostream> |
5 #include <iomanip> | 6 #include <iomanip> |
6 #include <cassert> | 7 #include <cassert> |
14 #endif | 15 #endif |
15 | 16 |
16 /* | 17 /* |
17 * Utility function to get pointer field. | 18 * Utility function to get pointer field. |
18 */ | 19 */ |
19 jlong getPointer(JNIEnv *jEnv, jobject jThis) { | 20 Exiv2::Image *getPointer(JNIEnv *jEnv, jobject jThis) { |
20 return jEnv->GetLongField(jThis, jEnv->GetFieldID(jEnv->GetObjectClass(jThis), "pointer", "J")); | 21 return reinterpret_cast<Exiv2::Image *> |
22 (jEnv->GetLongField(jThis, | |
23 jEnv->GetFieldID(jEnv->GetObjectClass(jThis), "pointer", "J"))); | |
21 } | 24 } |
22 | 25 |
23 /* | 26 /* |
24 * Class: name_blackcap_exifwasher_exiv2_Image | 27 * Class: name_blackcap_exifwasher_exiv2_Image |
25 * Method: _ctor | 28 * Method: _ctor |
45 * Method: _writeMetadata | 48 * Method: _writeMetadata |
46 * Signature: ()V | 49 * Signature: ()V |
47 */ | 50 */ |
48 JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1writeMetadata | 51 JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1writeMetadata |
49 (JNIEnv *jEnv, jobject jThis) { | 52 (JNIEnv *jEnv, jobject jThis) { |
50 Exiv2::Image *image = reinterpret_cast<Exiv2::Image *> (getPointer(jEnv, jThis)); | 53 Exiv2::Image *image = getPointer(jEnv, jThis); |
51 if (jEnv->ExceptionCheck()) return; | 54 if (jEnv->ExceptionCheck()) return; |
52 try { | 55 try { |
53 image->writeMetadata(); | 56 image->writeMetadata(); |
54 } catch (std::exception& e) { | 57 } catch (std::exception& e) { |
55 jEnv->ExceptionClear(); | 58 jEnv->ExceptionClear(); |
63 * Method: _getMetadata | 66 * Method: _getMetadata |
64 * Signature: ()J | 67 * Signature: ()J |
65 */ | 68 */ |
66 JNIEXPORT jlong JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1getMetadata | 69 JNIEXPORT jlong JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1getMetadata |
67 (JNIEnv *jEnv, jobject jThis) { | 70 (JNIEnv *jEnv, jobject jThis) { |
68 Exiv2::Image *image = reinterpret_cast<Exiv2::Image *> (getPointer(jEnv, jThis)); | 71 Exiv2::Image *image = getPointer(jEnv, jThis); |
69 if (jEnv->ExceptionCheck()) return 0; | 72 if (jEnv->ExceptionCheck()) return 0; |
70 try { | 73 try { |
71 image->readMetadata(); | 74 image->readMetadata(); |
72 } catch (std::exception& e) { | 75 } catch (std::exception& e) { |
73 jEnv->ExceptionClear(); | 76 jEnv->ExceptionClear(); |
74 jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception"); | 77 jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception"); |
75 jEnv->ThrowNew(ex, e.what()); | 78 jEnv->ThrowNew(ex, e.what()); |
76 return 0; | 79 return 0; |
77 } | 80 } |
78 return reinterpret_cast<jlong> (&(image->exifData())); | 81 return reinterpret_cast<jlong>(image); |
79 } | 82 } |
80 | 83 |
81 /* | 84 /* |
82 * Class: name_blackcap_exifwasher_exiv2_Image | 85 * Class: name_blackcap_exifwasher_exiv2_Image |
83 * Method: _dtor | 86 * Method: _dtor |
84 * Signature: ()V | 87 * Signature: ()V |
85 */ | 88 */ |
86 JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1dtor | 89 JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1dtor |
87 (JNIEnv *jEnv, jobject jThis) { | 90 (JNIEnv *jEnv, jobject jThis) { |
88 Exiv2::Image *image = reinterpret_cast<Exiv2::Image *> (getPointer(jEnv, jThis)); | 91 Exiv2::Image *image = getPointer(jEnv, jThis); |
89 if (jEnv->ExceptionCheck()) return; | 92 if (jEnv->ExceptionCheck()) return; |
90 delete image; | 93 delete image; |
91 } | 94 } |
92 | 95 |
93 #ifdef __cplusplus | 96 #ifdef __cplusplus |
94 } | 97 } |
95 #endif | 98 #endif |
96 #endif | 99 #endif |
97 /* Header for class name_blackcap_exifwasher_exiv2_ExifData */ | 100 /* Header for class name_blackcap_exifwasher_exiv2_ExifData */ |
98 | 101 |
102 /* | |
103 * Utility function to delete a (key, value) pair. | |
104 */ | |
105 template<class D, class K> | |
106 void deleteValue(D &data, const char *key) { | |
107 typename D::iterator found = data.findKey(K(std::string(key))); | |
108 data.erase(found); | |
109 } | |
110 | |
111 /* | |
112 * Utility function to retrieve a value, given a key. | |
113 */ | |
114 template<class D, class K> | |
115 jobject getValue(JNIEnv *jEnv, D &data, const char *key) { | |
116 typename D::iterator found = data.findKey(K(std::string(key))); | |
117 if (found == data.end()) { | |
118 return NULL; | |
119 } | |
120 jclass klass = jEnv->FindClass("name/blackcap/exifwasher/exiv2/ExifData$Value"); | |
121 if (jEnv->ExceptionCheck()) return NULL; | |
122 jstring type = jEnv->NewStringUTF(found->typeName()); | |
123 jstring value = jEnv->NewStringUTF(found->toString().c_str()); | |
124 jmethodID method = jEnv->GetMethodID(klass, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V"); | |
125 if (jEnv->ExceptionCheck()) return NULL; | |
126 return jEnv->NewObject(klass, method, type, value); | |
127 } | |
128 | |
129 /* | |
130 * Utility function to read keys, given a target to put them and a collection | |
131 * of data. | |
132 */ | |
133 template<class D> | |
134 jsize getKeys(JNIEnv *jEnv, jobjectArray target, jsize start, D &data) { | |
135 typename D::const_iterator end = data.end(); | |
136 jsize j = start; | |
137 for (typename D::const_iterator i = data.begin(); i != end; ++i) { | |
138 jEnv->SetObjectArrayElement(target, j++, jEnv->NewStringUTF(i->key().c_str())); | |
139 if (jEnv->ExceptionCheck()) break; | |
140 } | |
141 return j; | |
142 } | |
143 | |
99 #ifndef _Included_name_blackcap_exifwasher_exiv2_ExifData | 144 #ifndef _Included_name_blackcap_exifwasher_exiv2_ExifData |
100 #define _Included_name_blackcap_exifwasher_exiv2_ExifData | 145 #define _Included_name_blackcap_exifwasher_exiv2_ExifData |
101 #ifdef __cplusplus | 146 #ifdef __cplusplus |
102 extern "C" { | 147 extern "C" { |
103 #endif | 148 #endif |
149 | |
150 /* | |
151 * Utility function to parse out a type prefix from a key name. | |
152 */ | |
153 char *getType(const char *key) { | |
154 char *dot = strchr(key, '.'); | |
155 if (dot == NULL) | |
156 throw std::invalid_argument(std::string("invalid key: ") + std::string(key)); | |
157 int length = dot - key; | |
158 char *ret = (char *) malloc(length + 1); | |
159 memcpy(ret, key, length); | |
160 ret[length] = '\0'; | |
161 return ret; | |
162 } | |
163 | |
104 /* | 164 /* |
105 * Class: name_blackcap_exifwasher_exiv2_ExifData | 165 * Class: name_blackcap_exifwasher_exiv2_ExifData |
106 * Method: _erase | 166 * Method: _erase |
107 * Signature: (Ljava/lang/String;)V | 167 * Signature: (Ljava/lang/String;)V |
108 */ | 168 */ |
109 JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1erase | 169 JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1erase |
110 (JNIEnv *jEnv, jobject jThis, jstring key) { | 170 (JNIEnv *jEnv, jobject jThis, jstring key) { |
111 Exiv2::ExifData *data = reinterpret_cast<Exiv2::ExifData *> (getPointer(jEnv, jThis)); | 171 Exiv2::Image *image = getPointer(jEnv, jThis); |
112 if (jEnv->ExceptionCheck()) return; | 172 if (jEnv->ExceptionCheck()) return; |
113 const char *cKey = jEnv->GetStringUTFChars(key, NULL); | 173 const char *cKey = jEnv->GetStringUTFChars(key, NULL); |
114 Exiv2::ExifData::iterator found = data->findKey(Exiv2::ExifKey(std::string(cKey))); | 174 char *type = NULL; |
115 try { | 175 try { |
116 data->erase(found); | 176 type = getType(cKey); |
117 } catch (std::exception& e) { | 177 if (!strcmp(type, "Exif")) { |
118 jEnv->ExceptionClear(); | 178 deleteValue<Exiv2::ExifData, Exiv2::ExifKey>(image->exifData(), cKey); |
119 jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception"); | 179 } else if (!strcmp(type, "Xmp")) { |
120 jEnv->ThrowNew(ex, e.what()); | 180 deleteValue<Exiv2::XmpData, Exiv2::XmpKey>(image->xmpData(), cKey); |
121 } | 181 } else if (!strcmp(type, "Iptc")) { |
182 deleteValue<Exiv2::IptcData, Exiv2::IptcKey>(image->iptcData(), cKey); | |
183 } else { | |
184 throw std::invalid_argument(std::string("invalid key: ") + std::string(cKey)); | |
185 } | |
186 } catch (std::exception& e) { | |
187 jEnv->ExceptionClear(); | |
188 jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception"); | |
189 jEnv->ThrowNew(ex, e.what()); | |
190 } | |
191 if (type != NULL) free(type); | |
122 jEnv->ReleaseStringUTFChars(key, cKey); | 192 jEnv->ReleaseStringUTFChars(key, cKey); |
123 } | 193 } |
124 | 194 |
125 /* | 195 /* |
126 * Class: name_blackcap_exifwasher_exiv2_ExifData | 196 * Class: name_blackcap_exifwasher_exiv2_ExifData |
127 * Method: _value | 197 * Method: _value |
128 * Signature: (Ljava/lang/String;)Lname/blackcap/exifwasher/exiv2/ExifData/Value; | 198 * Signature: (Ljava/lang/String;)Lname/blackcap/exifwasher/exiv2/ExifData/Value; |
129 */ | 199 */ |
130 JNIEXPORT jobject JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1value | 200 JNIEXPORT jobject JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1value |
131 (JNIEnv *jEnv, jobject jThis, jstring key) { | 201 (JNIEnv *jEnv, jobject jThis, jstring key) { |
132 Exiv2::ExifData *data = reinterpret_cast<Exiv2::ExifData *> (getPointer(jEnv, jThis)); | 202 Exiv2::Image *image = getPointer(jEnv, jThis); |
133 if (jEnv->ExceptionCheck()) return NULL; | 203 if (jEnv->ExceptionCheck()) return NULL; |
134 const char *cKey = jEnv->GetStringUTFChars(key, NULL); | 204 const char *cKey = jEnv->GetStringUTFChars(key, NULL); |
135 Exiv2::ExifData::const_iterator found = data->findKey(Exiv2::ExifKey(std::string(cKey))); | 205 char *type = NULL; |
206 jobject ret = NULL; | |
207 try { | |
208 type = getType(cKey); | |
209 if (!strcmp(type, "Exif")) { | |
210 ret = getValue<Exiv2::ExifData, Exiv2::ExifKey>(jEnv, image->exifData(), cKey); | |
211 } else if (!strcmp(type, "Xmp")) { | |
212 ret = getValue<Exiv2::XmpData, Exiv2::XmpKey>(jEnv, image->xmpData(), cKey); | |
213 } else if (!strcmp(type, "Iptc")) { | |
214 ret = getValue<Exiv2::IptcData, Exiv2::IptcKey>(jEnv, image->iptcData(), cKey); | |
215 } else { | |
216 throw std::invalid_argument(std::string("invalid key: ") + std::string(cKey)); | |
217 } | |
218 } catch (std::exception& e) { | |
219 jEnv->ExceptionClear(); | |
220 jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception"); | |
221 jEnv->ThrowNew(ex, e.what()); | |
222 } | |
223 if (type != NULL) free(type); | |
136 jEnv->ReleaseStringUTFChars(key, cKey); | 224 jEnv->ReleaseStringUTFChars(key, cKey); |
137 if (found == data->end()) { | 225 return ret; |
138 return NULL; | |
139 } | |
140 jclass klass = jEnv->FindClass("name/blackcap/exifwasher/exiv2/ExifData$Value"); | |
141 if (jEnv->ExceptionCheck()) return NULL; | |
142 jstring type = jEnv->NewStringUTF(found->typeName()); | |
143 jstring value = jEnv->NewStringUTF(found->toString().c_str()); | |
144 jmethodID method = jEnv->GetMethodID(klass, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V"); | |
145 if (jEnv->ExceptionCheck()) return NULL; | |
146 return jEnv->NewObject(klass, method, type, value); | |
147 } | 226 } |
148 | 227 |
149 /* | 228 /* |
150 * Class: name_blackcap_exifwasher_exiv2_ExifData | 229 * Class: name_blackcap_exifwasher_exiv2_ExifData |
151 * Method: _keys | 230 * Method: _keys |
152 * Signature: ()[Ljava/lang/String; | 231 * Signature: ()[Ljava/lang/String; |
153 */ | 232 */ |
154 JNIEXPORT jobjectArray JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1keys | 233 JNIEXPORT jobjectArray JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1keys |
155 (JNIEnv *jEnv, jobject jThis) { | 234 (JNIEnv *jEnv, jobject jThis) { |
156 Exiv2::ExifData *data = reinterpret_cast<Exiv2::ExifData *> (getPointer(jEnv, jThis)); | 235 Exiv2::Image *image = getPointer(jEnv, jThis); |
236 Exiv2::ExifData eData = image->exifData(); | |
237 Exiv2::XmpData xData = image->xmpData(); | |
238 Exiv2::IptcData iData = image->iptcData(); | |
157 if (jEnv->ExceptionCheck()) return NULL; | 239 if (jEnv->ExceptionCheck()) return NULL; |
158 jclass klass = jEnv->FindClass("java/lang/String"); | 240 jclass klass = jEnv->FindClass("java/lang/String"); |
159 if (jEnv->ExceptionCheck()) return NULL; | 241 if (jEnv->ExceptionCheck()) return NULL; |
160 jobjectArray ret = jEnv->NewObjectArray(data->count(), klass, NULL); | 242 jobjectArray ret = jEnv->NewObjectArray(eData.count() + iData.count() + xData.count(), klass, NULL); |
161 if (jEnv->ExceptionCheck()) return NULL; | 243 if (jEnv->ExceptionCheck()) return NULL; |
162 Exiv2::ExifData::const_iterator end = data->end(); | 244 jsize start = getKeys(jEnv, ret, 0, eData); |
163 jsize j = 0; | 245 if (jEnv->ExceptionCheck()) return NULL; |
164 for (Exiv2::ExifData::const_iterator i = data->begin(); i != end; ++i) { | 246 start = getKeys(jEnv, ret, start, xData); |
165 jEnv->SetObjectArrayElement(ret, j++, jEnv->NewStringUTF(i->key().c_str())); | 247 if (jEnv->ExceptionCheck()) return NULL; |
166 if (jEnv->ExceptionCheck()) break; | 248 start = getKeys(jEnv, ret, start, iData); |
167 } | 249 if (jEnv->ExceptionCheck()) return NULL; |
168 return ret; | 250 return ret; |
169 } | 251 } |
170 | 252 |
171 #ifdef __cplusplus | 253 #ifdef __cplusplus |
172 } | 254 } |