summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Leon Scroggins III <scroggo@google.com> 2018-03-29 09:48:47 -0400
committer Leon Scroggins III <scroggo@google.com> 2018-03-29 13:44:22 -0400
commit1a69f4598faef083d0123bb9b6bfcd6acfdec4e0 (patch)
tree83f6a0313e55022743b339ad60884aa86fc26180
parent64481195e13e2dd7197fff569344e5a263b7871a (diff)
Add in/out ColorSpace to ImageDecoder
Bug: 76448408 Test: I851173b771668f0e6712bebfe06bfb8559801199 Add ImageInfo.getColorSpace() for retrieving the default ColorSpace. This matches BitmapFactory.Options.outColorSpace. Add ImageDecoder.setTargetColorSpace() for choosing a new ColorSpace. This matches BitmapFactory.Options.inPreferredColorSpace. Rename setSampleSize to setTargetSampleSize to match setTargetSize and setTargetColorSpace. Change-Id: If2f4e755dfc163f754849f896de24659198973db
-rw-r--r--api/current.txt4
-rw-r--r--core/jni/android/graphics/ImageDecoder.cpp15
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java95
3 files changed, 94 insertions, 20 deletions
diff --git a/api/current.txt b/api/current.txt
index a01ef0d4a09c..2837091a400b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13643,7 +13643,8 @@ package android.graphics {
method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor);
method public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
- method public android.graphics.ImageDecoder setSampleSize(int);
+ method public android.graphics.ImageDecoder setTargetColorSpace(android.graphics.ColorSpace);
+ method public android.graphics.ImageDecoder setTargetSampleSize(int);
method public android.graphics.ImageDecoder setTargetSize(int, int);
field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
@@ -13660,6 +13661,7 @@ package android.graphics {
}
public static class ImageDecoder.ImageInfo {
+ method public android.graphics.ColorSpace getColorSpace();
method public java.lang.String getMimeType();
method public android.util.Size getSize();
method public boolean isAnimated();
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 726c450a4af2..825b7a0a9884 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -210,7 +210,7 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
jint desiredWidth, jint desiredHeight, jobject jsubset,
jboolean requireMutable, jint allocator,
jboolean requireUnpremul, jboolean preferRamOverQuality,
- jboolean asAlphaMask) {
+ jboolean asAlphaMask, jobject jcolorSpace) {
auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
SkAndroidCodec* codec = decoder->mCodec.get();
const SkISize desiredSize = SkISize::Make(desiredWidth, desiredHeight);
@@ -264,7 +264,8 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
// This is currently the only way to know that we should decode to F16.
colorType = codec->computeOutputColorType(colorType);
}
- sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
+ sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
+ colorSpace = codec->computeOutputColorSpace(colorType, colorSpace);
decodeInfo = decodeInfo.makeColorType(colorType).makeColorSpace(colorSpace);
SkBitmap bm;
@@ -507,18 +508,26 @@ static jstring ImageDecoder_nGetMimeType(JNIEnv* env, jobject /*clazz*/, jlong n
return encodedFormatToString(env, decoder->mCodec->getEncodedFormat());
}
+static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+ auto* codec = reinterpret_cast<ImageDecoder*>(nativePtr)->mCodec.get();
+ auto colorType = codec->computeOutputColorType(codec->getInfo().colorType());
+ sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
+ return GraphicsJNI::getColorSpace(env, colorSpace, colorType);
+}
+
static const JNINativeMethod gImageDecoderMethods[] = {
{ "nCreate", "(JLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateAsset },
{ "nCreate", "(Ljava/nio/ByteBuffer;IILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
{ "nCreate", "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
{ "nCreate", "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
{ "nCreate", "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
- { "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
+ { "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZLandroid/graphics/ColorSpace;)Landroid/graphics/Bitmap;",
(void*) ImageDecoder_nDecodeBitmap },
{ "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize },
{ "nGetPadding", "(JLandroid/graphics/Rect;)V", (void*) ImageDecoder_nGetPadding },
{ "nClose", "(J)V", (void*) ImageDecoder_nClose},
{ "nGetMimeType", "(J)Ljava/lang/String;", (void*) ImageDecoder_nGetMimeType },
+ { "nGetColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*) ImageDecoder_nGetColorSpace },
};
int register_android_graphics_ImageDecoder(JNIEnv* env) {
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 6939907bb419..6051f88733bf 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -432,6 +432,18 @@ public final class ImageDecoder implements AutoCloseable {
public boolean isAnimated() {
return mDecoder.mAnimated;
}
+
+ /**
+ * If known, the color space the decoded bitmap will have. Note that the
+ * output color space is not guaranteed to be the color space the bitmap
+ * is encoded with. If not known (when the config is
+ * {@link Bitmap.Config#ALPHA_8} for instance), or there is an error,
+ * it is set to null.
+ */
+ @Nullable
+ public ColorSpace getColorSpace() {
+ return mDecoder.getColorSpace();
+ }
};
/** @removed
@@ -582,16 +594,17 @@ public final class ImageDecoder implements AutoCloseable {
private final int mHeight;
private final boolean mAnimated;
- private int mDesiredWidth;
- private int mDesiredHeight;
- private int mAllocator = ALLOCATOR_DEFAULT;
- private boolean mRequireUnpremultiplied = false;
- private boolean mMutable = false;
- private boolean mConserveMemory = false;
- private boolean mDecodeAsAlphaMask = false;
- private Rect mCropRect;
- private Rect mOutPaddingRect;
- private Source mSource;
+ private int mDesiredWidth;
+ private int mDesiredHeight;
+ private int mAllocator = ALLOCATOR_DEFAULT;
+ private boolean mRequireUnpremultiplied = false;
+ private boolean mMutable = false;
+ private boolean mConserveMemory = false;
+ private boolean mDecodeAsAlphaMask = false;
+ private ColorSpace mDesiredColorSpace = null;
+ private Rect mCropRect;
+ private Rect mOutPaddingRect;
+ private Source mSource;
private PostProcessor mPostProcessor;
private OnPartialImageListener mOnPartialImageListener;
@@ -806,7 +819,8 @@ public final class ImageDecoder implements AutoCloseable {
* image, which can be retrieved from the {@link ImageInfo} in
* {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
*
- * <p>Only the last call to this or {@link #setSampleSize} is respected.</p>
+ * <p>Only the last call to this or {@link #setTargetSampleSize} is
+ * respected.</p>
*
* @param width must be greater than 0.
* @param height must be greater than 0.
@@ -824,11 +838,11 @@ public final class ImageDecoder implements AutoCloseable {
}
/** @removed
- * @deprecated Renamed to {@link #setSampleSize}.
+ * @deprecated Renamed to {@link #setTargetSampleSize}.
*/
@java.lang.Deprecated
public ImageDecoder setResize(int sampleSize) {
- return this.setSampleSize(sampleSize);
+ return this.setTargetSampleSize(sampleSize);
}
private int getTargetDimension(int original, int sampleSize, int computed) {
@@ -877,7 +891,7 @@ public final class ImageDecoder implements AutoCloseable {
* @param sampleSize Sampling rate of the encoded image.
* @return this object for chaining.
*/
- public ImageDecoder setSampleSize(int sampleSize) {
+ public ImageDecoder setTargetSampleSize(int sampleSize) {
Size size = this.getSampledSize(sampleSize);
int targetWidth = getTargetDimension(mWidth, sampleSize, size.getWidth());
int targetHeight = getTargetDimension(mHeight, sampleSize, size.getHeight());
@@ -1179,6 +1193,37 @@ public final class ImageDecoder implements AutoCloseable {
return this.getDecodeAsAlphaMask();
}
+ /**
+ * Specify the desired {@link ColorSpace} for the output.
+ *
+ * <p>If non-null, the decoder will try to decode into this
+ * color space. If it is null, which is the default, or the request cannot
+ * be met, the decoder will pick either the color space embedded in the
+ * image or the color space best suited for the requested image
+ * configuration (for instance {@link ColorSpace.Named#SRGB sRGB} for
+ * the {@link Bitmap.Config#ARGB_8888} configuration).</p>
+ *
+ * <p>{@link Bitmap.Config#RGBA_F16} always uses the
+ * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space).
+ * Bitmaps in other configurations without an embedded color space are
+ * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
+ *
+ * <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
+ * currently supported. An <code>IllegalArgumentException</code> will
+ * be thrown by the decode methods when setting a non-RGB color space
+ * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
+ *
+ * <p class="note">The specified color space's transfer function must be
+ * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An
+ * <code>IllegalArgumentException</code> will be thrown by the decode methods
+ * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the
+ * specified color space returns null.</p>
+ */
+ public ImageDecoder setTargetColorSpace(ColorSpace colorSpace) {
+ mDesiredColorSpace = colorSpace;
+ return this;
+ }
+
@Override
public void close() {
mCloseGuard.close();
@@ -1217,6 +1262,17 @@ public final class ImageDecoder implements AutoCloseable {
if (mPostProcessor != null && mRequireUnpremultiplied) {
throw new IllegalStateException("Cannot draw to unpremultiplied pixels!");
}
+
+ if (mDesiredColorSpace != null) {
+ if (!(mDesiredColorSpace instanceof ColorSpace.Rgb)) {
+ throw new IllegalArgumentException("The target color space must use the "
+ + "RGB color model - provided: " + mDesiredColorSpace);
+ }
+ if (((ColorSpace.Rgb) mDesiredColorSpace).getTransferParameters() == null) {
+ throw new IllegalArgumentException("The target color space must use an "
+ + "ICC parametric transfer function - provided: " + mDesiredColorSpace);
+ }
+ }
}
private static void checkSubset(int width, int height, Rect r) {
@@ -1235,7 +1291,7 @@ public final class ImageDecoder implements AutoCloseable {
return nDecodeBitmap(mNativePtr, this, mPostProcessor != null,
mDesiredWidth, mDesiredHeight, mCropRect,
mMutable, mAllocator, mRequireUnpremultiplied,
- mConserveMemory, mDecodeAsAlphaMask);
+ mConserveMemory, mDecodeAsAlphaMask, mDesiredColorSpace);
}
private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -1425,6 +1481,11 @@ public final class ImageDecoder implements AutoCloseable {
return nGetMimeType(mNativePtr);
}
+ @Nullable
+ private ColorSpace getColorSpace() {
+ return nGetColorSpace(mNativePtr);
+ }
+
/**
* See {@link #decodeBitmap(Source, OnHeaderDecodedListener)}.
*/
@@ -1474,11 +1535,13 @@ public final class ImageDecoder implements AutoCloseable {
int width, int height,
@Nullable Rect cropRect, boolean mutable,
int allocator, boolean requireUnpremul,
- boolean conserveMemory, boolean decodeAsAlphaMask)
+ boolean conserveMemory, boolean decodeAsAlphaMask,
+ @Nullable ColorSpace desiredColorSpace)
throws IOException;
private static native Size nGetSampledSize(long nativePtr,
int sampleSize);
private static native void nGetPadding(long nativePtr, @NonNull Rect outRect);
private static native void nClose(long nativePtr);
private static native String nGetMimeType(long nativePtr);
+ private static native ColorSpace nGetColorSpace(long nativePtr);
}