diff options
| -rwxr-xr-x | core/jni/android/graphics/Bitmap.cpp | 87 | ||||
| -rw-r--r-- | core/jni/android/graphics/Graphics.cpp | 9 | ||||
| -rw-r--r-- | core/jni/android/graphics/GraphicsJNI.h | 1 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Bitmap.java | 16 |
4 files changed, 92 insertions, 21 deletions
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index e4493b1f489a..f85219453212 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -8,6 +8,8 @@ #include "SkImageInfo.h" #include "SkColor.h" #include "SkColorPriv.h" +#include "SkColorSpace.h" +#include "SkColorSpaceXform.h" #include "SkHalf.h" #include "SkMatrix44.h" #include "SkPM4f.h" @@ -29,6 +31,7 @@ #include "core_jni_helpers.h" #include <jni.h> +#include <string.h> #include <memory> #include <string> @@ -448,11 +451,32 @@ bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int // reset to to actual choice from caller dst = dstBitmap.getAddr(x, y); - // now copy/convert each scanline - for (int y = 0; y < height; y++) { - proc(dst, src, width, x, y); - src += srcStride; - dst = (char*)dst + dstBitmap.rowBytes(); + + SkColorSpace* colorSpace = dstBitmap.colorSpace(); + if (GraphicsJNI::isColorSpaceSRGB(colorSpace)) { + // now copy/convert each scanline + for (int y = 0; y < height; y++) { + proc(dst, src, width, x, y); + src += srcStride; + dst = (char*)dst + dstBitmap.rowBytes(); + } + } else { + auto sRGB = SkColorSpace::MakeSRGB(); + auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace); + + std::unique_ptr<SkColor[]> row(new SkColor[width]); + + // now copy/convert each scanline + for (int y = 0; y < height; y++) { + memcpy(row.get(), src, sizeof(SkColor) * width); + xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(), + SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(), width, + SkAlphaType::kUnpremul_SkAlphaType); + + proc(dst, row.get(), width, x, y); + src += srcStride; + dst = (char*)dst + dstBitmap.rowBytes(); + } } dstBitmap.notifyPixelsChanged(); @@ -1179,12 +1203,7 @@ static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) { if (!bitmapHolder.valid()) return JNI_TRUE; SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); - return colorSpace == nullptr || - colorSpace == SkColorSpace::MakeSRGB().get() || - colorSpace == SkColorSpace::MakeRGB( - SkColorSpace::kSRGB_RenderTargetGamma, - SkColorSpace::kSRGB_Gamut, - SkColorSpace::kNonLinearBlending_ColorSpaceFlag).get(); + return GraphicsJNI::isColorSpaceSRGB(colorSpace); } static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, @@ -1246,6 +1265,16 @@ static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, SkColor dst[1]; proc(dst, src, 1, bitmap.getColorTable()); + + SkColorSpace* colorSpace = bitmap.colorSpace(); + if (!GraphicsJNI::isColorSpaceSRGB(colorSpace)) { + auto sRGB = SkColorSpace::MakeSRGB(); + auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get()); + xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], + SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1, + SkAlphaType::kUnpremul_SkAlphaType); + } + return static_cast<jint>(dst[0]); } @@ -1268,11 +1297,30 @@ static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, SkColorTable* ctable = bitmap.getColorTable(); jint* dst = env->GetIntArrayElements(pixelArray, NULL); SkColor* d = (SkColor*)dst + offset; - while (--height >= 0) { - proc(d, src, width, ctable); - d += stride; - src = (void*)((const char*)src + bitmap.rowBytes()); + + SkColorSpace* colorSpace = bitmap.colorSpace(); + if (GraphicsJNI::isColorSpaceSRGB(colorSpace)) { + while (--height >= 0) { + proc(d, src, width, ctable); + d += stride; + src = (void*)((const char*)src + bitmap.rowBytes()); + } + } else { + auto sRGB = SkColorSpace::MakeSRGB(); + auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get()); + + while (--height >= 0) { + proc(d, src, width, ctable); + + xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, d, + SkColorSpaceXform::kBGRA_8888_ColorFormat, d, width, + SkAlphaType::kUnpremul_SkAlphaType); + + d += stride; + src = (void*)((const char*)src + bitmap.rowBytes()); + } } + env->ReleaseIntArrayElements(pixelArray, dst, 0); } @@ -1293,6 +1341,15 @@ static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, return; } + SkColorSpace* colorSpace = bitmap.colorSpace(); + if (!GraphicsJNI::isColorSpaceSRGB(colorSpace)) { + auto sRGB = SkColorSpace::MakeSRGB(); + auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace); + xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, + SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1, + SkAlphaType::kUnpremul_SkAlphaType); + } + proc(bitmap.getAddr(x, y), &color, 1, x, y); bitmap.notifyPixelsChanged(); } diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 5d7310167b7c..7c56c7bf4158 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -460,6 +460,15 @@ sk_sp<SkColorSpace> GraphicsJNI::colorSpaceForType(SkColorType type) { } } +bool GraphicsJNI::isColorSpaceSRGB(SkColorSpace* colorSpace) { + return colorSpace == nullptr + || colorSpace == SkColorSpace::MakeSRGB().get() + || colorSpace == SkColorSpace::MakeRGB( + SkColorSpace::kSRGB_RenderTargetGamma, + SkColorSpace::kSRGB_Gamut, + SkColorSpace::kNonLinearBlending_ColorSpaceFlag).get(); +} + /////////////////////////////////////////////////////////////////////////////// bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { mStorage = android::Bitmap::allocateHeapBitmap(bitmap, ctable); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 8a1ef6ee5d34..7d7c88159a55 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -111,6 +111,7 @@ public: static sk_sp<SkColorSpace> defaultColorSpace(); static sk_sp<SkColorSpace> linearColorSpace(); static sk_sp<SkColorSpace> colorSpaceForType(SkColorType type); + static bool isColorSpaceSRGB(SkColorSpace* colorSpace); }; class HeapAllocator : public SkBRDAllocator { diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 6bb8a2cac430..3d5ba7938b31 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -522,7 +522,7 @@ public final class Bitmap implements Parcelable { * <p>The content of the bitmap is copied into the buffer as-is. This means * that if this bitmap stores its pixels pre-multiplied * (see {@link #isPremultiplied()}, the values in the buffer will also be - * pre-multiplied.</p> + * pre-multiplied. The pixels remain in the color space of the bitmap.</p> * <p>After this method returns, the current position of the buffer is * updated: the position is incremented by the number of elements written * in the buffer.</p> @@ -562,7 +562,8 @@ public final class Bitmap implements Parcelable { * <p>Copy the pixels from the buffer, beginning at the current position, * overwriting the bitmap's pixels. The data in the buffer is not changed * in any way (unlike setPixels(), which converts from unpremultipled 32bit - * to whatever the bitmap's native format is.</p> + * to whatever the bitmap's native format is. The pixels in the source + * buffer are assumed to be in the bitmap's color space.</p> * <p>After this method returns, the current position of the buffer is * updated: the position is incremented by the number of elements read from * the buffer. If you need to read the bitmap from the buffer again you must @@ -1495,7 +1496,8 @@ public final class Bitmap implements Parcelable { /** * Returns the {@link Color} at the specified location. Throws an exception * if x or y are out of bounds (negative or >= to the width or height - * respectively). The returned color is a non-premultiplied ARGB value. + * respectively). The returned color is a non-premultiplied ARGB value in + * the {@link ColorSpace.Named#SRGB sRGB} color space. * * @param x The x coordinate (0...width-1) of the pixel to return * @param y The y coordinate (0...height-1) of the pixel to return @@ -1517,7 +1519,8 @@ public final class Bitmap implements Parcelable { * a packed int representing a {@link Color}. The stride parameter allows * the caller to allow for gaps in the returned pixels array between * rows. For normal packed results, just pass width for the stride value. - * The returned colors are non-premultiplied ARGB values. + * The returned colors are non-premultiplied ARGB values in the + * {@link ColorSpace.Named#SRGB sRGB} color space. * * @param pixels The array to receive the bitmap's colors * @param offset The first index to write into pixels[] @@ -1610,7 +1613,8 @@ public final class Bitmap implements Parcelable { /** * <p>Write the specified {@link Color} into the bitmap (assuming it is * mutable) at the x,y coordinate. The color must be a - * non-premultiplied ARGB value.</p> + * non-premultiplied ARGB value in the {@link ColorSpace.Named#SRGB sRGB} + * color space.</p> * * @param x The x coordinate of the pixel to replace (0...width-1) * @param y The y coordinate of the pixel to replace (0...height-1) @@ -1632,7 +1636,7 @@ public final class Bitmap implements Parcelable { /** * <p>Replace pixels in the bitmap with the colors in the array. Each element * in the array is a packed int representing a non-premultiplied ARGB - * {@link Color}.</p> + * {@link Color} in the {@link ColorSpace.Named#SRGB sRGB} color space.</p> * * @param pixels The colors to write to the bitmap * @param offset The index of the first color to read from pixels[] |