1 /* 2 * Copyright (C) 2008 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 org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotEquals; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertNull; 24 import static org.junit.Assert.assertSame; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assert.fail; 27 import static org.junit.Assume.assumeTrue; 28 import static org.testng.Assert.assertThrows; 29 30 import android.content.res.Resources; 31 import android.graphics.Bitmap; 32 import android.graphics.Bitmap.CompressFormat; 33 import android.graphics.Bitmap.Config; 34 import android.graphics.BitmapFactory; 35 import android.graphics.BitmapFactory.Options; 36 import android.graphics.Color; 37 import android.graphics.ImageDecoder; 38 import android.graphics.Rect; 39 import android.media.MediaCodecInfo; 40 import android.media.MediaCodecList; 41 import android.media.MediaFormat; 42 import android.os.Parcel; 43 import android.os.ParcelFileDescriptor; 44 import android.platform.test.annotations.RequiresDevice; 45 import android.system.ErrnoException; 46 import android.system.Os; 47 import android.util.DisplayMetrics; 48 import android.util.TypedValue; 49 50 import androidx.test.InstrumentationRegistry; 51 import androidx.test.filters.LargeTest; 52 import androidx.test.filters.SmallTest; 53 54 import com.android.compatibility.common.util.BitmapUtils; 55 import com.android.compatibility.common.util.CddTest; 56 57 import junitparams.JUnitParamsRunner; 58 import junitparams.Parameters; 59 60 import org.junit.Before; 61 import org.junit.Test; 62 import org.junit.runner.RunWith; 63 64 import java.io.ByteArrayInputStream; 65 import java.io.ByteArrayOutputStream; 66 import java.io.File; 67 import java.io.FileDescriptor; 68 import java.io.FileOutputStream; 69 import java.io.IOException; 70 import java.io.InputStream; 71 import java.io.RandomAccessFile; 72 import java.util.ArrayList; 73 import java.util.Arrays; 74 import java.util.concurrent.CountDownLatch; 75 76 @SmallTest 77 @RunWith(JUnitParamsRunner.class) 78 public class BitmapFactoryTest { 79 // height and width of start.jpg 80 private static final int START_HEIGHT = 31; 81 private static final int START_WIDTH = 31; 82 83 static class TestImage { TestImage(int id, int width, int height)84 TestImage(int id, int width, int height) { 85 this.id = id; 86 this.width = width; 87 this.height = height; 88 } 89 public final int id; 90 public final int width; 91 public final int height; 92 } 93 testImages()94 private Object[] testImages() { 95 ArrayList<Object> testImages = new ArrayList<>(Arrays.asList(new Object[] { 96 new TestImage(R.drawable.baseline_jpeg, 1280, 960), 97 new TestImage(R.drawable.png_test, 640, 480), 98 new TestImage(R.drawable.gif_test, 320, 240), 99 new TestImage(R.drawable.bmp_test, 320, 240), 100 new TestImage(R.drawable.webp_test, 640, 480) 101 })); 102 if (ImageDecoder.isMimeTypeSupported("image/heif")) { 103 // HEIF support is optional when HEVC decoder is not supported. 104 testImages.add(new TestImage(R.raw.heifwriter_input, 1920, 1080)); 105 } 106 if (ImageDecoder.isMimeTypeSupported("image/avif")) { 107 testImages.add(new TestImage(R.raw.avif_yuv_420_8bit, 120, 160)); 108 } 109 return testImages.toArray(new Object[] {}); 110 } 111 112 private static final int[] RAW_COLORS = new int[] { 113 // raw data from R.drawable.premul_data 114 Color.argb(255, 0, 0, 0), 115 Color.argb(128, 255, 0, 0), 116 Color.argb(128, 25, 26, 27), 117 Color.argb(2, 255, 254, 253), 118 }; 119 120 private static final int[] DEPREMUL_COLORS = new int[] { 121 // data from R.drawable.premul_data, after premultiplied store + un-premultiplied load 122 Color.argb(255, 0, 0, 0), 123 Color.argb(128, 255, 0, 0), 124 Color.argb(128, 26, 26, 28), 125 Color.argb(2, 255, 255, 255), 126 }; 127 128 private Resources mRes; 129 // opt for non-null 130 private BitmapFactory.Options mOpt1; 131 // opt for null 132 private BitmapFactory.Options mOpt2; 133 private int mDefaultDensity; 134 private int mTargetDensity; 135 136 @Before setup()137 public void setup() { 138 mRes = InstrumentationRegistry.getTargetContext().getResources(); 139 mDefaultDensity = DisplayMetrics.DENSITY_DEFAULT; 140 mTargetDensity = mRes.getDisplayMetrics().densityDpi; 141 142 mOpt1 = new BitmapFactory.Options(); 143 mOpt1.inScaled = false; 144 mOpt2 = new BitmapFactory.Options(); 145 mOpt2.inScaled = false; 146 mOpt2.inJustDecodeBounds = true; 147 } 148 149 @Test testConstructor()150 public void testConstructor() { 151 new BitmapFactory(); 152 } 153 154 @Test testDecodeResource1()155 public void testDecodeResource1() { 156 Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.start, 157 mOpt1); 158 assertNotNull(b); 159 // Test the bitmap size 160 assertEquals(START_HEIGHT, b.getHeight()); 161 assertEquals(START_WIDTH, b.getWidth()); 162 // Test if no bitmap 163 assertNull(BitmapFactory.decodeResource(mRes, R.drawable.start, mOpt2)); 164 } 165 166 @Test testDecodeResource2()167 public void testDecodeResource2() { 168 Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.start); 169 assertNotNull(b); 170 // Test the bitmap size 171 assertEquals(START_HEIGHT * mTargetDensity / mDefaultDensity, b.getHeight(), 1.1); 172 assertEquals(START_WIDTH * mTargetDensity / mDefaultDensity, b.getWidth(), 1.1); 173 } 174 175 @Test testDecodeResourceStream()176 public void testDecodeResourceStream() { 177 InputStream is = obtainInputStream(); 178 Rect r = new Rect(1, 1, 1, 1); 179 TypedValue value = new TypedValue(); 180 Bitmap b = BitmapFactory.decodeResourceStream(mRes, value, is, r, mOpt1); 181 assertNotNull(b); 182 // Test the bitmap size 183 assertEquals(START_HEIGHT, b.getHeight()); 184 assertEquals(START_WIDTH, b.getWidth()); 185 } 186 187 @Test testDecodeByteArray1()188 public void testDecodeByteArray1() { 189 byte[] array = obtainArray(); 190 Bitmap b = BitmapFactory.decodeByteArray(array, 0, array.length, mOpt1); 191 assertNotNull(b); 192 // Test the bitmap size 193 assertEquals(START_HEIGHT, b.getHeight()); 194 assertEquals(START_WIDTH, b.getWidth()); 195 // Test if no bitmap 196 assertNull(BitmapFactory.decodeByteArray(array, 0, array.length, mOpt2)); 197 } 198 199 @Test testDecodeByteArray2()200 public void testDecodeByteArray2() { 201 byte[] array = obtainArray(); 202 Bitmap b = BitmapFactory.decodeByteArray(array, 0, array.length); 203 assertNotNull(b); 204 // Test the bitmap size 205 assertEquals(START_HEIGHT, b.getHeight()); 206 assertEquals(START_WIDTH, b.getWidth()); 207 } 208 209 @Test testDecodeStream1()210 public void testDecodeStream1() { 211 InputStream is = obtainInputStream(); 212 Rect r = new Rect(1, 1, 1, 1); 213 Bitmap b = BitmapFactory.decodeStream(is, r, mOpt1); 214 assertNotNull(b); 215 // Test the bitmap size 216 assertEquals(START_HEIGHT, b.getHeight()); 217 assertEquals(START_WIDTH, b.getWidth()); 218 // Test if no bitmap 219 assertNull(BitmapFactory.decodeStream(is, r, mOpt2)); 220 } 221 222 @Test testDecodeStream2()223 public void testDecodeStream2() { 224 InputStream is = obtainInputStream(); 225 Bitmap b = BitmapFactory.decodeStream(is); 226 assertNotNull(b); 227 // Test the bitmap size 228 assertEquals(START_HEIGHT, b.getHeight()); 229 assertEquals(START_WIDTH, b.getWidth()); 230 } 231 232 @Test 233 @Parameters(method = "testImages") testDecodeStream3(TestImage testImage)234 public void testDecodeStream3(TestImage testImage) { 235 InputStream is = obtainInputStream(testImage.id); 236 Bitmap b = BitmapFactory.decodeStream(is); 237 assertNotNull(b); 238 // Test the bitmap size 239 assertEquals(testImage.width, b.getWidth()); 240 assertEquals(testImage.height, b.getHeight()); 241 } 242 paramsForWebpDecodeEncode()243 private Object[] paramsForWebpDecodeEncode() { 244 return new Object[] { 245 new Object[] {Config.ARGB_8888, 16}, 246 new Object[] {Config.RGB_565, 49} 247 }; 248 } 249 decodeOpaqueImage(int resId, BitmapFactory.Options options)250 private Bitmap decodeOpaqueImage(int resId, BitmapFactory.Options options) { 251 return decodeOpaqueImage(obtainInputStream(resId), options); 252 } 253 decodeOpaqueImage(InputStream stream, BitmapFactory.Options options)254 private Bitmap decodeOpaqueImage(InputStream stream, BitmapFactory.Options options) { 255 Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options); 256 assertNotNull(bitmap); 257 assertFalse(bitmap.isPremultiplied()); 258 assertFalse(bitmap.hasAlpha()); 259 return bitmap; 260 } 261 262 @Test 263 @Parameters(method = "paramsForWebpDecodeEncode") testWebpStreamDecode(Config config, int tolerance)264 public void testWebpStreamDecode(Config config, int tolerance) { 265 BitmapFactory.Options options = new BitmapFactory.Options(); 266 options.inPreferredConfig = config; 267 268 // Decode the PNG & WebP test images. The WebP test image has been encoded from PNG test 269 // image and should have same similar (within some error-tolerance) Bitmap data. 270 Bitmap bPng = decodeOpaqueImage(R.drawable.png_test, options); 271 assertEquals(bPng.getConfig(), config); 272 Bitmap bWebp = decodeOpaqueImage(R.drawable.webp_test, options); 273 BitmapUtils.assertBitmapsMse(bPng, bWebp, tolerance, true, bPng.isPremultiplied()); 274 } 275 276 @Test 277 @Parameters(method = "paramsForWebpDecodeEncode") testWebpStreamEncode(Config config, int tolerance)278 public void testWebpStreamEncode(Config config, int tolerance) { 279 BitmapFactory.Options options = new BitmapFactory.Options(); 280 options.inPreferredConfig = config; 281 282 Bitmap bPng = decodeOpaqueImage(R.drawable.png_test, options); 283 assertEquals(bPng.getConfig(), config); 284 285 // Compress the PNG image to WebP format (Quality=90) and decode it back. 286 // This will test end-to-end WebP encoding and decoding. 287 ByteArrayOutputStream oStreamWebp = new ByteArrayOutputStream(); 288 assertTrue(bPng.compress(CompressFormat.WEBP, 90, oStreamWebp)); 289 InputStream iStreamWebp = new ByteArrayInputStream(oStreamWebp.toByteArray()); 290 Bitmap bWebp2 = decodeOpaqueImage(iStreamWebp, options); 291 BitmapUtils.assertBitmapsMse(bPng, bWebp2, tolerance, true, bPng.isPremultiplied()); 292 } 293 294 @Test testDecodeStream5()295 public void testDecodeStream5() { 296 final int tolerance = 72; 297 BitmapFactory.Options options = new BitmapFactory.Options(); 298 options.inPreferredConfig = Config.ARGB_8888; 299 300 // Decode the PNG & WebP (google_logo) images. The WebP image has 301 // been encoded from PNG image. 302 InputStream iStreamPng = obtainInputStream(R.drawable.google_logo_1); 303 Bitmap bPng = BitmapFactory.decodeStream(iStreamPng, null, options); 304 assertNotNull(bPng); 305 assertEquals(bPng.getConfig(), Config.ARGB_8888); 306 assertTrue(bPng.isPremultiplied()); 307 assertTrue(bPng.hasAlpha()); 308 309 // Decode the corresponding WebP (transparent) image (google_logo_2.webp). 310 InputStream iStreamWebP1 = obtainInputStream(R.drawable.google_logo_2); 311 Bitmap bWebP1 = BitmapFactory.decodeStream(iStreamWebP1, null, options); 312 assertNotNull(bWebP1); 313 assertEquals(bWebP1.getConfig(), Config.ARGB_8888); 314 assertTrue(bWebP1.isPremultiplied()); 315 assertTrue(bWebP1.hasAlpha()); 316 BitmapUtils.assertBitmapsMse(bPng, bWebP1, tolerance, true, bPng.isPremultiplied()); 317 318 // Compress the PNG image to WebP format (Quality=90) and decode it back. 319 // This will test end-to-end WebP encoding and decoding. 320 ByteArrayOutputStream oStreamWebp = new ByteArrayOutputStream(); 321 assertTrue(bPng.compress(CompressFormat.WEBP, 90, oStreamWebp)); 322 InputStream iStreamWebp2 = new ByteArrayInputStream(oStreamWebp.toByteArray()); 323 Bitmap bWebP2 = BitmapFactory.decodeStream(iStreamWebp2, null, options); 324 assertNotNull(bWebP2); 325 assertEquals(bWebP2.getConfig(), Config.ARGB_8888); 326 assertTrue(bWebP2.isPremultiplied()); 327 assertTrue(bWebP2.hasAlpha()); 328 BitmapUtils.assertBitmapsMse(bPng, bWebP2, tolerance, true, bPng.isPremultiplied()); 329 } 330 331 @Test testDecodeFileDescriptor1()332 public void testDecodeFileDescriptor1() throws IOException { 333 ParcelFileDescriptor pfd = obtainParcelDescriptor(obtainPath()); 334 FileDescriptor input = pfd.getFileDescriptor(); 335 Rect r = new Rect(1, 1, 1, 1); 336 Bitmap b = BitmapFactory.decodeFileDescriptor(input, r, mOpt1); 337 assertNotNull(b); 338 // Test the bitmap size 339 assertEquals(START_HEIGHT, b.getHeight()); 340 assertEquals(START_WIDTH, b.getWidth()); 341 // Test if no bitmap 342 assertNull(BitmapFactory.decodeFileDescriptor(input, r, mOpt2)); 343 } 344 345 @Test testDecodeFileDescriptor2()346 public void testDecodeFileDescriptor2() throws IOException { 347 ParcelFileDescriptor pfd = obtainParcelDescriptor(obtainPath()); 348 FileDescriptor input = pfd.getFileDescriptor(); 349 Bitmap b = BitmapFactory.decodeFileDescriptor(input); 350 assertNotNull(b); 351 // Test the bitmap size 352 assertEquals(START_HEIGHT, b.getHeight()); 353 assertEquals(START_WIDTH, b.getWidth()); 354 } 355 356 357 // TODO: Better parameterize this and split it up. 358 @Test 359 @Parameters(method = "testImages") testDecodeFileDescriptor3(TestImage testImage)360 public void testDecodeFileDescriptor3(TestImage testImage) throws IOException { 361 // Arbitrary offsets to use. If the offset of the FD matches the offset of the image, 362 // decoding should succeed, but if they do not match, decoding should fail. 363 final long[] actual_offsets = new long[] { 0, 17 }; 364 for (int j = 0; j < actual_offsets.length; ++j) { 365 // FIXME: The purgeable test should attempt to purge the memory 366 // to force a re-decode. 367 for (boolean purgeable : new boolean[] { false, true }) { 368 BitmapFactory.Options opts = new BitmapFactory.Options(); 369 opts.inPurgeable = purgeable; 370 opts.inInputShareable = purgeable; 371 372 long actualOffset = actual_offsets[j]; 373 String path = Utils.obtainPath(testImage.id, actualOffset); 374 RandomAccessFile file = new RandomAccessFile(path, "r"); 375 FileDescriptor fd = file.getFD(); 376 assertTrue(fd.valid()); 377 378 // Set the offset to ACTUAL_OFFSET 379 file.seek(actualOffset); 380 assertEquals(file.getFilePointer(), actualOffset); 381 382 // Now decode. This should be successful and leave the offset 383 // unchanged. 384 Bitmap b = BitmapFactory.decodeFileDescriptor(fd, null, opts); 385 assertNotNull(b); 386 assertEquals(file.getFilePointer(), actualOffset); 387 388 // Now use the other offset. It should fail to decode, and 389 // the offset should remain unchanged. 390 long otherOffset = actual_offsets[(j + 1) % actual_offsets.length]; 391 assertFalse(otherOffset == actualOffset); 392 file.seek(otherOffset); 393 assertEquals(file.getFilePointer(), otherOffset); 394 395 b = BitmapFactory.decodeFileDescriptor(fd, null, opts); 396 assertNull(b); 397 assertEquals(file.getFilePointer(), otherOffset); 398 } 399 } 400 } 401 402 @Test testDecodeFile1()403 public void testDecodeFile1() throws IOException { 404 Bitmap b = BitmapFactory.decodeFile(obtainPath(), mOpt1); 405 assertNotNull(b); 406 // Test the bitmap size 407 assertEquals(START_HEIGHT, b.getHeight()); 408 assertEquals(START_WIDTH, b.getWidth()); 409 // Test if no bitmap 410 assertNull(BitmapFactory.decodeFile(obtainPath(), mOpt2)); 411 } 412 413 @Test testDecodeFile2()414 public void testDecodeFile2() throws IOException { 415 Bitmap b = BitmapFactory.decodeFile(obtainPath()); 416 assertNotNull(b); 417 // Test the bitmap size 418 assertEquals(START_HEIGHT, b.getHeight()); 419 assertEquals(START_WIDTH, b.getWidth()); 420 } 421 422 @Test testDecodeReuseBasic()423 public void testDecodeReuseBasic() { 424 BitmapFactory.Options options = new BitmapFactory.Options(); 425 options.inMutable = true; 426 options.inSampleSize = 0; // treated as 1 427 options.inScaled = false; 428 Bitmap start = BitmapFactory.decodeResource(mRes, R.drawable.start, options); 429 int originalSize = start.getByteCount(); 430 assertEquals(originalSize, start.getAllocationByteCount()); 431 432 options.inBitmap = start; 433 options.inMutable = false; // will be overridden by non-null inBitmap 434 options.inSampleSize = -42; // treated as 1 435 Bitmap pass = BitmapFactory.decodeResource(mRes, R.drawable.pass, options); 436 437 assertEquals(originalSize, pass.getByteCount()); 438 assertEquals(originalSize, pass.getAllocationByteCount()); 439 assertSame(start, pass); 440 assertTrue(pass.isMutable()); 441 } 442 443 @Test testDecodeReuseAttempt()444 public void testDecodeReuseAttempt() { 445 // BitmapFactory "silently" ignores an immutable inBitmap. (It does print a log message.) 446 BitmapFactory.Options options = new BitmapFactory.Options(); 447 options.inMutable = false; 448 449 Bitmap start = BitmapFactory.decodeResource(mRes, R.drawable.start, options); 450 assertFalse(start.isMutable()); 451 452 options.inBitmap = start; 453 Bitmap pass = BitmapFactory.decodeResource(mRes, R.drawable.pass, options); 454 assertNotNull(pass); 455 assertNotEquals(start, pass); 456 } 457 458 @Test testDecodeReuseRecycled()459 public void testDecodeReuseRecycled() { 460 BitmapFactory.Options options = new BitmapFactory.Options(); 461 options.inMutable = true; 462 463 Bitmap start = BitmapFactory.decodeResource(mRes, R.drawable.start, options); 464 assertNotNull(start); 465 start.recycle(); 466 467 options.inBitmap = start; 468 469 assertThrows(IllegalArgumentException.class, () -> { 470 BitmapFactory.decodeResource(mRes, R.drawable.pass, options); 471 }); 472 } 473 474 @Test testDecodeReuseHardware()475 public void testDecodeReuseHardware() { 476 BitmapFactory.Options options = new BitmapFactory.Options(); 477 options.inPreferredConfig = Bitmap.Config.HARDWARE; 478 479 Bitmap start = BitmapFactory.decodeResource(mRes, R.drawable.start, options); 480 assertNotNull(start); 481 482 options.inBitmap = start; 483 484 assertThrows(IllegalArgumentException.class, () -> { 485 BitmapFactory.decodeResource(mRes, R.drawable.pass, options); 486 }); 487 } 488 489 /** 490 * Create bitmap sized to load unscaled resources: start, pass, and alpha 491 */ createBitmapForReuse(int pixelCount)492 private Bitmap createBitmapForReuse(int pixelCount) { 493 Bitmap bitmap = Bitmap.createBitmap(pixelCount, 1, Config.ARGB_8888); 494 bitmap.eraseColor(Color.BLACK); 495 bitmap.setHasAlpha(false); 496 return bitmap; 497 } 498 499 /** 500 * Decode resource with ResId into reuse bitmap without scaling, verifying expected hasAlpha 501 */ decodeResourceWithReuse(Bitmap reuse, int resId, boolean hasAlpha)502 private void decodeResourceWithReuse(Bitmap reuse, int resId, boolean hasAlpha) { 503 BitmapFactory.Options options = new BitmapFactory.Options(); 504 options.inMutable = true; 505 options.inSampleSize = 1; 506 options.inScaled = false; 507 options.inBitmap = reuse; 508 Bitmap output = BitmapFactory.decodeResource(mRes, resId, options); 509 assertSame(reuse, output); 510 assertEquals(output.hasAlpha(), hasAlpha); 511 } 512 513 @Test testDecodeReuseHasAlpha()514 public void testDecodeReuseHasAlpha() { 515 final int bitmapSize = 31; // size in pixels of start, pass, and alpha resources 516 final int pixelCount = bitmapSize * bitmapSize; 517 518 // Test reuse, hasAlpha false and true 519 Bitmap bitmap = createBitmapForReuse(pixelCount); 520 decodeResourceWithReuse(bitmap, R.drawable.start, false); 521 decodeResourceWithReuse(bitmap, R.drawable.alpha, true); 522 523 // Test pre-reconfigure, hasAlpha false and true 524 bitmap = createBitmapForReuse(pixelCount); 525 bitmap.reconfigure(bitmapSize, bitmapSize, Config.ARGB_8888); 526 bitmap.setHasAlpha(true); 527 decodeResourceWithReuse(bitmap, R.drawable.start, false); 528 529 bitmap = createBitmapForReuse(pixelCount); 530 bitmap.reconfigure(bitmapSize, bitmapSize, Config.ARGB_8888); 531 decodeResourceWithReuse(bitmap, R.drawable.alpha, true); 532 } 533 534 @Test 535 @Parameters(method = "testImages") testDecodeReuseFormats(TestImage testImage)536 public void testDecodeReuseFormats(TestImage testImage) { 537 // reuse should support all image formats 538 Bitmap reuseBuffer = Bitmap.createBitmap(1000000, 1, Bitmap.Config.ALPHA_8); 539 540 BitmapFactory.Options options = new BitmapFactory.Options(); 541 options.inBitmap = reuseBuffer; 542 options.inSampleSize = 4; 543 options.inScaled = false; 544 Bitmap decoded = BitmapFactory.decodeResource(mRes, testImage.id, options); 545 assertSame(reuseBuffer, decoded); 546 } 547 548 @Test testDecodeReuseFailure()549 public void testDecodeReuseFailure() { 550 BitmapFactory.Options options = new BitmapFactory.Options(); 551 options.inMutable = true; 552 options.inScaled = false; 553 options.inSampleSize = 4; 554 Bitmap reduced = BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 555 556 options.inBitmap = reduced; 557 options.inSampleSize = 1; 558 try { 559 BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 560 fail("should throw exception due to lack of space"); 561 } catch (IllegalArgumentException e) { 562 } 563 } 564 565 @Test testDecodeReuseScaling()566 public void testDecodeReuseScaling() { 567 BitmapFactory.Options options = new BitmapFactory.Options(); 568 options.inMutable = true; 569 options.inScaled = false; 570 Bitmap original = BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 571 int originalSize = original.getByteCount(); 572 assertEquals(originalSize, original.getAllocationByteCount()); 573 574 options.inBitmap = original; 575 options.inSampleSize = 4; 576 Bitmap reduced = BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 577 578 assertSame(original, reduced); 579 assertEquals(originalSize, reduced.getAllocationByteCount()); 580 assertEquals(originalSize, reduced.getByteCount() * 16); 581 } 582 583 @Test testDecodeReuseDoubleScaling()584 public void testDecodeReuseDoubleScaling() { 585 BitmapFactory.Options options = new BitmapFactory.Options(); 586 options.inMutable = true; 587 options.inScaled = false; 588 options.inSampleSize = 1; 589 Bitmap original = BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 590 int originalSize = original.getByteCount(); 591 592 // Verify that inSampleSize and density scaling both work with reuse concurrently 593 options.inBitmap = original; 594 options.inScaled = true; 595 options.inSampleSize = 2; 596 options.inDensity = 2; 597 options.inTargetDensity = 4; 598 Bitmap doubleScaled = BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 599 600 assertSame(original, doubleScaled); 601 assertEquals(4, doubleScaled.getDensity()); 602 assertEquals(originalSize, doubleScaled.getByteCount()); 603 } 604 605 @Test testDecodeReuseEquivalentScaling()606 public void testDecodeReuseEquivalentScaling() { 607 BitmapFactory.Options options = new BitmapFactory.Options(); 608 options.inMutable = true; 609 options.inScaled = true; 610 options.inDensity = 4; 611 options.inTargetDensity = 2; 612 Bitmap densityReduced = BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 613 assertEquals(2, densityReduced.getDensity()); 614 options.inBitmap = densityReduced; 615 options.inDensity = 0; 616 options.inScaled = false; 617 options.inSampleSize = 2; 618 Bitmap scaleReduced = BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 619 // verify that density isn't incorrectly carried over during bitmap reuse 620 assertFalse(densityReduced.getDensity() == 2); 621 assertFalse(densityReduced.getDensity() == 0); 622 assertSame(densityReduced, scaleReduced); 623 } 624 625 @Test testDecodePremultipliedDefault()626 public void testDecodePremultipliedDefault() { 627 Bitmap simplePremul = BitmapFactory.decodeResource(mRes, R.drawable.premul_data); 628 assertTrue(simplePremul.isPremultiplied()); 629 } 630 631 @Test testDecodePremultipliedData()632 public void testDecodePremultipliedData() { 633 BitmapFactory.Options options = new BitmapFactory.Options(); 634 options.inScaled = false; 635 Bitmap premul = BitmapFactory.decodeResource(mRes, R.drawable.premul_data, options); 636 options.inPremultiplied = false; 637 Bitmap unpremul = BitmapFactory.decodeResource(mRes, R.drawable.premul_data, options); 638 assertEquals(premul.getConfig(), Bitmap.Config.ARGB_8888); 639 assertEquals(unpremul.getConfig(), Bitmap.Config.ARGB_8888); 640 assertTrue(premul.getHeight() == 1 && unpremul.getHeight() == 1); 641 assertTrue(premul.getWidth() == unpremul.getWidth() && 642 DEPREMUL_COLORS.length == RAW_COLORS.length && 643 premul.getWidth() == DEPREMUL_COLORS.length); 644 645 // verify pixel data - unpremul should have raw values, premul will have rounding errors 646 for (int i = 0; i < premul.getWidth(); i++) { 647 assertEquals(premul.getPixel(i, 0), DEPREMUL_COLORS[i]); 648 assertEquals(unpremul.getPixel(i, 0), RAW_COLORS[i]); 649 } 650 } 651 652 @Test testDecodeInPurgeableAllocationCount()653 public void testDecodeInPurgeableAllocationCount() { 654 BitmapFactory.Options options = new BitmapFactory.Options(); 655 options.inSampleSize = 1; 656 options.inJustDecodeBounds = false; 657 options.inPurgeable = true; 658 options.inInputShareable = false; 659 byte[] array = obtainArray(); 660 Bitmap purgeableBitmap = BitmapFactory.decodeByteArray(array, 0, array.length, options); 661 assertFalse(purgeableBitmap.getAllocationByteCount() == 0); 662 } 663 664 private int mDefaultCreationDensity; verifyScaled(Bitmap b)665 private void verifyScaled(Bitmap b) { 666 assertEquals(b.getWidth(), START_WIDTH * 2); 667 assertEquals(b.getDensity(), 2); 668 } 669 verifyUnscaled(Bitmap b)670 private void verifyUnscaled(Bitmap b) { 671 assertEquals(b.getWidth(), START_WIDTH); 672 assertEquals(b.getDensity(), mDefaultCreationDensity); 673 } 674 675 @Test testDecodeScaling()676 public void testDecodeScaling() { 677 BitmapFactory.Options defaultOpt = new BitmapFactory.Options(); 678 679 BitmapFactory.Options unscaledOpt = new BitmapFactory.Options(); 680 unscaledOpt.inScaled = false; 681 682 BitmapFactory.Options scaledOpt = new BitmapFactory.Options(); 683 scaledOpt.inScaled = true; 684 scaledOpt.inDensity = 1; 685 scaledOpt.inTargetDensity = 2; 686 687 mDefaultCreationDensity = Bitmap.createBitmap(1, 1, Config.ARGB_8888).getDensity(); 688 689 byte[] bytes = obtainArray(); 690 691 verifyUnscaled(BitmapFactory.decodeByteArray(bytes, 0, bytes.length)); 692 verifyUnscaled(BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null)); 693 verifyUnscaled(BitmapFactory.decodeByteArray(bytes, 0, bytes.length, unscaledOpt)); 694 verifyUnscaled(BitmapFactory.decodeByteArray(bytes, 0, bytes.length, defaultOpt)); 695 696 verifyUnscaled(BitmapFactory.decodeStream(obtainInputStream())); 697 verifyUnscaled(BitmapFactory.decodeStream(obtainInputStream(), null, null)); 698 verifyUnscaled(BitmapFactory.decodeStream(obtainInputStream(), null, unscaledOpt)); 699 verifyUnscaled(BitmapFactory.decodeStream(obtainInputStream(), null, defaultOpt)); 700 701 // scaling should only occur if Options are passed with inScaled=true 702 verifyScaled(BitmapFactory.decodeByteArray(bytes, 0, bytes.length, scaledOpt)); 703 verifyScaled(BitmapFactory.decodeStream(obtainInputStream(), null, scaledOpt)); 704 } 705 706 @Test testParcel()707 public void testParcel() { 708 BitmapFactory.Options opts = new BitmapFactory.Options(); 709 opts.inScaled = false; 710 Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.gif_test, opts); 711 assertNotNull(b); 712 713 Parcel p = Parcel.obtain(); 714 b.writeToParcel(p, 0); 715 716 p.setDataPosition(0); 717 Bitmap b2 = Bitmap.CREATOR.createFromParcel(p); 718 assertTrue(BitmapUtils.compareBitmaps(b, b2)); 719 720 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 721 assertTrue(b2.compress(Bitmap.CompressFormat.JPEG, 50, baos)); 722 } 723 724 @Test testConfigs()725 public void testConfigs() { 726 // The output Config of a BitmapFactory decode depends on the request from the 727 // client and the properties of the image to be decoded. 728 // 729 // Options.inPreferredConfig = Config.ARGB_8888 730 // This is the default value of inPreferredConfig. In this case, the image 731 // will always be decoded to Config.ARGB_8888. 732 // Options.inPreferredConfig = Config.RGB_565 733 // If the encoded image is opaque, we will decode to Config.RGB_565, 734 // otherwise we will decode to whichever color type is the most natural match 735 // for the encoded data. 736 // Options.inPreferredConfig = Config.ARGB_4444 737 // This is deprecated and will always decode to Config.ARGB_8888. 738 // Options.inPreferredConfig = Config.ALPHA_8 739 // If the encoded image is gray, we will decode to 8-bit grayscale values 740 // and indicate that the output bitmap is Config.ALPHA_8. This is somewhat 741 // misleading because the image is really opaque and grayscale, but we are 742 // labeling each pixel as if it is a translucency (alpha) value. If the 743 // encoded image is not gray, we will decode to whichever color type is the 744 // most natural match for the encoded data. 745 // Options.inPreferredConfig = null 746 // We will decode to whichever Config is the most natural match with the 747 // encoded data. This could be ALPHA_8 (gray) or ARGB_8888. 748 // 749 // This test ensures that images are decoded to the intended Config and that the 750 // decodes match regardless of the Config. 751 decodeConfigs(R.drawable.alpha, 31, 31, true, false); 752 decodeConfigs(R.drawable.baseline_jpeg, 1280, 960, false, false); 753 decodeConfigs(R.drawable.bmp_test, 320, 240, false, false); 754 decodeConfigs(R.drawable.scaled2, 6, 8, false, false); 755 decodeConfigs(R.drawable.grayscale_jpg, 128, 128, false, true); 756 decodeConfigs(R.drawable.grayscale_png, 128, 128, false, true); 757 } 758 759 @Test(expected=IllegalArgumentException.class) testMutableHardwareInDecodeResource()760 public void testMutableHardwareInDecodeResource() { 761 Options options = new Options(); 762 options.inMutable = true; 763 options.inPreferredConfig = Config.HARDWARE; 764 BitmapFactory.decodeResource(mRes, R.drawable.alpha, options); 765 } 766 767 @Test(expected=IllegalArgumentException.class) testMutableHardwareInDecodeByteArray()768 public void testMutableHardwareInDecodeByteArray() { 769 Options options = new Options(); 770 options.inMutable = true; 771 options.inPreferredConfig = Config.HARDWARE; 772 BitmapFactory.decodeByteArray(new byte[100], 1, 20, options); 773 } 774 775 @Test(expected=IllegalArgumentException.class) testMutableHardwareInDecodeFile()776 public void testMutableHardwareInDecodeFile() { 777 Options options = new Options(); 778 options.inMutable = true; 779 options.inPreferredConfig = Config.HARDWARE; 780 BitmapFactory.decodeFile("barely/care.jpg", options); 781 } 782 783 @Test(expected=IllegalArgumentException.class) testMutableHardwareInDecodeFileDescriptor()784 public void testMutableHardwareInDecodeFileDescriptor() { 785 Options options = new Options(); 786 options.inMutable = true; 787 options.inPreferredConfig = Config.HARDWARE; 788 BitmapFactory.decodeFileDescriptor(null, new Rect(), options); 789 } 790 791 @Test(expected=IllegalArgumentException.class) testMutableHardwareInDecodeResourceStream()792 public void testMutableHardwareInDecodeResourceStream() { 793 Options options = new Options(); 794 options.inMutable = true; 795 options.inPreferredConfig = Config.HARDWARE; 796 TypedValue value = new TypedValue(); 797 BitmapFactory.decodeResourceStream(mRes, value, 798 new ByteArrayInputStream(new byte[20]), new Rect(), options); 799 } 800 801 @Test testDecodeHardwareBitmap()802 public void testDecodeHardwareBitmap() { 803 BitmapFactory.Options options = new BitmapFactory.Options(); 804 options.inPreferredConfig = Bitmap.Config.HARDWARE; 805 Bitmap hardwareBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, options); 806 assertNotNull(hardwareBitmap); 807 // Test that checks that correct bitmap was obtained is in uirendering/HardwareBitmapTests 808 assertEquals(Config.HARDWARE, hardwareBitmap.getConfig()); 809 } 810 811 @Test testJpegInfiniteLoop()812 public void testJpegInfiniteLoop() { 813 BitmapFactory.Options options = new BitmapFactory.Options(); 814 options.inSampleSize = 19; 815 Bitmap bm = BitmapFactory.decodeResource(mRes, R.raw.b78329453, options); 816 assertNotNull(bm); 817 } 818 819 private static final class DNG { 820 public final int resId; 821 public final int width; 822 public final int height; 823 DNG(int resId, int width, int height)824 DNG(int resId, int width, int height) { 825 this.resId = resId; 826 this.width = width; 827 this.height = height; 828 } 829 } 830 831 @Test 832 @CddTest(requirements = {"5.1.5/C-0-6"}) 833 @Parameters(method = "parametersForTestDng") 834 @LargeTest testDng(DNG dng)835 public void testDng(DNG dng) { 836 byte[] bytes = ImageDecoderTest.getAsByteArray(dng.resId); 837 // No scaling 838 Bitmap bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, mOpt1); 839 assertNotNull(bm); 840 assertEquals(dng.width, bm.getWidth()); 841 assertEquals(dng.height, bm.getHeight()); 842 } 843 parametersForTestDng()844 private Object[] parametersForTestDng() { 845 return new Object[]{ 846 new DNG(R.raw.sample_1mp, 600, 338), 847 new DNG(R.raw.sample_arw, 1616, 1080), 848 new DNG(R.raw.sample_cr2, 2304, 1536), 849 new DNG(R.raw.sample_nef, 4608, 3072), 850 new DNG(R.raw.sample_nrw, 4000, 3000), 851 new DNG(R.raw.sample_orf, 3200, 2400), 852 new DNG(R.raw.sample_pef, 4928, 3264), 853 new DNG(R.raw.sample_raf, 2048, 1536), 854 new DNG(R.raw.sample_rw2, 1920, 1440), 855 new DNG(R.raw.sample_srw, 5472, 3648), 856 }; 857 } 858 859 @Test testDecodePngFromPipe()860 public void testDecodePngFromPipe() { 861 // This test verifies that we can send a PNG over a pipe and 862 // successfully decode it. This behavior worked in N, so this 863 // verifies that do not break it for backwards compatibility. 864 // This was already not supported for the other Bitmap.CompressFormats 865 // (JPEG and WEBP), so we do not test those. 866 Bitmap source = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 867 source.eraseColor(Color.RED); 868 try { 869 Bitmap result = sendOverPipe(source, CompressFormat.PNG); 870 assertTrue(source.sameAs(result)); 871 } catch (Exception e) { 872 fail(e.toString()); 873 } 874 } 875 sendOverPipe(Bitmap source, CompressFormat format)876 private Bitmap sendOverPipe(Bitmap source, CompressFormat format) 877 throws IOException, ErrnoException, InterruptedException { 878 FileDescriptor[] pipeFds = Os.pipe(); 879 final FileDescriptor readFd = pipeFds[0]; 880 final FileDescriptor writeFd = pipeFds[1]; 881 final Throwable[] compressErrors = new Throwable[1]; 882 final CountDownLatch writeFinished = new CountDownLatch(1); 883 final CountDownLatch readFinished = new CountDownLatch(1); 884 final Bitmap[] decodedResult = new Bitmap[1]; 885 Thread writeThread = new Thread() { 886 @Override 887 public void run() { 888 try { 889 FileOutputStream output = new FileOutputStream(writeFd); 890 source.compress(format, 100, output); 891 output.close(); 892 } catch (Throwable t) { 893 compressErrors[0] = t; 894 // Try closing the FD to unblock the test thread 895 try { 896 Os.close(writeFd); 897 } catch (Throwable ignore) {} 898 } finally { 899 writeFinished.countDown(); 900 } 901 } 902 }; 903 Thread readThread = new Thread() { 904 @Override 905 public void run() { 906 decodedResult[0] = BitmapFactory.decodeFileDescriptor(readFd); 907 } 908 }; 909 writeThread.start(); 910 readThread.start(); 911 writeThread.join(1000); 912 readThread.join(1000); 913 assertFalse(writeThread.isAlive()); 914 if (compressErrors[0] != null) { 915 fail(compressErrors[0].toString()); 916 } 917 if (readThread.isAlive()) { 918 // Test failure, try to clean up 919 Os.close(writeFd); 920 readThread.join(500); 921 fail("Read timed out"); 922 } 923 assertValidFd("readFd", readFd); 924 assertValidFd("writeFd", writeFd); 925 Os.close(readFd); 926 Os.close(writeFd); 927 return decodedResult[0]; 928 } 929 assertValidFd(String name, FileDescriptor fd)930 private static void assertValidFd(String name, FileDescriptor fd) { 931 try { 932 assertTrue(fd.valid()); 933 // Hacky check to test that the underlying FD is still valid without using 934 // the private fcntlVoid to do F_GETFD 935 Os.close(Os.dup(fd)); 936 } catch (ErrnoException ex) { 937 fail(name + " is invalid: " + ex.getMessage()); 938 } 939 } 940 decodeConfigs(int id, int width, int height, boolean hasAlpha, boolean isGray)941 private void decodeConfigs(int id, int width, int height, boolean hasAlpha, boolean isGray) { 942 Options opts = new BitmapFactory.Options(); 943 opts.inScaled = false; 944 assertEquals(Config.ARGB_8888, opts.inPreferredConfig); 945 Bitmap reference = BitmapFactory.decodeResource(mRes, id, opts); 946 assertNotNull(reference); 947 assertEquals(width, reference.getWidth()); 948 assertEquals(height, reference.getHeight()); 949 assertEquals(Config.ARGB_8888, reference.getConfig()); 950 951 opts.inPreferredConfig = Config.ARGB_4444; 952 Bitmap argb4444 = BitmapFactory.decodeResource(mRes, id, opts); 953 assertNotNull(argb4444); 954 assertEquals(width, argb4444.getWidth()); 955 assertEquals(height, argb4444.getHeight()); 956 // ARGB_4444 is deprecated and we should decode to ARGB_8888. 957 assertEquals(Config.ARGB_8888, argb4444.getConfig()); 958 assertTrue(BitmapUtils.compareBitmaps(reference, argb4444)); 959 960 opts.inPreferredConfig = Config.RGB_565; 961 Bitmap rgb565 = BitmapFactory.decodeResource(mRes, id, opts); 962 assertNotNull(rgb565); 963 assertEquals(width, rgb565.getWidth()); 964 assertEquals(height, rgb565.getHeight()); 965 if (!hasAlpha) { 966 assertEquals(Config.RGB_565, rgb565.getConfig()); 967 // Convert the RGB_565 bitmap to ARGB_8888 and test that it is similar to 968 // the reference. We lose information when decoding to 565, so there must 969 // be some tolerance. The tolerance is intentionally loose to allow us some 970 // flexibility regarding if we dither and how we color convert. 971 BitmapUtils.assertBitmapsMse(reference, rgb565.copy(Config.ARGB_8888, false), 30, true, 972 true); 973 } 974 975 opts.inPreferredConfig = Config.ALPHA_8; 976 Bitmap alpha8 = BitmapFactory.decodeResource(mRes, id, opts); 977 assertNotNull(alpha8); 978 assertEquals(width, reference.getWidth()); 979 assertEquals(height, reference.getHeight()); 980 if (isGray) { 981 assertEquals(Config.ALPHA_8, alpha8.getConfig()); 982 // Convert the ALPHA_8 bitmap to ARGB_8888 and test that it is identical to 983 // the reference. We must do this manually because we are abusing ALPHA_8 984 // in order to represent grayscale. 985 assertTrue(BitmapUtils.compareBitmaps(reference, grayToARGB(alpha8))); 986 assertNull(alpha8.getColorSpace()); 987 } 988 989 // Setting inPreferredConfig to nullptr will cause the default Config to be 990 // selected, which in this case is ARGB_8888. 991 opts.inPreferredConfig = null; 992 Bitmap defaultBitmap = BitmapFactory.decodeResource(mRes, id, opts); 993 assertNotNull(defaultBitmap); 994 assertEquals(width, defaultBitmap.getWidth()); 995 assertEquals(height, defaultBitmap.getHeight()); 996 assertEquals(Config.ARGB_8888, defaultBitmap.getConfig()); 997 assertTrue(BitmapUtils.compareBitmaps(reference, defaultBitmap)); 998 } 999 grayToARGB(Bitmap gray)1000 private static Bitmap grayToARGB(Bitmap gray) { 1001 Bitmap argb = Bitmap.createBitmap(gray.getWidth(), gray.getHeight(), Config.ARGB_8888); 1002 for (int y = 0; y < argb.getHeight(); y++) { 1003 for (int x = 0; x < argb.getWidth(); x++) { 1004 int grayByte = Color.alpha(gray.getPixel(x, y)); 1005 argb.setPixel(x, y, Color.rgb(grayByte, grayByte, grayByte)); 1006 } 1007 } 1008 return argb; 1009 } 1010 1011 @Test 1012 @RequiresDevice testDecode10BitHEIF10BitBitmap()1013 public void testDecode10BitHEIF10BitBitmap() { 1014 assumeTrue("HEIF is not supported on this device, skip this test.", 1015 ImageDecoder.isMimeTypeSupported("image/heif")); 1016 assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder()); 1017 1018 Config expectedConfig = Config.RGBA_1010102; 1019 1020 // Even if the device advertises that 10 bits profile is supported, the output 1021 // format might not be CPU readable, but the video can still be displayed. When the 1022 // hevc decoder doesn't support YUVP010 format, and inPreferredConfig is RGBA_1010102, 1023 // then the color type of output falls back to RGBA_8888 automatically. 1024 if (!hasHEVCDecoderSupportsYUVP010()) { 1025 expectedConfig = Config.ARGB_8888; 1026 } 1027 1028 BitmapFactory.Options opt = new BitmapFactory.Options(); 1029 opt.inPreferredConfig = Config.RGBA_1010102; 1030 Bitmap bm = BitmapFactory.decodeStream(obtainInputStream(R.raw.heifimage_10bit), null, opt); 1031 assertNotNull(bm); 1032 assertEquals(4096, bm.getWidth()); 1033 assertEquals(3072, bm.getHeight()); 1034 assertEquals(expectedConfig, bm.getConfig()); 1035 } 1036 1037 @Test 1038 @CddTest(requirements = {"5.1.5/C-0-7"}) 1039 @RequiresDevice testDecode10BitAVIFTo10BitBitmap()1040 public void testDecode10BitAVIFTo10BitBitmap() { 1041 assumeTrue("AVIF is not supported on this device, skip this test.", 1042 ImageDecoder.isMimeTypeSupported("image/avif")); 1043 1044 BitmapFactory.Options opt = new BitmapFactory.Options(); 1045 opt.inPreferredConfig = Config.RGBA_1010102; 1046 Bitmap bm = BitmapFactory.decodeStream( 1047 obtainInputStream(R.raw.avif_yuv_420_10bit), null, opt); 1048 assertNotNull(bm); 1049 assertEquals(120, bm.getWidth()); 1050 assertEquals(160, bm.getHeight()); 1051 assertEquals(Config.RGBA_1010102, bm.getConfig()); 1052 } 1053 1054 @Test 1055 @RequiresDevice testDecode10BitHEIFTo8BitBitmap()1056 public void testDecode10BitHEIFTo8BitBitmap() { 1057 assumeTrue("HEIF is not supported on this device, skip this test.", 1058 ImageDecoder.isMimeTypeSupported("image/heif")); 1059 assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder()); 1060 1061 // When device does not support P010 color type of output is RGBA_8888 when decoding 10-bit 1062 // heif, and this behavior is tested in testDecode10BitHEIF10BitBitmap. So skipping this 1063 // test when P010 is not supported. 1064 assumeTrue("No HEVC decoder that supports YUVP010, skip the test.", 1065 hasHEVCDecoderSupportsYUVP010()); 1066 1067 BitmapFactory.Options opt = new BitmapFactory.Options(); 1068 opt.inPreferredConfig = Config.ARGB_8888; 1069 Bitmap bm1 = 1070 BitmapFactory.decodeStream(obtainInputStream(R.raw.heifimage_10bit), null, opt); 1071 Bitmap bm2 = BitmapFactory.decodeStream(obtainInputStream(R.raw.heifimage_10bit)); 1072 assertNotNull(bm1); 1073 assertEquals(4096, bm1.getWidth()); 1074 assertEquals(3072, bm1.getHeight()); 1075 assertEquals(Config.RGBA_1010102, bm1.getConfig()); 1076 assertNotNull(bm2); 1077 assertEquals(4096, bm2.getWidth()); 1078 assertEquals(3072, bm2.getHeight()); 1079 assertEquals(Config.RGBA_1010102, bm2.getConfig()); 1080 } 1081 1082 @Test 1083 @CddTest(requirements = {"5.1.5/C-0-7"}) 1084 @RequiresDevice testDecode10BitAVIFTo8BitBitmap()1085 public void testDecode10BitAVIFTo8BitBitmap() { 1086 assumeTrue("AVIF is not supported on this device, skip this test.", 1087 ImageDecoder.isMimeTypeSupported("image/avif")); 1088 1089 BitmapFactory.Options opt = new BitmapFactory.Options(); 1090 opt.inPreferredConfig = Config.ARGB_8888; 1091 Bitmap bm1 = 1092 BitmapFactory.decodeStream(obtainInputStream(R.raw.avif_yuv_420_10bit), null, opt); 1093 Bitmap bm2 = BitmapFactory.decodeStream(obtainInputStream(R.raw.avif_yuv_420_10bit)); 1094 assertNotNull(bm1); 1095 assertEquals(120, bm1.getWidth()); 1096 assertEquals(160, bm1.getHeight()); 1097 assertEquals(Config.RGBA_1010102, bm1.getConfig()); 1098 assertNotNull(bm2); 1099 assertEquals(120, bm2.getWidth()); 1100 assertEquals(160, bm2.getHeight()); 1101 assertEquals(Config.RGBA_1010102, bm2.getConfig()); 1102 } 1103 1104 @Test 1105 @RequiresDevice testDecode8BitHEIFTo10BitBitmap()1106 public void testDecode8BitHEIFTo10BitBitmap() { 1107 if (!ImageDecoder.isMimeTypeSupported("image/heif")) { 1108 return; 1109 } 1110 BitmapFactory.Options opt = new BitmapFactory.Options(); 1111 opt.inPreferredConfig = Config.RGBA_1010102; 1112 Bitmap bm1 = 1113 BitmapFactory.decodeStream(obtainInputStream(R.raw.heifwriter_input), null, opt); 1114 Bitmap bm2 = BitmapFactory.decodeStream(obtainInputStream(R.raw.heifwriter_input)); 1115 assertNotNull(bm1); 1116 assertEquals(1920, bm1.getWidth()); 1117 assertEquals(1080, bm1.getHeight()); 1118 assertEquals(Config.ARGB_8888, bm1.getConfig()); 1119 assertNotNull(bm2); 1120 assertEquals(1920, bm2.getWidth()); 1121 assertEquals(1080, bm2.getHeight()); 1122 assertEquals(Config.ARGB_8888, bm2.getConfig()); 1123 } 1124 1125 @Test 1126 @CddTest(requirements = {"5.1.5/C-0-7"}) 1127 @RequiresDevice testDecode8BitAVIFTo10BitBitmap()1128 public void testDecode8BitAVIFTo10BitBitmap() { 1129 assumeTrue("AVIF is not supported on this device, skip this test.", 1130 ImageDecoder.isMimeTypeSupported("image/avif")); 1131 1132 BitmapFactory.Options opt = new BitmapFactory.Options(); 1133 opt.inPreferredConfig = Config.RGBA_1010102; 1134 Bitmap bm1 = 1135 BitmapFactory.decodeStream(obtainInputStream(R.raw.avif_yuv_420_8bit), null, opt); 1136 Bitmap bm2 = BitmapFactory.decodeStream(obtainInputStream(R.raw.avif_yuv_420_8bit)); 1137 assertNotNull(bm1); 1138 assertEquals(120, bm1.getWidth()); 1139 assertEquals(160, bm1.getHeight()); 1140 assertEquals(Config.ARGB_8888, bm1.getConfig()); 1141 assertNotNull(bm2); 1142 assertEquals(120, bm2.getWidth()); 1143 assertEquals(160, bm2.getHeight()); 1144 assertEquals(Config.ARGB_8888, bm2.getConfig()); 1145 } 1146 1147 @Test testAssertionFromColorSpace()1148 public void testAssertionFromColorSpace() { 1149 BitmapFactory.Options opt = new BitmapFactory.Options(); 1150 Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.b198155681, opt); 1151 assertNotNull(b); 1152 assertNull(opt.outColorSpace); 1153 } 1154 obtainArray()1155 private byte[] obtainArray() { 1156 ByteArrayOutputStream stm = new ByteArrayOutputStream(); 1157 Options opt = new BitmapFactory.Options(); 1158 opt.inScaled = false; 1159 Bitmap bitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, opt); 1160 bitmap.compress(Bitmap.CompressFormat.JPEG, 0, stm); 1161 return(stm.toByteArray()); 1162 } 1163 obtainInputStream()1164 private InputStream obtainInputStream() { 1165 return mRes.openRawResource(R.drawable.start); 1166 } 1167 obtainInputStream(int resId)1168 private InputStream obtainInputStream(int resId) { 1169 return mRes.openRawResource(resId); 1170 } 1171 obtainParcelDescriptor(String path)1172 private static ParcelFileDescriptor obtainParcelDescriptor(String path) throws IOException { 1173 File file = new File(path); 1174 return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); 1175 } 1176 obtainPath()1177 private String obtainPath() throws IOException { 1178 return Utils.obtainPath(R.drawable.start, 0); 1179 } 1180 has10BitHEVCDecoder()1181 private static boolean has10BitHEVCDecoder() { 1182 MediaFormat format = new MediaFormat(); 1183 format.setString(MediaFormat.KEY_MIME, "video/hevc"); 1184 format.setInteger( 1185 MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10); 1186 format.setInteger( 1187 MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.HEVCMainTierLevel5); 1188 1189 MediaCodecList mcl = new MediaCodecList(MediaCodecList.ALL_CODECS); 1190 if (mcl.findDecoderForFormat(format) == null) { 1191 return false; 1192 } 1193 return true; 1194 } 1195 hasHEVCDecoderSupportsYUVP010()1196 private static boolean hasHEVCDecoderSupportsYUVP010() { 1197 MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS); 1198 for (MediaCodecInfo mediaCodecInfo : codecList.getCodecInfos()) { 1199 if (mediaCodecInfo.isEncoder()) { 1200 continue; 1201 } 1202 for (String mediaType : mediaCodecInfo.getSupportedTypes()) { 1203 if (mediaType.equalsIgnoreCase("video/hevc")) { 1204 MediaCodecInfo.CodecCapabilities codecCapabilities = 1205 mediaCodecInfo.getCapabilitiesForType(mediaType); 1206 for (int i = 0; i < codecCapabilities.colorFormats.length; ++i) { 1207 if (codecCapabilities.colorFormats[i] 1208 == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010) { 1209 return true; 1210 } 1211 } 1212 } 1213 } 1214 } 1215 return false; 1216 } 1217 } 1218