blob: 31f24955f63ef084dc880aeabeb62d25ddbd69ed [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.graphics.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ColorSpace;
import android.graphics.ImageDecoder;
import android.os.Parcel;
import android.util.Log;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.RequiresDevice;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BitmapColorSpaceTest {
private static final String LOG_TAG = "BitmapColorSpaceTest";
private Resources mResources;
@Before
public void setup() {
mResources = InstrumentationRegistry.getTargetContext().getResources();
}
@SuppressWarnings("deprecation")
@Test
public void createWithColorSpace() {
Bitmap b;
ColorSpace cs;
ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
// We don't test HARDWARE configs because they are not compatible with mutable bitmaps
b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(sRGB, cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true,
ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGBA_F16, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGBA_F16, true,
ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(sRGB, cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true,
ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(sRGB, cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(sRGB, cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true,
ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(sRGB, cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true, sRGB);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(sRGB, cs);
b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true,
ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(sRGB, cs);
}
@Test
public void createDefaultColorSpace() {
ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
Bitmap.Config[] configs = new Bitmap.Config[] {
Bitmap.Config.ALPHA_8, Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888
};
for (Bitmap.Config config : configs) {
Bitmap bitmap = Bitmap.createBitmap(32, 32, config, true);
assertSame(sRGB, bitmap.getColorSpace());
}
}
@Test(expected = IllegalArgumentException.class)
public void createWithoutColorSpace() {
Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, null);
}
@Test(expected = IllegalArgumentException.class)
public void createWithNonRgbColorSpace() {
Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true,
ColorSpace.get(ColorSpace.Named.CIE_LAB));
}
@Test
public void sRGB() {
Bitmap b = BitmapFactory.decodeResource(mResources, R.drawable.robot);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
}
@Test
public void p3() {
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
Bitmap b = BitmapFactory.decodeStream(in);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void extendedSRGB() {
try (InputStream in = mResources.getAssets().open("prophoto-rgba16f.png")) {
Bitmap b = BitmapFactory.decodeStream(in);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void reconfigure() {
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inMutable = true;
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
b.reconfigure(b.getWidth() / 2, b.getHeight() / 2, Bitmap.Config.RGBA_F16);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
b.reconfigure(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void reuse() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inMutable = true;
Bitmap bitmap1 = null;
try (InputStream in = mResources.getAssets().open("green-srgb.png")) {
bitmap1 = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = bitmap1.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
} catch (IOException e) {
fail();
}
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
opts.inBitmap = bitmap1;
Bitmap bitmap2 = BitmapFactory.decodeStream(in, null, opts);
assertSame(bitmap1, bitmap2);
ColorSpace cs = bitmap2.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void getPixel() {
verifyGetPixel("green-p3.png", 0x75fb4cff, 0xff00ff00);
verifyGetPixel("translucent-green-p3.png", 0x3a7d267f, 0x7f00ff00); // 50% translucent
}
private void verifyGetPixel(@NonNull String fileName,
@ColorInt int rawColor, @ColorInt int srgbColor) {
try (InputStream in = mResources.getAssets().open(fileName)) {
Bitmap b = BitmapFactory.decodeStream(in);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
verifyGetPixel(b, rawColor, srgbColor);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
verifyGetPixel(b, rawColor, srgbColor);
b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
verifyGetPixel(b, rawColor, srgbColor);
} catch (IOException e) {
fail();
}
}
private static void verifyGetPixel(@NonNull Bitmap b,
@ColorInt int rawColor, @ColorInt int srgbColor) {
ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
b.copyPixelsToBuffer(dst);
dst.rewind();
// Stored as RGBA
assertEquals(rawColor, dst.asIntBuffer().get());
int srgb = b.getPixel(15, 15);
almostEqual(srgbColor, srgb, 3, 15 * b.getWidth() + 15);
}
@Test
public void getPixels() {
verifyGetPixels("green-p3.png", 0xff00ff00);
verifyGetPixels("translucent-green-p3.png", 0x7f00ff00); // 50% translucent
}
private void verifyGetPixels(@NonNull String fileName, @ColorInt int expected) {
try (InputStream in = mResources.getAssets().open(fileName)) {
Bitmap b = BitmapFactory.decodeStream(in);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
verifyGetPixels(b, expected);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
verifyGetPixels(b, expected);
b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
verifyGetPixels(b, expected);
} catch (IOException e) {
fail();
}
}
private static void verifyGetPixels(@NonNull Bitmap b, @ColorInt int expected) {
int[] pixels = new int[b.getWidth() * b.getHeight()];
b.getPixels(pixels, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight());
for (int i = 0; i < pixels.length; i++) {
int pixel = pixels[i];
almostEqual(expected, pixel, 3, i);
}
}
@Test
public void setPixel() {
verifySetPixel("green-p3.png", 0xffff0000, 0xea3323ff);
verifySetPixel("translucent-green-p3.png", 0x7fff0000, 0x7519117f);
}
private void verifySetPixel(@NonNull String fileName,
@ColorInt int newColor, @ColorInt int expectedColor) {
try (InputStream in = mResources.getAssets().open(fileName)) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inMutable = true;
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
verifySetPixel(b, newColor, expectedColor);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
verifySetPixel(b, newColor, expectedColor);
b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
verifySetPixel(b, newColor, expectedColor);
} catch (IOException e) {
fail();
}
}
private static void verifySetPixel(@NonNull Bitmap b,
@ColorInt int newColor, @ColorInt int expectedColor) {
b.setPixel(0, 0, newColor);
ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
b.copyPixelsToBuffer(dst);
dst.rewind();
// Stored as RGBA
assertEquals(expectedColor, dst.asIntBuffer().get());
}
@Test
public void setPixels() {
verifySetPixels("green-p3.png", 0xffff0000, 0xea3323ff);
verifySetPixels("translucent-green-p3.png", 0x7fff0000, 0x7519117f);
}
private void verifySetPixels(@NonNull String fileName,
@ColorInt int newColor, @ColorInt int expectedColor) {
try (InputStream in = mResources.getAssets().open(fileName)) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inMutable = true;
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
verifySetPixels(b, newColor, expectedColor);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth() / 2, b.getHeight() / 2);
verifySetPixels(b, newColor, expectedColor);
b = Bitmap.createScaledBitmap(b, b.getWidth() / 2, b.getHeight() / 2, true);
verifySetPixels(b, newColor, expectedColor);
} catch (IOException e) {
fail();
}
}
private static void verifySetPixels(@NonNull Bitmap b,
@ColorInt int newColor, @ColorInt int expectedColor) {
int[] pixels = new int[b.getWidth() * b.getHeight()];
Arrays.fill(pixels, newColor);
b.setPixels(pixels, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight());
ByteBuffer dst = ByteBuffer.allocate(b.getByteCount());
b.copyPixelsToBuffer(dst);
dst.rewind();
IntBuffer buffer = dst.asIntBuffer();
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < pixels.length; i++) {
// Stored as RGBA
assertEquals(expectedColor, buffer.get());
}
}
@Test
public void writeColorSpace() {
verifyColorSpaceMarshalling("green-srgb.png", ColorSpace.get(ColorSpace.Named.SRGB));
verifyColorSpaceMarshalling("green-p3.png", ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
verifyColorSpaceMarshalling("prophoto-rgba16f.png",
ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB));
// Special case where the color space will be null in native
Bitmap bitmapIn = BitmapFactory.decodeResource(mResources, R.drawable.robot);
verifyParcelUnparcel(bitmapIn, ColorSpace.get(ColorSpace.Named.SRGB));
}
private void verifyColorSpaceMarshalling(
@NonNull String fileName, @NonNull ColorSpace colorSpace) {
try (InputStream in = mResources.getAssets().open(fileName)) {
Bitmap bitmapIn = BitmapFactory.decodeStream(in);
verifyParcelUnparcel(bitmapIn, colorSpace);
} catch (IOException e) {
fail();
}
}
private void verifyParcelUnparcel(Bitmap bitmapIn, ColorSpace expected) {
ColorSpace cs = bitmapIn.getColorSpace();
assertNotNull(cs);
assertSame(expected, cs);
Parcel p = Parcel.obtain();
bitmapIn.writeToParcel(p, 0);
p.setDataPosition(0);
Bitmap bitmapOut = Bitmap.CREATOR.createFromParcel(p);
cs = bitmapOut.getColorSpace();
assertNotNull(cs);
assertSame(expected, cs);
p.recycle();
}
@Test
public void p3rgb565() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredConfig = Bitmap.Config.RGB_565;
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void p3hardware() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredConfig = Bitmap.Config.HARDWARE;
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void guessSRGB() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
try (InputStream in = mResources.getAssets().open("green-srgb.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = opts.outColorSpace;
assertNull(b);
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void guessProPhotoRGB() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
try (InputStream in = mResources.getAssets().open("prophoto-rgba16f.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = opts.outColorSpace;
assertNull(b);
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void guessP3() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = opts.outColorSpace;
assertNull(b);
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void guessAdobeRGB() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
try (InputStream in = mResources.getAssets().open("red-adobergb.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = opts.outColorSpace;
assertNull(b);
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void guessUnknown() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
try (InputStream in = mResources.getAssets().open("purple-displayprofile.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = opts.outColorSpace;
assertNull(b);
assertNotNull(cs);
assertEquals("Unknown", cs.getName());
} catch (IOException e) {
fail();
}
}
@Test
public void guessCMYK() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
try (InputStream in = mResources.getAssets().open("purple-cmyk.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = opts.outColorSpace;
assertNull(b);
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
} catch (IOException e) {
fail();
}
}
@Test
public void inColorSpaceP3ToSRGB() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
assertEquals(opts.inPreferredColorSpace, opts.outColorSpace);
verifyGetPixel(b, 0x3ff00ff, 0xff00ff00);
} catch (IOException e) {
fail();
}
}
@Test
public void inColorSpaceSRGBToP3() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
try (InputStream in = mResources.getAssets().open("green-srgb.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
assertEquals(opts.inPreferredColorSpace, opts.outColorSpace);
verifyGetPixel(b, 0x75fb4cff, 0xff00ff00);
} catch (IOException e) {
fail();
}
}
@Test
public void inColorSpaceRGBA16F() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
try (InputStream in = mResources.getAssets().open("prophoto-rgba16f.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
assertNotEquals(opts.inPreferredColorSpace, opts.outColorSpace);
} catch (IOException e) {
fail();
}
}
@Test
public void inColorSpace565() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
opts.inPreferredConfig = Bitmap.Config.RGB_565;
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
Bitmap b = BitmapFactory.decodeStream(in, null, opts);
ColorSpace cs = b.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
assertNotEquals(opts.inPreferredColorSpace, opts.outColorSpace);
} catch (IOException e) {
fail();
}
}
@Test(expected = IllegalArgumentException.class)
public void inColorSpaceNotRGB() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.CIE_LAB);
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
BitmapFactory.decodeStream(in, null, opts);
} catch (IOException e) {
fail();
}
}
@Test(expected = IllegalArgumentException.class)
public void inColorSpaceNoTransferParameters() {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
BitmapFactory.decodeStream(in, null, opts);
} catch (IOException e) {
fail();
}
}
@Test
public void copy() {
Bitmap b = BitmapFactory.decodeResource(mResources, R.drawable.robot);
Bitmap c = b.copy(Bitmap.Config.ARGB_8888, false);
ColorSpace cs = c.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
c = b.copy(Bitmap.Config.ARGB_8888, true);
cs = c.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
try (InputStream in = mResources.getAssets().open("green-p3.png")) {
b = BitmapFactory.decodeStream(in);
c = b.copy(Bitmap.Config.ARGB_8888, false);
cs = c.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
c = b.copy(Bitmap.Config.ARGB_8888, true);
cs = c.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
} catch (IOException e) {
fail();
}
try (InputStream in = mResources.getAssets().open("prophoto-rgba16f.png")) {
b = BitmapFactory.decodeStream(in);
c = b.copy(Bitmap.Config.RGBA_F16, false);
cs = c.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
c = b.copy(Bitmap.Config.RGBA_F16, true);
cs = c.getColorSpace();
assertNotNull(cs);
assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
} catch (IOException e) {
fail();
}
}
@SuppressWarnings("SameParameterValue")
private static void almostEqual(@ColorInt int expected,
@ColorInt int pixel, int threshold, int index) {
int diffA = Math.abs(expected >>> 24 - pixel >>> 24);
int diffR = Math.abs((expected >> 16) & 0xff - (pixel >> 16) & 0xff);
int diffG = Math.abs((expected >> 8) & 0xff - (pixel >> 8) & 0xff);
int diffB = Math.abs((expected ) & 0xff - (pixel ) & 0xff);
boolean pass = diffA + diffR + diffG + diffB < threshold;
if (!pass) {
Log.d(LOG_TAG, "Expected 0x" + Integer.toHexString(expected) +
" but was 0x" + Integer.toHexString(pixel) + " with index " + index);
}
assertTrue(pass);
}
@Test
public void testEncodeP3() {
Bitmap b = null;
ImageDecoder.Source src = ImageDecoder.createSource(mResources.getAssets(),
"prophoto-rgba16f.png");
try {
b = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
});
assertNotNull(b);
assertEquals(Bitmap.Config.RGBA_F16, b.getConfig());
} catch (IOException e) {
fail("Failed with " + e);
}
for (Bitmap.CompressFormat format : new Bitmap.CompressFormat[] {
Bitmap.CompressFormat.JPEG,
Bitmap.CompressFormat.WEBP,
Bitmap.CompressFormat.PNG,
}) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
assertTrue("Failed to encode F16 to " + format, b.compress(format, 100, out));
byte[] array = out.toByteArray();
src = ImageDecoder.createSource(ByteBuffer.wrap(array));
try {
Bitmap b2 = ImageDecoder.decodeBitmap(src);
assertEquals("Wrong color space for " + format,
ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b2.getColorSpace());
} catch (IOException e) {
fail("Failed with " + e);
}
}
}
@Test
public void testEncodeP3hardware() {
Bitmap b = null;
ImageDecoder.Source src = ImageDecoder.createSource(mResources.getAssets(),
"green-p3.png");
try {
b = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
decoder.setAllocator(ImageDecoder.ALLOCATOR_HARDWARE);
});
assertNotNull(b);
assertEquals(Bitmap.Config.HARDWARE, b.getConfig());
assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b.getColorSpace());
} catch (IOException e) {
fail("Failed with " + e);
}
for (Bitmap.CompressFormat format : new Bitmap.CompressFormat[] {
Bitmap.CompressFormat.JPEG,
Bitmap.CompressFormat.WEBP,
Bitmap.CompressFormat.PNG,
}) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
assertTrue("Failed to encode 8888 to " + format, b.compress(format, 100, out));
byte[] array = out.toByteArray();
src = ImageDecoder.createSource(ByteBuffer.wrap(array));
try {
Bitmap b2 = ImageDecoder.decodeBitmap(src);
assertEquals("Wrong color space for " + format,
ColorSpace.get(ColorSpace.Named.DISPLAY_P3), b2.getColorSpace());
} catch (IOException e) {
fail("Failed with " + e);
}
}
}
@Test
@RequiresDevice // SwiftShader does not yet have support for F16 in HARDWARE b/75778024
public void test16bitHardware() {
// Decoding to HARDWARE may use LINEAR_EXTENDED_SRGB or SRGB, depending
// on whether F16 is supported in HARDWARE.
try (InputStream in = mResources.getAssets().open("prophoto-rgba16f.png")) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.HARDWARE;
Bitmap b = BitmapFactory.decodeStream(in, null, options);
assertEquals(Bitmap.Config.HARDWARE, b.getConfig());
final ColorSpace cs = b.getColorSpace();
if (cs != ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB)
&& cs != ColorSpace.get(ColorSpace.Named.SRGB)) {
fail("Unexpected color space " + cs);
}
} catch (Exception e) {
fail("Failed with " + e);
}
}
}