1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.O; 4 import static android.os.Build.VERSION_CODES.S; 5 import static com.google.common.truth.Truth.assertThat; 6 import static org.robolectric.Shadows.shadowOf; 7 8 import android.graphics.Bitmap; 9 import android.graphics.Canvas; 10 import android.graphics.Color; 11 import android.graphics.ColorMatrix; 12 import android.graphics.ColorMatrixColorFilter; 13 import android.graphics.Matrix; 14 import android.graphics.Paint; 15 import android.graphics.Rect; 16 import android.os.Parcel; 17 import android.util.DisplayMetrics; 18 import androidx.test.ext.junit.runners.AndroidJUnit4; 19 import java.io.ByteArrayOutputStream; 20 import java.nio.ByteBuffer; 21 import java.nio.IntBuffer; 22 import java.nio.LongBuffer; 23 import java.nio.ShortBuffer; 24 import java.util.Arrays; 25 import org.junit.Test; 26 import org.junit.runner.RunWith; 27 import org.robolectric.Shadows; 28 import org.robolectric.annotation.Config; 29 import org.robolectric.annotation.GraphicsMode; 30 import org.robolectric.annotation.GraphicsMode.Mode; 31 import org.robolectric.shadow.api.Shadow; 32 33 @RunWith(AndroidJUnit4.class) 34 @GraphicsMode(Mode.LEGACY) 35 public class ShadowBitmapTest { 36 @Test shouldCreateScaledBitmap()37 public void shouldCreateScaledBitmap() { 38 Bitmap originalBitmap = create("Original bitmap"); 39 Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, 100, 200, false); 40 assertThat(shadowOf(scaledBitmap).getDescription()) 41 .isEqualTo("Original bitmap scaled to 100 x 200"); 42 assertThat(scaledBitmap.getWidth()).isEqualTo(100); 43 assertThat(scaledBitmap.getHeight()).isEqualTo(200); 44 scaledBitmap.getPixels(new int[20000], 0, 0, 0, 0, 100, 200); 45 } 46 47 @Test createScaledBitmap_succeedForLargeBitmapWithFilter()48 public void createScaledBitmap_succeedForLargeBitmapWithFilter() { 49 createScaledBitmap_succeedForLargeBitmap(true); 50 } 51 52 @Test createScaledBitmap_succeedForLargeBitmapWithoutFilter()53 public void createScaledBitmap_succeedForLargeBitmapWithoutFilter() { 54 createScaledBitmap_succeedForLargeBitmap(false); 55 } 56 57 @Test createScaledBitmap_modifiesPixelsWithFilter()58 public void createScaledBitmap_modifiesPixelsWithFilter() { 59 createScaledBitmap_modifiesPixels(true); 60 } 61 62 @Test createScaledBitmap_modifiesPixelsWithoutFilter()63 public void createScaledBitmap_modifiesPixelsWithoutFilter() { 64 createScaledBitmap_modifiesPixels(false); 65 } 66 67 @Test createScaledBitmap_expectedUpSizeWithFilter()68 public void createScaledBitmap_expectedUpSizeWithFilter() { 69 createScaledBitmap_expectedUpSize(true); 70 } 71 72 @Test createScaledBitmap_expectedUpSizeWithoutFilter()73 public void createScaledBitmap_expectedUpSizeWithoutFilter() { 74 createScaledBitmap_expectedUpSize(false); 75 } 76 77 @Test createScaledBitmap_expectedDownSizeWithFilter()78 public void createScaledBitmap_expectedDownSizeWithFilter() { 79 createScaledBitmap_expectedDownSize(true); 80 } 81 82 @Test createScaledBitmap_expectedDownSizeWithoutFilter()83 public void createScaledBitmap_expectedDownSizeWithoutFilter() { 84 createScaledBitmap_expectedDownSize(false); 85 } 86 87 @Test createScaledBitmap_drawOnScaledWithFilter()88 public void createScaledBitmap_drawOnScaledWithFilter() { 89 createScaledBitmap_drawOnScaled(true); 90 } 91 92 @Test createScaledBitmap_drawOnScaledWithoutFilter()93 public void createScaledBitmap_drawOnScaledWithoutFilter() { 94 createScaledBitmap_drawOnScaled(false); 95 } 96 97 @Test shouldCreateActiveBitmap()98 public void shouldCreateActiveBitmap() { 99 Bitmap bitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 100 assertThat(bitmap.isRecycled()).isFalse(); 101 assertThat(bitmap.getPixel(0, 0)).isEqualTo(0); 102 assertThat(bitmap.getWidth()).isEqualTo(100); 103 assertThat(bitmap.getHeight()).isEqualTo(200); 104 assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ARGB_8888); 105 } 106 107 @Test hasAlpha()108 public void hasAlpha() { 109 Bitmap bitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 110 assertThat(bitmap.hasAlpha()).isTrue(); 111 bitmap.setHasAlpha(false); 112 assertThat(bitmap.hasAlpha()).isFalse(); 113 } 114 115 @Test hasMipmap()116 public void hasMipmap() { 117 Bitmap bitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 118 assertThat(bitmap.hasMipMap()).isFalse(); 119 bitmap.setHasMipMap(true); 120 assertThat(bitmap.hasMipMap()).isTrue(); 121 } 122 123 @Test getAllocationByteCount()124 public void getAllocationByteCount() { 125 Bitmap bitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 126 assertThat(bitmap.getAllocationByteCount()).isGreaterThan(0); 127 } 128 129 @Test shouldCreateBitmapWithColors()130 public void shouldCreateBitmapWithColors() { 131 int[] colors = 132 new int[] { 133 Color.parseColor("#ff0000"), Color.parseColor("#00ff00"), Color.parseColor("#0000ff"), 134 Color.parseColor("#990000"), Color.parseColor("#009900"), Color.parseColor("#000099") 135 }; 136 Bitmap bitmap = Bitmap.createBitmap(colors, 3, 2, Bitmap.Config.ARGB_8888); 137 assertThat(bitmap.getWidth()).isEqualTo(3); 138 assertThat(bitmap.getHeight()).isEqualTo(2); 139 assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ARGB_8888); 140 assertThat(bitmap.getPixel(0, 0)).isEqualTo(Color.parseColor("#ff0000")); 141 assertThat(bitmap.getPixel(0, 1)).isEqualTo(Color.parseColor("#990000")); 142 assertThat(bitmap.getPixel(1, 0)).isEqualTo(Color.parseColor("#00ff00")); 143 assertThat(bitmap.getPixel(1, 1)).isEqualTo(Color.parseColor("#009900")); 144 assertThat(bitmap.getPixel(2, 0)).isEqualTo(Color.parseColor("#0000ff")); 145 assertThat(bitmap.getPixel(2, 1)).isEqualTo(Color.parseColor("#000099")); 146 } 147 148 @Test shouldCreateBitmapWithMatrix()149 public void shouldCreateBitmapWithMatrix() { 150 Bitmap originalBitmap = create("Original bitmap"); 151 ((ShadowLegacyBitmap) Shadow.extract(originalBitmap)).setWidth(200); 152 ((ShadowLegacyBitmap) Shadow.extract(originalBitmap)).setHeight(200); 153 Matrix m = new Matrix(); 154 m.postRotate(90); 155 Bitmap newBitmap = Bitmap.createBitmap(originalBitmap, 0, 0, 100, 50, m, true); 156 157 ShadowLegacyBitmap shadowBitmap = Shadow.extract(newBitmap); 158 assertThat(shadowBitmap.getDescription()) 159 .isEqualTo( 160 "Original bitmap at (0,0) with width 100 and height 50" 161 + " using matrix Matrix[pre=[], set={}, post=[rotate 90.0]] with filter"); 162 assertThat(shadowBitmap.getCreatedFromBitmap()).isEqualTo(originalBitmap); 163 assertThat(shadowBitmap.getCreatedFromX()).isEqualTo(0); 164 assertThat(shadowBitmap.getCreatedFromY()).isEqualTo(0); 165 assertThat(shadowBitmap.getCreatedFromWidth()).isEqualTo(100); 166 assertThat(shadowBitmap.getCreatedFromHeight()).isEqualTo(50); 167 assertThat(shadowBitmap.getCreatedFromMatrix()).isEqualTo(m); 168 assertThat(shadowBitmap.getCreatedFromFilter()).isEqualTo(true); 169 assertThat(shadowBitmap.getWidth()).isEqualTo(50); 170 assertThat(shadowBitmap.getHeight()).isEqualTo(100); 171 } 172 173 @Test shouldCreateMutableBitmap()174 public void shouldCreateMutableBitmap() { 175 Bitmap mutableBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 176 assertThat(mutableBitmap.isMutable()).isTrue(); 177 } 178 179 @Test shouldCreateMutableBitmapWithDisplayMetrics()180 public void shouldCreateMutableBitmapWithDisplayMetrics() { 181 final DisplayMetrics metrics = new DisplayMetrics(); 182 metrics.densityDpi = 1000; 183 184 final Bitmap bitmap = Bitmap.createBitmap(metrics, 100, 100, Bitmap.Config.ARGB_8888); 185 assertThat(bitmap.isMutable()).isTrue(); 186 assertThat(bitmap.getDensity()).isEqualTo(1000); 187 } 188 189 @Test shouldRecycleBitmap()190 public void shouldRecycleBitmap() { 191 Bitmap bitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 192 bitmap.recycle(); 193 assertThat(bitmap.isRecycled()).isTrue(); 194 } 195 196 @Test shouldReceiveDescriptionWhenDrawingToCanvas()197 public void shouldReceiveDescriptionWhenDrawingToCanvas() { 198 Bitmap bitmap1 = create("Bitmap One"); 199 Bitmap bitmap2 = create("Bitmap Two"); 200 201 Canvas canvas = new Canvas(bitmap1); 202 canvas.drawBitmap(bitmap2, 0, 0, null); 203 204 assertThat(shadowOf(bitmap1).getDescription()).isEqualTo("Bitmap One\nBitmap Two"); 205 } 206 207 @Test shouldReceiveDescriptionWhenDrawingToCanvasWithBitmapAndMatrixAndPaint()208 public void shouldReceiveDescriptionWhenDrawingToCanvasWithBitmapAndMatrixAndPaint() { 209 Bitmap bitmap1 = create("Bitmap One"); 210 Bitmap bitmap2 = create("Bitmap Two"); 211 212 Canvas canvas = new Canvas(bitmap1); 213 canvas.drawBitmap(bitmap2, new Matrix(), null); 214 215 assertThat(shadowOf(bitmap1).getDescription()) 216 .isEqualTo("Bitmap One\nBitmap Two transformed by Matrix[pre=[], set={}, post=[]]"); 217 } 218 219 @Test shouldReceiveDescriptionWhenDrawABitmapToCanvasWithAPaintEffect()220 public void shouldReceiveDescriptionWhenDrawABitmapToCanvasWithAPaintEffect() { 221 Bitmap bitmap1 = create("Bitmap One"); 222 Bitmap bitmap2 = create("Bitmap Two"); 223 224 Canvas canvas = new Canvas(bitmap1); 225 Paint paint = new Paint(); 226 paint.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix())); 227 canvas.drawBitmap(bitmap2, new Matrix(), paint); 228 229 assertThat(shadowOf(bitmap1).getDescription()) 230 .isEqualTo( 231 "Bitmap One\n" 232 + "Bitmap Two with ColorMatrixColorFilter" 233 + " transformed by Matrix[pre=[], set={}, post=[]]"); 234 } 235 236 @Test visualize_shouldReturnDescription()237 public void visualize_shouldReturnDescription() { 238 Bitmap bitmap = create("Bitmap One"); 239 assertThat(ShadowBitmap.visualize(bitmap)).isEqualTo("Bitmap One"); 240 } 241 242 @Test shouldCopyBitmap()243 public void shouldCopyBitmap() { 244 Bitmap bitmap = Shadow.newInstanceOf(Bitmap.class); 245 Bitmap bitmapCopy = bitmap.copy(Bitmap.Config.ARGB_8888, true); 246 assertThat(bitmapCopy.getConfig()).isEqualTo(Bitmap.Config.ARGB_8888); 247 assertThat(bitmapCopy.isMutable()).isTrue(); 248 } 249 250 @Test(expected = NullPointerException.class) rowBytesIsAccurate()251 public void rowBytesIsAccurate() { 252 Bitmap b1 = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 253 assertThat(b1.getRowBytes()).isEqualTo(40); 254 Bitmap b2 = Bitmap.createBitmap(10, 10, Bitmap.Config.RGB_565); 255 assertThat(b2.getRowBytes()).isEqualTo(20); 256 257 // Null Bitmap.Config is not allowed. 258 Bitmap b3 = Bitmap.createBitmap(10, 10, null); 259 b3.getRowBytes(); 260 } 261 262 @Test(expected = NullPointerException.class) byteCountIsAccurate()263 public void byteCountIsAccurate() { 264 Bitmap b1 = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 265 assertThat(b1.getByteCount()).isEqualTo(400); 266 Bitmap b2 = Bitmap.createBitmap(10, 10, Bitmap.Config.RGB_565); 267 assertThat(b2.getByteCount()).isEqualTo(200); 268 269 // Null Bitmap.Config is not allowed. 270 Bitmap b3 = Bitmap.createBitmap(10, 10, null); 271 b3.getByteCount(); 272 } 273 274 @Test shouldSetDensity()275 public void shouldSetDensity() { 276 final Bitmap bitmap = 277 Bitmap.createBitmap(new DisplayMetrics(), 100, 100, Bitmap.Config.ARGB_8888); 278 bitmap.setDensity(1000); 279 assertThat(bitmap.getDensity()).isEqualTo(1000); 280 } 281 282 @Test shouldSetPixel()283 public void shouldSetPixel() { 284 Bitmap bitmap = Bitmap.createBitmap(new int[] {1}, 1, 1, Bitmap.Config.ARGB_8888); 285 shadowOf(bitmap).setMutable(true); 286 bitmap.setPixel(0, 0, 2); 287 assertThat(bitmap.getPixel(0, 0)).isEqualTo(2); 288 assertThat(shadowOf(bitmap).getCreatedFromColors()).isEqualTo(new int[] {1}); 289 } 290 291 @Test shouldSetPixel_allocateOnTheFly()292 public void shouldSetPixel_allocateOnTheFly() { 293 Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 294 shadowOf(bitmap).setMutable(true); 295 bitmap.setPixel(0, 0, 2); 296 assertThat(bitmap.getPixel(0, 0)).isEqualTo(2); 297 assertThat(shadowOf(bitmap).getCreatedFromColors()).isNull(); 298 } 299 300 @Test testGetPixels()301 public void testGetPixels() { 302 // Create a dummy bitmap. 303 Bitmap bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 304 for (int y = 0; y < bmp.getHeight(); ++y) { 305 for (int x = 0; x < bmp.getWidth(); ++x) { 306 bmp.setPixel(x, y, packRGB(x, y, 0)); 307 } 308 } 309 310 // Use getPixels to get pixels as an array (getPixels was the missing Shadowed Function). 311 int[] pixels = new int[bmp.getWidth() * bmp.getHeight()]; 312 bmp.getPixels(pixels, 0, bmp.getWidth(), 0, 0, bmp.getWidth(), bmp.getHeight()); 313 314 // Every entry should match regardless of accessing it by getPixel vs getPixels. 315 for (int y = 0; y < bmp.getHeight(); ++y) { 316 for (int x = 0; x < bmp.getWidth(); ++x) { 317 assertThat(bmp.getPixel(x, y)).isEqualTo(pixels[y * bmp.getWidth() + x]); 318 } 319 } 320 } 321 322 @Test(expected = IllegalStateException.class) shouldThrowExceptionForSetPixelOnImmutableBitmap()323 public void shouldThrowExceptionForSetPixelOnImmutableBitmap() { 324 Bitmap bitmap = Bitmap.createBitmap(new int[] {1}, 1, 1, Bitmap.Config.ARGB_8888); 325 bitmap.setPixel(0, 0, 2); 326 } 327 328 @Test(expected = IllegalStateException.class) shouldThrowExceptionForSetPixelsOnImmutableBitmap()329 public void shouldThrowExceptionForSetPixelsOnImmutableBitmap() { 330 Bitmap bitmap = Bitmap.createBitmap(new int[] {1}, 1, 1, Bitmap.Config.ARGB_8888); 331 bitmap.setPixels(new int[] {1}, 0, 0, 0, 0, 1, 1); 332 } 333 334 @Test bitmapsAreReused()335 public void bitmapsAreReused() { 336 Bitmap b = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 337 Bitmap b1 = Bitmap.createBitmap(b, 0, 0, 10, 10); 338 assertThat(b1).isSameInstanceAs(b); 339 Bitmap b2 = Bitmap.createBitmap(b, 0, 0, 10, 10, null, false); 340 assertThat(b2).isSameInstanceAs(b); 341 Bitmap b3 = Bitmap.createScaledBitmap(b, 10, 10, false); 342 assertThat(b3).isSameInstanceAs(b); 343 } 344 345 @Test equalsSizeTransformReturnsOriginal()346 public void equalsSizeTransformReturnsOriginal() { 347 Bitmap b1 = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 348 Bitmap b2 = Bitmap.createBitmap(b1, 0, 0, 10, 10, null, false); 349 assertThat(b1).isSameInstanceAs(b2); 350 Bitmap b3 = Bitmap.createBitmap(b1, 0, 0, 10, 10, null, true); 351 assertThat(b1).isSameInstanceAs(b3); 352 } 353 354 @Test(expected = IllegalArgumentException.class) throwsExceptionForInvalidDimensions()355 public void throwsExceptionForInvalidDimensions() { 356 Bitmap b = Bitmap.createBitmap(10, 20, Bitmap.Config.ARGB_8888); 357 Bitmap.createBitmap(b, 0, 0, 20, 10, null, false); 358 } 359 360 @Test(expected = IllegalArgumentException.class) throwsExceptionForNegativeWidth()361 public void throwsExceptionForNegativeWidth() { 362 Bitmap.createBitmap(-100, 10, Bitmap.Config.ARGB_8888); 363 } 364 365 @Test(expected = IllegalArgumentException.class) throwsExceptionForZeroHeight()366 public void throwsExceptionForZeroHeight() { 367 Bitmap.createBitmap(100, 0, Bitmap.Config.ARGB_8888); 368 } 369 370 @Test shouldGetPixelsFromAnyNonNullableCreatedBitmap()371 public void shouldGetPixelsFromAnyNonNullableCreatedBitmap() { 372 Bitmap bitmap; 373 int width = 10; 374 int height = 10; 375 376 int[] pixels = new int[width * height]; 377 bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 378 bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 379 380 bitmap = Bitmap.createBitmap(bitmap); 381 bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 382 383 bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height); 384 bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 385 386 bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, new Matrix(), false); 387 bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 388 389 bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 390 bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 391 392 bitmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); 393 bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 394 } 395 396 @Test shouldGetPixelsFromSubsetOfBitmap()397 public void shouldGetPixelsFromSubsetOfBitmap() { 398 int width = 10; 399 int height = 10; 400 Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 401 int offset = 7; 402 int subWidth = 3; 403 int subHeight = 4; 404 int x = 2; 405 int y = 5; 406 407 // Fill a region of the bitmap with increasing redness. 408 int r = 0; 409 for (int y0 = y; y0 < y + subHeight; y0++) { 410 for (int x0 = x; x0 < x + subWidth; x0++) { 411 bitmap.setPixel(x0, y0, packRGB(r++, 0, 0)); 412 } 413 } 414 415 // Get the pixels from that region. 416 int[] pixels = new int[offset + subWidth * subHeight]; 417 bitmap.getPixels(pixels, offset, subWidth, x, y, subWidth, subHeight); 418 419 // Verify that pixels contains the expected colors. 420 r = 0; 421 int index = offset; 422 for (int y0 = 0; y0 < subHeight; y0++) { 423 for (int x0 = 0; x0 < subWidth; x0++) { 424 assertThat(pixels[index++]).isEqualTo(packRGB(r++, 0, 0)); 425 } 426 } 427 } 428 429 @Test shouldAdjustDimensionsForMatrix()430 public void shouldAdjustDimensionsForMatrix() { 431 Bitmap transformedBitmap; 432 int width = 10; 433 int height = 20; 434 435 Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 436 Matrix matrix = new Matrix(); 437 transformedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false); 438 assertThat(transformedBitmap.getWidth()).isEqualTo(width); 439 assertThat(transformedBitmap.getHeight()).isEqualTo(height); 440 441 matrix.setRotate(90); 442 transformedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false); 443 assertThat(transformedBitmap.getWidth()).isEqualTo(height); 444 assertThat(transformedBitmap.getHeight()).isEqualTo(width); 445 446 matrix.setScale(2, 3); 447 transformedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false); 448 assertThat(transformedBitmap.getWidth()).isEqualTo(width * 2); 449 assertThat(transformedBitmap.getHeight()).isEqualTo(height * 3); 450 } 451 452 @Test shouldWriteToParcelAndReconstruct()453 public void shouldWriteToParcelAndReconstruct() { 454 Bitmap bitmapOriginal; 455 int originalWidth = 10; 456 int originalHeight = 10; 457 458 bitmapOriginal = Bitmap.createBitmap(originalWidth, originalHeight, Bitmap.Config.ARGB_8888); 459 460 Parcel parcel = Parcel.obtain(); 461 bitmapOriginal.writeToParcel(parcel, 0); 462 463 parcel.setDataPosition(0); 464 465 Bitmap bitmapReconstructed = Bitmap.CREATOR.createFromParcel(parcel); 466 467 // get reconstructed properties 468 int reconstructedHeight = bitmapReconstructed.getHeight(); 469 int reconstructedWidth = bitmapReconstructed.getWidth(); 470 471 // compare bitmap properties 472 assertThat(originalHeight).isEqualTo(reconstructedHeight); 473 assertThat(originalWidth).isEqualTo(reconstructedWidth); 474 assertThat(bitmapOriginal.getConfig()).isEqualTo(bitmapReconstructed.getConfig()); 475 476 int[] pixelsOriginal = new int[originalWidth * originalHeight]; 477 bitmapOriginal.getPixels(pixelsOriginal, 0, originalWidth, 0, 0, originalWidth, originalHeight); 478 479 int[] pixelsReconstructed = new int[reconstructedWidth * reconstructedHeight]; 480 bitmapReconstructed.getPixels( 481 pixelsReconstructed, 0, reconstructedWidth, 0, 0, reconstructedWidth, reconstructedHeight); 482 483 assertThat(Arrays.equals(pixelsOriginal, pixelsReconstructed)).isTrue(); 484 } 485 486 @Test shouldCopyPixelsToBufferAndReconstruct()487 public void shouldCopyPixelsToBufferAndReconstruct() { 488 int width = 10; 489 int height = 10; 490 491 Bitmap bitmapOriginal = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 492 bitmapOriginal.setPixel(0, 0, 123); 493 bitmapOriginal.setPixel(1, 1, 456); 494 bitmapOriginal.setPixel(2, 2, 789); 495 int[] pixelsOriginal = new int[width * height]; 496 bitmapOriginal.getPixels(pixelsOriginal, 0, width, 0, 0, width, height); 497 498 ByteBuffer buffer = ByteBuffer.allocate(bitmapOriginal.getByteCount()); 499 bitmapOriginal.copyPixelsToBuffer(buffer); 500 assertThat(buffer.position()).isEqualTo(bitmapOriginal.getByteCount()); 501 502 buffer.rewind(); 503 Bitmap bitmapReconstructed = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 504 // Set some random pixels to ensure that they're properly overwritten. 505 bitmapReconstructed.setPixel(1, 1, 999); 506 bitmapReconstructed.setPixel(4, 4, 999); 507 bitmapReconstructed.copyPixelsFromBuffer(buffer); 508 assertThat(buffer.position()).isEqualTo(bitmapOriginal.getByteCount()); 509 510 assertThat(bitmapReconstructed.getPixel(0, 0)).isEqualTo(123); 511 assertThat(bitmapReconstructed.getPixel(1, 1)).isEqualTo(456); 512 assertThat(bitmapReconstructed.getPixel(2, 2)).isEqualTo(789); 513 514 int[] pixelsReconstructed = new int[width * height]; 515 bitmapReconstructed.getPixels(pixelsReconstructed, 0, width, 0, 0, width, height); 516 assertThat(Arrays.equals(pixelsOriginal, pixelsReconstructed)).isTrue(); 517 } 518 519 @Test compress_shouldLessThanBeforeForWebp()520 public void compress_shouldLessThanBeforeForWebp() { 521 Bitmap bitmap = Bitmap.createBitmap(400, 200, Bitmap.Config.ARGB_8888); 522 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 523 bitmap.compress(Bitmap.CompressFormat.WEBP, 75, stream); 524 byte[] compressedImageByteArray = stream.toByteArray(); 525 assertThat(compressedImageByteArray.length).isLessThan(bitmap.getByteCount()); 526 } 527 528 @Test compress_shouldSucceedForNullPixelData()529 public void compress_shouldSucceedForNullPixelData() { 530 Bitmap bitmap = Shadow.newInstanceOf(Bitmap.class); 531 ShadowLegacyBitmap shadowBitmap = Shadow.extract(bitmap); 532 shadowBitmap.setWidth(100); 533 shadowBitmap.setHeight(100); 534 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 535 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream); 536 } 537 538 @Config(sdk = O) 539 @Test getBytesPerPixel_O()540 public void getBytesPerPixel_O() { 541 assertThat(ShadowLegacyBitmap.getBytesPerPixel(Bitmap.Config.RGBA_F16)).isEqualTo(8); 542 } 543 544 @Test getBytesPerPixel_preO()545 public void getBytesPerPixel_preO() { 546 assertThat(ShadowLegacyBitmap.getBytesPerPixel(Bitmap.Config.ARGB_8888)).isEqualTo(4); 547 assertThat(ShadowLegacyBitmap.getBytesPerPixel(Bitmap.Config.RGB_565)).isEqualTo(2); 548 assertThat(ShadowLegacyBitmap.getBytesPerPixel(Bitmap.Config.ARGB_4444)).isEqualTo(2); 549 assertThat(ShadowLegacyBitmap.getBytesPerPixel(Bitmap.Config.ALPHA_8)).isEqualTo(1); 550 } 551 552 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsToShortBuffer()553 public void throwsExceptionCopyPixelsToShortBuffer() { 554 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 555 ShortBuffer buffer = ShortBuffer.allocate(bitmapOriginal.getByteCount()); 556 bitmapOriginal.copyPixelsToBuffer(buffer); 557 } 558 559 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsToLongBuffer()560 public void throwsExceptionCopyPixelsToLongBuffer() { 561 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 562 LongBuffer buffer = LongBuffer.allocate(bitmapOriginal.getByteCount()); 563 bitmapOriginal.copyPixelsToBuffer(buffer); 564 } 565 566 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsToBufferTooSmall()567 public void throwsExceptionCopyPixelsToBufferTooSmall() { 568 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 569 ByteBuffer buffer = ByteBuffer.allocate(bitmapOriginal.getByteCount() - 1); 570 bitmapOriginal.copyPixelsToBuffer(buffer); 571 } 572 573 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsToBufferNonArgb8888()574 public void throwsExceptionCopyPixelsToBufferNonArgb8888() { 575 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_4444); 576 ByteBuffer buffer = ByteBuffer.allocate(bitmapOriginal.getByteCount()); 577 bitmapOriginal.copyPixelsToBuffer(buffer); 578 } 579 580 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsFromShortBuffer()581 public void throwsExceptionCopyPixelsFromShortBuffer() { 582 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 583 ShortBuffer buffer = ShortBuffer.allocate(bitmapOriginal.getByteCount()); 584 bitmapOriginal.copyPixelsFromBuffer(buffer); 585 } 586 587 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsFromIntBufferTooSmall()588 public void throwsExceptionCopyPixelsFromIntBufferTooSmall() { 589 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 590 IntBuffer buffer = 591 IntBuffer.allocate(bitmapOriginal.getWidth() * bitmapOriginal.getHeight() - 1); 592 bitmapOriginal.copyPixelsFromBuffer(buffer); 593 } 594 595 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsFromLongBuffer()596 public void throwsExceptionCopyPixelsFromLongBuffer() { 597 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 598 LongBuffer buffer = LongBuffer.allocate(bitmapOriginal.getByteCount()); 599 bitmapOriginal.copyPixelsFromBuffer(buffer); 600 } 601 602 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsFromBufferTooSmall()603 public void throwsExceptionCopyPixelsFromBufferTooSmall() { 604 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 605 ByteBuffer buffer = ByteBuffer.allocate(bitmapOriginal.getByteCount() - 1); 606 bitmapOriginal.copyPixelsFromBuffer(buffer); 607 } 608 609 @Test(expected = RuntimeException.class) throwsExceptionCopyPixelsFromBufferNonArgb8888()610 public void throwsExceptionCopyPixelsFromBufferNonArgb8888() { 611 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_4444); 612 ByteBuffer buffer = ByteBuffer.allocate(bitmapOriginal.getByteCount()); 613 bitmapOriginal.copyPixelsFromBuffer(buffer); 614 } 615 616 @Test(expected = IllegalStateException.class) throwsExceptionCopyPixelsFromBufferRecycled()617 public void throwsExceptionCopyPixelsFromBufferRecycled() { 618 Bitmap bitmapOriginal = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 619 ByteBuffer buffer = ByteBuffer.allocate(bitmapOriginal.getByteCount()); 620 bitmapOriginal.recycle(); 621 bitmapOriginal.copyPixelsFromBuffer(buffer); 622 } 623 624 @Test reconfigure_withArgb8888Bitmap_validDimensionsAndConfig_doesNotThrow()625 public void reconfigure_withArgb8888Bitmap_validDimensionsAndConfig_doesNotThrow() { 626 Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 627 original.reconfigure(100, 100, Bitmap.Config.ARGB_8888); 628 } 629 630 @Config(sdk = O) 631 @Test(expected = IllegalStateException.class) reconfigure_withHardwareBitmap_validDimensionsAndConfig_throws()632 public void reconfigure_withHardwareBitmap_validDimensionsAndConfig_throws() { 633 Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 634 original.setConfig(Bitmap.Config.HARDWARE); 635 original.reconfigure(100, 100, Bitmap.Config.ARGB_8888); 636 } 637 638 @Test isPremultiplied_argb888_defaultsTrue()639 public void isPremultiplied_argb888_defaultsTrue() { 640 Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 641 642 assertThat(original.isPremultiplied()).isTrue(); 643 } 644 645 @Test isPremultiplied_argb888_noAlpha_defaultsFalse()646 public void isPremultiplied_argb888_noAlpha_defaultsFalse() { 647 Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 648 original.setHasAlpha(false); 649 650 assertThat(original.isPremultiplied()).isFalse(); 651 } 652 653 @Test isPremultiplied_rgb565_defaultsFalse()654 public void isPremultiplied_rgb565_defaultsFalse() { 655 Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565); 656 657 assertThat(original.isPremultiplied()).isFalse(); 658 } 659 660 @Test setPremultiplied_argb888_isFalse()661 public void setPremultiplied_argb888_isFalse() { 662 Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 663 original.setPremultiplied(false); 664 665 assertThat(original.isPremultiplied()).isFalse(); 666 } 667 668 @Test sameAs_bitmapsDifferentWidth()669 public void sameAs_bitmapsDifferentWidth() { 670 Bitmap original1 = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 671 Bitmap original2 = Bitmap.createBitmap(101, 100, Bitmap.Config.ARGB_8888); 672 assertThat(original1.sameAs(original2)).isFalse(); 673 } 674 675 @Test sameAs_bitmapsDifferentHeight()676 public void sameAs_bitmapsDifferentHeight() { 677 Bitmap original1 = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 678 Bitmap original2 = Bitmap.createBitmap(100, 101, Bitmap.Config.ARGB_8888); 679 assertThat(original1.sameAs(original2)).isFalse(); 680 } 681 682 @Test sameAs_bitmapsDifferentConfig()683 public void sameAs_bitmapsDifferentConfig() { 684 Bitmap original1 = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 685 Bitmap original2 = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_4444); 686 assertThat(original1.sameAs(original2)).isFalse(); 687 } 688 689 @Test sameAs_bitmapsDifferentPixels()690 public void sameAs_bitmapsDifferentPixels() { 691 int[] pixels1 = new int[] {0, 1, 2, 3}; 692 Bitmap original1 = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); 693 original1.setPixels(pixels1, 0, 1, 0, 0, 2, 2); 694 695 int[] pixels2 = new int[] {3, 2, 1, 0}; 696 Bitmap original2 = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); 697 original2.setPixels(pixels2, 0, 1, 0, 0, 2, 2); 698 assertThat(original1.sameAs(original2)).isFalse(); 699 } 700 701 @Test sameAs_bitmapsSamePixels()702 public void sameAs_bitmapsSamePixels() { 703 int[] pixels = new int[] {0, 1, 2, 3}; 704 Bitmap original1 = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); 705 original1.setPixels(pixels, 0, 1, 0, 0, 2, 2); 706 707 Bitmap original2 = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); 708 original2.setPixels(pixels, 0, 1, 0, 0, 2, 2); 709 assertThat(original1.sameAs(original2)).isTrue(); 710 } 711 712 @Test extractAlpha()713 public void extractAlpha() { 714 int[] pixels = new int[] {0xFF123456, 0x00123456, 0x88999999, 0x12345678}; 715 Bitmap bitmap = Bitmap.createBitmap(/* width= */ 2, /* height= */ 2, Bitmap.Config.ARGB_8888); 716 bitmap.setPixels( 717 pixels, 718 /* offset= */ 0, 719 /* stride= */ 2, 720 /* x= */ 0, 721 /* y= */ 0, 722 /* width= */ 2, 723 /* height= */ 2); 724 725 Bitmap alpha = bitmap.extractAlpha(); 726 727 assertThat(alpha.getPixel(0, 0)).isEqualTo(0xFF000000); 728 assertThat(alpha.getPixel(1, 0)).isEqualTo(0x00000000); 729 assertThat(alpha.getPixel(0, 1)).isEqualTo(0x88000000); 730 assertThat(alpha.getPixel(1, 1)).isEqualTo(0x12000000); 731 } 732 733 @Test extractAlpha_withArgs()734 public void extractAlpha_withArgs() { 735 int[] pixels = new int[] {0xFF123456, 0x00123456, 0x88999999, 0x12345678}; 736 Bitmap bitmap = Bitmap.createBitmap(/* width= */ 2, /* height= */ 2, Bitmap.Config.ARGB_8888); 737 bitmap.setPixels( 738 pixels, 739 /* offset= */ 0, 740 /* stride= */ 2, 741 /* x= */ 0, 742 /* y= */ 0, 743 /* width= */ 2, 744 /* height= */ 2); 745 746 Bitmap alpha = bitmap.extractAlpha(/* paint= */ null, /* offsetXY= */ new int[2]); 747 748 assertThat(alpha.getPixel(0, 0)).isEqualTo(0xFF000000); 749 assertThat(alpha.getPixel(1, 0)).isEqualTo(0x00000000); 750 assertThat(alpha.getPixel(0, 1)).isEqualTo(0x88000000); 751 assertThat(alpha.getPixel(1, 1)).isEqualTo(0x12000000); 752 } 753 754 @Test eraseColor_clearsDescription()755 public void eraseColor_clearsDescription() { 756 Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 757 Bitmap scaled = Bitmap.createScaledBitmap(original, 200, 200, false); 758 scaled.eraseColor(Color.TRANSPARENT); 759 String description = Shadows.shadowOf(scaled).getDescription(); 760 assertThat(description).isEqualTo("Bitmap (200, 200)"); 761 scaled.eraseColor(Color.BLUE); 762 description = Shadows.shadowOf(scaled).getDescription(); 763 assertThat(description).isEqualTo("Bitmap (200, 200) erased with 0xff0000ff"); 764 } 765 766 @Config(minSdk = S) 767 @Test asShared_shouldReturnImmutableInstance()768 public void asShared_shouldReturnImmutableInstance() { 769 Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 770 771 assertThat(original.asShared().isMutable()).isFalse(); 772 } 773 create(String name)774 private static Bitmap create(String name) { 775 Bitmap bitmap = Shadow.newInstanceOf(Bitmap.class); 776 shadowOf(bitmap).appendDescription(name); 777 return bitmap; 778 } 779 packRGB(int r, int g, int b)780 private static int packRGB(int r, int g, int b) { 781 return 0xff000000 | r << 16 | g << 8 | b; 782 } 783 createScaledBitmap_succeedForLargeBitmap(boolean filter)784 private void createScaledBitmap_succeedForLargeBitmap(boolean filter) { 785 Bitmap bitmap = Bitmap.createBitmap(100000, 10, Bitmap.Config.ARGB_8888); 786 Bitmap.createScaledBitmap(bitmap, 480000, 48, filter); 787 } 788 createScaledBitmap_modifiesPixels(boolean filter)789 private void createScaledBitmap_modifiesPixels(boolean filter) { 790 Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 791 bitmap.eraseColor(Color.BLUE); 792 Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, 50, 50, filter); 793 assertThat(scaledBitmap.getPixel(0, 0)).isEqualTo(Color.BLUE); 794 } 795 createScaledBitmap_expectedUpSize(boolean filter)796 private void createScaledBitmap_expectedUpSize(boolean filter) { 797 Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 798 Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, 32, 32, filter); 799 ShadowLegacyBitmap shadowBitmap = Shadow.extract(scaledBitmap); 800 assertThat(shadowBitmap.getBufferedImage().getWidth()).isEqualTo(32); 801 assertThat(shadowBitmap.getBufferedImage().getHeight()).isEqualTo(32); 802 } 803 createScaledBitmap_expectedDownSize(boolean filter)804 private void createScaledBitmap_expectedDownSize(boolean filter) { 805 Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888); 806 Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, 10, 10, filter); 807 ShadowLegacyBitmap shadowBitmap = Shadow.extract(scaledBitmap); 808 assertThat(shadowBitmap.getBufferedImage().getWidth()).isEqualTo(10); 809 assertThat(shadowBitmap.getBufferedImage().getHeight()).isEqualTo(10); 810 } 811 createScaledBitmap_drawOnScaled(boolean filter)812 private void createScaledBitmap_drawOnScaled(boolean filter) { 813 Bitmap original = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); 814 Bitmap scaled = Bitmap.createScaledBitmap(original, 32, 32, filter); 815 Canvas canvas = new Canvas(scaled); 816 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); 817 p.setColor(Color.BLACK); 818 canvas.drawRect(new Rect(0, 0, 32, 32), p); 819 } 820 } 821