Skip to content

Commit

Permalink
Support Re-using Bitmaps with RGBA_F16 configs.
Browse files Browse the repository at this point in the history
Also adds emulator tests for wide gamut images on API 26+.
  • Loading branch information
sjudd committed Dec 24, 2017
1 parent cfeb4a4 commit cc0288c
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package com.bumptech.glide;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.ColorSpace;
import android.graphics.ColorSpace.Named;
import android.os.Build;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool;
import com.bumptech.glide.test.ConcurrencyHelper;
import com.bumptech.glide.test.GlideApp;
import com.bumptech.glide.test.ResourceIds;
import com.bumptech.glide.test.TearDownGlide;
import java.io.ByteArrayOutputStream;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class WideGamutTest {
@Rule public final TestRule tearDownGlide = new TearDownGlide();
private final ConcurrencyHelper concurrency = new ConcurrencyHelper();
private final Context context = InstrumentationRegistry.getTargetContext();

@Before
public void setUp() {
assumeTrue(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O);
}

@Test
public void load_withWideGamutImage_returnsWideGamutBitmap() {
Bitmap bitmap =
concurrency.get(
Glide.with(context)
.asBitmap()
.load(ResourceIds.raw.webkit_logo_p3)
.submit());
assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.RGBA_F16);
}

@Test
public void load_withWideGamutImage_bitmapInPoolWithSizeAndConfig_usesBitmapFromPool() {
int bitmapDimension = 1000;
Glide.init(
context,
new GlideBuilder()
.setBitmapPool(new LruBitmapPool(bitmapDimension * bitmapDimension * 8 * 4)));
Bitmap expected = Bitmap.createBitmap(bitmapDimension, bitmapDimension, Bitmap.Config.RGBA_F16);

Glide.get(context)
.getBitmapPool()
.put(expected);

Bitmap bitmap =
concurrency.get(
Glide.with(context)
.asBitmap()
.load(ResourceIds.raw.webkit_logo_p3)
.submit());
assertThat(bitmap).isSameAs(expected);
}

@Test
public void load_withWideGamutImage_hardwareAllowed_returnsHardwareBitmap() {
Bitmap bitmap =
concurrency.get(
GlideApp.with(context)
.asBitmap()
.format(DecodeFormat.PREFER_ARGB_8888)
.load(ResourceIds.raw.webkit_logo_p3)
.submit());
assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.HARDWARE);
}

@Test
public void load_withEncodedPngWideGamutImage_decodesWideGamut() {
Bitmap toCompress =
Bitmap.createBitmap(
100, 100, Bitmap.Config.RGBA_F16, /*hasAlpha=*/ true, ColorSpace.get(Named.DCI_P3));

ByteArrayOutputStream os = new ByteArrayOutputStream();
toCompress.compress(CompressFormat.PNG, 100, os);
byte[] data = os.toByteArray();

Bitmap bitmap =
concurrency.get(
Glide.with(context)
.asBitmap()
.load(data)
.submit());
assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.RGBA_F16);
}

@Test
public void load_withEncodedJpegWideGamutImage_decodesArgb8888() {
Bitmap toCompress =
Bitmap.createBitmap(
100, 100, Bitmap.Config.RGBA_F16, /*hasAlpha=*/ true, ColorSpace.get(Named.DCI_P3));

ByteArrayOutputStream os = new ByteArrayOutputStream();
toCompress.compress(CompressFormat.JPEG, 100, os);
byte[] data = os.toByteArray();

Bitmap bitmap =
concurrency.get(
Glide.with(context)
.asBitmap()
.load(data)
.submit());
assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ARGB_8888);
}

@Test
public void load_withEncodedWebpWideGamutImage_decodesArgb8888() {
Bitmap toCompress =
Bitmap.createBitmap(
100, 100, Bitmap.Config.RGBA_F16, /*hasAlpha=*/ true, ColorSpace.get(Named.DCI_P3));

ByteArrayOutputStream os = new ByteArrayOutputStream();
toCompress.compress(CompressFormat.WEBP, 100, os);
byte[] data = os.toByteArray();

Bitmap bitmap =
concurrency.get(
Glide.with(context)
.asBitmap()
.load(data)
.submit());
assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ARGB_8888);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public interface raw {
int transparent_gif = getResourceId("raw", "transparent_gif");
int opaque_gif = getResourceId("raw", "opaque_gif");
int opaque_interlaced_gif = getResourceId("raw", "opaque_interlaced_gif");
int webkit_logo_p3 = getResourceId("raw", "webkit_logo_p3");
}

public interface drawable {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -664,16 +664,27 @@ private static IOException newIoExceptionForInBitmapAssertion(IllegalArgumentExc

@SuppressWarnings("PMD.CollapsibleIfStatements")
@TargetApi(Build.VERSION_CODES.O)
private static void setInBitmap(BitmapFactory.Options options, BitmapPool bitmapPool, int width,
int height) {
private static void setInBitmap(
BitmapFactory.Options options, BitmapPool bitmapPool, int width, int height) {

Bitmap.Config expectedConfig;
// Avoid short circuiting, it appears to break on some devices.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (options.inPreferredConfig == Config.HARDWARE) {
return;
}
expectedConfig = options.outConfig;
} else {
// We're going to guess that BitmapFactory will return us the config we're requesting. This
// isn't always the case, even though our guesses tend to be conservative and prefer configs
// of larger sizes so that the Bitmap will fit our image anyway. If we're wrong here and the
// config we choose is too small, our initial decode will fail, but we will retry with no
// inBitmap which will succeed so if we're wrong here, we're less efficient but still correct.
expectedConfig = options.inPreferredConfig;
}

// BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe.
options.inBitmap = bitmapPool.getDirty(width, height, options.inPreferredConfig);
options.inBitmap = bitmapPool.getDirty(width, height, expectedConfig);
}

private static synchronized BitmapFactory.Options getDefaultOptions() {
Expand Down

0 comments on commit cc0288c

Please sign in to comment.