Merge "Implement Bitmap get/setPixel(s) using SkBitmap::read/writePixels"

This commit is contained in:
Brian Osman
2018-08-22 15:08:08 +00:00
committed by Android (Google) Code Review
3 changed files with 26 additions and 376 deletions

View File

@@ -310,180 +310,17 @@ bool unlockPixels(JNIEnv* env, jobject bitmap) {
using namespace android;
using namespace android::bitmap;
///////////////////////////////////////////////////////////////////////////////
// Conversions to/from SkColor, for get/setPixels, and the create method, which
// is basically like setPixels
typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
int x, int y);
static void FromColor_F16(void* dst, const SkColor src[], int width,
int, int) {
uint64_t* d = (uint64_t*)dst;
for (int i = 0; i < width; i++) {
*d++ = SkColor4f::FromColor(*src++).premul().toF16();
}
}
static void FromColor_F16_Raw(void* dst, const SkColor src[], int width,
int, int) {
uint64_t* d = (uint64_t*)dst;
for (int i = 0; i < width; i++) {
const SkColor4f color = SkColor4f::FromColor(*src++);
uint16_t* scratch = reinterpret_cast<uint16_t*>(d++);
scratch[0] = SkFloatToHalf(color.fR);
scratch[1] = SkFloatToHalf(color.fG);
scratch[2] = SkFloatToHalf(color.fB);
scratch[3] = SkFloatToHalf(color.fA);
}
}
static void FromColor_D32(void* dst, const SkColor src[], int width,
int, int) {
SkPMColor* d = (SkPMColor*)dst;
for (int i = 0; i < width; i++) {
*d++ = SkPreMultiplyColor(*src++);
}
}
static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
int, int) {
// Needed to thwart the unreachable code detection from clang.
static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
// SkColor's ordering may be different from SkPMColor
if (sk_color_ne_zero) {
memcpy(dst, src, width * sizeof(SkColor));
return;
}
// order isn't same, repack each pixel manually
SkPMColor* d = (SkPMColor*)dst;
for (int i = 0; i < width; i++) {
SkColor c = *src++;
*d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
SkColorGetG(c), SkColorGetB(c));
}
}
static void FromColor_D565(void* dst, const SkColor src[], int width,
int x, int y) {
uint16_t* d = (uint16_t*)dst;
DITHER_565_SCAN(y);
for (int stop = x + width; x < stop; x++) {
SkColor c = *src++;
*d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
DITHER_VALUE(x));
}
}
static void FromColor_D4444(void* dst, const SkColor src[], int width,
int x, int y) {
SkPMColor16* d = (SkPMColor16*)dst;
DITHER_4444_SCAN(y);
for (int stop = x + width; x < stop; x++) {
SkPMColor pmc = SkPreMultiplyColor(*src++);
*d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
// *d++ = SkPixel32ToPixel4444(pmc);
}
}
static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
int x, int y) {
SkPMColor16* d = (SkPMColor16*)dst;
DITHER_4444_SCAN(y);
for (int stop = x + width; x < stop; x++) {
SkColor c = *src++;
// SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
SkColorGetG(c), SkColorGetB(c));
*d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
// *d++ = SkPixel32ToPixel4444(pmc);
}
}
static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
uint8_t* d = (uint8_t*)dst;
for (int stop = x + width; x < stop; x++) {
*d++ = SkColorGetA(*src++);
}
}
// can return NULL
static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
switch (bitmap.colorType()) {
case kN32_SkColorType:
return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
case kARGB_4444_SkColorType:
return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
FromColor_D4444_Raw;
case kRGB_565_SkColorType:
return FromColor_D565;
case kAlpha_8_SkColorType:
return FromColor_DA8;
case kRGBA_F16_SkColorType:
return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw;
default:
break;
}
return NULL;
}
static bool IsColorSpaceSRGB(SkColorSpace* colorSpace) {
return colorSpace == nullptr || colorSpace->isSRGB();
}
bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
int x, int y, int width, int height, const SkBitmap& dstBitmap) {
void* dst = dstBitmap.getPixels();
FromColorProc proc = ChooseFromColorProc(dstBitmap);
if (NULL == dst || NULL == proc) {
return false;
}
int x, int y, int width, int height, SkBitmap* dstBitmap) {
const jint* array = env->GetIntArrayElements(srcColors, NULL);
const SkColor* src = (const SkColor*)array + srcOffset;
// reset to to actual choice from caller
dst = dstBitmap.getAddr(x, y);
auto sRGB = SkColorSpace::MakeSRGB();
SkImageInfo srcInfo = SkImageInfo::Make(
width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
SkPixmap srcPM(srcInfo, src, srcStride * 4);
SkColorSpace* colorSpace = dstBitmap.colorSpace();
if (dstBitmap.colorType() == kRGBA_F16_SkColorType || 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();
dstBitmap->writePixels(srcPM, x, y);
env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
return true;
@@ -491,90 +328,6 @@ bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int
//////////////////// ToColor procs
typedef void (*ToColorProc)(SkColor dst[], const void* src, int width);
static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
uint64_t* s = (uint64_t*)src;
do {
*dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor();
} while (--width != 0);
}
static void ToColor_F16_Raw(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
uint64_t* s = (uint64_t*)src;
do {
*dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++)));
} while (--width != 0);
}
static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
const SkPMColor* s = (const SkPMColor*)src;
do {
*dst++ = SkUnPreMultiply::PMColorToColor(*s++);
} while (--width != 0);
}
static void ToColor_S32_Raw(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
const SkPMColor* s = (const SkPMColor*)src;
do {
SkPMColor c = *s++;
*dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
SkGetPackedG32(c), SkGetPackedB32(c));
} while (--width != 0);
}
static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
const SkPMColor* s = (const SkPMColor*)src;
do {
SkPMColor c = *s++;
*dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
SkGetPackedB32(c));
} while (--width != 0);
}
static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
const SkPMColor16* s = (const SkPMColor16*)src;
do {
*dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
} while (--width != 0);
}
static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
const SkPMColor16* s = (const SkPMColor16*)src;
do {
SkPMColor c = SkPixel4444ToPixel32(*s++);
*dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
SkGetPackedG32(c), SkGetPackedB32(c));
} while (--width != 0);
}
static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
const SkPMColor16* s = (const SkPMColor16*)src;
do {
SkPMColor c = SkPixel4444ToPixel32(*s++);
*dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
SkGetPackedB32(c));
} while (--width != 0);
}
static void ToColor_S565(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
const uint16_t* s = (const uint16_t*)src;
do {
uint16_t c = *s++;
*dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
SkPacked16ToB32(c));
} while (--width != 0);
}
static void ToColor_SA8(SkColor dst[], const void* src, int width) {
SkASSERT(width > 0);
const uint8_t* s = (const uint8_t*)src;
@@ -584,52 +337,6 @@ static void ToColor_SA8(SkColor dst[], const void* src, int width) {
} while (--width != 0);
}
// can return NULL
static ToColorProc ChooseToColorProc(const SkBitmap& src) {
switch (src.colorType()) {
case kN32_SkColorType:
switch (src.alphaType()) {
case kOpaque_SkAlphaType:
return ToColor_S32_Opaque;
case kPremul_SkAlphaType:
return ToColor_S32_Alpha;
case kUnpremul_SkAlphaType:
return ToColor_S32_Raw;
default:
return NULL;
}
case kARGB_4444_SkColorType:
switch (src.alphaType()) {
case kOpaque_SkAlphaType:
return ToColor_S4444_Opaque;
case kPremul_SkAlphaType:
return ToColor_S4444_Alpha;
case kUnpremul_SkAlphaType:
return ToColor_S4444_Raw;
default:
return NULL;
}
case kRGB_565_SkColorType:
return ToColor_S565;
case kAlpha_8_SkColorType:
return ToColor_SA8;
case kRGBA_F16_SkColorType:
switch (src.alphaType()) {
case kOpaque_SkAlphaType:
return ToColor_F16_Raw;
case kPremul_SkAlphaType:
return ToColor_F16_Alpha;
case kUnpremul_SkAlphaType:
return ToColor_F16_Raw;
default:
return NULL;
}
default:
break;
}
return NULL;
}
static void ToF16_SA8(void* dst, const void* src, int width) {
SkASSERT(width > 0);
uint64_t* d = (uint64_t*)dst;
@@ -694,7 +401,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
}
if (jColors != NULL) {
GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap);
GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, &bitmap);
}
return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
@@ -1271,7 +978,7 @@ static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
if (!bitmapHolder.valid()) return JNI_TRUE;
SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
return IsColorSpaceSRGB(colorSpace);
return colorSpace == nullptr || colorSpace->isSRGB();
}
static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -1330,28 +1037,13 @@ static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
SkBitmap bitmap;
reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
ToColorProc proc = ChooseToColorProc(bitmap);
if (NULL == proc) {
return 0;
}
const void* src = bitmap.getAddr(x, y);
if (NULL == src) {
return 0;
}
auto sRGB = SkColorSpace::MakeSRGB();
SkImageInfo dstInfo = SkImageInfo::Make(
1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
SkColor dst[1];
proc(dst, src, 1);
SkColorSpace* colorSpace = bitmap.colorSpace();
if (bitmap.colorType() != kRGBA_F16_SkColorType && !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]);
SkColor dst;
bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
return static_cast<jint>(dst);
}
static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
@@ -1360,41 +1052,12 @@ static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
SkBitmap bitmap;
reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
ToColorProc proc = ChooseToColorProc(bitmap);
if (NULL == proc) {
return;
}
const void* src = bitmap.getAddr(x, y);
if (NULL == src) {
return;
}
auto sRGB = SkColorSpace::MakeSRGB();
SkImageInfo dstInfo = SkImageInfo::Make(
width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
jint* dst = env->GetIntArrayElements(pixelArray, NULL);
SkColor* d = (SkColor*)dst + offset;
SkColorSpace* colorSpace = bitmap.colorSpace();
if (bitmap.colorType() == kRGBA_F16_SkColorType || IsColorSpaceSRGB(colorSpace)) {
while (--height >= 0) {
proc(d, src, width);
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);
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());
}
}
bitmap.readPixels(dstInfo, dst + offset, stride * 4, x, y);
env->ReleaseIntArrayElements(pixelArray, dst, 0);
}
@@ -1405,26 +1068,13 @@ static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
SkBitmap bitmap;
reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
SkColor color = static_cast<SkColor>(colorHandle);
if (NULL == bitmap.getPixels()) {
return;
}
FromColorProc proc = ChooseFromColorProc(bitmap);
if (NULL == proc) {
return;
}
auto sRGB = SkColorSpace::MakeSRGB();
SkImageInfo srcInfo = SkImageInfo::Make(
1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
SkPixmap srcPM(srcInfo, &color, srcInfo.minRowBytes());
SkColorSpace* colorSpace = bitmap.colorSpace();
if (bitmap.colorType() != kRGBA_F16_SkColorType && !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();
bitmap.writePixels(srcPM, x, y);
}
static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
@@ -1433,7 +1083,7 @@ static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
SkBitmap bitmap;
reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
x, y, width, height, bitmap);
x, y, width, height, &bitmap);
}
static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,

View File

@@ -102,7 +102,7 @@ public:
*/
static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset,
int srcStride, int x, int y, int width, int height,
const SkBitmap& dstBitmap);
SkBitmap* dstBitmap);
static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams);
static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);

View File

@@ -462,7 +462,7 @@ static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
return;
}
if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, &bitmap)) {
return;
}