1 /* 2 * Copyright (C) 2017 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.assertNotNull; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertSame; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 26 import android.content.res.Resources; 27 import android.graphics.Bitmap; 28 import android.graphics.BitmapFactory; 29 import android.graphics.Canvas; 30 import android.graphics.Color; 31 import android.graphics.ColorSpace; 32 import android.graphics.ImageDecoder; 33 import android.graphics.Matrix; 34 import android.os.Parcel; 35 import android.util.Log; 36 37 import androidx.annotation.ColorInt; 38 import androidx.annotation.NonNull; 39 import androidx.test.InstrumentationRegistry; 40 import androidx.test.filters.RequiresDevice; 41 import androidx.test.filters.SmallTest; 42 import androidx.test.runner.AndroidJUnit4; 43 44 import com.android.compatibility.common.util.ColorUtils; 45 46 import org.junit.Before; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 50 import java.io.ByteArrayOutputStream; 51 import java.io.IOException; 52 import java.io.InputStream; 53 import java.nio.ByteBuffer; 54 import java.nio.IntBuffer; 55 import java.util.Arrays; 56 57 @SmallTest 58 @RunWith(AndroidJUnit4.class) 59 public class BitmapColorSpaceTest { 60 private static final String LOG_TAG = "BitmapColorSpaceTest"; 61 62 private Resources mResources; 63 64 @Before setup()65 public void setup() { 66 mResources = InstrumentationRegistry.getTargetContext().getResources(); 67 } 68 69 @SuppressWarnings("deprecation") 70 @Test createWithColorSpace()71 public void createWithColorSpace() { 72 // We don't test HARDWARE configs because they are not compatible with mutable bitmaps 73 74 Bitmap.Config[] configs = new Bitmap.Config[] { 75 Bitmap.Config.ARGB_8888, 76 Bitmap.Config.RGB_565, 77 Bitmap.Config.ARGB_4444, 78 Bitmap.Config.RGBA_F16, 79 }; 80 // in most cases, createBitmap respects the ColorSpace 81 for (Bitmap.Config config : configs) { 82 for (ColorSpace.Named e : new ColorSpace.Named[] { 83 ColorSpace.Named.PRO_PHOTO_RGB, 84 ColorSpace.Named.ADOBE_RGB, 85 ColorSpace.Named.DISPLAY_P3, 86 ColorSpace.Named.DCI_P3, 87 ColorSpace.Named.BT709, 88 ColorSpace.Named.BT2020, 89 }) { 90 ColorSpace requested = ColorSpace.get(e); 91 Bitmap b = Bitmap.createBitmap(32, 32, config, false, requested); 92 ColorSpace cs = b.getColorSpace(); 93 assertNotNull(cs); 94 assertSame(requested, cs); 95 } 96 97 // SRGB and LINEAR_SRGB are special. 98 ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB); 99 ColorSpace extendedSrgb = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB); 100 for (ColorSpace requested : new ColorSpace[] { 101 sRGB, 102 extendedSrgb, 103 }) { 104 Bitmap b = Bitmap.createBitmap(32, 32, config, false, requested); 105 ColorSpace cs = b.getColorSpace(); 106 assertNotNull(cs); 107 if (config == Bitmap.Config.RGBA_F16) { 108 assertSame(extendedSrgb, cs); 109 } else { 110 assertSame(sRGB, cs); 111 } 112 } 113 114 ColorSpace linearRgb = ColorSpace.get(ColorSpace.Named.LINEAR_SRGB); 115 ColorSpace linearExtendedSrgb = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB); 116 for (ColorSpace requested : new ColorSpace[] { 117 linearRgb, 118 linearExtendedSrgb, 119 }) { 120 Bitmap b = Bitmap.createBitmap(32, 32, config, false, requested); 121 ColorSpace cs = b.getColorSpace(); 122 assertNotNull(cs); 123 if (config == Bitmap.Config.RGBA_F16) { 124 assertSame(linearExtendedSrgb, cs); 125 } else { 126 assertSame(linearRgb, cs); 127 } 128 } 129 } 130 } 131 132 @Test createAlpha8ColorSpace()133 public void createAlpha8ColorSpace() { 134 Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8); 135 assertNull(bitmap.getColorSpace()); 136 137 for (ColorSpace cs : BitmapTest.getRgbColorSpaces()) { 138 bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true, cs); 139 assertNull(bitmap.getColorSpace()); 140 } 141 } 142 143 @Test createDefaultColorSpace()144 public void createDefaultColorSpace() { 145 ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB); 146 Bitmap.Config[] configs = new Bitmap.Config[] { 147 Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888 148 }; 149 for (Bitmap.Config config : configs) { 150 Bitmap bitmap = Bitmap.createBitmap(32, 32, config, true); 151 assertSame(sRGB, bitmap.getColorSpace()); 152 } 153 } 154 155 @Test(expected = IllegalArgumentException.class) createWithoutColorSpace()156 public void createWithoutColorSpace() { 157 Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, null); 158 } 159 160 @Test(expected = IllegalArgumentException.class) createWithNonRgbColorSpace()161 public void createWithNonRgbColorSpace() { 162 Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, 163 ColorSpace.get(ColorSpace.Named.CIE_LAB)); 164 } 165 166 @Test(expected = IllegalArgumentException.class) createWithNoTransferParameters()167 public void createWithNoTransferParameters() { 168 Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, 169 new ColorSpace.Rgb("NoTransferParams", 170 new float[]{ 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }, 171 ColorSpace.ILLUMINANT_D50, 172 x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f), 173 0, 1)); 174 } 175 176 @Test createFromSourceWithColorSpace()177 public void createFromSourceWithColorSpace() { 178 for (ColorSpace rgb : BitmapTest.getRgbColorSpaces()) { 179 Bitmap.Config[] configs = new Bitmap.Config[] { 180 Bitmap.Config.ARGB_8888, 181 Bitmap.Config.RGB_565, 182 Bitmap.Config.ALPHA_8, 183 Bitmap.Config.ARGB_4444, 184 Bitmap.Config.RGBA_F16, 185 }; 186 for (Bitmap.Config config : configs) { 187 Bitmap orig = Bitmap.createBitmap(32, 32, config, false, rgb); 188 Bitmap cropped = Bitmap.createBitmap(orig, 0, 0, orig.getWidth() / 2, 189 orig.getHeight() / 2, null, false); 190 assertSame(orig.getColorSpace(), cropped.getColorSpace()); 191 if (config == Bitmap.Config.ALPHA_8) { 192 assertNull(cropped.getColorSpace()); 193 } 194 195 Matrix m = new Matrix(); 196 m.setRotate(45, orig.getWidth() / 2, orig.getHeight() / 2); 197 Bitmap rotated = Bitmap.createBitmap(orig, 0, 0, orig.getWidth(), 198 orig.getHeight(), m, false); 199 switch (config) { 200 case ALPHA_8: 201 assertSame(Bitmap.Config.ARGB_8888, rotated.getConfig()); 202 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), rotated.getColorSpace()); 203 break; 204 case RGB_565: 205 assertSame(Bitmap.Config.ARGB_8888, rotated.getConfig()); 206 // Fallthrough. 207 default: 208 assertSame("Mismatch with Config " + config, 209 orig.getColorSpace(), rotated.getColorSpace()); 210 break; 211 } 212 } 213 } 214 } 215 216 @Test sRGB()217 public void sRGB() { 218 Bitmap b = BitmapFactory.decodeResource(mResources, R.drawable.robot); 219 ColorSpace cs = b.getColorSpace(); 220 assertNotNull(cs); 221 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs); 222 223 b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2); 224 cs = b.getColorSpace(); 225 assertNotNull(cs); 226 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs); 227 228 b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true); 229 cs = b.getColorSpace(); 230 assertNotNull(cs); 231 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs); 232 } 233 234 @Test p3()235 public void p3() { 236 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 237 Bitmap b = BitmapFactory.decodeStream(in); 238 ColorSpace cs = b.getColorSpace(); 239 assertNotNull(cs); 240 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 241 242 b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2); 243 cs = b.getColorSpace(); 244 assertNotNull(cs); 245 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 246 247 b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true); 248 cs = b.getColorSpace(); 249 assertNotNull(cs); 250 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 251 } catch (IOException e) { 252 fail(); 253 } 254 } 255 256 @Test extendedSRGB()257 public void extendedSRGB() { 258 try (InputStream in = mResources.getAssets().open("blue-16bit-srgb.png")) { 259 Bitmap b = BitmapFactory.decodeStream(in); 260 ColorSpace cs = b.getColorSpace(); 261 assertNotNull(cs); 262 assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), cs); 263 264 b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2); 265 cs = b.getColorSpace(); 266 assertNotNull(cs); 267 assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), cs); 268 269 b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true); 270 cs = b.getColorSpace(); 271 assertNotNull(cs); 272 assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), cs); 273 } catch (IOException e) { 274 fail(); 275 } 276 } 277 278 @Test linearSRGB()279 public void linearSRGB() { 280 String assetInLinearSRGB = "grayscale-linearSrgb.png"; 281 try (InputStream in = mResources.getAssets().open(assetInLinearSRGB)) { 282 Bitmap b = BitmapFactory.decodeStream(in); 283 ColorSpace cs = b.getColorSpace(); 284 assertNotNull(cs); 285 assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_SRGB), cs); 286 } catch (IOException e) { 287 fail(); 288 } 289 290 try (InputStream in = mResources.getAssets().open(assetInLinearSRGB)) { 291 BitmapFactory.Options options = new BitmapFactory.Options(); 292 options.inPreferredConfig = Bitmap.Config.RGBA_F16; 293 Bitmap b = BitmapFactory.decodeStream(in, null, options); 294 ColorSpace cs = b.getColorSpace(); 295 assertNotNull(cs); 296 assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs); 297 } catch (IOException e) { 298 fail(); 299 } 300 } 301 302 private static class Asset { 303 public final String name; 304 public final ColorSpace colorSpace; Asset(String name, ColorSpace.Named e)305 Asset(String name, ColorSpace.Named e) { 306 this.name = name; 307 this.colorSpace = ColorSpace.get(e); 308 } 309 }; 310 311 @Test reconfigure()312 public void reconfigure() { 313 Asset[] assets = new Asset[] { 314 new Asset("green-p3.png", ColorSpace.Named.DISPLAY_P3), 315 new Asset("red-adobergb.png", ColorSpace.Named.ADOBE_RGB), 316 }; 317 for (Asset asset : assets) { 318 for (Bitmap.Config config : new Bitmap.Config[] { 319 Bitmap.Config.ARGB_8888, 320 Bitmap.Config.RGB_565, 321 }) { 322 try (InputStream in = mResources.getAssets().open(asset.name)) { 323 BitmapFactory.Options opts = new BitmapFactory.Options(); 324 opts.inMutable = true; 325 opts.inPreferredConfig = config; 326 327 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 328 ColorSpace cs = b.getColorSpace(); 329 assertNotNull(cs); 330 assertSame(asset.colorSpace, cs); 331 332 b.reconfigure(b.getWidth() / 4, b.getHeight() / 4, Bitmap.Config.RGBA_F16); 333 cs = b.getColorSpace(); 334 assertNotNull(cs); 335 assertSame(asset.colorSpace, cs); 336 337 b.reconfigure(b.getWidth(), b.getHeight(), config); 338 cs = b.getColorSpace(); 339 assertNotNull(cs); 340 assertSame(asset.colorSpace, cs); 341 } catch (IOException e) { 342 fail(); 343 } 344 } 345 } 346 } 347 348 @Test reuse()349 public void reuse() { 350 BitmapFactory.Options opts = new BitmapFactory.Options(); 351 opts.inMutable = true; 352 353 Bitmap bitmap1 = null; 354 try (InputStream in = mResources.getAssets().open("green-srgb.png")) { 355 bitmap1 = BitmapFactory.decodeStream(in, null, opts); 356 ColorSpace cs = bitmap1.getColorSpace(); 357 assertNotNull(cs); 358 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs); 359 } catch (IOException e) { 360 fail(); 361 } 362 363 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 364 opts.inBitmap = bitmap1; 365 366 Bitmap bitmap2 = BitmapFactory.decodeStream(in, null, opts); 367 assertSame(bitmap1, bitmap2); 368 ColorSpace cs = bitmap2.getColorSpace(); 369 assertNotNull(cs); 370 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 371 } catch (IOException e) { 372 fail(); 373 } 374 } 375 376 @Test getPixel()377 public void getPixel() { 378 verifyGetPixel("green-p3.png", 0x75fb4cff); 379 verifyGetPixel("translucent-green-p3.png", 0x3a7d267f); // 50% translucent 380 } 381 verifyGetPixel(@onNull String fileName, @ColorInt int rawColor)382 private void verifyGetPixel(@NonNull String fileName, @ColorInt int rawColor) { 383 try (InputStream in = mResources.getAssets().open(fileName)) { 384 Bitmap b = BitmapFactory.decodeStream(in); 385 ColorSpace cs = b.getColorSpace(); 386 assertNotNull(cs); 387 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 388 389 verifyGetPixel(b, rawColor); 390 391 b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2); 392 verifyGetPixel(b, rawColor); 393 394 b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true); 395 verifyGetPixel(b, rawColor); 396 } catch (IOException e) { 397 fail(); 398 } 399 } 400 verifyGetPixel(@onNull Bitmap b, @ColorInt int rawColor)401 private static void verifyGetPixel(@NonNull Bitmap b, @ColorInt int rawColor) { 402 ByteBuffer dst = ByteBuffer.allocate(b.getByteCount()); 403 b.copyPixelsToBuffer(dst); 404 dst.rewind(); 405 406 // Stored as RGBA 407 assertEquals(rawColor, dst.asIntBuffer().get()); 408 409 int srgbColor = convertPremulColorToColorInt(rawColor, b.getColorSpace()); 410 int srgb = b.getPixel(15, 15); 411 almostEqual(srgbColor, srgb, 3, 15 * b.getWidth() + 15); 412 } 413 convertPremulColorToColorInt(int premulColor, ColorSpace premulCS)414 private static int convertPremulColorToColorInt(int premulColor, ColorSpace premulCS) { 415 float alpha = (premulColor & 0xff) / 255.0f; 416 return Color.toArgb(Color.convert((premulColor >>> 24) / 255.0f / alpha, 417 ((premulColor >> 16) & 0xff) / 255.0f / alpha, 418 ((premulColor >> 8) & 0xff) / 255.0f / alpha, 419 alpha, premulCS, ColorSpace.get(ColorSpace.Named.SRGB))); 420 } 421 422 @Test getPixels()423 public void getPixels() { 424 verifyGetPixels("green-p3.png"); 425 verifyGetPixels("translucent-green-p3.png"); // 50% translucent 426 } 427 verifyGetPixels(@onNull String fileName)428 private void verifyGetPixels(@NonNull String fileName) { 429 try (InputStream in = mResources.getAssets().open(fileName)) { 430 Bitmap b = BitmapFactory.decodeStream(in); 431 ColorSpace cs = b.getColorSpace(); 432 assertNotNull(cs); 433 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 434 435 ByteBuffer dst = ByteBuffer.allocate(b.getByteCount()); 436 b.copyPixelsToBuffer(dst); 437 dst.rewind(); 438 439 // Stored as RGBA 440 int expected = convertPremulColorToColorInt(dst.asIntBuffer().get(), b.getColorSpace()); 441 442 verifyGetPixels(b, expected); 443 444 b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2); 445 verifyGetPixels(b, expected); 446 447 b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true); 448 verifyGetPixels(b, expected); 449 } catch (IOException e) { 450 fail(); 451 } 452 } 453 verifyGetPixels(@onNull Bitmap b, @ColorInt int expected)454 private static void verifyGetPixels(@NonNull Bitmap b, @ColorInt int expected) { 455 int[] pixels = new int[b.getWidth() * b.getHeight()]; 456 b.getPixels(pixels, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight()); 457 458 for (int i = 0; i < pixels.length; i++) { 459 int pixel = pixels[i]; 460 almostEqual(expected, pixel, 3, i); 461 } 462 } 463 464 @Test setPixel()465 public void setPixel() { 466 verifySetPixel("green-p3.png", 0xffff0000, 0xea3323ff); 467 verifySetPixel("translucent-green-p3.png", 0x7fff0000, 0x7519127f); 468 } 469 verifySetPixel(@onNull String fileName, @ColorInt int newColor, @ColorInt int expectedColor)470 private void verifySetPixel(@NonNull String fileName, 471 @ColorInt int newColor, @ColorInt int expectedColor) { 472 try (InputStream in = mResources.getAssets().open(fileName)) { 473 BitmapFactory.Options opts = new BitmapFactory.Options(); 474 opts.inMutable = true; 475 476 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 477 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace()); 478 assertTrue(b.isMutable()); 479 verifySetPixel(b, newColor, expectedColor); 480 481 b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2); 482 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace()); 483 assertTrue(b.isMutable()); 484 verifySetPixel(b, newColor, expectedColor); 485 486 b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true); 487 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace()); 488 assertTrue(b.isMutable()); 489 verifySetPixel(b, newColor, expectedColor); 490 } catch (IOException e) { 491 fail(); 492 } 493 } 494 verifySetPixel(@onNull Bitmap b, @ColorInt int newColor, @ColorInt int expectedColor)495 private static void verifySetPixel(@NonNull Bitmap b, 496 @ColorInt int newColor, @ColorInt int expectedColor) { 497 assertTrue(b.isMutable()); 498 b.setPixel(0, 0, newColor); 499 500 ByteBuffer dst = ByteBuffer.allocate(b.getByteCount()); 501 b.copyPixelsToBuffer(dst); 502 dst.rewind(); 503 // Stored as RGBA 504 ColorUtils.verifyColor(expectedColor, dst.asIntBuffer().get(), 1); 505 } 506 507 @Test setPixels()508 public void setPixels() { 509 verifySetPixels("green-p3.png", 0xffff0000, 0xea3323ff); 510 verifySetPixels("translucent-green-p3.png", 0x7fff0000, 0x7519127f); 511 } 512 verifySetPixels(@onNull String fileName, @ColorInt int newColor, @ColorInt int expectedColor)513 private void verifySetPixels(@NonNull String fileName, 514 @ColorInt int newColor, @ColorInt int expectedColor) { 515 try (InputStream in = mResources.getAssets().open(fileName)) { 516 BitmapFactory.Options opts = new BitmapFactory.Options(); 517 opts.inMutable = true; 518 519 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 520 assertNotNull(b.getColorSpace()); 521 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace()); 522 523 verifySetPixels(b, newColor, expectedColor); 524 525 b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2); 526 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace()); 527 assertTrue(b.isMutable()); 528 verifySetPixels(b, newColor, expectedColor); 529 530 b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true); 531 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace()); 532 assertTrue(b.isMutable()); 533 verifySetPixels(b, newColor, expectedColor); 534 } catch (IOException e) { 535 fail(); 536 } 537 } 538 verifySetPixels(@onNull Bitmap b, @ColorInt int newColor, @ColorInt int expectedColor)539 private static void verifySetPixels(@NonNull Bitmap b, 540 @ColorInt int newColor, @ColorInt int expectedColor) { 541 assertTrue(b.isMutable()); 542 int[] pixels = new int[b.getWidth() * b.getHeight()]; 543 Arrays.fill(pixels, newColor); 544 b.setPixels(pixels, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight()); 545 546 ByteBuffer dst = ByteBuffer.allocate(b.getByteCount()); 547 b.copyPixelsToBuffer(dst); 548 dst.rewind(); 549 550 IntBuffer buffer = dst.asIntBuffer(); 551 //noinspection ForLoopReplaceableByForEach 552 for (int i = 0; i < pixels.length; i++) { 553 // Stored as RGBA 554 ColorUtils.verifyColor(expectedColor, buffer.get(), 1); 555 } 556 } 557 558 @Test writeColorSpace()559 public void writeColorSpace() { 560 verifyColorSpaceMarshalling("green-srgb.png", ColorSpace.get(ColorSpace.Named.SRGB)); 561 verifyColorSpaceMarshalling("green-p3.png", ColorSpace.get(ColorSpace.Named.DISPLAY_P3)); 562 verifyColorSpaceMarshalling("blue-16bit-srgb.png", 563 ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); 564 565 Bitmap bitmapIn = BitmapFactory.decodeResource(mResources, R.drawable.robot); 566 verifyParcelUnparcel(bitmapIn, ColorSpace.get(ColorSpace.Named.SRGB)); 567 } 568 verifyColorSpaceMarshalling( @onNull String fileName, @NonNull ColorSpace colorSpace)569 private void verifyColorSpaceMarshalling( 570 @NonNull String fileName, @NonNull ColorSpace colorSpace) { 571 try (InputStream in = mResources.getAssets().open(fileName)) { 572 Bitmap bitmapIn = BitmapFactory.decodeStream(in); 573 verifyParcelUnparcel(bitmapIn, colorSpace); 574 } catch (IOException e) { 575 fail(); 576 } 577 } 578 verifyParcelUnparcel(Bitmap bitmapIn, ColorSpace expected)579 private void verifyParcelUnparcel(Bitmap bitmapIn, ColorSpace expected) { 580 ColorSpace cs = bitmapIn.getColorSpace(); 581 assertNotNull(cs); 582 assertSame(expected, cs); 583 584 Parcel p = Parcel.obtain(); 585 bitmapIn.writeToParcel(p, 0); 586 p.setDataPosition(0); 587 588 Bitmap bitmapOut = Bitmap.CREATOR.createFromParcel(p); 589 cs = bitmapOut.getColorSpace(); 590 assertNotNull(cs); 591 assertSame(expected, cs); 592 593 p.recycle(); 594 } 595 596 @Test p3rgb565()597 public void p3rgb565() { 598 BitmapFactory.Options opts = new BitmapFactory.Options(); 599 opts.inPreferredConfig = Bitmap.Config.RGB_565; 600 601 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 602 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 603 ColorSpace cs = b.getColorSpace(); 604 assertNotNull(cs); 605 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 606 } catch (IOException e) { 607 fail(); 608 } 609 } 610 611 @Test p3hardware()612 public void p3hardware() { 613 BitmapFactory.Options opts = new BitmapFactory.Options(); 614 opts.inPreferredConfig = Bitmap.Config.HARDWARE; 615 616 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 617 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 618 ColorSpace cs = b.getColorSpace(); 619 assertNotNull(cs); 620 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 621 } catch (IOException e) { 622 fail(); 623 } 624 } 625 626 @Test guessSRGB()627 public void guessSRGB() { 628 BitmapFactory.Options opts = new BitmapFactory.Options(); 629 opts.inJustDecodeBounds = true; 630 631 try (InputStream in = mResources.getAssets().open("green-srgb.png")) { 632 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 633 ColorSpace cs = opts.outColorSpace; 634 assertNull(b); 635 assertNotNull(cs); 636 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs); 637 } catch (IOException e) { 638 fail(); 639 } 640 } 641 642 @Test guess16bitUntagged()643 public void guess16bitUntagged() { 644 BitmapFactory.Options opts = new BitmapFactory.Options(); 645 opts.inJustDecodeBounds = true; 646 647 try (InputStream in = mResources.getAssets().open("blue-16bit-srgb.png")) { 648 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 649 ColorSpace cs = opts.outColorSpace; 650 assertNull(b); 651 assertNotNull(cs); 652 assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), cs); 653 } catch (IOException e) { 654 fail(); 655 } 656 } 657 658 @Test guessProPhotoRGB()659 public void guessProPhotoRGB() { 660 BitmapFactory.Options opts = new BitmapFactory.Options(); 661 opts.inJustDecodeBounds = true; 662 663 try (InputStream in = mResources.getAssets().open("blue-16bit-prophoto.png")) { 664 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 665 ColorSpace cs = opts.outColorSpace; 666 assertNull(b); 667 assertNotNull(cs); 668 assertSame(ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), cs); 669 } catch (IOException e) { 670 fail(); 671 } 672 } 673 674 @Test guessP3()675 public void guessP3() { 676 BitmapFactory.Options opts = new BitmapFactory.Options(); 677 opts.inJustDecodeBounds = true; 678 679 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 680 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 681 ColorSpace cs = opts.outColorSpace; 682 assertNull(b); 683 assertNotNull(cs); 684 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 685 } catch (IOException e) { 686 fail(); 687 } 688 } 689 690 @Test guessAdobeRGB()691 public void guessAdobeRGB() { 692 BitmapFactory.Options opts = new BitmapFactory.Options(); 693 opts.inJustDecodeBounds = true; 694 695 try (InputStream in = mResources.getAssets().open("red-adobergb.png")) { 696 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 697 ColorSpace cs = opts.outColorSpace; 698 assertNull(b); 699 assertNotNull(cs); 700 assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs); 701 } catch (IOException e) { 702 fail(); 703 } 704 } 705 706 @Test guessUnknown()707 public void guessUnknown() { 708 BitmapFactory.Options opts = new BitmapFactory.Options(); 709 opts.inJustDecodeBounds = true; 710 711 try (InputStream in = mResources.getAssets().open("purple-displayprofile.png")) { 712 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 713 ColorSpace cs = opts.outColorSpace; 714 assertNull(b); 715 assertNotNull(cs); 716 assertEquals("Unknown", cs.getName()); 717 } catch (IOException e) { 718 fail(); 719 } 720 } 721 722 @Test guessCMYK()723 public void guessCMYK() { 724 BitmapFactory.Options opts = new BitmapFactory.Options(); 725 opts.inJustDecodeBounds = true; 726 727 try (InputStream in = mResources.getAssets().open("purple-cmyk.png")) { 728 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 729 ColorSpace cs = opts.outColorSpace; 730 assertNull(b); 731 assertNotNull(cs); 732 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs); 733 } catch (IOException e) { 734 fail(); 735 } 736 } 737 738 @Test inColorSpaceP3ToSRGB()739 public void inColorSpaceP3ToSRGB() { 740 BitmapFactory.Options opts = new BitmapFactory.Options(); 741 opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB); 742 743 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 744 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 745 ColorSpace cs = b.getColorSpace(); 746 assertNotNull(cs); 747 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs); 748 assertEquals(opts.inPreferredColorSpace, opts.outColorSpace); 749 750 verifyGetPixel(b, 0x2ff00ff); 751 } catch (IOException e) { 752 fail(); 753 } 754 } 755 756 @Test inColorSpaceSRGBToP3()757 public void inColorSpaceSRGBToP3() { 758 BitmapFactory.Options opts = new BitmapFactory.Options(); 759 opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3); 760 761 try (InputStream in = mResources.getAssets().open("green-srgb.png")) { 762 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 763 ColorSpace cs = b.getColorSpace(); 764 assertNotNull(cs); 765 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 766 assertEquals(opts.inPreferredColorSpace, opts.outColorSpace); 767 768 verifyGetPixel(b, 0x75fb4cff); 769 } catch (IOException e) { 770 fail(); 771 } 772 } 773 774 @Test inColorSpaceWith16BitSrc()775 public void inColorSpaceWith16BitSrc() { 776 BitmapFactory.Options opts = new BitmapFactory.Options(); 777 opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB); 778 779 try (InputStream in = mResources.getAssets().open("blue-16bit-srgb.png")) { 780 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 781 ColorSpace cs = b.getColorSpace(); 782 assertNotNull(cs); 783 assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs); 784 assertSame(opts.inPreferredColorSpace, opts.outColorSpace); 785 } catch (IOException e) { 786 fail(); 787 } 788 } 789 790 @Test inColorSpaceWith16BitDst()791 public void inColorSpaceWith16BitDst() { 792 BitmapFactory.Options opts = new BitmapFactory.Options(); 793 opts.inPreferredConfig = Bitmap.Config.RGBA_F16; 794 795 try (InputStream in = mResources.getAssets().open("blue-16bit-srgb.png")) { 796 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 797 ColorSpace cs = b.getColorSpace(); 798 assertNotNull(cs); 799 assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), cs); 800 } catch (IOException e) { 801 fail(); 802 } 803 } 804 805 @Test inColorSpaceWith16BitSrcAndDst()806 public void inColorSpaceWith16BitSrcAndDst() { 807 BitmapFactory.Options opts = new BitmapFactory.Options(); 808 opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB); 809 opts.inPreferredConfig = Bitmap.Config.RGBA_F16; 810 811 try (InputStream in = mResources.getAssets().open("blue-16bit-srgb.png")) { 812 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 813 ColorSpace cs = b.getColorSpace(); 814 assertNotNull(cs); 815 assertSame(opts.inPreferredColorSpace, cs); 816 assertSame(opts.inPreferredColorSpace, opts.outColorSpace); 817 } catch (IOException e) { 818 fail(); 819 } 820 } 821 822 @Test inColorSpaceWith16BitWithDecreasedGamut()823 public void inColorSpaceWith16BitWithDecreasedGamut() { 824 final String asset = "blue-16bit-prophoto.png"; 825 BitmapFactory.Options opts = new BitmapFactory.Options(); 826 opts.inJustDecodeBounds = true; 827 try (InputStream in = mResources.getAssets().open(asset)) { 828 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 829 assertNull(b); 830 assertEquals(ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), opts.outColorSpace); 831 assertEquals(Bitmap.Config.RGBA_F16, opts.outConfig); 832 } catch (IOException e) { 833 fail(); 834 } 835 836 opts.inJustDecodeBounds = false; 837 opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3); 838 839 try (InputStream in = mResources.getAssets().open(asset)) { 840 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 841 ColorSpace cs = b.getColorSpace(); 842 assertNotNull(cs); 843 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 844 } catch (IOException e) { 845 fail(); 846 } 847 } 848 849 @Test inColorSpace565()850 public void inColorSpace565() { 851 BitmapFactory.Options opts = new BitmapFactory.Options(); 852 opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB); 853 opts.inPreferredConfig = Bitmap.Config.RGB_565; 854 855 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 856 Bitmap b = BitmapFactory.decodeStream(in, null, opts); 857 ColorSpace cs = b.getColorSpace(); 858 assertNotNull(cs); 859 assertSame(opts.inPreferredColorSpace, cs); 860 assertSame(opts.inPreferredColorSpace, opts.outColorSpace); 861 } catch (IOException e) { 862 fail(); 863 } 864 } 865 866 @Test(expected = IllegalArgumentException.class) inColorSpaceNotRGB()867 public void inColorSpaceNotRGB() { 868 BitmapFactory.Options opts = new BitmapFactory.Options(); 869 opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.CIE_LAB); 870 871 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 872 BitmapFactory.decodeStream(in, null, opts); 873 } catch (IOException e) { 874 fail(); 875 } 876 } 877 878 @Test(expected = IllegalArgumentException.class) inColorSpaceNoTransferParameters()879 public void inColorSpaceNoTransferParameters() { 880 BitmapFactory.Options opts = new BitmapFactory.Options(); 881 opts.inPreferredColorSpace = new ColorSpace.Rgb("NoTransferParams", 882 new float[]{ 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }, 883 ColorSpace.ILLUMINANT_D50, 884 x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f), 885 0, 1); 886 887 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 888 BitmapFactory.decodeStream(in, null, opts); 889 } catch (IOException e) { 890 fail(); 891 } 892 } 893 894 @Test copyF16()895 public void copyF16() { 896 // Copying from (LINEAR_)SRGB to RGBA_F16 results in (LINEAR_)EXTENDED_SRGB. 897 ColorSpace[] srcCS = new ColorSpace[] { ColorSpace.get(ColorSpace.Named.SRGB), 898 ColorSpace.get(ColorSpace.Named.LINEAR_SRGB) }; 899 ColorSpace[] dstCS = new ColorSpace[] { ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), 900 ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB) }; 901 902 for (int i = 0; i < srcCS.length; ++i) { 903 for (Bitmap.Config config : new Bitmap.Config[] { Bitmap.Config.ARGB_8888, 904 Bitmap.Config.RGB_565 }) { 905 Bitmap b = Bitmap.createBitmap(10, 10, config, false, srcCS[i]); 906 assertSame(srcCS[i], b.getColorSpace()); 907 908 for (boolean mutable : new boolean[] { true, false }) { 909 Bitmap copy = b.copy(Bitmap.Config.RGBA_F16, mutable); 910 assertSame(dstCS[i], copy.getColorSpace()); 911 } 912 } 913 } 914 915 // The same is true for the reverse 916 for (int i = 0; i < srcCS.length; ++i) { 917 Bitmap b = Bitmap.createBitmap(10, 10, Bitmap.Config.RGBA_F16, false, dstCS[i]); 918 assertSame(dstCS[i], b.getColorSpace()); 919 for (Bitmap.Config config : new Bitmap.Config[] { Bitmap.Config.ARGB_8888, 920 Bitmap.Config.RGB_565 }) { 921 for (boolean mutable : new boolean[] { true, false }) { 922 Bitmap copy = b.copy(config, mutable); 923 assertSame(srcCS[i], copy.getColorSpace()); 924 } 925 } 926 } 927 } 928 929 @Test copyAlpha8()930 public void copyAlpha8() { 931 for (Bitmap.Config srcConfig : new Bitmap.Config[] { 932 Bitmap.Config.ALPHA_8, 933 Bitmap.Config.RGB_565, 934 Bitmap.Config.ARGB_8888, 935 Bitmap.Config.RGBA_F16, 936 }) { 937 Bitmap b = Bitmap.createBitmap(1, 1, srcConfig); 938 assertNotNull(b); 939 if (srcConfig == Bitmap.Config.ALPHA_8) { 940 assertNull(b.getColorSpace()); 941 } else { 942 assertNotNull(b.getColorSpace()); 943 } 944 945 Bitmap copy = b.copy(Bitmap.Config.ALPHA_8, false); 946 assertNotNull(copy); 947 assertNull(copy.getColorSpace()); 948 949 Bitmap copy2 = copy.copy(srcConfig, false); 950 switch (srcConfig) { 951 case RGBA_F16: 952 assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), 953 copy2.getColorSpace()); 954 break; 955 case ALPHA_8: 956 assertNull(b.getColorSpace()); 957 break; 958 default: 959 assertSame("Copied from ALPHA_8 to " + srcConfig, 960 ColorSpace.get(ColorSpace.Named.SRGB), copy2.getColorSpace()); 961 } 962 } 963 } 964 965 @Test copyHardwareToAlpha8()966 public void copyHardwareToAlpha8() { 967 BitmapFactory.Options options = new BitmapFactory.Options(); 968 options.inPreferredConfig = Bitmap.Config.HARDWARE; 969 Bitmap b = BitmapFactory.decodeResource(mResources, R.drawable.robot, options); 970 assertSame(Bitmap.Config.HARDWARE, b.getConfig()); 971 assertNotNull(b.getColorSpace()); 972 973 Bitmap copy = b.copy(Bitmap.Config.ALPHA_8, false); 974 assertNull(copy.getColorSpace()); 975 } 976 977 @Test copy()978 public void copy() { 979 Bitmap b = BitmapFactory.decodeResource(mResources, R.drawable.robot); 980 Bitmap c; 981 ColorSpace cs; 982 boolean[] trueFalse = new boolean[] { true, false }; 983 984 for (boolean mutable : trueFalse) { 985 c = b.copy(Bitmap.Config.ARGB_8888, mutable); 986 cs = c.getColorSpace(); 987 assertNotNull(cs); 988 assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs); 989 } 990 991 try (InputStream in = mResources.getAssets().open("green-p3.png")) { 992 b = BitmapFactory.decodeStream(in); 993 c = b.copy(Bitmap.Config.ARGB_8888, false); 994 cs = c.getColorSpace(); 995 assertNotNull(cs); 996 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 997 998 c = b.copy(Bitmap.Config.ARGB_8888, true); 999 cs = c.getColorSpace(); 1000 assertNotNull(cs); 1001 assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs); 1002 } catch (IOException e) { 1003 fail(); 1004 } 1005 1006 try (InputStream in = mResources.getAssets().open("blue-16bit-srgb.png")) { 1007 b = BitmapFactory.decodeStream(in); 1008 c = b.copy(Bitmap.Config.RGBA_F16, false); 1009 cs = c.getColorSpace(); 1010 assertNotNull(cs); 1011 assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), cs); 1012 1013 c = b.copy(Bitmap.Config.RGBA_F16, true); 1014 cs = c.getColorSpace(); 1015 assertNotNull(cs); 1016 assertSame(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), cs); 1017 } catch (IOException e) { 1018 fail(); 1019 } 1020 } 1021 1022 @SuppressWarnings("SameParameterValue") almostEqual(@olorInt int expected, @ColorInt int pixel, int threshold, int index)1023 private static void almostEqual(@ColorInt int expected, 1024 @ColorInt int pixel, int threshold, int index) { 1025 int diffA = Math.abs((expected >>> 24) - (pixel >>> 24)); 1026 int diffR = Math.abs(((expected >> 16) & 0xff) - ((pixel >> 16) & 0xff)); 1027 int diffG = Math.abs(((expected >> 8) & 0xff) - ((pixel >> 8) & 0xff)); 1028 int diffB = Math.abs((expected & 0xff) - (pixel & 0xff)); 1029 1030 boolean pass = diffA + diffR + diffG + diffB <= threshold; 1031 if (!pass) { 1032 Log.d(LOG_TAG, "Expected 0x" + Integer.toHexString(expected) + 1033 " but was 0x" + Integer.toHexString(pixel) + " with index " + index); 1034 } 1035 1036 assertTrue(pass); 1037 } 1038 1039 @Test testEncodeP3()1040 public void testEncodeP3() { 1041 Bitmap b = null; 1042 ImageDecoder.Source src = ImageDecoder.createSource(mResources.getAssets(), 1043 "blue-16bit-srgb.png"); 1044 try { 1045 b = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> { 1046 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 1047 }); 1048 assertNotNull(b); 1049 assertEquals(Bitmap.Config.RGBA_F16, b.getConfig()); 1050 } catch (IOException e) { 1051 fail("Failed with " + e); 1052 } 1053 1054 for (Bitmap.CompressFormat format : new Bitmap.CompressFormat[] { 1055 Bitmap.CompressFormat.JPEG, 1056 Bitmap.CompressFormat.WEBP, 1057 Bitmap.CompressFormat.PNG, 1058 }) { 1059 ByteArrayOutputStream out = new ByteArrayOutputStream(); 1060 assertTrue("Failed to encode F16 to " + format, b.compress(format, 100, out)); 1061 1062 byte[] array = out.toByteArray(); 1063 src = ImageDecoder.createSource(ByteBuffer.wrap(array)); 1064 1065 try { 1066 Bitmap b2 = ImageDecoder.decodeBitmap(src); 1067 assertEquals("Wrong color space for " + format, 1068 ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b2.getColorSpace()); 1069 } catch (IOException e) { 1070 fail("Failed with " + e); 1071 } 1072 } 1073 } 1074 1075 @Test testEncodeP3hardware()1076 public void testEncodeP3hardware() { 1077 Bitmap b = null; 1078 ImageDecoder.Source src = ImageDecoder.createSource(mResources.getAssets(), 1079 "green-p3.png"); 1080 try { 1081 b = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> { 1082 decoder.setAllocator(ImageDecoder.ALLOCATOR_HARDWARE); 1083 }); 1084 assertNotNull(b); 1085 assertEquals(Bitmap.Config.HARDWARE, b.getConfig()); 1086 assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace()); 1087 } catch (IOException e) { 1088 fail("Failed with " + e); 1089 } 1090 1091 for (Bitmap.CompressFormat format : new Bitmap.CompressFormat[] { 1092 Bitmap.CompressFormat.JPEG, 1093 Bitmap.CompressFormat.WEBP, 1094 Bitmap.CompressFormat.PNG, 1095 }) { 1096 ByteArrayOutputStream out = new ByteArrayOutputStream(); 1097 assertTrue("Failed to encode 8888 to " + format, b.compress(format, 100, out)); 1098 1099 byte[] array = out.toByteArray(); 1100 src = ImageDecoder.createSource(ByteBuffer.wrap(array)); 1101 1102 try { 1103 Bitmap b2 = ImageDecoder.decodeBitmap(src); 1104 assertEquals("Wrong color space for " + format, 1105 ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b2.getColorSpace()); 1106 } catch (IOException e) { 1107 fail("Failed with " + e); 1108 } 1109 } 1110 } 1111 1112 @Test 1113 @RequiresDevice // SwiftShader does not yet have support for F16 in HARDWARE b/75778024 test16bitHardware()1114 public void test16bitHardware() { 1115 // Decoding to HARDWARE may use EXTENDED_SRGB or SRGB, depending 1116 // on whether F16 is supported in HARDWARE. 1117 try (InputStream in = mResources.getAssets().open("blue-16bit-srgb.png")) { 1118 BitmapFactory.Options options = new BitmapFactory.Options(); 1119 options.inPreferredConfig = Bitmap.Config.HARDWARE; 1120 Bitmap b = BitmapFactory.decodeStream(in, null, options); 1121 assertEquals(Bitmap.Config.HARDWARE, b.getConfig()); 1122 1123 final ColorSpace cs = b.getColorSpace(); 1124 if (cs != ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB) 1125 && cs != ColorSpace.get(ColorSpace.Named.SRGB)) { 1126 fail("Unexpected color space " + cs); 1127 } 1128 } catch (Exception e) { 1129 fail("Failed with " + e); 1130 } 1131 } 1132 1133 @Test testProPhoto()1134 public void testProPhoto() throws IOException { 1135 ColorSpace extendedSrgb = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB); 1136 Color blue = Color.valueOf(0, 0, 1, 1, ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB)); 1137 Color expected = blue.convert(extendedSrgb); 1138 try (InputStream in = mResources.getAssets().open("blue-16bit-prophoto.png")) { 1139 Bitmap src = BitmapFactory.decodeStream(in, null, null); 1140 1141 Bitmap dst = Bitmap.createBitmap(src.getWidth(), src.getHeight(), 1142 Bitmap.Config.RGBA_F16, true, extendedSrgb); 1143 Canvas c = new Canvas(dst); 1144 c.drawBitmap(src, 0, 0, null); 1145 ColorUtils.verifyColor("PRO_PHOTO image did not convert properly", expected, 1146 dst.getColor(0, 0), .001f); 1147 } 1148 } 1149 } 1150