@@ -23,6 +23,43 @@ class AndroidPlatformContext : public PlatformContext {
2323private:
2424 jobject _blobModule;
2525
26+ std::vector<uint8_t > resolveBlob (JNIEnv *env, const std::string &blobId,
27+ double offset, double size) {
28+ if (!_blobModule) {
29+ throw std::runtime_error (" BlobModule instance is null" );
30+ }
31+
32+ jclass blobModuleClass = env->GetObjectClass (_blobModule);
33+ if (!blobModuleClass) {
34+ throw std::runtime_error (" Couldn't find BlobModule class" );
35+ }
36+
37+ jmethodID resolveMethod = env->GetMethodID (blobModuleClass, " resolve" ,
38+ " (Ljava/lang/String;II)[B" );
39+ env->DeleteLocalRef (blobModuleClass);
40+
41+ if (!resolveMethod) {
42+ throw std::runtime_error (" Couldn't find resolve method in BlobModule" );
43+ }
44+
45+ jstring jBlobId = env->NewStringUTF (blobId.c_str ());
46+ jbyteArray blobData = (jbyteArray)env->CallObjectMethod (
47+ _blobModule, resolveMethod, jBlobId, static_cast <jint>(offset),
48+ static_cast <jint>(size));
49+ env->DeleteLocalRef (jBlobId);
50+
51+ if (!blobData) {
52+ throw std::runtime_error (" Couldn't retrieve blob data" );
53+ }
54+
55+ jsize len = env->GetArrayLength (blobData);
56+ std::vector<uint8_t > data (len);
57+ env->GetByteArrayRegion (blobData, 0 , len,
58+ reinterpret_cast <jbyte *>(data.data ()));
59+ env->DeleteLocalRef (blobData);
60+ return data;
61+ }
62+
2663public:
2764 explicit AndroidPlatformContext (jobject blobModule)
2865 : _blobModule(blobModule) {}
@@ -52,188 +89,116 @@ class AndroidPlatformContext : public PlatformContext {
5289 throw std::runtime_error (" Couldn't get JNI environment" );
5390 }
5491
55- // Use the BlobModule instance from _blobModule
56- if (!_blobModule) {
57- throw std::runtime_error (" BlobModule instance is null" );
58- }
92+ auto data = resolveBlob (env, blobId, offset, size);
93+ return createImageBitmapFromData (data);
94+ }
5995
60- // Get the resolve method ID
61- jclass blobModuleClass = env->GetObjectClass (_blobModule);
62- if (!blobModuleClass) {
63- throw std::runtime_error (" Couldn't find BlobModule class" );
64- }
96+ void createImageBitmapAsync (
97+ std::string blobId, double offset, double size,
98+ std::function<void (ImageData)> onSuccess,
99+ std::function<void(std::string)> onError) override {
100+ std::thread ([this , blobId = std::move (blobId), offset, size,
101+ onSuccess = std::move (onSuccess),
102+ onError = std::move (onError)]() {
103+ jni::Environment::ensureCurrentThreadIsAttached ();
104+ try {
105+ JNIEnv *env = facebook::jni::Environment::current ();
106+ if (!env) {
107+ throw std::runtime_error (" Couldn't get JNI environment" );
108+ }
109+ auto data = resolveBlob (env, blobId, offset, size);
110+ auto result = createImageBitmapFromData (data);
111+ onSuccess (std::move (result));
112+ } catch (const std::exception &e) {
113+ onError (e.what ());
114+ }
115+ }).detach ();
116+ }
65117
66- jmethodID resolveMethod = env->GetMethodID (blobModuleClass, " resolve" ,
67- " (Ljava/lang/String;II)[B" );
68- if (!resolveMethod) {
69- throw std::runtime_error (" Couldn't find resolve method in BlobModule" );
70- }
118+ ImageData createImageBitmapFromData (std::span<const uint8_t > data) override {
119+ jni::Environment::ensureCurrentThreadIsAttached ();
71120
72- // Resolve the blob data
73- jstring jBlobId = env->NewStringUTF (blobId.c_str ());
74- jbyteArray blobData = (jbyteArray)env->CallObjectMethod (
75- _blobModule, resolveMethod, jBlobId, static_cast <jint>(offset),
76- static_cast <jint>(size));
77- env->DeleteLocalRef (jBlobId);
121+ JNIEnv *env = facebook::jni::Environment::current ();
122+ if (!env) {
123+ throw std::runtime_error (" Couldn't get JNI environment" );
124+ }
78125
79- if (!blobData) {
80- throw std::runtime_error (" Couldn't retrieve blob data" );
126+ // Create jbyteArray from the raw bytes
127+ jbyteArray byteArray = env->NewByteArray (static_cast <jsize>(data.size ()));
128+ if (!byteArray) {
129+ throw std::runtime_error (" Couldn't allocate byte array" );
81130 }
131+ env->SetByteArrayRegion (byteArray, 0 , static_cast <jsize>(data.size ()),
132+ reinterpret_cast <const jbyte *>(data.data ()));
82133
83- // Create a Bitmap from the blob data
134+ // Decode via BitmapFactory
84135 jclass bitmapFactoryClass =
85136 env->FindClass (" android/graphics/BitmapFactory" );
137+ if (!bitmapFactoryClass) {
138+ env->DeleteLocalRef (byteArray);
139+ throw std::runtime_error (" Couldn't find BitmapFactory class" );
140+ }
86141 jmethodID decodeByteArrayMethod =
87142 env->GetStaticMethodID (bitmapFactoryClass, " decodeByteArray" ,
88143 " ([BII)Landroid/graphics/Bitmap;" );
89- jint blobLength = env->GetArrayLength (blobData);
144+ if (!decodeByteArrayMethod) {
145+ env->DeleteLocalRef (byteArray);
146+ env->DeleteLocalRef (bitmapFactoryClass);
147+ throw std::runtime_error (" Couldn't find decodeByteArray method" );
148+ }
149+ jint length = static_cast <jint>(data.size ());
90150 jobject bitmap = env->CallStaticObjectMethod (
91- bitmapFactoryClass, decodeByteArrayMethod, blobData, 0 , blobLength);
151+ bitmapFactoryClass, decodeByteArrayMethod, byteArray, 0 , length);
152+ env->DeleteLocalRef (bitmapFactoryClass);
92153
93154 if (!bitmap) {
94- env->DeleteLocalRef (blobData );
155+ env->DeleteLocalRef (byteArray );
95156 throw std::runtime_error (" Couldn't decode image" );
96157 }
97158
98- // Get bitmap info
99159 AndroidBitmapInfo bitmapInfo;
100160 if (AndroidBitmap_getInfo (env, bitmap, &bitmapInfo) !=
101161 ANDROID_BITMAP_RESULT_SUCCESS) {
102- env->DeleteLocalRef (blobData );
162+ env->DeleteLocalRef (byteArray );
103163 env->DeleteLocalRef (bitmap);
104164 throw std::runtime_error (" Couldn't get bitmap info" );
105165 }
106166
107- // Lock the bitmap pixels
108167 void *bitmapPixels;
109168 if (AndroidBitmap_lockPixels (env, bitmap, &bitmapPixels) !=
110169 ANDROID_BITMAP_RESULT_SUCCESS) {
111- env->DeleteLocalRef (blobData );
170+ env->DeleteLocalRef (byteArray );
112171 env->DeleteLocalRef (bitmap);
113172 throw std::runtime_error (" Couldn't lock bitmap pixels" );
114173 }
115174
116- // Copy the bitmap data
117- std::vector<uint8_t > imageData (bitmapInfo.height * bitmapInfo.stride );
118- memcpy (imageData.data (), bitmapPixels, imageData.size ());
175+ ImageData result;
176+ result.width = static_cast <int >(bitmapInfo.width );
177+ result.height = static_cast <int >(bitmapInfo.height );
178+ result.data .resize (bitmapInfo.height * bitmapInfo.stride );
179+ memcpy (result.data .data (), bitmapPixels, result.data .size ());
119180
120- // Unlock the bitmap pixels
121181 AndroidBitmap_unlockPixels (env, bitmap);
122182
123- // Clean up JNI references
124- env->DeleteLocalRef (blobData);
183+ env->DeleteLocalRef (byteArray);
125184 env->DeleteLocalRef (bitmap);
126185
127- ImageData result;
128- result.width = static_cast <int >(bitmapInfo.width );
129- result.height = static_cast <int >(bitmapInfo.height );
130- result.data = imageData;
131186 return result;
132187 }
133188
134- void createImageBitmapAsync (
135- std::string blobId, double offset, double size,
136- std::function<void (ImageData)> onSuccess,
189+ void createImageBitmapFromDataAsync (
190+ std::span<const uint8_t > data, std::function<void (ImageData)> onSuccess,
137191 std::function<void(std::string)> onError) override {
138- // Capture blobModule for the background thread
139- jobject blobModule = _blobModule;
140-
141- // Dispatch to a background thread
142- std::thread ([blobModule, blobId = std::move (blobId), offset, size,
192+ std::thread ([this , ownedData = std::vector<uint8_t >(data.begin (), data.end ()),
143193 onSuccess = std::move (onSuccess),
144- onError = std::move (onError)]() {
194+ onError = std::move (onError)]() mutable {
145195 jni::Environment::ensureCurrentThreadIsAttached ();
146-
147- JNIEnv *env = facebook::jni::Environment::current ();
148- if (!env) {
149- onError (" Couldn't get JNI environment" );
150- return ;
151- }
152-
153- if (!blobModule) {
154- onError (" BlobModule instance is null" );
155- return ;
156- }
157-
158- // Get the resolve method ID
159- jclass blobModuleClass = env->GetObjectClass (blobModule);
160- if (!blobModuleClass) {
161- onError (" Couldn't find BlobModule class" );
162- return ;
163- }
164-
165- jmethodID resolveMethod = env->GetMethodID (blobModuleClass, " resolve" ,
166- " (Ljava/lang/String;II)[B" );
167- if (!resolveMethod) {
168- onError (" Couldn't find resolve method in BlobModule" );
169- return ;
170- }
171-
172- // Resolve the blob data
173- jstring jBlobId = env->NewStringUTF (blobId.c_str ());
174- jbyteArray blobData = (jbyteArray)env->CallObjectMethod (
175- blobModule, resolveMethod, jBlobId, static_cast <jint>(offset),
176- static_cast <jint>(size));
177- env->DeleteLocalRef (jBlobId);
178-
179- if (!blobData) {
180- onError (" Couldn't retrieve blob data" );
181- return ;
196+ try {
197+ auto result = createImageBitmapFromData (ownedData);
198+ onSuccess (std::move (result));
199+ } catch (const std::exception &e) {
200+ onError (e.what ());
182201 }
183-
184- // Create a Bitmap from the blob data
185- jclass bitmapFactoryClass =
186- env->FindClass (" android/graphics/BitmapFactory" );
187- jmethodID decodeByteArrayMethod =
188- env->GetStaticMethodID (bitmapFactoryClass, " decodeByteArray" ,
189- " ([BII)Landroid/graphics/Bitmap;" );
190- jint blobLength = env->GetArrayLength (blobData);
191- jobject bitmap = env->CallStaticObjectMethod (
192- bitmapFactoryClass, decodeByteArrayMethod, blobData, 0 , blobLength);
193-
194- if (!bitmap) {
195- env->DeleteLocalRef (blobData);
196- onError (" Couldn't decode image" );
197- return ;
198- }
199-
200- // Get bitmap info
201- AndroidBitmapInfo bitmapInfo;
202- if (AndroidBitmap_getInfo (env, bitmap, &bitmapInfo) !=
203- ANDROID_BITMAP_RESULT_SUCCESS) {
204- env->DeleteLocalRef (blobData);
205- env->DeleteLocalRef (bitmap);
206- onError (" Couldn't get bitmap info" );
207- return ;
208- }
209-
210- // Lock the bitmap pixels
211- void *bitmapPixels;
212- if (AndroidBitmap_lockPixels (env, bitmap, &bitmapPixels) !=
213- ANDROID_BITMAP_RESULT_SUCCESS) {
214- env->DeleteLocalRef (blobData);
215- env->DeleteLocalRef (bitmap);
216- onError (" Couldn't lock bitmap pixels" );
217- return ;
218- }
219-
220- // Copy the bitmap data
221- std::vector<uint8_t > imageData (bitmapInfo.height * bitmapInfo.stride );
222- memcpy (imageData.data (), bitmapPixels, imageData.size ());
223-
224- // Unlock the bitmap pixels
225- AndroidBitmap_unlockPixels (env, bitmap);
226-
227- // Clean up JNI references
228- env->DeleteLocalRef (blobData);
229- env->DeleteLocalRef (bitmap);
230-
231- ImageData result;
232- result.width = static_cast <int >(bitmapInfo.width );
233- result.height = static_cast <int >(bitmapInfo.height );
234- result.data = std::move (imageData);
235-
236- onSuccess (std::move (result));
237202 }).detach ();
238203 }
239204};
0 commit comments