1 /* 2 * Copyright (C) 2006 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; 18 19 import android.hardware.HardwareBuffer; 20 21 import androidx.test.filters.SmallTest; 22 23 import junit.framework.TestCase; 24 25 import java.nio.ByteBuffer; 26 import java.nio.IntBuffer; 27 import java.nio.ShortBuffer; 28 29 public class BitmapTest extends TestCase { 30 31 @SmallTest testBasic()32 public void testBasic() throws Exception { 33 Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 34 Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); 35 Bitmap bm3 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_4444); 36 37 assertTrue("mutability", bm1.isMutable()); 38 assertTrue("mutability", bm2.isMutable()); 39 assertTrue("mutability", bm3.isMutable()); 40 41 assertEquals("width", 100, bm1.getWidth()); 42 assertEquals("width", 100, bm2.getWidth()); 43 assertEquals("width", 100, bm3.getWidth()); 44 45 assertEquals("rowbytes", 400, bm1.getRowBytes()); 46 assertEquals("rowbytes", 200, bm2.getRowBytes()); 47 assertEquals("rowbytes", 400, bm3.getRowBytes()); 48 49 assertEquals("byteCount", 80000, bm1.getByteCount()); 50 assertEquals("byteCount", 40000, bm2.getByteCount()); 51 assertEquals("byteCount", 80000, bm3.getByteCount()); 52 53 assertEquals("height", 200, bm1.getHeight()); 54 assertEquals("height", 200, bm2.getHeight()); 55 assertEquals("height", 200, bm3.getHeight()); 56 57 assertTrue("hasAlpha", bm1.hasAlpha()); 58 assertFalse("hasAlpha", bm2.hasAlpha()); 59 assertTrue("hasAlpha", bm3.hasAlpha()); 60 61 assertTrue("getConfig", bm1.getConfig() == Bitmap.Config.ARGB_8888); 62 assertTrue("getConfig", bm2.getConfig() == Bitmap.Config.RGB_565); 63 assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_8888); 64 } 65 66 @SmallTest testMutability()67 public void testMutability() throws Exception { 68 Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); 69 Bitmap bm2 = Bitmap.createBitmap(new int[100 * 200], 100, 200, 70 Bitmap.Config.ARGB_8888); 71 72 assertTrue("mutability", bm1.isMutable()); 73 assertFalse("mutability", bm2.isMutable()); 74 75 bm1.eraseColor(0); 76 77 try { 78 bm2.eraseColor(0); 79 fail("eraseColor should throw exception"); 80 } catch (IllegalStateException ex) { 81 // safe to catch and ignore this 82 } 83 } 84 85 @SmallTest testGetPixelsWithAlpha()86 public void testGetPixelsWithAlpha() throws Exception { 87 int[] colors = new int[100]; 88 for (int i = 0; i < 100; i++) { 89 colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; 90 } 91 92 Bitmap bm = Bitmap.createBitmap(colors, 10, 10, 93 Bitmap.Config.ARGB_8888); 94 95 int[] pixels = new int[100]; 96 bm.getPixels(pixels, 0, 10, 0, 0, 10, 10); 97 for (int i = 0; i < 100; i++) { 98 int p = bm.getPixel(i % 10, i / 10); 99 assertEquals("getPixels", p, pixels[i]); 100 } 101 102 for (int i = 0; i < 100; i++) { 103 int p = bm.getPixel(i % 10, i / 10); 104 assertEquals("getPixel", p, colors[i]); 105 assertEquals("pixel value", p, 106 ((0xFF << 24) | (i << 16) | (i << 8) | i)); 107 } 108 109 } 110 111 @SmallTest testGetPixelsWithoutAlpha()112 public void testGetPixelsWithoutAlpha() throws Exception { 113 int[] colors = new int[100]; 114 for (int i = 0; i < 100; i++) { 115 colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; 116 } 117 118 Bitmap bm = Bitmap.createBitmap(colors, 10, 10, Bitmap.Config.RGB_565); 119 120 int[] pixels = new int[100]; 121 bm.getPixels(pixels, 0, 10, 0, 0, 10, 10); 122 for (int i = 0; i < 100; i++) { 123 int p = bm.getPixel(i % 10, i / 10); 124 assertEquals("getPixels", p, pixels[i]); 125 } 126 } 127 128 @SmallTest testSetPixelsWithAlpha()129 public void testSetPixelsWithAlpha() throws Exception { 130 int[] colors = new int[100]; 131 for (int i = 0; i < 100; i++) { 132 colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; 133 } 134 135 Bitmap.Config config = Bitmap.Config.ARGB_8888; 136 Bitmap bm1 = Bitmap.createBitmap(colors, 10, 10, config); 137 Bitmap bm2 = Bitmap.createBitmap(10, 10, config); 138 139 for (int i = 0; i < 100; i++) { 140 bm2.setPixel(i % 10, i / 10, colors[i]); 141 } 142 143 for (int i = 0; i < 100; i++) { 144 assertEquals("setPixel", 145 bm1.getPixel(i % 10, i / 10), bm2.getPixel(i % 10, i / 10)); 146 } 147 148 for (int i = 0; i < 100; i++) { 149 assertEquals("setPixel value", 150 bm1.getPixel(i % 10, i / 10), colors[i]); 151 } 152 } 153 154 @SmallTest testSetPixelsWithoutAlpha()155 public void testSetPixelsWithoutAlpha() throws Exception { 156 int[] colors = new int[100]; 157 for (int i = 0; i < 100; i++) { 158 colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; 159 } 160 161 Bitmap.Config config = Bitmap.Config.RGB_565; 162 Bitmap bm1 = Bitmap.createBitmap(colors, 10, 10, config); 163 Bitmap bm2 = Bitmap.createBitmap(10, 10, config); 164 165 for (int i = 0; i < 100; i++) { 166 bm2.setPixel(i % 10, i / 10, colors[i]); 167 } 168 169 for (int i = 0; i < 100; i++) { 170 assertEquals("setPixel", bm1.getPixel(i % 10, i / 10), 171 bm2.getPixel(i % 10, i / 10)); 172 } 173 } 174 computePrePostMul(int alpha, int comp)175 private static int computePrePostMul(int alpha, int comp) { 176 if (alpha == 0) { 177 return 0; 178 } 179 int premul = Math.round(alpha * comp / 255.f); 180 int unpre = Math.round(255.0f * premul / alpha); 181 return unpre; 182 } 183 184 @SmallTest testSetPixelsWithNonOpaqueAlpha()185 public void testSetPixelsWithNonOpaqueAlpha() throws Exception { 186 int[] colors = new int[256]; 187 for (int i = 0; i < 256; i++) { 188 colors[i] = (i << 24) | (0xFF << 16) | (0x80 << 8) | 0; 189 } 190 191 Bitmap.Config config = Bitmap.Config.ARGB_8888; 192 193 // create a bitmap with the color array specified 194 Bitmap bm1 = Bitmap.createBitmap(colors, 16, 16, config); 195 196 // create a bitmap with no colors, but then call setPixels 197 Bitmap bm2 = Bitmap.createBitmap(16, 16, config); 198 bm2.setPixels(colors, 0, 16, 0, 0, 16, 16); 199 200 // now check that we did a good job returning the unpremultiplied alpha 201 final int tolerance = 1; 202 for (int i = 0; i < 256; i++) { 203 int c0 = colors[i]; 204 int c1 = bm1.getPixel(i % 16, i / 16); 205 int c2 = bm2.getPixel(i % 16, i / 16); 206 207 // these two should always be identical 208 assertEquals("getPixel", c1, c2); 209 210 // comparing the original (c0) with the returned color is tricky, 211 // since it gets premultiplied during the set(), and unpremultiplied 212 // by the get(). 213 int a0 = Color.alpha(c0); 214 int a1 = Color.alpha(c1); 215 assertEquals("alpha", a0, a1); 216 217 int r0 = Color.red(c0); 218 int r1 = Color.red(c1); 219 int rr = computePrePostMul(a0, r0); 220 assertTrue("red", Math.abs(rr - r1) <= tolerance); 221 222 int g0 = Color.green(c0); 223 int g1 = Color.green(c1); 224 int gg = computePrePostMul(a0, g0); 225 assertTrue("green", Math.abs(gg - g1) <= tolerance); 226 227 int b0 = Color.blue(c0); 228 int b1 = Color.blue(c1); 229 int bb = computePrePostMul(a0, b0); 230 assertTrue("blue", Math.abs(bb - b1) <= tolerance); 231 232 if (false) { 233 int cc = Color.argb(a0, rr, gg, bb); 234 android.util.Log.d("skia", "original " + Integer.toHexString(c0) + 235 " set+get " + Integer.toHexString(c1) + 236 " local " + Integer.toHexString(cc)); 237 } 238 } 239 } 240 241 @SmallTest testWrapHardwareBufferWithSrgbColorSpace()242 public void testWrapHardwareBufferWithSrgbColorSpace() { 243 GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888, 244 GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_SOFTWARE_MASK); 245 Canvas canvas = buffer.lockCanvas(); 246 canvas.drawColor(Color.YELLOW); 247 buffer.unlockCanvasAndPost(canvas); 248 Bitmap hardwareBitmap = 249 Bitmap.wrapHardwareBuffer(HardwareBuffer.createFromGraphicBuffer(buffer), null); 250 assertTrue(hardwareBitmap.isPremultiplied()); 251 assertFalse(hardwareBitmap.isMutable()); 252 assertEquals(ColorSpace.get(ColorSpace.Named.SRGB), hardwareBitmap.getColorSpace()); 253 } 254 255 @SmallTest testWrapHardwareBufferWithDisplayP3ColorSpace()256 public void testWrapHardwareBufferWithDisplayP3ColorSpace() { 257 GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888, 258 GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_SOFTWARE_MASK); 259 Canvas canvas = buffer.lockCanvas(); 260 canvas.drawColor(Color.YELLOW); 261 buffer.unlockCanvasAndPost(canvas); 262 Bitmap hardwareBitmap = Bitmap.wrapHardwareBuffer( 263 HardwareBuffer.createFromGraphicBuffer(buffer), 264 ColorSpace.get(ColorSpace.Named.DISPLAY_P3)); 265 assertTrue(hardwareBitmap.isPremultiplied()); 266 assertFalse(hardwareBitmap.isMutable()); 267 assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), hardwareBitmap.getColorSpace()); 268 } 269 270 @SmallTest testCopyWithDirectByteBuffer()271 public void testCopyWithDirectByteBuffer() { 272 // Initialize Bitmap 273 final int width = 2; 274 final int height = 2; 275 final int bytesPerPixel = 2; 276 Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 277 bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); 278 279 // Copy bytes to direct buffer, buffer is padded by fixed amount (pad bytes) either side 280 // of bitmap. 281 final int pad = 1; 282 final byte padValue = 0x5a; 283 final int bytesPerElement = 1; 284 final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; 285 ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize); 286 287 // Write padding 288 directBuffer.put(0, padValue); 289 directBuffer.put(directBuffer.limit() - 1, padValue); 290 291 // Copy bitmap 292 directBuffer.position(pad); 293 bm1.copyPixelsToBuffer(directBuffer); 294 assertEquals(directBuffer.position(), 295 pad + width * height * bytesPerPixel / bytesPerElement); 296 297 // Check padding 298 assertEquals(directBuffer.get(0), padValue); 299 assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); 300 301 // Create bitmap from direct buffer and check match. 302 directBuffer.position(pad); 303 Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 304 bm2.copyPixelsFromBuffer(directBuffer); 305 assertTrue(bm2.sameAs(bm1)); 306 } 307 308 @SmallTest testCopyWithDirectShortBuffer()309 public void testCopyWithDirectShortBuffer() { 310 // Initialize Bitmap 311 final int width = 2; 312 final int height = 2; 313 final int bytesPerPixel = 2; 314 Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 315 bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); 316 317 // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side 318 // of bitmap. 319 final int pad = 1; 320 final short padValue = 0x55aa; 321 final int bytesPerElement = 2; 322 final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; 323 ShortBuffer directBuffer = 324 ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asShortBuffer(); 325 326 // Write padding 327 directBuffer.put(0, padValue); 328 directBuffer.put(directBuffer.limit() - 1, padValue); 329 330 // Copy bitmap 331 directBuffer.position(pad); 332 bm1.copyPixelsToBuffer(directBuffer); 333 assertEquals(directBuffer.position(), 334 pad + width * height * bytesPerPixel / bytesPerElement); 335 336 // Check padding 337 assertEquals(directBuffer.get(0), padValue); 338 assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); 339 340 // Create bitmap from heap buffer and check match. 341 directBuffer.position(pad); 342 Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 343 bm2.copyPixelsFromBuffer(directBuffer); 344 assertTrue(bm2.sameAs(bm1)); 345 } 346 347 @SmallTest testCopyWithDirectIntBuffer()348 public void testCopyWithDirectIntBuffer() { 349 // Initialize Bitmap 350 final int width = 2; 351 final int height = 2; 352 final int bytesPerPixel = 2; 353 Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 354 bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); 355 356 // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side 357 // of bitmap. 358 final int pad = 1; 359 final int padValue = 0x55aa5a5a; 360 final int bytesPerElement = 4; 361 final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; 362 IntBuffer directBuffer = 363 ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asIntBuffer(); 364 365 // Write padding 366 directBuffer.put(0, padValue); 367 directBuffer.put(directBuffer.limit() - 1, padValue); 368 369 // Copy bitmap 370 directBuffer.position(pad); 371 bm1.copyPixelsToBuffer(directBuffer); 372 assertEquals(directBuffer.position(), 373 pad + width * height * bytesPerPixel / bytesPerElement); 374 375 // Check padding 376 assertEquals(directBuffer.get(0), padValue); 377 assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); 378 379 // Create bitmap from heap buffer and check match. 380 directBuffer.position(pad); 381 Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 382 bm2.copyPixelsFromBuffer(directBuffer); 383 assertTrue(bm2.sameAs(bm1)); 384 } 385 386 @SmallTest testCopyWithHeapByteBuffer()387 public void testCopyWithHeapByteBuffer() { 388 // Initialize Bitmap 389 final int width = 2; 390 final int height = 2; 391 final int bytesPerPixel = 2; 392 Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 393 bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); 394 395 // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side 396 // of bitmap. 397 final int pad = 1; 398 final byte padValue = 0x5a; 399 final int bytesPerElement = 1; 400 final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; 401 ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize); 402 403 // Write padding 404 heapBuffer.put(0, padValue); 405 heapBuffer.put(heapBuffer.limit() - 1, padValue); 406 407 // Copy bitmap 408 heapBuffer.position(pad); 409 bm1.copyPixelsToBuffer(heapBuffer); 410 assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); 411 412 // Check padding 413 assertEquals(heapBuffer.get(0), padValue); 414 assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); 415 416 // Create bitmap from heap buffer and check match. 417 heapBuffer.position(pad); 418 Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 419 bm2.copyPixelsFromBuffer(heapBuffer); 420 assertTrue(bm2.sameAs(bm1)); 421 } 422 423 @SmallTest testCopyWithHeapShortBuffer()424 public void testCopyWithHeapShortBuffer() { 425 // Initialize Bitmap 426 final int width = 2; 427 final int height = 2; 428 final int bytesPerPixel = 2; 429 Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 430 bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); 431 432 // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side 433 // of bitmap. 434 final int pad = 1; 435 final short padValue = 0x55aa; 436 final int bytesPerElement = 2; 437 final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; 438 ShortBuffer heapBuffer = ShortBuffer.allocate(bufferSize); 439 440 // Write padding 441 heapBuffer.put(0, padValue); 442 heapBuffer.put(heapBuffer.limit() - 1, padValue); 443 444 // Copy bitmap 445 heapBuffer.position(pad); 446 bm1.copyPixelsToBuffer(heapBuffer); 447 assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); 448 449 // Check padding 450 assertEquals(heapBuffer.get(0), padValue); 451 assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); 452 453 // Create bitmap from heap buffer and check match. 454 heapBuffer.position(pad); 455 Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 456 bm2.copyPixelsFromBuffer(heapBuffer); 457 assertTrue(bm2.sameAs(bm1)); 458 } 459 460 @SmallTest testCopyWithHeapIntBuffer()461 public void testCopyWithHeapIntBuffer() { 462 // Initialize Bitmap 463 final int width = 2; 464 final int height = 2; 465 final int bytesPerPixel = 2; 466 Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 467 bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); 468 469 // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side 470 // of bitmap. 471 final int pad = 1; 472 final int padValue = 0x55aa5a5a; 473 final int bytesPerElement = 4; 474 final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad; 475 IntBuffer heapBuffer = IntBuffer.allocate(bufferSize); 476 477 // Write padding 478 heapBuffer.put(0, padValue); 479 heapBuffer.put(heapBuffer.limit() - 1, padValue); 480 481 // Copy bitmap 482 heapBuffer.position(pad); 483 bm1.copyPixelsToBuffer(heapBuffer); 484 assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement); 485 486 // Check padding 487 assertEquals(heapBuffer.get(0), padValue); 488 assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); 489 490 // Create bitmap from heap buffer and check match. 491 heapBuffer.position(pad); 492 Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 493 bm2.copyPixelsFromBuffer(heapBuffer); 494 assertTrue(bm2.sameAs(bm1)); 495 } 496 } 497