1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 #define LOG_TAG "AImageDecoderTest"
19
20 #include <jni.h>
21 #include <android/asset_manager.h>
22 #include <android/asset_manager_jni.h>
23 #include <android/data_space.h>
24 #include <android/bitmap.h>
25 #include <android/imagedecoder.h>
26 #include <android/rect.h>
27
28 #include "NativeTestHelpers.h"
29
30 #include <cstdlib>
31 #include <cstring>
32 #include <initializer_list>
33 #include <limits>
34 #include <memory>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <vector>
38
39 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
40
41 using AssetCloser = std::unique_ptr<AAsset, decltype(&AAsset_close)>;
42 using DecoderDeleter = std::unique_ptr<AImageDecoder, decltype(&AImageDecoder_delete)>;
43
testEmptyCreate(JNIEnv * env,jclass)44 static void testEmptyCreate(JNIEnv* env, jclass) {
45 AImageDecoder* decoderPtr = nullptr;
46 for (AImageDecoder** outDecoder : { &decoderPtr, (AImageDecoder**) nullptr }) {
47 for (AAsset* asset : { nullptr }) {
48 int result = AImageDecoder_createFromAAsset(asset, outDecoder);
49 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
50 if (outDecoder) {
51 ASSERT_EQ(nullptr, *outDecoder);
52 }
53 }
54
55 for (int fd : { 0, -1 }) {
56 int result = AImageDecoder_createFromFd(fd, outDecoder);
57 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
58 if (outDecoder) {
59 ASSERT_EQ(nullptr, *outDecoder);
60 }
61 }
62
63 auto testEmptyBuffer = [env, outDecoder](void* buffer, size_t length) {
64 int result = AImageDecoder_createFromBuffer(buffer, length, outDecoder);
65 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
66 if (outDecoder) {
67 ASSERT_EQ(nullptr, *outDecoder);
68 }
69 };
70 testEmptyBuffer(nullptr, 0);
71 char buf[4];
72 testEmptyBuffer(buf, 0);
73 }
74 }
75
openAsset(JNIEnv * env,jobject jAssets,jstring jFile,int mode)76 static AAsset* openAsset(JNIEnv* env, jobject jAssets, jstring jFile, int mode) {
77 AAssetManager* nativeManager = AAssetManager_fromJava(env, jAssets);
78 const char* file = env->GetStringUTFChars(jFile, nullptr);
79 AAsset* asset = AAssetManager_open(nativeManager, file, mode);
80 if (!asset) {
81 ALOGE("Could not open %s", file);
82 } else {
83 ALOGD("Testing %s", file);
84 }
85 env->ReleaseStringUTFChars(jFile, file);
86 return asset;
87 }
88
testNullDecoder(JNIEnv * env,jclass,jobject jAssets,jstring jFile)89 static void testNullDecoder(JNIEnv* env, jclass, jobject jAssets, jstring jFile) {
90 AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_BUFFER);
91 ASSERT_NE(asset, nullptr);
92 AssetCloser assetCloser(asset, AAsset_close);
93
94 AImageDecoder_delete(nullptr);
95
96 #pragma clang diagnostic push
97 #pragma clang diagnostic ignored "-Wnonnull"
98 {
99 int result = AImageDecoder_createFromAAsset(asset, nullptr);
100 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
101 }
102
103 {
104 const void* buffer = AAsset_getBuffer(asset);
105 ASSERT_NE(buffer, nullptr);
106
107 int result = AImageDecoder_createFromBuffer(buffer, AAsset_getLength(asset), nullptr);
108 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
109 }
110
111 {
112 off_t start, length;
113 int fd = AAsset_openFileDescriptor(asset, &start, &length);
114 ASSERT_GT(fd, 0);
115
116 off_t offset = ::lseek(fd, start, SEEK_SET);
117 ASSERT_EQ(start, offset);
118
119 int result = AImageDecoder_createFromFd(fd, nullptr);
120 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
121 close(fd);
122 }
123
124 {
125 auto stride = AImageDecoder_getMinimumStride(nullptr);
126 ASSERT_EQ(0, stride);
127 }
128
129 {
130 char buf[4];
131 int result = AImageDecoder_decodeImage(nullptr, buf, 4, 4);
132 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
133 }
134
135 {
136 int result = AImageDecoder_setAndroidBitmapFormat(nullptr, ANDROID_BITMAP_FORMAT_RGBA_8888);
137 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
138
139 auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(nullptr);
140 ASSERT_EQ(ANDROID_BITMAP_FORMAT_NONE, format);
141 }
142
143 {
144 int result = AImageDecoder_setUnpremultipliedRequired(nullptr, true);
145 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
146
147 int alpha = AImageDecoderHeaderInfo_getAlphaFlags(nullptr);
148 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, alpha);
149 }
150
151 ASSERT_EQ(0, AImageDecoderHeaderInfo_getWidth(nullptr));
152 ASSERT_EQ(0, AImageDecoderHeaderInfo_getHeight(nullptr));
153 ASSERT_EQ(nullptr, AImageDecoderHeaderInfo_getMimeType(nullptr));
154 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, AImageDecoderHeaderInfo_getDataSpace(nullptr));
155
156 {
157 int result = AImageDecoder_setTargetSize(nullptr, 1, 1);
158 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
159 }
160 {
161 ARect rect {0, 0, 10, 10};
162 int result = AImageDecoder_setCrop(nullptr, rect);
163 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
164 }
165
166 for (ADataSpace dataSpace : { ADATASPACE_UNKNOWN, ADATASPACE_SCRGB_LINEAR, ADATASPACE_SRGB,
167 ADATASPACE_SCRGB, ADATASPACE_DISPLAY_P3, ADATASPACE_BT2020_PQ,
168 ADATASPACE_ADOBE_RGB, ADATASPACE_BT2020, ADATASPACE_BT709,
169 ADATASPACE_DCI_P3, ADATASPACE_SRGB_LINEAR }) {
170 int result = AImageDecoder_setDataSpace(nullptr, dataSpace);
171 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
172 }
173
174 ASSERT_FALSE(AImageDecoder_isAnimated(nullptr));
175
176 {
177 int result = AImageDecoder_getRepeatCount(nullptr);
178 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
179 }
180 #pragma clang diagnostic pop
181 }
182
testInfo(JNIEnv * env,jclass,jlong imageDecoderPtr,jint width,jint height,jstring jMimeType,jboolean isF16,jint dataSpace)183 static void testInfo(JNIEnv* env, jclass, jlong imageDecoderPtr, jint width, jint height,
184 jstring jMimeType, jboolean isF16, jint dataSpace) {
185 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
186 ASSERT_NE(decoder, nullptr);
187 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
188
189 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
190 ASSERT_NE(info, nullptr);
191 int32_t actualWidth = AImageDecoderHeaderInfo_getWidth(info);
192 ASSERT_EQ(width, actualWidth);
193 int32_t actualHeight = AImageDecoderHeaderInfo_getHeight(info);
194 ASSERT_EQ(height, actualHeight);
195
196 const char* mimeType = env->GetStringUTFChars(jMimeType, nullptr);
197 ASSERT_NE(mimeType, nullptr);
198 ASSERT_EQ(0, strcmp(mimeType, AImageDecoderHeaderInfo_getMimeType(info)));
199 env->ReleaseStringUTFChars(jMimeType, mimeType);
200 auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
201 if (isF16) {
202 ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_F16, format);
203 } else {
204 ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_8888, format);
205 }
206
207 ASSERT_EQ(dataSpace, AImageDecoderHeaderInfo_getDataSpace(info));
208 }
209
openAssetNative(JNIEnv * env,jclass,jobject jAssets,jstring jFile)210 static jlong openAssetNative(JNIEnv* env, jclass, jobject jAssets, jstring jFile) {
211 // FIXME: Test the other modes? Or more to the point, pass in the mode? It
212 // seems that when we want a buffer we should use AASSET_MODE_BUFFER.
213 AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_UNKNOWN);
214 if (!asset) {
215 fail(env, "Failed to open native asset!");
216 }
217 return reinterpret_cast<jlong>(asset);
218 }
219
closeAsset(JNIEnv *,jclass,jlong asset)220 static void closeAsset(JNIEnv*, jclass, jlong asset) {
221 AAsset_close(reinterpret_cast<AAsset*>(asset));
222 }
223
createFromAsset(JNIEnv * env,jclass,jlong asset)224 static jlong createFromAsset(JNIEnv* env, jclass, jlong asset) {
225 AImageDecoder* decoder = nullptr;
226 int result = AImageDecoder_createFromAAsset(reinterpret_cast<AAsset*>(asset), &decoder);
227 if (ANDROID_IMAGE_DECODER_SUCCESS != result || !decoder) {
228 fail(env, "Failed to create AImageDecoder!");
229 }
230 return reinterpret_cast<jlong>(decoder);
231 }
232
createFromFd(JNIEnv * env,jclass,int fd)233 static jlong createFromFd(JNIEnv* env, jclass, int fd) {
234 AImageDecoder* decoder = nullptr;
235 int result = AImageDecoder_createFromFd(fd, &decoder);
236 if (ANDROID_IMAGE_DECODER_SUCCESS != result || !decoder) {
237 fail(env, "Failed to create AImageDecoder!");
238 }
239 return reinterpret_cast<jlong>(decoder);
240 }
241
createFromAssetFd(JNIEnv * env,jclass,jlong assetPtr)242 static jlong createFromAssetFd(JNIEnv* env, jclass, jlong assetPtr) {
243 AAsset* asset = reinterpret_cast<AAsset*>(assetPtr);
244 off_t start, length;
245 int fd = AAsset_openFileDescriptor(asset, &start, &length);
246 if (fd <= 0) {
247 fail(env, "Failed to open file descriptor!");
248 return -1;
249 }
250
251 off_t offset = ::lseek(fd, start, SEEK_SET);
252 if (offset != start) {
253 fail(env, "Failed to seek file descriptor!");
254 return -1;
255 }
256
257 return createFromFd(env, nullptr, fd);
258 }
259
createFromAssetBuffer(JNIEnv * env,jclass,jlong assetPtr)260 static jlong createFromAssetBuffer(JNIEnv* env, jclass, jlong assetPtr) {
261 AAsset* asset = reinterpret_cast<AAsset*>(assetPtr);
262 const void* buffer = AAsset_getBuffer(asset);
263 if (!buffer) {
264 fail(env, "AAsset_getBuffer failed!");
265 return -1;
266 }
267
268 AImageDecoder* decoder = nullptr;
269 int result = AImageDecoder_createFromBuffer(buffer, AAsset_getLength(asset), &decoder);
270 if (ANDROID_IMAGE_DECODER_SUCCESS != result || !decoder) {
271 fail(env, "AImageDecoder_createFromBuffer failed!");
272 return -1;
273 }
274 return reinterpret_cast<jlong>(decoder);
275 }
276
testCreateIncomplete(JNIEnv * env,jclass,jobject jAssets,jstring jFile,jint truncatedLength)277 static void testCreateIncomplete(JNIEnv* env, jclass, jobject jAssets, jstring jFile,
278 jint truncatedLength) {
279 AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_UNKNOWN);
280 ASSERT_NE(asset, nullptr);
281 AssetCloser assetCloser(asset, AAsset_close);
282
283 const void* buffer = AAsset_getBuffer(asset);
284 ASSERT_NE(buffer, nullptr);
285
286 AImageDecoder* decoder;
287 int result = AImageDecoder_createFromBuffer(buffer, truncatedLength, &decoder);
288 ASSERT_EQ(ANDROID_IMAGE_DECODER_INCOMPLETE, result);
289 ASSERT_EQ(decoder, nullptr);
290 }
291
testCreateUnsupported(JNIEnv * env,jclass,jobject jAssets,jstring jFile)292 static void testCreateUnsupported(JNIEnv* env, jclass, jobject jAssets, jstring jFile) {
293 AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_UNKNOWN);
294 ASSERT_NE(asset, nullptr);
295 AssetCloser assetCloser(asset, AAsset_close);
296
297 AImageDecoder* decoder;
298 int result = AImageDecoder_createFromAAsset(asset, &decoder);
299 ASSERT_EQ(ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT, result);
300 ASSERT_EQ(decoder, nullptr);
301 }
302
testSetFormat(JNIEnv * env,jclass,jlong imageDecoderPtr,jboolean isF16,jboolean isGray)303 static void testSetFormat(JNIEnv* env, jclass, jlong imageDecoderPtr,
304 jboolean isF16, jboolean isGray) {
305 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
306 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
307
308 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
309 ASSERT_NE(info, nullptr);
310
311 // Store the format so we can ensure that it doesn't change when we call
312 // AImageDecoder_setAndroidBitmapFormat.
313 const auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
314 if (isF16) {
315 ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_F16, format);
316 } else {
317 ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_8888, format);
318 }
319
320 int result = AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_A_8);
321 if (isGray) {
322 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
323 } else {
324 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
325 }
326 ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
327
328 result = AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_RGB_565);
329 int alpha = AImageDecoderHeaderInfo_getAlphaFlags(info);
330 if (alpha == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
331 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
332 } else {
333 ASSERT_EQ(ANDROID_BITMAP_FLAGS_ALPHA_PREMUL, alpha);
334 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
335 }
336 ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
337
338 for (auto newFormat : { ANDROID_BITMAP_FORMAT_RGBA_4444, ANDROID_BITMAP_FORMAT_NONE }) {
339 result = AImageDecoder_setAndroidBitmapFormat(decoder, newFormat);
340 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
341 ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
342 }
343
344 for (auto newFormat : { ANDROID_BITMAP_FORMAT_RGBA_8888, ANDROID_BITMAP_FORMAT_RGBA_F16 }) {
345 result = AImageDecoder_setAndroidBitmapFormat(decoder, newFormat);
346 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
347 ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
348 }
349
350 for (auto invalidFormat : { -1, 42, 67 }) {
351 result = AImageDecoder_setAndroidBitmapFormat(decoder, invalidFormat);
352 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
353 ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
354 }
355 }
356
testSetUnpremul(JNIEnv * env,jclass,jlong imageDecoderPtr,jboolean hasAlpha)357 static void testSetUnpremul(JNIEnv* env, jclass, jlong imageDecoderPtr, jboolean hasAlpha) {
358 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
359 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
360
361 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
362 ASSERT_NE(info, nullptr);
363
364 // Store the alpha so we can ensure that it doesn't change when we call
365 // AImageDecoder_setUnpremultipliedRequired.
366 const int alpha = AImageDecoderHeaderInfo_getAlphaFlags(info);
367 if (hasAlpha) {
368 ASSERT_EQ(ANDROID_BITMAP_FLAGS_ALPHA_PREMUL, alpha);
369 } else {
370 ASSERT_EQ(ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE, alpha);
371 }
372
373 for (bool required : { true, false }) {
374 int result = AImageDecoder_setUnpremultipliedRequired(decoder, required);
375 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
376 ASSERT_EQ(alpha, AImageDecoderHeaderInfo_getAlphaFlags(info));
377 }
378 }
379
bytesPerPixel(int32_t format)380 static int bytesPerPixel(int32_t format) {
381 switch (format) {
382 case ANDROID_BITMAP_FORMAT_RGBA_8888:
383 return 4;
384 case ANDROID_BITMAP_FORMAT_RGB_565:
385 return 2;
386 case ANDROID_BITMAP_FORMAT_A_8:
387 return 1;
388 case ANDROID_BITMAP_FORMAT_RGBA_F16:
389 return 8;
390 case ANDROID_BITMAP_FORMAT_NONE:
391 case ANDROID_BITMAP_FORMAT_RGBA_4444:
392 default:
393 return 0;
394 }
395 }
396
testGetMinimumStride(JNIEnv * env,jclass,jlong imageDecoderPtr,jboolean isF16,jboolean isGray)397 static void testGetMinimumStride(JNIEnv* env, jclass, jlong imageDecoderPtr,
398 jboolean isF16, jboolean isGray) {
399 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
400 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
401
402 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
403 ASSERT_NE(info, nullptr);
404
405 const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
406 size_t stride = AImageDecoder_getMinimumStride(decoder);
407
408 if (isF16) {
409 ASSERT_EQ(bytesPerPixel(ANDROID_BITMAP_FORMAT_RGBA_F16) * width, stride);
410 } else {
411 ASSERT_EQ(bytesPerPixel(ANDROID_BITMAP_FORMAT_RGBA_8888) * width, stride);
412 }
413
414 auto setFormatAndCheckStride = [env, decoder, width, &stride](AndroidBitmapFormat format) {
415 int result = AImageDecoder_setAndroidBitmapFormat(decoder, format);
416 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
417
418 stride = AImageDecoder_getMinimumStride(decoder);
419 ASSERT_EQ(bytesPerPixel(format) * width, stride);
420 };
421
422 int alpha = AImageDecoderHeaderInfo_getAlphaFlags(info);
423 if (alpha == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
424 setFormatAndCheckStride(ANDROID_BITMAP_FORMAT_RGB_565);
425 }
426
427 if (isGray) {
428 setFormatAndCheckStride(ANDROID_BITMAP_FORMAT_A_8);
429 }
430
431 for (auto newFormat : { ANDROID_BITMAP_FORMAT_RGBA_8888, ANDROID_BITMAP_FORMAT_RGBA_F16 }) {
432 setFormatAndCheckStride(newFormat);
433 }
434
435 for (auto badFormat : { ANDROID_BITMAP_FORMAT_RGBA_4444, ANDROID_BITMAP_FORMAT_NONE }) {
436 int result = AImageDecoder_setAndroidBitmapFormat(decoder, badFormat);
437 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
438
439 // Stride is unchanged.
440 ASSERT_EQ(stride, AImageDecoder_getMinimumStride(decoder));
441 }
442 }
443
bitmapsEqual(size_t minStride,int height,void * pixelsA,size_t strideA,void * pixelsB,size_t strideB)444 static bool bitmapsEqual(size_t minStride, int height,
445 void* pixelsA, size_t strideA,
446 void* pixelsB, size_t strideB) {
447 for (int y = 0; y < height; ++y) {
448 auto* rowA = reinterpret_cast<char*>(pixelsA) + strideA * y;
449 auto* rowB = reinterpret_cast<char*>(pixelsB) + strideB * y;
450 if (memcmp(rowA, rowB, minStride) != 0) {
451 ALOGE("Bitmap mismatch on line %i", y);
452 return false;
453 }
454 }
455 return true;
456 }
457
458 #define EXPECT_EQ(msg, a, b) \
459 if ((a) != (b)) { \
460 ALOGE(msg); \
461 return false; \
462 }
463
464 #define EXPECT_GE(msg, a, b) \
465 if ((a) < (b)) { \
466 ALOGE(msg); \
467 return false; \
468 }
469
bitmapsEqual(JNIEnv * env,jobject jbitmap,int32_t androidBitmapFormat,int width,int height,int alphaFlags,size_t minStride,void * pixelsA,size_t strideA)470 static bool bitmapsEqual(JNIEnv* env, jobject jbitmap, int32_t androidBitmapFormat,
471 int width, int height, int alphaFlags, size_t minStride,
472 void* pixelsA, size_t strideA) {
473 AndroidBitmapInfo jInfo;
474 int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
475 EXPECT_EQ("Failed to getInfo on Bitmap", ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
476
477 EXPECT_EQ("Wrong format", jInfo.format, androidBitmapFormat);
478
479 // If the image is truly opaque, the Java Bitmap will report OPAQUE, even if
480 // the AImageDecoder requested PREMUL/UNPREMUL. In that case, it is okay for
481 // the two to disagree. We must ensure that we don't end up with one PREMUL
482 // and the other UNPREMUL, though.
483 int jAlphaFlags = jInfo.flags & ANDROID_BITMAP_FLAGS_ALPHA_MASK;
484 if (jAlphaFlags != ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE
485 && alphaFlags != ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
486 EXPECT_EQ("Wrong alpha type", jAlphaFlags, alphaFlags);
487 }
488
489 EXPECT_EQ("Wrong width", jInfo.width, width);
490 EXPECT_EQ("Wrong height", jInfo.height, height);
491
492 EXPECT_GE("Stride too small", jInfo.stride, minStride);
493
494 void* jPixels;
495 bitmapResult = AndroidBitmap_lockPixels(env, jbitmap, &jPixels);
496 EXPECT_EQ("Failed to lockPixels", ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
497
498 bool equal = bitmapsEqual(minStride, height, pixelsA, strideA, jPixels, jInfo.stride);
499
500 bitmapResult = AndroidBitmap_unlockPixels(env, jbitmap);
501 EXPECT_EQ("Failed to unlockPixels", ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
502
503 return equal;
504 }
505
testDecode(JNIEnv * env,jclass,jlong imageDecoderPtr,jint androidBitmapFormat,jboolean unpremul,jobject jbitmap)506 static void testDecode(JNIEnv* env, jclass, jlong imageDecoderPtr,
507 jint androidBitmapFormat, jboolean unpremul, jobject jbitmap) {
508 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
509 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
510
511 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
512 ASSERT_NE(info, nullptr);
513
514 int result;
515 int alphaFlags = AImageDecoderHeaderInfo_getAlphaFlags(info);
516 if (androidBitmapFormat == ANDROID_BITMAP_FORMAT_NONE) {
517 androidBitmapFormat = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
518 } else {
519 result = AImageDecoder_setAndroidBitmapFormat(decoder, androidBitmapFormat);
520 if (androidBitmapFormat == ANDROID_BITMAP_FORMAT_RGB_565) {
521 if (alphaFlags != ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
522 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
523
524 // The caller only passes down the Bitmap if it is opaque.
525 ASSERT_EQ(nullptr, jbitmap);
526 return;
527 }
528 }
529 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
530 }
531
532 if (unpremul) {
533 result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
534 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
535 alphaFlags = ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL;
536 }
537
538 const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
539 const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
540 size_t minStride = AImageDecoder_getMinimumStride(decoder);
541
542 size_t size = minStride * height;
543 void* pixels = malloc(size);
544
545 {
546 // Try some invalid parameters.
547 #pragma clang diagnostic push
548 #pragma clang diagnostic ignored "-Wnonnull"
549 result = AImageDecoder_decodeImage(decoder, nullptr, minStride, size);
550 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
551 #pragma clang diagnostic pop
552
553 result = AImageDecoder_decodeImage(decoder, pixels, minStride - 1, size);
554 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
555
556 result = AImageDecoder_decodeImage(decoder, pixels, minStride, size - minStride);
557 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
558
559 result = AImageDecoder_decodeImage(decoder, pixels, 0, size);
560 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
561 }
562
563 result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
564 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
565
566 ASSERT_NE(jbitmap, nullptr);
567 ASSERT_TRUE(bitmapsEqual(env, jbitmap, (AndroidBitmapFormat) androidBitmapFormat,
568 width, height, alphaFlags, minStride, pixels, minStride));
569
570 // Setting to an invalid data space is unsupported, and has no effect on the
571 // decodes below.
572 for (int32_t dataSpace : std::initializer_list<int32_t>{ -1, ADATASPACE_UNKNOWN, 400 }) {
573 result = AImageDecoder_setDataSpace(decoder, dataSpace);
574 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
575 }
576
577 // Used for subsequent decodes, to ensure they are identical to the
578 // original. For opaque images, this verifies that using PREMUL or UNPREMUL
579 // look the same. For all images, this verifies that decodeImage can be
580 // called multiple times.
581 auto decodeAgain = [=](bool unpremultipliedRequired) {
582 int r = AImageDecoder_setUnpremultipliedRequired(decoder, unpremultipliedRequired);
583 if (ANDROID_IMAGE_DECODER_SUCCESS != r) {
584 fail(env, "Failed to set alpha");
585 return false;
586 }
587
588 void* otherPixels = malloc(size);
589 r = AImageDecoder_decodeImage(decoder, otherPixels, minStride, size);
590 if (ANDROID_IMAGE_DECODER_SUCCESS != r) {
591 fail(env, "Failed to decode again with different settings");
592 return false;
593 }
594
595 if (!bitmapsEqual(minStride, height, pixels, minStride, otherPixels, minStride)) {
596 free(otherPixels);
597 fail(env, "Decoding again with different settings did not match!");
598 return false;
599 }
600 free(otherPixels);
601 return true;
602 };
603 if (alphaFlags == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
604 for (bool unpremultipliedRequired: { true, false }) {
605 if (!decodeAgain(unpremultipliedRequired)) return;
606 }
607 } else {
608 if (!decodeAgain(unpremul)) return;
609 }
610
611 if (androidBitmapFormat == ANDROID_BITMAP_FORMAT_A_8) {
612 // Attempting to set an ADataSpace is ignored by an A_8 decode.
613 for (ADataSpace dataSpace : { ADATASPACE_DCI_P3, ADATASPACE_ADOBE_RGB }) {
614 result = AImageDecoder_setDataSpace(decoder, dataSpace);
615 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
616 if (!decodeAgain(alphaFlags)) return;
617 }
618 }
619
620 free(pixels);
621 }
622
testDecodeStride(JNIEnv * env,jclass,jlong imageDecoderPtr)623 static void testDecodeStride(JNIEnv* env, jclass, jlong imageDecoderPtr) {
624 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
625 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
626
627 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
628 ASSERT_NE(info, nullptr);
629
630 const int height = AImageDecoderHeaderInfo_getHeight(info);
631 const int origWidth = AImageDecoderHeaderInfo_getWidth(info);
632
633 for (int width : { origWidth, origWidth / 3 }) {
634 if (width == 0) {
635 // The 1 x 1 image cannot be downscaled.
636 continue;
637 }
638 int result = AImageDecoder_setTargetSize(decoder, width, height);
639 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
640 for (AndroidBitmapFormat format : {
641 ANDROID_BITMAP_FORMAT_RGBA_8888,
642 ANDROID_BITMAP_FORMAT_RGB_565,
643 ANDROID_BITMAP_FORMAT_A_8,
644 ANDROID_BITMAP_FORMAT_RGBA_F16,
645 }) {
646 result = AImageDecoder_setAndroidBitmapFormat(decoder, format);
647 if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
648 // Not all images can be decoded to all formats. This is okay, and
649 // we've tested that we can decode to the expected formats elsewhere.
650 continue;
651 }
652
653 size_t minStride = AImageDecoder_getMinimumStride(decoder);
654 void* pixels = nullptr;
655
656 // The code in the below loop relies on minStride being used first.
657 std::vector<size_t> strides;
658 strides.push_back(minStride);
659 for (int i = 1; i <= 16; i++) {
660 strides.push_back(i + minStride);
661 }
662 strides.push_back(minStride * 2);
663 strides.push_back(minStride * 3);
664 for (size_t stride : strides) {
665 size_t size = stride * (height - 1) + minStride;
666 void* decodePixels = malloc(size);
667 result = AImageDecoder_decodeImage(decoder, decodePixels, stride, size);
668 if ((stride - minStride) % bytesPerPixel(format) != 0) {
669 // The stride is not pixel aligned.
670 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
671 continue;
672 }
673 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
674
675 if (pixels == nullptr) {
676 pixels = decodePixels;
677 } else {
678 ASSERT_TRUE(bitmapsEqual(minStride, height, pixels, minStride, decodePixels,
679 stride));
680 free(decodePixels);
681 }
682 }
683
684 free(pixels);
685 }
686 }
687 }
688
testSetTargetSize(JNIEnv * env,jclass,jlong imageDecoderPtr)689 static void testSetTargetSize(JNIEnv* env, jclass, jlong imageDecoderPtr) {
690 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
691 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
692
693 const size_t defaultStride = AImageDecoder_getMinimumStride(decoder);
694
695 for (int32_t width : { -1, 0, -500 }) {
696 int result = AImageDecoder_setTargetSize(decoder, width, 100);
697 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
698 // stride is unchanged, as the target size did not change.
699 ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
700 }
701
702 for (int32_t height : { -1, 0, -300 }) {
703 int result = AImageDecoder_setTargetSize(decoder, 100, height);
704 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
705 // stride is unchanged, as the target size did not change.
706 ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
707 }
708
709 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
710 ASSERT_NE(info, nullptr);
711 const int bpp = bytesPerPixel(AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
712
713 for (int32_t width : { 7, 100, 275, 300 }) {
714 int result = AImageDecoder_setTargetSize(decoder, width, 100);
715 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
716
717 size_t actualStride = AImageDecoder_getMinimumStride(decoder);
718 size_t expectedStride = bpp * width;
719 ASSERT_EQ(expectedStride, actualStride);
720 }
721
722 // Verify that setting a large enough width to overflow 31 bits fails.
723 constexpr auto kMaxInt32 = std::numeric_limits<int32_t>::max();
724 int32_t maxWidth = kMaxInt32 / bpp;
725 for (int32_t width : { maxWidth / 2, maxWidth - 1, maxWidth }) {
726 int result = AImageDecoder_setTargetSize(decoder, width, 1);
727 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
728
729 size_t actualStride = AImageDecoder_getMinimumStride(decoder);
730 size_t expectedStride = bpp * width;
731 ASSERT_EQ(expectedStride, actualStride);
732 }
733
734 for (int32_t width : { maxWidth + 1, (int32_t) (maxWidth * 1.5) }) {
735 int result = AImageDecoder_setTargetSize(decoder, width, 1);
736 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
737 }
738
739 // A height that results in overflowing 31 bits also fails.
740 int32_t maxHeight = kMaxInt32 / defaultStride;
741 const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
742 for (int32_t height : { maxHeight / 2, maxHeight - 1, maxHeight }) {
743 int result = AImageDecoder_setTargetSize(decoder, width, height);
744 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
745
746 size_t actualStride = AImageDecoder_getMinimumStride(decoder);
747 size_t expectedStride = bpp * width;
748 ASSERT_EQ(expectedStride, actualStride);
749 }
750
751 for (int32_t height : { maxHeight + 1, (int32_t) (maxHeight * 1.5) }) {
752 int result = AImageDecoder_setTargetSize(decoder, width, height);
753 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
754 }
755 }
756
757 struct SampledSizeParams {
758 AImageDecoder* decoder;
759 int sampleSize;
760 int32_t* width;
761 int32_t* height;
762 };
763
testComputeSampledSize(JNIEnv * env,jclass,jlong imageDecoderPtr,jobject jbitmap,jint sampleSize)764 static void testComputeSampledSize(JNIEnv* env, jclass, jlong imageDecoderPtr,
765 jobject jbitmap, jint sampleSize) {
766 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
767 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
768
769 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
770 ASSERT_NE(info, nullptr);
771 const int32_t origWidth = AImageDecoderHeaderInfo_getWidth(info);
772 const int32_t origHeight = AImageDecoderHeaderInfo_getHeight(info);
773
774 int32_t width, height;
775 // Test some bad parameters.
776 for (SampledSizeParams p : std::initializer_list<SampledSizeParams>{
777 { nullptr, 2, &width, &height },
778 { decoder, 0, &width, &height },
779 { decoder, -1, &width, &height },
780 { decoder, 2, nullptr, &height },
781 { decoder, 2, &width, nullptr },
782 }) {
783 int result = AImageDecoder_computeSampledSize(p.decoder, p.sampleSize, p.width, p.height);
784 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
785 }
786
787 // Verify that width and height will never be less than one.
788 for (SampledSizeParams p : std::initializer_list<SampledSizeParams>{
789 { decoder, origWidth, &width, &height },
790 { decoder, origWidth + 5, &width, &height },
791 { decoder, origWidth * 2, &width, &height },
792 { decoder, origHeight, &width, &height },
793 { decoder, origHeight + 5, &width, &height },
794 { decoder, origHeight * 2, &width, &height },
795 }) {
796 width = height = 0;
797 int result = AImageDecoder_computeSampledSize(p.decoder, p.sampleSize, p.width, p.height);
798 if (ANDROID_IMAGE_DECODER_SUCCESS != result) {
799 fail(env, "computeSampledSize(%i) failed on image with dims %i x %i",
800 p.sampleSize, origWidth, origHeight);
801 return;
802 }
803
804 ASSERT_GE(width, 1);
805 ASSERT_GE(height, 1);
806 }
807
808 // jbitmap was created with the same sampleSize. Verify that AImageDecoder
809 // computes the same output dimensions, that using those dimensions succeeds
810 // with AImageDecoder, and the output matches.
811 AndroidBitmapInfo jInfo;
812 int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
813 ASSERT_EQ(ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
814
815 width = height = 0;
816 int result = AImageDecoder_computeSampledSize(decoder, sampleSize, &width, &height);
817 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
818
819 if (jInfo.width != width) {
820 fail(env, "Orig image: %i x %i sampled by %i yields %i x %i expected %i x %i",
821 origWidth, origHeight, sampleSize, width, height, jInfo.width, jInfo.height);
822 return;
823 }
824 ASSERT_EQ(jInfo.width, width);
825 ASSERT_EQ(jInfo.height, height);
826 {
827
828 ASSERT_LT(width, origWidth);
829 ASSERT_LT(height, origHeight);
830
831 ASSERT_LT(width, origWidth / sampleSize + sampleSize);
832 ASSERT_LT(height, origHeight / sampleSize + sampleSize);
833 }
834
835 result = AImageDecoder_setTargetSize(decoder, width, height);
836 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
837
838 size_t minStride = AImageDecoder_getMinimumStride(decoder);
839 size_t size = minStride * height;
840 void* pixels = malloc(size);
841 result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
842 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
843
844 ASSERT_TRUE(bitmapsEqual(env, jbitmap, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info),
845 width, height, AImageDecoderHeaderInfo_getAlphaFlags(info),
846 minStride, pixels, minStride));
847 free(pixels);
848 }
849
testDecodeScaled(JNIEnv * env,jclass,jlong imageDecoderPtr,jobject jbitmap)850 static void testDecodeScaled(JNIEnv* env, jclass, jlong imageDecoderPtr,
851 jobject jbitmap) {
852 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
853 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
854
855 AndroidBitmapInfo jInfo;
856 int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
857 ASSERT_EQ(ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
858
859 int result = AImageDecoder_setTargetSize(decoder, jInfo.width, jInfo.height);
860 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
861
862 size_t minStride = AImageDecoder_getMinimumStride(decoder);
863 size_t size = minStride * jInfo.height;
864 void* pixels = malloc(size);
865
866 {
867 // Try some invalid parameters.
868 #pragma clang diagnostic push
869 #pragma clang diagnostic ignored "-Wnonnull"
870 result = AImageDecoder_decodeImage(decoder, nullptr, minStride, size);
871 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
872 #pragma clang diagnostic pop
873
874 result = AImageDecoder_decodeImage(decoder, pixels, minStride - 1, size);
875 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
876
877 result = AImageDecoder_decodeImage(decoder, pixels, minStride, size - minStride);
878 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
879 }
880
881 result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
882 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
883
884 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
885 ASSERT_NE(info, nullptr);
886
887 ASSERT_NE(jbitmap, nullptr);
888 ASSERT_TRUE(bitmapsEqual(env, jbitmap, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info),
889 jInfo.width, jInfo.height, AImageDecoderHeaderInfo_getAlphaFlags(info),
890 minStride, pixels, minStride));
891
892 // Verify that larger strides still behave as expected.
893 for (size_t stride : { minStride * 2, minStride * 3 }) {
894 size_t size = stride * (jInfo.height - 1) + minStride;
895 void* decodePixels = malloc(size);
896 result = AImageDecoder_decodeImage(decoder, decodePixels, stride, size);
897 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
898
899 ASSERT_TRUE(bitmapsEqual(minStride, jInfo.height, pixels, minStride, decodePixels, stride));
900 free(decodePixels);
901 }
902
903 free(pixels);
904 }
905
testSetCrop(JNIEnv * env,jclass,jobject jAssets,jstring jFile)906 static void testSetCrop(JNIEnv* env, jclass, jobject jAssets, jstring jFile) {
907 AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_UNKNOWN);
908 ASSERT_NE(asset, nullptr);
909 AssetCloser assetCloser(asset, AAsset_close);
910
911 AImageDecoder* decoder;
912 int result = AImageDecoder_createFromAAsset(asset, &decoder);
913 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
914 ASSERT_NE(decoder, nullptr);
915 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
916
917 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
918 ASSERT_NE(info, nullptr);
919
920 const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
921 const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
922 const auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
923 const size_t defaultStride = AImageDecoder_getMinimumStride(decoder);
924
925 if (width == 1 && height == 1) {
926 // The more general crop tests do not map well to this image. Test 1 x 1
927 // specifically.
928 for (ARect invalidCrop : std::initializer_list<ARect> {
929 { -1, 0, width, height },
930 { 0, -1, width, height },
931 { width, 0, 2 * width, height },
932 { 0, height, width, 2 * height },
933 { 1, 0, width + 1, height },
934 { 0, 1, width, height + 1 },
935 { 0, 0, 0, height },
936 { 0, 0, width, 0 },
937 }) {
938 int result = AImageDecoder_setCrop(decoder, invalidCrop);
939 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
940 ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
941 }
942 return;
943 }
944
945 for (ARect invalidCrop : std::initializer_list<ARect> {
946 { -1, 0, width, height },
947 { 0, -1, width, height },
948 { width, 0, 2 * width, height },
949 { 0, height, width, 2 * height },
950 { 1, 0, width + 1, height },
951 { 0, 1, width, height + 1 },
952 { width - 1, 0, 1, height },
953 { 0, height - 1, width, 1 },
954 { 0, 0, 0, height },
955 { 0, 0, width, 0 },
956 { 1, 1, 1, 1 },
957 { width, height, 0, 0 },
958 }) {
959 int result = AImageDecoder_setCrop(decoder, invalidCrop);
960 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
961 ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
962 }
963
964 for (ARect validCrop : std::initializer_list<ARect> {
965 { 0, 0, width, height },
966 { 0, 0, width / 2, height / 2},
967 { 0, 0, width / 3, height },
968 { 0, 0, width, height / 4},
969 { width / 2, 0, width, height / 2},
970 { 0, height / 2, width / 2, height },
971 { width / 2, height / 2, width, height },
972 { 1, 1, width - 1, height - 1 },
973 }) {
974 int result = AImageDecoder_setCrop(decoder, validCrop);
975 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
976 size_t actualStride = AImageDecoder_getMinimumStride(decoder);
977 size_t expectedStride = bytesPerPixel(format) * (validCrop.right - validCrop.left);
978 ASSERT_EQ(expectedStride, actualStride);
979 }
980
981 // Reset the crop, so we can test setting a crop *after* changing the
982 // target size.
983 result = AImageDecoder_setCrop(decoder, { 0, 0, 0, 0 });
984 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
985 ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
986
987 int32_t newWidth = width / 2, newHeight = height / 2;
988 result = AImageDecoder_setTargetSize(decoder, newWidth, newHeight);
989 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
990 const size_t halfStride = AImageDecoder_getMinimumStride(decoder);
991 {
992 size_t expectedStride = bytesPerPixel(format) * newWidth;
993 ASSERT_EQ(expectedStride, halfStride);
994 }
995
996 // At the smaller target size, crops that were previously valid no longer
997 // are.
998 for (ARect invalidCrop : std::initializer_list<ARect> {
999 { 0, 0, width / 3, height },
1000 { 0, 0, width, height / 4},
1001 { width / 2, 0, width, height / 2},
1002 { 0, height / 2, width / 2, height },
1003 { width / 2, height / 2, width, height },
1004 { 1, 1, width - 1, height - 1 },
1005 }) {
1006 int result = AImageDecoder_setCrop(decoder, invalidCrop);
1007 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
1008 ASSERT_EQ(halfStride, AImageDecoder_getMinimumStride(decoder));
1009 }
1010
1011 for (ARect validCrop : std::initializer_list<ARect> {
1012 { 0, 0, newWidth, newHeight },
1013 { 0, 0, newWidth / 3, newHeight },
1014 { 0, 0, newWidth, newHeight / 4},
1015 { newWidth / 2, 0, newWidth, newHeight / 2},
1016 { 0, newHeight / 2, newWidth / 2, newHeight },
1017 { newWidth / 2, newHeight / 2, newWidth, newHeight },
1018 { 1, 1, newWidth - 1, newHeight - 1 },
1019 }) {
1020 int result = AImageDecoder_setCrop(decoder, validCrop);
1021 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1022 size_t actualStride = AImageDecoder_getMinimumStride(decoder);
1023 size_t expectedStride = bytesPerPixel(format) * (validCrop.right - validCrop.left);
1024 ASSERT_EQ(expectedStride, actualStride);
1025 }
1026
1027 newWidth = width * 2;
1028 newHeight = height * 2;
1029 result = AImageDecoder_setTargetSize(decoder, newWidth, newHeight);
1030 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1031
1032 for (ARect validCrop : std::initializer_list<ARect> {
1033 { width, 0, newWidth, height },
1034 { 0, height * 3 / 4, width * 4 / 3, height }
1035 }) {
1036 int result = AImageDecoder_setCrop(decoder, validCrop);
1037 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1038 size_t actualStride = AImageDecoder_getMinimumStride(decoder);
1039 size_t expectedStride = bytesPerPixel(format) * (validCrop.right - validCrop.left);
1040 ASSERT_EQ(expectedStride, actualStride);
1041 }
1042
1043 // Reset crop and target size, so that we can verify that setting a crop and
1044 // then setting target size that will not support the crop fails.
1045 result = AImageDecoder_setCrop(decoder, { 0, 0, 0, 0 });
1046 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1047 result = AImageDecoder_setTargetSize(decoder, width, height);
1048 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1049 ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
1050
1051 ARect crop{ width / 2, height / 2, width, height };
1052 result = AImageDecoder_setCrop(decoder, crop);
1053 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1054 const size_t croppedStride = AImageDecoder_getMinimumStride(decoder);
1055 {
1056 size_t expectedStride = bytesPerPixel(format) * (crop.right - crop.left);
1057 ASSERT_EQ(expectedStride, croppedStride);
1058 }
1059 result = AImageDecoder_setTargetSize(decoder, width / 2, height / 2);
1060 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
1061 ASSERT_EQ(croppedStride, AImageDecoder_getMinimumStride(decoder));
1062 }
1063
testDecodeCrop(JNIEnv * env,jclass,jlong imageDecoderPtr,jobject jbitmap,jint targetWidth,jint targetHeight,jint left,jint top,jint right,jint bottom)1064 static void testDecodeCrop(JNIEnv* env, jclass, jlong imageDecoderPtr,
1065 jobject jbitmap, jint targetWidth, jint targetHeight,
1066 jint left, jint top, jint right, jint bottom) {
1067 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1068 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1069
1070 int result;
1071 if (targetWidth != 0 && targetHeight != 0) {
1072 result = AImageDecoder_setTargetSize(decoder, targetWidth, targetHeight);
1073 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1074 }
1075
1076 ARect rect { left, top, right, bottom };
1077 result = AImageDecoder_setCrop(decoder, rect);
1078 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1079
1080 const int32_t width = right - left;
1081 const int32_t height = bottom - top;
1082 size_t minStride = AImageDecoder_getMinimumStride(decoder);
1083 size_t size = minStride * height;
1084 void* pixels = malloc(size);
1085
1086 {
1087 // Try some invalid parameters.
1088 #pragma clang diagnostic push
1089 #pragma clang diagnostic ignored "-Wnonnull"
1090 result = AImageDecoder_decodeImage(decoder, nullptr, minStride, size);
1091 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
1092 #pragma clang diagnostic pop
1093
1094 result = AImageDecoder_decodeImage(decoder, pixels, minStride - 1, size);
1095 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
1096
1097 result = AImageDecoder_decodeImage(decoder, pixels, minStride, size - minStride);
1098 ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
1099 }
1100
1101 result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
1102 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1103
1104 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
1105 ASSERT_NE(info, nullptr);
1106
1107 ASSERT_NE(jbitmap, nullptr);
1108 ASSERT_TRUE(bitmapsEqual(env, jbitmap, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info),
1109 width, height, AImageDecoderHeaderInfo_getAlphaFlags(info),
1110 minStride, pixels, minStride));
1111
1112 // Verify that larger strides still behave as expected.
1113 for (size_t stride : { minStride * 2, minStride * 3 }) {
1114 size_t size = stride * (height - 1) + minStride;
1115 void* decodePixels = malloc(size);
1116 result = AImageDecoder_decodeImage(decoder, decodePixels, stride, size);
1117 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1118
1119 ASSERT_TRUE(bitmapsEqual(minStride, height, pixels, minStride, decodePixels, stride));
1120 free(decodePixels);
1121 }
1122
1123 free(pixels);
1124 }
1125
testScalePlusUnpremul(JNIEnv * env,jclass,jlong imageDecoderPtr)1126 static void testScalePlusUnpremul(JNIEnv* env, jclass, jlong imageDecoderPtr) {
1127 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1128 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1129
1130 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
1131 ASSERT_NE(nullptr, info);
1132
1133 const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
1134 const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
1135 const int alpha = AImageDecoderHeaderInfo_getAlphaFlags(info);
1136
1137 if (alpha == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
1138 // Set unpremul, then scale. This succeeds for an opaque image.
1139 int result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1140 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1141
1142 result = AImageDecoder_setTargetSize(decoder, width * 2, height * 2);
1143 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1144
1145 result = AImageDecoder_setTargetSize(decoder, width * 2/3, height * 2/3);
1146 if (width * 2/3 == 0 || height * 2/3 == 0) {
1147 // The image that is 1x1 cannot be downscaled.
1148 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
1149 } else {
1150 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1151 }
1152
1153 // Reset to the original settings to test the other order.
1154 result = AImageDecoder_setUnpremultipliedRequired(decoder, false);
1155 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1156
1157 result = AImageDecoder_setTargetSize(decoder, width, height);
1158 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1159
1160 // Specify scale and then unpremul.
1161 if (width * 2/3 == 0 || height * 2/3 == 0) {
1162 // The image that is 1x1 cannot be downscaled. Scale up instead.
1163 result = AImageDecoder_setTargetSize(decoder, width * 2, height * 2);
1164 } else {
1165 result = AImageDecoder_setTargetSize(decoder, width * 2/3, height * 2/3);
1166 }
1167 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1168
1169 result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1170 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1171 } else {
1172 // Use unpremul and then scale. Setting to unpremul is successful, but
1173 // later calls to change the scale fail.
1174 int result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1175 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1176
1177 result = AImageDecoder_setTargetSize(decoder, width * 2, height * 2);
1178 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
1179
1180 result = AImageDecoder_setTargetSize(decoder, width * 2/3, height * 2/3);
1181 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
1182
1183 // Set back to premul to verify that the opposite order also fails.
1184 result = AImageDecoder_setUnpremultipliedRequired(decoder, false);
1185 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1186
1187 result = AImageDecoder_setTargetSize(decoder, width * 2, height * 2);
1188 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1189 result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1190 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
1191
1192 result = AImageDecoder_setTargetSize(decoder, width * 2/3, height * 2/3);
1193 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1194 result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1195 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
1196 }
1197 }
1198
testDecodeSetDataSpace(JNIEnv * env,jclass,jlong imageDecoderPtr,jobject jbitmap,jint dataSpace)1199 static void testDecodeSetDataSpace(JNIEnv* env, jclass, jlong imageDecoderPtr,
1200 jobject jbitmap, jint dataSpace) {
1201 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1202 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1203
1204 ASSERT_EQ(dataSpace, AndroidBitmap_getDataSpace(env, jbitmap));
1205
1206 int result = AImageDecoder_setDataSpace(decoder, dataSpace);
1207 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1208
1209 AndroidBitmapInfo jInfo;
1210 int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
1211 ASSERT_EQ(ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
1212
1213 result = AImageDecoder_setAndroidBitmapFormat(decoder, jInfo.format);
1214 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1215
1216 const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
1217 ASSERT_NE(info, nullptr);
1218
1219 const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
1220 const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
1221 int alphaFlags = AImageDecoderHeaderInfo_getAlphaFlags(info);
1222
1223 size_t minStride = AImageDecoder_getMinimumStride(decoder);
1224 size_t size = minStride * height;
1225 void* pixels = malloc(size);
1226
1227 result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
1228 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1229
1230 ASSERT_TRUE(bitmapsEqual(env, jbitmap, (AndroidBitmapFormat) jInfo.format,
1231 width, height, alphaFlags, minStride, pixels, minStride));
1232 free(pixels);
1233 }
1234
testIsAnimated(JNIEnv * env,jclass,jlong imageDecoderPtr,jboolean animated)1235 static void testIsAnimated(JNIEnv* env, jclass, jlong imageDecoderPtr, jboolean animated) {
1236 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1237 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1238
1239 ASSERT_TRUE(decoder);
1240 ASSERT_EQ(animated, AImageDecoder_isAnimated(decoder));
1241 }
1242
testRepeatCount(JNIEnv * env,jclass,jlong imageDecoderPtr,jint repeatCount)1243 static void testRepeatCount(JNIEnv* env, jclass, jlong imageDecoderPtr, jint repeatCount) {
1244 AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1245 DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1246
1247 if (repeatCount == -1) { // AnimatedImageDrawable.REPEAT_INFINITE
1248 repeatCount = ANDROID_IMAGE_DECODER_INFINITE;
1249 }
1250
1251 ASSERT_TRUE(decoder);
1252 ASSERT_EQ(repeatCount, AImageDecoder_getRepeatCount(decoder));
1253 }
1254
1255 #define ASSET_MANAGER "Landroid/content/res/AssetManager;"
1256 #define STRING "Ljava/lang/String;"
1257 #define BITMAP "Landroid/graphics/Bitmap;"
1258
1259 static JNINativeMethod gMethods[] = {
1260 { "nTestEmptyCreate", "()V", (void*) testEmptyCreate },
1261 { "nTestNullDecoder", "(" ASSET_MANAGER STRING ")V", (void*) testNullDecoder },
1262 { "nTestInfo", "(JII" STRING "ZI)V", (void*) testInfo },
1263 { "nOpenAsset", "(" ASSET_MANAGER STRING ")J", (void*) openAssetNative },
1264 { "nCloseAsset", "(J)V", (void*) closeAsset },
1265 { "nCreateFromAsset", "(J)J", (void*) createFromAsset },
1266 { "nCreateFromAssetFd", "(J)J", (void*) createFromAssetFd },
1267 { "nCreateFromAssetBuffer", "(J)J", (void*) createFromAssetBuffer },
1268 { "nCreateFromFd", "(I)J", (void*) createFromFd },
1269 { "nTestCreateIncomplete", "(" ASSET_MANAGER STRING "I)V", (void*) testCreateIncomplete },
1270 { "nTestCreateUnsupported", "(" ASSET_MANAGER STRING ")V", (void*) testCreateUnsupported },
1271 { "nTestSetFormat", "(JZZ)V", (void*) testSetFormat },
1272 { "nTestSetUnpremul", "(JZ)V", (void*) testSetUnpremul },
1273 { "nTestGetMinimumStride", "(JZZ)V", (void*) testGetMinimumStride },
1274 { "nTestDecode", "(JIZ" BITMAP ")V", (void*) testDecode },
1275 { "nTestDecodeStride", "(J)V", (void*) testDecodeStride },
1276 { "nTestSetTargetSize", "(J)V", (void*) testSetTargetSize },
1277 { "nTestComputeSampledSize", "(J" BITMAP "I)V", (void*) testComputeSampledSize },
1278 { "nTestDecodeScaled", "(J" BITMAP ")V", (void*) testDecodeScaled },
1279 { "nTestSetCrop", "(" ASSET_MANAGER STRING ")V", (void*) testSetCrop },
1280 { "nTestDecodeCrop", "(J" BITMAP "IIIIII)V", (void*) testDecodeCrop },
1281 { "nTestScalePlusUnpremul", "(J)V", (void*) testScalePlusUnpremul },
1282 { "nTestDecode", "(J" BITMAP "I)V", (void*) testDecodeSetDataSpace },
1283 { "nTestIsAnimated", "(JZ)V", (void*) testIsAnimated },
1284 { "nTestRepeatCount", "(JI)V", (void*) testRepeatCount },
1285 };
1286
register_android_graphics_cts_AImageDecoderTest(JNIEnv * env)1287 int register_android_graphics_cts_AImageDecoderTest(JNIEnv* env) {
1288 jclass clazz = env->FindClass("android/graphics/cts/AImageDecoderTest");
1289 return env->RegisterNatives(clazz, gMethods,
1290 sizeof(gMethods) / sizeof(JNINativeMethod));
1291 }
1292
1293