1 /* 2 * Copyright (C) 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 package android.graphics.cts; 18 19 import static android.system.OsConstants.SEEK_SET; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertNull; 24 import static org.junit.Assert.fail; 25 26 import android.content.ContentResolver; 27 import android.content.res.AssetManager; 28 import android.content.res.Resources; 29 import android.graphics.Bitmap; 30 import android.graphics.BitmapFactory; 31 import android.graphics.Color; 32 import android.graphics.ColorSpace; 33 import android.graphics.ColorSpace.Named; 34 import android.graphics.ImageDecoder; 35 import android.graphics.Rect; 36 import android.graphics.drawable.cts.AnimatedImageDrawableTest; 37 import android.net.Uri; 38 import android.os.ParcelFileDescriptor; 39 import android.system.ErrnoException; 40 import android.system.Os; 41 import android.util.DisplayMetrics; 42 43 import androidx.test.InstrumentationRegistry; 44 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 48 import java.io.File; 49 import java.io.FileDescriptor; 50 import java.io.FileNotFoundException; 51 import java.io.FileOutputStream; 52 import java.io.IOException; 53 import java.io.InputStream; 54 55 import junitparams.JUnitParamsRunner; 56 import junitparams.Parameters; 57 58 @RunWith(JUnitParamsRunner.class) 59 public class AImageDecoderTest { 60 static { 61 System.loadLibrary("ctsgraphics_jni"); 62 } 63 getAssetManager()64 private static AssetManager getAssetManager() { 65 return InstrumentationRegistry.getTargetContext().getAssets(); 66 } 67 getResources()68 private static Resources getResources() { 69 return InstrumentationRegistry.getTargetContext().getResources(); 70 } 71 getContentResolver()72 private static ContentResolver getContentResolver() { 73 return InstrumentationRegistry.getTargetContext().getContentResolver(); 74 } 75 76 // These match the formats in the NDK. 77 // ANDROID_BITMAP_FORMAT_NONE is used by nTestDecode to signal using the default. 78 private static final int ANDROID_BITMAP_FORMAT_NONE = 0; 79 private static final int ANDROID_BITMAP_FORMAT_RGB_565 = 4; 80 private static final int ANDROID_BITMAP_FORMAT_A_8 = 8; 81 private static final int ANDROID_BITMAP_FORMAT_RGBA_F16 = 9; 82 83 @Test testEmptyCreate()84 public void testEmptyCreate() { 85 nTestEmptyCreate(); 86 } 87 getAssetRecords()88 private static Object[] getAssetRecords() { 89 return ImageDecoderTest.getAssetRecords(); 90 } 91 getRecords()92 private static Object[] getRecords() { 93 return ImageDecoderTest.getRecords(); 94 } 95 96 // For testing all of the assets as premul and unpremul. getAssetRecordsUnpremul()97 private static Object[] getAssetRecordsUnpremul() { 98 return Utils.crossProduct(getAssetRecords(), new Object[] { true, false }); 99 } 100 getRecordsUnpremul()101 private static Object[] getRecordsUnpremul() { 102 return Utils.crossProduct(getRecords(), new Object[] { true, false }); 103 } 104 105 // For testing all of the assets at different sample sizes. getAssetRecordsSample()106 private static Object[] getAssetRecordsSample() { 107 return Utils.crossProduct(getAssetRecords(), new Object[] { 2, 3, 4, 8, 16 }); 108 } 109 getRecordsSample()110 private static Object[] getRecordsSample() { 111 return Utils.crossProduct(getRecords(), new Object[] { 2, 3, 4, 8, 16 }); 112 } 113 114 @Test 115 @Parameters(method = "getAssetRecords") testNullDecoder(ImageDecoderTest.AssetRecord record)116 public void testNullDecoder(ImageDecoderTest.AssetRecord record) { 117 nTestNullDecoder(getAssetManager(), record.name); 118 } 119 nativeDataSpace(ColorSpace cs)120 private static int nativeDataSpace(ColorSpace cs) { 121 if (cs == null) { 122 return DataSpace.ADATASPACE_UNKNOWN; 123 } 124 return DataSpace.fromColorSpace(cs); 125 } 126 127 @Test 128 @Parameters(method = "getAssetRecords") testCreateBuffer(ImageDecoderTest.AssetRecord record)129 public void testCreateBuffer(ImageDecoderTest.AssetRecord record) { 130 // Note: This uses an asset for simplicity, but in native it gets a 131 // buffer. 132 long asset = nOpenAsset(getAssetManager(), record.name); 133 long aimagedecoder = nCreateFromAssetBuffer(asset); 134 135 nTestInfo(aimagedecoder, record.width, record.height, "image/png", 136 record.isF16, nativeDataSpace(record.getColorSpace())); 137 nCloseAsset(asset); 138 } 139 140 @Test 141 @Parameters(method = "getAssetRecords") testCreateFd(ImageDecoderTest.AssetRecord record)142 public void testCreateFd(ImageDecoderTest.AssetRecord record) { 143 // Note: This uses an asset for simplicity, but in native it gets a 144 // file descriptor. 145 long asset = nOpenAsset(getAssetManager(), record.name); 146 long aimagedecoder = nCreateFromAssetFd(asset); 147 148 nTestInfo(aimagedecoder, record.width, record.height, "image/png", 149 record.isF16, nativeDataSpace(record.getColorSpace())); 150 nCloseAsset(asset); 151 } 152 153 @Test 154 @Parameters(method = "getAssetRecords") testCreateAsset(ImageDecoderTest.AssetRecord record)155 public void testCreateAsset(ImageDecoderTest.AssetRecord record) { 156 long asset = nOpenAsset(getAssetManager(), record.name); 157 long aimagedecoder = nCreateFromAsset(asset); 158 159 nTestInfo(aimagedecoder, record.width, record.height, "image/png", 160 record.isF16, nativeDataSpace(record.getColorSpace())); 161 nCloseAsset(asset); 162 } 163 open(int resId, int offset)164 private static ParcelFileDescriptor open(int resId, int offset) throws FileNotFoundException { 165 File file = Utils.obtainFile(resId, offset); 166 assertNotNull(file); 167 168 ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, 169 ParcelFileDescriptor.MODE_READ_ONLY); 170 assertNotNull(pfd); 171 return pfd; 172 } 173 open(int resId)174 private static ParcelFileDescriptor open(int resId) throws FileNotFoundException { 175 return open(resId, 0); 176 } 177 178 @Test 179 @Parameters(method = "getRecords") testCreateFdResources(ImageDecoderTest.Record record)180 public void testCreateFdResources(ImageDecoderTest.Record record) throws IOException { 181 try (ParcelFileDescriptor pfd = open(record.resId)) { 182 long aimagedecoder = nCreateFromFd(pfd.getFd()); 183 184 nTestInfo(aimagedecoder, record.width, record.height, record.mimeType, 185 false /*isF16*/, nativeDataSpace(record.colorSpace)); 186 } catch (FileNotFoundException e) { 187 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 188 } 189 } 190 191 @Test 192 @Parameters(method = "getRecords") testCreateFdOffset(ImageDecoderTest.Record record)193 public void testCreateFdOffset(ImageDecoderTest.Record record) throws IOException { 194 // Use an arbitrary offset. This ensures that we rewind to the correct offset. 195 final int offset = 15; 196 try (ParcelFileDescriptor pfd = open(record.resId, offset)) { 197 FileDescriptor fd = pfd.getFileDescriptor(); 198 Os.lseek(fd, offset, SEEK_SET); 199 long aimagedecoder = nCreateFromFd(pfd.getFd()); 200 201 nTestInfo(aimagedecoder, record.width, record.height, record.mimeType, 202 false /*isF16*/, nativeDataSpace(record.colorSpace)); 203 } catch (FileNotFoundException e) { 204 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 205 } catch (ErrnoException err) { 206 fail("Failed to seek " + Utils.getAsResourceUri(record.resId)); 207 } 208 } 209 210 @Test testCreateIncomplete()211 public void testCreateIncomplete() { 212 String file = "green-srgb.png"; 213 // This truncates the file before the IDAT. 214 nTestCreateIncomplete(getAssetManager(), file, 823); 215 } 216 217 @Test 218 @Parameters({"shaders/tri.frag", "test_video.mp4"}) testUnsupportedFormat(String file)219 public void testUnsupportedFormat(String file) { 220 nTestCreateUnsupported(getAssetManager(), file); 221 } 222 223 @Test 224 @Parameters(method = "getAssetRecords") testSetFormat(ImageDecoderTest.AssetRecord record)225 public void testSetFormat(ImageDecoderTest.AssetRecord record) { 226 long asset = nOpenAsset(getAssetManager(), record.name); 227 long aimagedecoder = nCreateFromAsset(asset); 228 229 nTestSetFormat(aimagedecoder, record.isF16, record.isGray); 230 nCloseAsset(asset); 231 } 232 233 @Test 234 @Parameters(method = "getRecords") testSetFormatResources(ImageDecoderTest.Record record)235 public void testSetFormatResources(ImageDecoderTest.Record record) throws IOException { 236 try (ParcelFileDescriptor pfd = open(record.resId)) { 237 long aimagedecoder = nCreateFromFd(pfd.getFd()); 238 239 nTestSetFormat(aimagedecoder, false /* isF16 */, record.isGray); 240 } catch (FileNotFoundException e) { 241 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 242 } 243 } 244 245 @Test 246 @Parameters(method = "getAssetRecords") testSetUnpremul(ImageDecoderTest.AssetRecord record)247 public void testSetUnpremul(ImageDecoderTest.AssetRecord record) { 248 long asset = nOpenAsset(getAssetManager(), record.name); 249 long aimagedecoder = nCreateFromAsset(asset); 250 251 nTestSetUnpremul(aimagedecoder, record.hasAlpha); 252 nCloseAsset(asset); 253 } 254 255 @Test 256 @Parameters(method = "getRecords") testSetUnpremulResources(ImageDecoderTest.Record record)257 public void testSetUnpremulResources(ImageDecoderTest.Record record) throws IOException { 258 try (ParcelFileDescriptor pfd = open(record.resId)) { 259 long aimagedecoder = nCreateFromFd(pfd.getFd()); 260 261 nTestSetUnpremul(aimagedecoder, record.hasAlpha); 262 } catch (FileNotFoundException e) { 263 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 264 } 265 } 266 267 @Test 268 @Parameters(method = "getAssetRecords") testGetMinimumStride(ImageDecoderTest.AssetRecord record)269 public void testGetMinimumStride(ImageDecoderTest.AssetRecord record) { 270 long asset = nOpenAsset(getAssetManager(), record.name); 271 long aimagedecoder = nCreateFromAsset(asset); 272 273 nTestGetMinimumStride(aimagedecoder, record.isF16, record.isGray); 274 } 275 276 @Test 277 @Parameters(method = "getRecords") testGetMinimumStrideResources(ImageDecoderTest.Record record)278 public void testGetMinimumStrideResources(ImageDecoderTest.Record record) throws IOException { 279 try (ParcelFileDescriptor pfd = open(record.resId)) { 280 long aimagedecoder = nCreateFromFd(pfd.getFd()); 281 282 nTestGetMinimumStride(aimagedecoder, false /* isF16 */, record.isGray); 283 } catch (FileNotFoundException e) { 284 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 285 } 286 } 287 decode(ImageDecoder.Source src, boolean unpremul)288 private static Bitmap decode(ImageDecoder.Source src, boolean unpremul) { 289 try { 290 return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> { 291 // So we can compare pixels to the native decode. 292 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 293 decoder.setUnpremultipliedRequired(unpremul); 294 }); 295 } catch (IOException e) { 296 fail("Failed to decode in Java with " + e); 297 return null; 298 } 299 } 300 decode(int resId, boolean unpremul)301 private static Bitmap decode(int resId, boolean unpremul) { 302 // This test relies on ImageDecoder *not* scaling to account for density. 303 // Temporarily change the DisplayMetrics to prevent that scaling. 304 Resources res = getResources(); 305 final int originalDensity = res.getDisplayMetrics().densityDpi; 306 try { 307 res.getDisplayMetrics().densityDpi = DisplayMetrics.DENSITY_DEFAULT; 308 ImageDecoder.Source src = ImageDecoder.createSource(res, resId); 309 return decode(src, unpremul); 310 } finally { 311 res.getDisplayMetrics().densityDpi = originalDensity; 312 } 313 } 314 315 @Test 316 @Parameters(method = "getAssetRecordsUnpremul") testDecode(ImageDecoderTest.AssetRecord record, boolean unpremul)317 public void testDecode(ImageDecoderTest.AssetRecord record, boolean unpremul) { 318 AssetManager assets = getAssetManager(); 319 ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name); 320 Bitmap bm = decode(src, unpremul); 321 322 long asset = nOpenAsset(assets, record.name); 323 long aimagedecoder = nCreateFromAsset(asset); 324 325 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_NONE, unpremul, bm); 326 nCloseAsset(asset); 327 } 328 329 @Test 330 @Parameters(method = "getRecordsUnpremul") testDecodeResources(ImageDecoderTest.Record record, boolean unpremul)331 public void testDecodeResources(ImageDecoderTest.Record record, boolean unpremul) 332 throws IOException { 333 Bitmap bm = decode(record.resId, unpremul); 334 try (ParcelFileDescriptor pfd = open(record.resId)) { 335 long aimagedecoder = nCreateFromFd(pfd.getFd()); 336 337 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_NONE, unpremul, bm); 338 } catch (FileNotFoundException e) { 339 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 340 } 341 } 342 decode(ImageDecoder.Source src, Bitmap.Config config)343 private static Bitmap decode(ImageDecoder.Source src, Bitmap.Config config) { 344 try { 345 return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> { 346 // So we can compare pixels to the native decode. 347 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 348 switch (config) { 349 case RGB_565: 350 decoder.setMemorySizePolicy(ImageDecoder.MEMORY_POLICY_LOW_RAM); 351 break; 352 case ALPHA_8: 353 decoder.setDecodeAsAlphaMaskEnabled(true); 354 break; 355 default: 356 fail("Unexpected Config " + config); 357 break; 358 } 359 }); 360 } catch (IOException e) { 361 fail("Failed to decode in Java with " + e); 362 return null; 363 } 364 } 365 366 private static Bitmap decode(int resId, Bitmap.Config config) { 367 // This test relies on ImageDecoder *not* scaling to account for density. 368 // Temporarily change the DisplayMetrics to prevent that scaling. 369 Resources res = getResources(); 370 final int originalDensity = res.getDisplayMetrics().densityDpi; 371 try { 372 res.getDisplayMetrics().densityDpi = DisplayMetrics.DENSITY_DEFAULT; 373 ImageDecoder.Source src = ImageDecoder.createSource(res, resId); 374 return decode(src, config); 375 } finally { 376 res.getDisplayMetrics().densityDpi = originalDensity; 377 } 378 } 379 380 @Test 381 @Parameters(method = "getAssetRecords") 382 public void testDecode565(ImageDecoderTest.AssetRecord record) { 383 AssetManager assets = getAssetManager(); 384 ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name); 385 Bitmap bm = decode(src, Bitmap.Config.RGB_565); 386 387 if (bm.getConfig() != Bitmap.Config.RGB_565) { 388 bm = null; 389 } 390 391 long asset = nOpenAsset(assets, record.name); 392 long aimagedecoder = nCreateFromAsset(asset); 393 394 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_RGB_565, false, bm); 395 nCloseAsset(asset); 396 } 397 398 @Test 399 @Parameters(method = "getRecords") 400 public void testDecode565Resources(ImageDecoderTest.Record record) 401 throws IOException { 402 Bitmap bm = decode(record.resId, Bitmap.Config.RGB_565); 403 404 if (bm.getConfig() != Bitmap.Config.RGB_565) { 405 bm = null; 406 } 407 408 try (ParcelFileDescriptor pfd = open(record.resId)) { 409 long aimagedecoder = nCreateFromFd(pfd.getFd()); 410 411 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_RGB_565, false, bm); 412 } catch (FileNotFoundException e) { 413 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 414 } 415 } 416 417 @Test 418 @Parameters("grayscale-linearSrgb.png") 419 public void testDecodeA8(String name) { 420 AssetManager assets = getAssetManager(); 421 ImageDecoder.Source src = ImageDecoder.createSource(assets, name); 422 Bitmap bm = decode(src, Bitmap.Config.ALPHA_8); 423 424 assertNotNull(bm); 425 assertNull(bm.getColorSpace()); 426 assertEquals(Bitmap.Config.ALPHA_8, bm.getConfig()); 427 428 long asset = nOpenAsset(assets, name); 429 long aimagedecoder = nCreateFromAsset(asset); 430 431 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_A_8, false, bm); 432 nCloseAsset(asset); 433 } 434 435 @Test 436 public void testDecodeA8Resources() 437 throws IOException { 438 final int resId = R.drawable.grayscale_jpg; 439 Bitmap bm = decode(resId, Bitmap.Config.ALPHA_8); 440 441 assertNotNull(bm); 442 assertNull(bm.getColorSpace()); 443 assertEquals(Bitmap.Config.ALPHA_8, bm.getConfig()); 444 445 try (ParcelFileDescriptor pfd = open(resId)) { 446 long aimagedecoder = nCreateFromFd(pfd.getFd()); 447 448 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_A_8, false, bm); 449 } catch (FileNotFoundException e) { 450 fail("Could not open " + Utils.getAsResourceUri(resId)); 451 } 452 } 453 454 @Test 455 @Parameters(method = "getAssetRecordsUnpremul") 456 public void testDecodeF16(ImageDecoderTest.AssetRecord record, boolean unpremul) { 457 AssetManager assets = getAssetManager(); 458 459 // ImageDecoder doesn't allow forcing a decode to F16, so use BitmapFactory. 460 BitmapFactory.Options options = new BitmapFactory.Options(); 461 options.inPreferredConfig = Bitmap.Config.RGBA_F16; 462 options.inPremultiplied = !unpremul; 463 464 InputStream is = null; 465 try { 466 is = assets.open(record.name); 467 } catch (IOException e) { 468 fail("Failed to open " + record.name + " with " + e); 469 } 470 assertNotNull(is); 471 472 Bitmap bm = BitmapFactory.decodeStream(is, null, options); 473 assertNotNull(bm); 474 475 long asset = nOpenAsset(assets, record.name); 476 long aimagedecoder = nCreateFromAsset(asset); 477 478 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_RGBA_F16, unpremul, bm); 479 nCloseAsset(asset); 480 } 481 482 @Test 483 @Parameters(method = "getRecordsUnpremul") 484 public void testDecodeF16Resources(ImageDecoderTest.Record record, boolean unpremul) 485 throws IOException { 486 // ImageDecoder doesn't allow forcing a decode to F16, so use BitmapFactory. 487 BitmapFactory.Options options = new BitmapFactory.Options(); 488 options.inPreferredConfig = Bitmap.Config.RGBA_F16; 489 options.inPremultiplied = !unpremul; 490 options.inScaled = false; 491 492 Bitmap bm = BitmapFactory.decodeResource(getResources(), 493 record.resId, options); 494 assertNotNull(bm); 495 496 try (ParcelFileDescriptor pfd = open(record.resId)) { 497 long aimagedecoder = nCreateFromFd(pfd.getFd()); 498 499 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_RGBA_F16, unpremul, bm); 500 } catch (FileNotFoundException e) { 501 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 502 } 503 } 504 505 @Test 506 @Parameters(method = "getAssetRecords") 507 public void testDecodeStride(ImageDecoderTest.AssetRecord record) { 508 long asset = nOpenAsset(getAssetManager(), record.name); 509 long aimagedecoder = nCreateFromAsset(asset); 510 nTestDecodeStride(aimagedecoder); 511 nCloseAsset(asset); 512 } 513 514 @Test 515 @Parameters(method = "getRecords") 516 public void testDecodeStrideResources(ImageDecoderTest.Record record) 517 throws IOException { 518 try (ParcelFileDescriptor pfd = open(record.resId)) { 519 long aimagedecoder = nCreateFromFd(pfd.getFd()); 520 521 nTestDecodeStride(aimagedecoder); 522 } catch (FileNotFoundException e) { 523 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 524 } 525 } 526 527 @Test 528 @Parameters(method = "getAssetRecords") 529 public void testSetTargetSize(ImageDecoderTest.AssetRecord record) { 530 long asset = nOpenAsset(getAssetManager(), record.name); 531 long aimagedecoder = nCreateFromAsset(asset); 532 nTestSetTargetSize(aimagedecoder); 533 nCloseAsset(asset); 534 } 535 536 @Test 537 @Parameters(method = "getRecords") 538 public void testSetTargetSizeResources(ImageDecoderTest.Record record) 539 throws IOException { 540 try (ParcelFileDescriptor pfd = open(record.resId)) { 541 long aimagedecoder = nCreateFromFd(pfd.getFd()); 542 543 nTestSetTargetSize(aimagedecoder); 544 } catch (FileNotFoundException e) { 545 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 546 } 547 } 548 549 private Bitmap decodeSampled(String name, ImageDecoder.Source src, int sampleSize) { 550 try { 551 return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> { 552 // So we can compare pixels to the native decode. 553 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 554 decoder.setTargetSampleSize(sampleSize); 555 }); 556 } catch (IOException e) { 557 fail("Failed to decode " + name + " in Java (sampleSize: " 558 + sampleSize + ") with " + e); 559 return null; 560 } 561 } 562 563 @Test 564 @Parameters(method = "getAssetRecordsSample") 565 public void testDecodeSampled(ImageDecoderTest.AssetRecord record, int sampleSize) { 566 AssetManager assets = getAssetManager(); 567 ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name); 568 Bitmap bm = decodeSampled(record.name, src, sampleSize); 569 570 long asset = nOpenAsset(assets, record.name); 571 long aimagedecoder = nCreateFromAsset(asset); 572 573 nTestDecodeScaled(aimagedecoder, bm); 574 nCloseAsset(asset); 575 } 576 577 @Test 578 @Parameters(method = "getRecordsSample") 579 public void testDecodeResourceSampled(ImageDecoderTest.Record record, int sampleSize) 580 throws IOException { 581 ImageDecoder.Source src = ImageDecoder.createSource(getResources(), 582 record.resId); 583 String name = Utils.getAsResourceUri(record.resId).toString(); 584 Bitmap bm = decodeSampled(name, src, sampleSize); 585 assertNotNull(bm); 586 587 try (ParcelFileDescriptor pfd = open(record.resId)) { 588 long aimagedecoder = nCreateFromFd(pfd.getFd()); 589 590 nTestDecodeScaled(aimagedecoder, bm); 591 } catch (FileNotFoundException e) { 592 fail("Could not open " + name + ": " + e); 593 } 594 } 595 596 @Test 597 @Parameters(method = "getRecordsSample") 598 public void testComputeSampledSize(ImageDecoderTest.Record record, int sampleSize) 599 throws IOException { 600 if (record.mimeType.equals("image/x-adobe-dng")) { 601 // SkRawCodec does not support sampling. 602 return; 603 } 604 testComputeSampledSizeInternal(record.resId, sampleSize); 605 } 606 607 private void testComputeSampledSizeInternal(int resId, int sampleSize) 608 throws IOException { 609 ImageDecoder.Source src = ImageDecoder.createSource(getResources(), resId); 610 String name = Utils.getAsResourceUri(resId).toString(); 611 Bitmap bm = decodeSampled(name, src, sampleSize); 612 assertNotNull(bm); 613 614 try (ParcelFileDescriptor pfd = open(resId)) { 615 long aimagedecoder = nCreateFromFd(pfd.getFd()); 616 617 nTestComputeSampledSize(aimagedecoder, bm, sampleSize); 618 } catch (FileNotFoundException e) { 619 fail("Could not open " + name + ": " + e); 620 } 621 } 622 623 private static Object[] getExifsSample() { 624 return Utils.crossProduct(getExifImages(), new Object[] { 2, 3, 4, 8, 16 }); 625 } 626 627 @Test 628 @Parameters(method = "getExifsSample") 629 public void testComputeSampledSizeExif(int resId, int sampleSize) 630 throws IOException { 631 testComputeSampledSizeInternal(resId, sampleSize); 632 } 633 634 private Bitmap decodeScaled(String name, ImageDecoder.Source src) { 635 try { 636 return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> { 637 // So we can compare pixels to the native decode. 638 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 639 640 // Scale to an arbitrary width and height. 641 decoder.setTargetSize(300, 300); 642 }); 643 } catch (IOException e) { 644 fail("Failed to decode " + name + " in Java (size: " 645 + "300 x 300) with " + e); 646 return null; 647 } 648 } 649 650 @Test 651 @Parameters(method = "getAssetRecords") 652 public void testDecodeScaled(ImageDecoderTest.AssetRecord record) { 653 AssetManager assets = getAssetManager(); 654 ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name); 655 Bitmap bm = decodeScaled(record.name, src); 656 657 long asset = nOpenAsset(assets, record.name); 658 long aimagedecoder = nCreateFromAsset(asset); 659 660 nTestDecodeScaled(aimagedecoder, bm); 661 nCloseAsset(asset); 662 } 663 664 @Test 665 @Parameters(method = "getRecords") 666 public void testDecodeResourceScaled(ImageDecoderTest.Record record) 667 throws IOException { 668 ImageDecoder.Source src = ImageDecoder.createSource(getResources(), 669 record.resId); 670 String name = Utils.getAsResourceUri(record.resId).toString(); 671 Bitmap bm = decodeScaled(name, src); 672 assertNotNull(bm); 673 674 try (ParcelFileDescriptor pfd = open(record.resId)) { 675 long aimagedecoder = nCreateFromFd(pfd.getFd()); 676 677 nTestDecodeScaled(aimagedecoder, bm); 678 } catch (FileNotFoundException e) { 679 fail("Could not open " + name + ": " + e); 680 } 681 } 682 683 private Bitmap decodeScaleUp(String name, ImageDecoder.Source src) { 684 try { 685 return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> { 686 // So we can compare pixels to the native decode. 687 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 688 689 decoder.setTargetSize(info.getSize().getWidth() * 2, 690 info.getSize().getHeight() * 2); 691 }); 692 } catch (IOException e) { 693 fail("Failed to decode " + name + " in Java (scaled up) with " + e); 694 return null; 695 } 696 } 697 698 @Test 699 @Parameters(method = "getAssetRecords") 700 public void testDecodeScaleUp(ImageDecoderTest.AssetRecord record) { 701 AssetManager assets = getAssetManager(); 702 ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name); 703 Bitmap bm = decodeScaleUp(record.name, src); 704 705 long asset = nOpenAsset(assets, record.name); 706 long aimagedecoder = nCreateFromAsset(asset); 707 708 nTestDecodeScaled(aimagedecoder, bm); 709 nCloseAsset(asset); 710 } 711 712 @Test 713 @Parameters(method = "getRecords") 714 public void testDecodeResourceScaleUp(ImageDecoderTest.Record record) 715 throws IOException { 716 ImageDecoder.Source src = ImageDecoder.createSource(getResources(), 717 record.resId); 718 String name = Utils.getAsResourceUri(record.resId).toString(); 719 Bitmap bm = decodeScaleUp(name, src); 720 assertNotNull(bm); 721 722 try (ParcelFileDescriptor pfd = open(record.resId)) { 723 long aimagedecoder = nCreateFromFd(pfd.getFd()); 724 725 nTestDecodeScaled(aimagedecoder, bm); 726 } catch (FileNotFoundException e) { 727 fail("Could not open " + name + ": " + e); 728 } 729 } 730 731 @Test 732 @Parameters(method = "getAssetRecords") 733 public void testSetCrop(ImageDecoderTest.AssetRecord record) { 734 nTestSetCrop(getAssetManager(), record.name); 735 } 736 737 private static class Cropper implements ImageDecoder.OnHeaderDecodedListener { 738 Cropper(boolean scale) { 739 mScale = scale; 740 } 741 742 public boolean withScale() { 743 return mScale; 744 } 745 746 public int getWidth() { 747 return mWidth; 748 } 749 750 public int getHeight() { 751 return mHeight; 752 } 753 754 public Rect getCropRect() { 755 return mCropRect; 756 } 757 758 @Override 759 public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, 760 ImageDecoder.Source source) { 761 mWidth = info.getSize().getWidth(); 762 mHeight = info.getSize().getHeight(); 763 if (mScale) { 764 mWidth = 40; 765 mHeight = 40; 766 decoder.setTargetSize(mWidth, mHeight); 767 } 768 769 mCropRect = new Rect(mWidth / 2, mHeight / 2, mWidth, mHeight); 770 decoder.setCrop(mCropRect); 771 772 // So we can compare pixels to the native decode. 773 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 774 } 775 776 private final boolean mScale; 777 private Rect mCropRect; 778 private int mWidth; 779 private int mHeight; 780 } 781 782 private static Bitmap decodeCropped(String name, Cropper cropper, ImageDecoder.Source src) { 783 try { 784 return ImageDecoder.decodeBitmap(src, cropper); 785 } catch (IOException e) { 786 fail("Failed to decode " + name + " in Java with " 787 + (cropper.withScale() ? "scale and " : "a ") + "crop (" 788 + cropper.getCropRect() + "): " + e); 789 return null; 790 } 791 } 792 793 private static Bitmap decodeCropped(String name, Cropper cropper, int resId) { 794 // This test relies on ImageDecoder *not* scaling to account for density. 795 // Temporarily change the DisplayMetrics to prevent that scaling. 796 Resources res = getResources(); 797 final int originalDensity = res.getDisplayMetrics().densityDpi; 798 try { 799 res.getDisplayMetrics().densityDpi = DisplayMetrics.DENSITY_DEFAULT; 800 ImageDecoder.Source src = ImageDecoder.createSource(res, resId); 801 return decodeCropped(name, cropper, src); 802 } finally { 803 res.getDisplayMetrics().densityDpi = originalDensity; 804 } 805 } 806 807 @Test 808 @Parameters(method = "getAssetRecords") 809 public void testCrop(ImageDecoderTest.AssetRecord record) { 810 AssetManager assets = getAssetManager(); 811 ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name); 812 Cropper cropper = new Cropper(false /* scale */); 813 Bitmap bm = decodeCropped(record.name, cropper, src); 814 815 long asset = nOpenAsset(assets, record.name); 816 long aimagedecoder = nCreateFromAsset(asset); 817 818 Rect crop = cropper.getCropRect(); 819 nTestDecodeCrop(aimagedecoder, bm, 0, 0, crop.left, crop.top, crop.right, crop.bottom); 820 nCloseAsset(asset); 821 } 822 823 @Test 824 @Parameters(method = "getRecords") 825 public void testCropResource(ImageDecoderTest.Record record) 826 throws IOException { 827 String name = Utils.getAsResourceUri(record.resId).toString(); 828 Cropper cropper = new Cropper(false /* scale */); 829 Bitmap bm = decodeCropped(name, cropper, record.resId); 830 assertNotNull(bm); 831 832 try (ParcelFileDescriptor pfd = open(record.resId)) { 833 long aimagedecoder = nCreateFromFd(pfd.getFd()); 834 835 Rect crop = cropper.getCropRect(); 836 nTestDecodeCrop(aimagedecoder, bm, 0, 0, crop.left, crop.top, crop.right, crop.bottom); 837 } catch (FileNotFoundException e) { 838 fail("Could not open " + name + ": " + e); 839 } 840 } 841 842 @Test 843 @Parameters(method = "getAssetRecords") 844 public void testCropAndScale(ImageDecoderTest.AssetRecord record) { 845 AssetManager assets = getAssetManager(); 846 ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name); 847 Cropper cropper = new Cropper(true /* scale */); 848 Bitmap bm = decodeCropped(record.name, cropper, src); 849 850 long asset = nOpenAsset(assets, record.name); 851 long aimagedecoder = nCreateFromAsset(asset); 852 853 Rect crop = cropper.getCropRect(); 854 nTestDecodeCrop(aimagedecoder, bm, cropper.getWidth(), cropper.getHeight(), 855 crop.left, crop.top, crop.right, crop.bottom); 856 nCloseAsset(asset); 857 } 858 859 @Test 860 @Parameters(method = "getRecords") 861 public void testCropAndScaleResource(ImageDecoderTest.Record record) 862 throws IOException { 863 ImageDecoder.Source src = ImageDecoder.createSource(getResources(), 864 record.resId); 865 String name = Utils.getAsResourceUri(record.resId).toString(); 866 Cropper cropper = new Cropper(true /* scale */); 867 Bitmap bm = decodeCropped(name, cropper, src); 868 assertNotNull(bm); 869 870 try (ParcelFileDescriptor pfd = open(record.resId)) { 871 long aimagedecoder = nCreateFromFd(pfd.getFd()); 872 873 Rect crop = cropper.getCropRect(); 874 nTestDecodeCrop(aimagedecoder, bm, cropper.getWidth(), cropper.getHeight(), 875 crop.left, crop.top, crop.right, crop.bottom); 876 } catch (FileNotFoundException e) { 877 fail("Could not open " + name + ": " + e); 878 } 879 } 880 881 private static Object[] getExifImages() { 882 return new Object[] { 883 R.drawable.orientation_1, 884 R.drawable.orientation_2, 885 R.drawable.orientation_3, 886 R.drawable.orientation_4, 887 R.drawable.orientation_5, 888 R.drawable.orientation_6, 889 R.drawable.orientation_7, 890 R.drawable.orientation_8, 891 R.drawable.webp_orientation1, 892 R.drawable.webp_orientation2, 893 R.drawable.webp_orientation3, 894 R.drawable.webp_orientation4, 895 R.drawable.webp_orientation5, 896 R.drawable.webp_orientation6, 897 R.drawable.webp_orientation7, 898 R.drawable.webp_orientation8, 899 }; 900 } 901 902 @Test 903 @Parameters(method = "getExifImages") 904 public void testRespectOrientation(int resId) throws IOException { 905 Uri uri = Utils.getAsResourceUri(resId); 906 ImageDecoder.Source src = ImageDecoder.createSource(getContentResolver(), 907 uri); 908 Bitmap bm = decode(src, false /* unpremul */); 909 assertNotNull(bm); 910 assertEquals(100, bm.getWidth()); 911 assertEquals(80, bm.getHeight()); 912 913 // First verify that the info (and in particular, the width and height) 914 // are correct. This uses a separate ParcelFileDescriptor/aimagedecoder 915 // because the native methods delete the aimagedecoder. 916 try (ParcelFileDescriptor pfd = open(resId)) { 917 long aimagedecoder = nCreateFromFd(pfd.getFd()); 918 919 String mimeType = uri.toString().contains("webp") ? "image/webp" : "image/jpeg"; 920 nTestInfo(aimagedecoder, 100, 80, mimeType, false, 921 DataSpace.fromColorSpace(bm.getColorSpace())); 922 } catch (FileNotFoundException e) { 923 e.printStackTrace(); 924 fail("Could not open " + uri + " to check info"); 925 } 926 927 try (ParcelFileDescriptor pfd = open(resId)) { 928 long aimagedecoder = nCreateFromFd(pfd.getFd()); 929 930 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_NONE, false /* unpremul */, bm); 931 } catch (FileNotFoundException e) { 932 e.printStackTrace(); 933 fail("Could not open " + uri); 934 } 935 bm.recycle(); 936 } 937 938 @Test 939 @Parameters(method = "getAssetRecords") 940 public void testScalePlusUnpremul(ImageDecoderTest.AssetRecord record) { 941 long asset = nOpenAsset(getAssetManager(), record.name); 942 long aimagedecoder = nCreateFromAsset(asset); 943 944 nTestScalePlusUnpremul(aimagedecoder); 945 nCloseAsset(asset); 946 } 947 948 private static File createCompressedBitmap(int width, int height, ColorSpace colorSpace, 949 Bitmap.CompressFormat format) { 950 File dir = InstrumentationRegistry.getTargetContext().getFilesDir(); 951 dir.mkdirs(); 952 953 File file = new File(dir, colorSpace.getName()); 954 try { 955 file.createNewFile(); 956 } catch (IOException e) { 957 e.printStackTrace(); 958 // If the file does not exist it will be handled below. 959 } 960 if (!file.exists()) { 961 fail("Failed to create new File for " + file + "!"); 962 } 963 964 Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888, true, 965 colorSpace); 966 bitmap.eraseColor(Color.BLUE); 967 968 try (FileOutputStream fOutput = new FileOutputStream(file)) { 969 bitmap.compress(format, 80, fOutput); 970 return file; 971 } catch (IOException e) { 972 e.printStackTrace(); 973 fail("Failed to create file \"" + file + "\" with exception " + e); 974 return null; 975 } 976 } 977 978 private static Object[] rgbColorSpaces() { 979 return BitmapTest.getRgbColorSpaces().toArray(); 980 } 981 982 private static Object[] rgbColorSpacesAndCompressFormats() { 983 return Utils.crossProduct(rgbColorSpaces(), Bitmap.CompressFormat.values()); 984 } 985 986 String toMimeType(Bitmap.CompressFormat format) { 987 switch (format) { 988 case JPEG: 989 return "image/jpeg"; 990 case PNG: 991 return "image/png"; 992 case WEBP: 993 case WEBP_LOSSY: 994 case WEBP_LOSSLESS: 995 return "image/webp"; 996 default: 997 return ""; 998 } 999 } 1000 1001 @Test 1002 @Parameters(method = "rgbColorSpacesAndCompressFormats") 1003 public void testGetDataSpace(ColorSpace colorSpace, Bitmap.CompressFormat format) { 1004 if (colorSpace == ColorSpace.get(Named.EXTENDED_SRGB) 1005 || colorSpace == ColorSpace.get(Named.LINEAR_EXTENDED_SRGB)) { 1006 // These will only be reported when the default AndroidBitmapFormat is F16. 1007 // Bitmap.compress will not compress to an image that will be decoded as F16 by default, 1008 // so these are covered by the AssetRecord tests. 1009 return; 1010 } 1011 1012 final int width = 10; 1013 final int height = 10; 1014 File file = createCompressedBitmap(width, height, colorSpace, format); 1015 assertNotNull(file); 1016 1017 int dataSpace = DataSpace.fromColorSpace(colorSpace); 1018 1019 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, 1020 ParcelFileDescriptor.MODE_READ_ONLY)) { 1021 long aimagedecoder = nCreateFromFd(pfd.getFd()); 1022 nTestInfo(aimagedecoder, width, height, toMimeType(format), false, dataSpace); 1023 } catch (IOException e) { 1024 e.printStackTrace(); 1025 fail("Could not read " + file); 1026 } 1027 } 1028 1029 private static Bitmap decode(ImageDecoder.Source src, ColorSpace colorSpace) { 1030 try { 1031 return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> { 1032 // So we can compare pixels to the native decode. 1033 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 1034 1035 decoder.setTargetColorSpace(colorSpace); 1036 }); 1037 } catch (IOException e) { 1038 fail("Failed to decode in Java with " + e); 1039 return null; 1040 } 1041 } 1042 1043 @Test 1044 @Parameters(method = "rgbColorSpaces") 1045 public void testSetDataSpace(ColorSpace colorSpace) { 1046 int dataSpace = DataSpace.fromColorSpace(colorSpace); 1047 if (dataSpace == DataSpace.ADATASPACE_UNKNOWN) { 1048 // AImageDecoder cannot decode to these ADATASPACEs 1049 return; 1050 } 1051 1052 String name = "translucent-green-p3.png"; 1053 AssetManager assets = getAssetManager(); 1054 ImageDecoder.Source src = ImageDecoder.createSource(assets, name); 1055 Bitmap bm = decode(src, colorSpace); 1056 assertEquals(colorSpace, bm.getColorSpace()); 1057 1058 long asset = nOpenAsset(assets, name); 1059 long aimagedecoder = nCreateFromAsset(asset); 1060 1061 nTestDecode(aimagedecoder, bm, dataSpace); 1062 nCloseAsset(asset); 1063 } 1064 1065 @Test 1066 @Parameters({ "cmyk_yellow_224_224_32.jpg", "wide_gamut_yellow_224_224_64.jpeg" }) 1067 public void testNonStandardDataSpaces(String name) { 1068 AssetManager assets = getAssetManager(); 1069 long asset = nOpenAsset(assets, name); 1070 long aimagedecoder = nCreateFromAsset(asset); 1071 1072 // These images have profiles that do not map to ADataSpaces (or even SkColorSpaces). 1073 // Verify that by default, AImageDecoder will treat them as ADATASPACE_UNKNOWN. 1074 nTestInfo(aimagedecoder, 32, 32, "image/jpeg", false, DataSpace.ADATASPACE_UNKNOWN); 1075 nCloseAsset(asset); 1076 } 1077 1078 @Test 1079 @Parameters({ "cmyk_yellow_224_224_32.jpg,#FFD8FC04", 1080 "wide_gamut_yellow_224_224_64.jpeg,#FFE0E040" }) 1081 public void testNonStandardDataSpacesDecode(String name, String color) { 1082 AssetManager assets = getAssetManager(); 1083 long asset = nOpenAsset(assets, name); 1084 long aimagedecoder = nCreateFromAsset(asset); 1085 1086 // These images are each a solid color. If we correctly do no color correction, they should 1087 // match |color|. 1088 int colorInt = Color.parseColor(color); 1089 Bitmap bm = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888); 1090 bm.eraseColor(colorInt); 1091 1092 nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_NONE, false /* unpremul */, bm); 1093 nCloseAsset(asset); 1094 } 1095 1096 @Test 1097 @Parameters(method = "getAssetRecords") 1098 public void testNotAnimatedAssets(ImageDecoderTest.AssetRecord record) { 1099 long asset = nOpenAsset(getAssetManager(), record.name); 1100 long aimagedecoder = nCreateFromAsset(asset); 1101 1102 nTestIsAnimated(aimagedecoder, false); 1103 nCloseAsset(asset); 1104 } 1105 1106 @Test 1107 @Parameters(method = "getRecords") 1108 public void testNotAnimated(ImageDecoderTest.Record record) throws IOException { 1109 try (ParcelFileDescriptor pfd = open(record.resId)) { 1110 long aimagedecoder = nCreateFromFd(pfd.getFd()); 1111 1112 nTestIsAnimated(aimagedecoder, false); 1113 } catch (FileNotFoundException e) { 1114 fail("Could not open " + Utils.getAsResourceUri(record.resId)); 1115 } 1116 } 1117 1118 private static Object[] getAnimatedImagesPlusRepeatCounts() { 1119 return AnimatedImageDrawableTest.parametersForTestEncodedRepeats(); 1120 } 1121 1122 // Although these images have an encoded repeat count, they have only one frame, 1123 // so they are not considered animated. 1124 @Test 1125 @Parameters({"still_with_loop_count.gif", "webp_still_with_loop_count.webp"}) 1126 public void testStill(String name) { 1127 long asset = nOpenAsset(getAssetManager(), name); 1128 long aimagedecoder = nCreateFromAsset(asset); 1129 1130 nTestIsAnimated(aimagedecoder, false); 1131 nCloseAsset(asset); 1132 } 1133 1134 @Test 1135 @Parameters(method = "getAnimatedImagesPlusRepeatCounts") 1136 public void testAnimated(int resId, int unused) throws IOException { 1137 try (ParcelFileDescriptor pfd = open(resId)) { 1138 long aimagedecoder = nCreateFromFd(pfd.getFd()); 1139 1140 nTestIsAnimated(aimagedecoder, true); 1141 } catch (FileNotFoundException e) { 1142 fail("Could not open " + Utils.getAsResourceUri(resId)); 1143 } 1144 } 1145 1146 @Test 1147 @Parameters(method = "getAnimatedImagesPlusRepeatCounts") 1148 public void testRepeatCount(int resId, int repeatCount) throws IOException { 1149 try (ParcelFileDescriptor pfd = open(resId)) { 1150 long aimagedecoder = nCreateFromFd(pfd.getFd()); 1151 1152 nTestRepeatCount(aimagedecoder, repeatCount); 1153 } catch (FileNotFoundException e) { 1154 fail("Could not open " + Utils.getAsResourceUri(resId)); 1155 } 1156 } 1157 1158 @Test 1159 @Parameters({"still_with_loop_count.gif, 1", "webp_still_with_loop_count.webp,31999"}) 1160 public void testRepeatCountStill(String name, int repeatCount) { 1161 long asset = nOpenAsset(getAssetManager(), name); 1162 long aimagedecoder = nCreateFromAsset(asset); 1163 1164 nTestRepeatCount(aimagedecoder, repeatCount); 1165 nCloseAsset(asset); 1166 } 1167 1168 // Return a pointer to the native AAsset named |file|. Must be closed with nCloseAsset. 1169 // Throws an Exception on failure. 1170 private static native long nOpenAsset(AssetManager assets, String file); 1171 private static native void nCloseAsset(long asset); 1172 1173 // Methods for creating and returning a pointer to an AImageDecoder. All 1174 // throw an Exception on failure. 1175 private static native long nCreateFromFd(int fd); 1176 private static native long nCreateFromAsset(long asset); 1177 private static native long nCreateFromAssetFd(long asset); 1178 private static native long nCreateFromAssetBuffer(long asset); 1179 1180 private static native void nTestEmptyCreate(); 1181 private static native void nTestNullDecoder(AssetManager assets, String file); 1182 private static native void nTestCreateIncomplete(AssetManager assets, 1183 String file, int truncatedLength); 1184 private static native void nTestCreateUnsupported(AssetManager assets, String file); 1185 1186 // For convenience, all methods that take aimagedecoder as a parameter delete 1187 // it. 1188 private static native void nTestInfo(long aimagedecoder, int width, int height, 1189 String mimeType, boolean isF16, int dataspace); 1190 private static native void nTestSetFormat(long aimagedecoder, boolean isF16, boolean isGray); 1191 private static native void nTestSetUnpremul(long aimagedecoder, boolean hasAlpha); 1192 private static native void nTestGetMinimumStride(long aimagedecoder, 1193 boolean isF16, boolean isGray); 1194 private static native void nTestDecode(long aimagedecoder, 1195 int requestedAndroidBitmapFormat, boolean unpremul, Bitmap bitmap); 1196 private static native void nTestDecodeStride(long aimagedecoder); 1197 private static native void nTestSetTargetSize(long aimagedecoder); 1198 // Decode with the target width and height to match |bitmap|. 1199 private static native void nTestDecodeScaled(long aimagedecoder, Bitmap bitmap); 1200 private static native void nTestComputeSampledSize(long aimagedecoder, Bitmap bm, 1201 int sampleSize); 1202 private static native void nTestSetCrop(AssetManager assets, String file); 1203 // Decode and compare to |bitmap|, where they both use the specified target 1204 // size and crop rect. target size of 0 means to skip scaling. 1205 private static native void nTestDecodeCrop(long aimagedecoder, 1206 Bitmap bitmap, int targetWidth, int targetHeight, 1207 int cropLeft, int cropTop, int cropRight, int cropBottom); 1208 private static native void nTestScalePlusUnpremul(long aimagedecoder); 1209 private static native void nTestDecode(long aimagedecoder, Bitmap bm, int dataSpace); 1210 private static native void nTestIsAnimated(long aimagedecoder, boolean animated); 1211 private static native void nTestRepeatCount(long aimagedecoder, int repeatCount); 1212 } 1213