Skip to content

Commit 7910f68

Browse files
sjuddglide-copybara-robot
authored andcommitted
Add support for P3 and SRGB in Glide.
Allows users of the library to manually set an option to support displaying wide gamut images with the DISPLAY_P3 color space on P+. Defaults Glide to using SRGB on O and for all loads where the option isn't set to DISPLAY_P3. Does not allow callers to specify other color spaces. Does not allow callers to convert SRGB images to DISPLAY_P3. Does not verify that screens/renderers are capable of displaying P3 images when it's requested. PiperOrigin-RevId: 260580611
1 parent 7fe334f commit 7910f68

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.bumptech.glide.load;
2+
3+
/**
4+
* Glide's supported handling of color spaces on Android O+, defaults to {@link #SRGB}.
5+
*
6+
* <p>On Android O, Glide will always request SRGB and will ignore this option if set. A bug on
7+
* Android O prevents P3 images from being compressed correctly and can result in color distortion.
8+
* We may eventually work around this in Glide if sufficient demand arises, but doing so will
9+
* require a memory intensive conversion to SRGB prior to compressing Bitmaps to Glide's disk cache.
10+
* This work around would also work only for Glide's compression, not for any compression that a
11+
* caller performs on a Bitmap returned by Glide.
12+
*
13+
* <p>On Android P+, Glide supports SRGB and display P3. However, if display p3 is requested, we
14+
* will still decode to SRGB unless {@link android.graphics.BitmapFactory.Options#outColorSpace} is
15+
* also {@link android.graphics.ColorSpace.Named#DISPLAY_P3}. Preferring P3 for SRGB images adds
16+
* unnecessary CPU work to convert back and forth between the color spaces at decode time.
17+
*
18+
* <p>Using {@link #DISPLAY_P3} is wasteful if either the screen or the renderer do not support P3.
19+
* Currently Glide does not attempt to detect whether or not this support is present. Do not use
20+
* {@link #DISPLAY_P3} thinking that you're going to get higher quality by default. Only use {@link
21+
* #DISPLAY_P3} if you're confident you understand color spaces, your application is working with a
22+
* display that supports wide gamut and you've set the appropriate options to render wide gamut
23+
* colors. If you've missed one or more of these steps, {@link #DISPLAY_P3} can lead to poor color
24+
* quality and washed out looking images. When in doubt, always use {@link #SRGB}, which is Glide's
25+
* default.
26+
*
27+
* <p>As with {@link DecodeFormat} we cannot directly set color spaces, we can only suggest to the
28+
* framework which one we want. Setting one of these values is not a guarantee that any returned
29+
* Bitmap will actually use the requested color space.
30+
*/
31+
public enum PreferredColorSpace {
32+
/** Prefers to decode images using {@link android.graphics.ColorSpace.Named#SRGB}. */
33+
SRGB,
34+
/** Prefers to decode images using {@link android.graphics.ColorSpace.Named#DISPLAY_P3}. */
35+
DISPLAY_P3,
36+
}

library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java

+30
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import android.graphics.Bitmap;
55
import android.graphics.Bitmap.Config;
66
import android.graphics.BitmapFactory;
7+
import android.graphics.ColorSpace;
78
import android.os.Build;
89
import android.util.DisplayMetrics;
910
import android.util.Log;
@@ -14,6 +15,7 @@
1415
import com.bumptech.glide.load.ImageHeaderParserUtils;
1516
import com.bumptech.glide.load.Option;
1617
import com.bumptech.glide.load.Options;
18+
import com.bumptech.glide.load.PreferredColorSpace;
1719
import com.bumptech.glide.load.engine.Resource;
1820
import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool;
1921
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
@@ -48,6 +50,18 @@ public final class Downsampler {
4850
public static final Option<DecodeFormat> DECODE_FORMAT =
4951
Option.memory(
5052
"com.bumptech.glide.load.resource.bitmap.Downsampler.DecodeFormat", DecodeFormat.DEFAULT);
53+
54+
/**
55+
* Sets the {@link PreferredColorSpace} that will be used along with the version of Android and
56+
* color space of the requested image to determine the final color space used to decode the image.
57+
*
58+
* <p>Refer to {@link PreferredColorSpace} for details on how this option works and its various
59+
* limitations.
60+
*/
61+
public static final Option<PreferredColorSpace> PREFERRED_COLOR_SPACE =
62+
Option.memory(
63+
"com.bumptech.glide.load.resource.bitmap.Downsampler.PreferredColorSpace",
64+
PreferredColorSpace.SRGB);
5165
/**
5266
* Indicates the {@link com.bumptech.glide.load.resource.bitmap.DownsampleStrategy} option that
5367
* will be used to calculate the sample size to use to downsample an image given the original and
@@ -199,6 +213,7 @@ public Resource<Bitmap> decode(
199213
bitmapFactoryOptions.inTempStorage = bytesForOptions;
200214

201215
DecodeFormat decodeFormat = options.get(DECODE_FORMAT);
216+
PreferredColorSpace preferredColorSpace = options.get(PREFERRED_COLOR_SPACE);
202217
DownsampleStrategy downsampleStrategy = options.get(DownsampleStrategy.OPTION);
203218
boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS);
204219
boolean isHardwareConfigAllowed =
@@ -211,6 +226,7 @@ public Resource<Bitmap> decode(
211226
bitmapFactoryOptions,
212227
downsampleStrategy,
213228
decodeFormat,
229+
preferredColorSpace,
214230
isHardwareConfigAllowed,
215231
requestedWidth,
216232
requestedHeight,
@@ -228,6 +244,7 @@ private Bitmap decodeFromWrappedStreams(
228244
BitmapFactory.Options options,
229245
DownsampleStrategy downsampleStrategy,
230246
DecodeFormat decodeFormat,
247+
PreferredColorSpace preferredColorSpace,
231248
boolean isHardwareConfigAllowed,
232249
int requestedWidth,
233250
int requestedHeight,
@@ -328,6 +345,18 @@ private Bitmap decodeFromWrappedStreams(
328345
setInBitmap(options, bitmapPool, expectedWidth, expectedHeight);
329346
}
330347
}
348+
349+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
350+
boolean isP3Eligible =
351+
preferredColorSpace == PreferredColorSpace.DISPLAY_P3
352+
&& options.outColorSpace != null
353+
&& options.outColorSpace.isWideGamut();
354+
options.inPreferredColorSpace =
355+
ColorSpace.get(isP3Eligible ? ColorSpace.Named.DISPLAY_P3 : ColorSpace.Named.SRGB);
356+
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
357+
options.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
358+
}
359+
331360
Bitmap downsampled = decodeStream(is, options, callbacks, bitmapPool);
332361
callbacks.onDecodeComplete(bitmapPool, downsampled);
333362

@@ -860,6 +889,7 @@ private static void resetOptions(BitmapFactory.Options decodeBitmapOptions) {
860889
decodeBitmapOptions.inDensity = 0;
861890
decodeBitmapOptions.inTargetDensity = 0;
862891
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
892+
decodeBitmapOptions.outColorSpace = null;
863893
decodeBitmapOptions.outConfig = null;
864894
}
865895
decodeBitmapOptions.outWidth = 0;

0 commit comments

Comments
 (0)