Improved support for images/bitmaps in SkJSONCanvas
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1662063003 Review URL: https://codereview.chromium.org/1662063003
This commit is contained in:
parent
7b5e5536a1
commit
0bd103497a
@ -181,15 +181,31 @@ static void flatten(const SkFlattenable* flattenable, Json::Value* target, bool
|
||||
static bool SK_WARN_UNUSED_RESULT flatten(const SkImage& image, Json::Value* target,
|
||||
bool sendBinaries) {
|
||||
if (sendBinaries) {
|
||||
SkData* png = image.encode(SkImageEncoder::kPNG_Type, 100);
|
||||
if (png == nullptr) {
|
||||
SkDebugf("could not encode image\n");
|
||||
return false;
|
||||
SkData* encoded = image.encode(SkImageEncoder::kPNG_Type, 100);
|
||||
if (encoded == nullptr) {
|
||||
// PNG encode doesn't necessarily support all color formats, convert to a different
|
||||
// format
|
||||
size_t rowBytes = 4 * image.width();
|
||||
void* buffer = sk_malloc_throw(rowBytes * image.height());
|
||||
SkImageInfo dstInfo = SkImageInfo::Make(image.width(), image.height(),
|
||||
kN32_SkColorType, kPremul_SkAlphaType);
|
||||
if (!image.readPixels(dstInfo, buffer, rowBytes, 0, 0)) {
|
||||
SkDebugf("readPixels failed\n");
|
||||
return false;
|
||||
}
|
||||
SkImage* converted = SkImage::NewRasterCopy(dstInfo, buffer, rowBytes);
|
||||
encoded = converted->encode(SkImageEncoder::kPNG_Type, 100);
|
||||
if (encoded == nullptr) {
|
||||
SkDebugf("image encode failed\n");
|
||||
return false;
|
||||
}
|
||||
free(converted);
|
||||
free(buffer);
|
||||
}
|
||||
Json::Value bytes;
|
||||
encode_data(png->data(), png->size(), &bytes);
|
||||
encode_data(encoded->data(), encoded->size(), &bytes);
|
||||
(*target)[SKJSONCANVAS_ATTRIBUTE_BYTES] = bytes;
|
||||
png->unref();
|
||||
encoded->unref();
|
||||
}
|
||||
else {
|
||||
SkString description = SkStringPrintf("%dx%d pixel image", image.width(), image.height());
|
||||
@ -198,11 +214,50 @@ static bool SK_WARN_UNUSED_RESULT flatten(const SkImage& image, Json::Value* tar
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* color_type_name(SkColorType colorType) {
|
||||
switch (colorType) {
|
||||
case kARGB_4444_SkColorType:
|
||||
return SKJSONCANVAS_COLORTYPE_ARGB4444;
|
||||
case kRGBA_8888_SkColorType:
|
||||
return SKJSONCANVAS_COLORTYPE_RGBA8888;
|
||||
case kBGRA_8888_SkColorType:
|
||||
return SKJSONCANVAS_COLORTYPE_BGRA8888;
|
||||
case kRGB_565_SkColorType:
|
||||
return SKJSONCANVAS_COLORTYPE_565;
|
||||
case kGray_8_SkColorType:
|
||||
return SKJSONCANVAS_COLORTYPE_GRAY8;
|
||||
case kIndex_8_SkColorType:
|
||||
return SKJSONCANVAS_COLORTYPE_INDEX8;
|
||||
case kAlpha_8_SkColorType:
|
||||
return SKJSONCANVAS_COLORTYPE_ALPHA8;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
return SKJSONCANVAS_COLORTYPE_RGBA8888;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* alpha_type_name(SkAlphaType alphaType) {
|
||||
switch (alphaType) {
|
||||
case kOpaque_SkAlphaType:
|
||||
return SKJSONCANVAS_ALPHATYPE_OPAQUE;
|
||||
case kPremul_SkAlphaType:
|
||||
return SKJSONCANVAS_ALPHATYPE_PREMUL;
|
||||
case kUnpremul_SkAlphaType:
|
||||
return SKJSONCANVAS_ALPHATYPE_UNPREMUL;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
return SKJSONCANVAS_ALPHATYPE_OPAQUE;
|
||||
}
|
||||
}
|
||||
|
||||
static bool SK_WARN_UNUSED_RESULT flatten(const SkBitmap& bitmap, Json::Value* target,
|
||||
bool sendBinaries) {
|
||||
SkImage* image = SkImage::NewFromBitmap(bitmap);
|
||||
bitmap.lockPixels();
|
||||
SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
|
||||
bitmap.unlockPixels();
|
||||
(*target)[SKJSONCANVAS_ATTRIBUTE_COLOR] = Json::Value(color_type_name(bitmap.colorType()));
|
||||
(*target)[SKJSONCANVAS_ATTRIBUTE_ALPHA] = Json::Value(alpha_type_name(bitmap.alphaType()));
|
||||
bool success = flatten(*image, target, sendBinaries);
|
||||
image->unref();
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -361,6 +416,15 @@ static void apply_paint_xfermode(const SkPaint& paint, Json::Value* target, bool
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_paint_imagefilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
|
||||
SkFlattenable* imageFilter = paint.getImageFilter();
|
||||
if (imageFilter != nullptr) {
|
||||
Json::Value jsonImageFilter;
|
||||
flatten(imageFilter, &jsonImageFilter, sendBinaries);
|
||||
(*target)[SKJSONCANVAS_ATTRIBUTE_IMAGEFILTER] = jsonImageFilter;
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) {
|
||||
Json::Value result(Json::objectValue);
|
||||
store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f);
|
||||
@ -379,6 +443,7 @@ Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) {
|
||||
apply_paint_maskfilter(paint, &result, fSendBinaries);
|
||||
apply_paint_shader(paint, &result, fSendBinaries);
|
||||
apply_paint_xfermode(paint, &result, fSendBinaries);
|
||||
apply_paint_imagefilter(paint, &result, fSendBinaries);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -601,7 +666,7 @@ void SkJSONCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, c
|
||||
this->updateMatrix();
|
||||
Json::Value command(Json::objectValue);
|
||||
command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_BITMAPRECT);
|
||||
command[SKJSONCANVAS_ATTRIBUTE_IMAGE] = encoded;
|
||||
command[SKJSONCANVAS_ATTRIBUTE_BITMAP] = encoded;
|
||||
if (src != nullptr) {
|
||||
command[SKJSONCANVAS_ATTRIBUTE_SRC] = this->makeRect(*src);
|
||||
}
|
||||
@ -729,6 +794,7 @@ void SkJSONCanvas::willRestore() {
|
||||
}
|
||||
|
||||
SkCanvas::SaveLayerStrategy SkJSONCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
|
||||
this->updateMatrix();
|
||||
Json::Value command(Json::objectValue);
|
||||
command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_SAVELAYER);
|
||||
if (rec.fBounds != nullptr) {
|
||||
|
@ -58,6 +58,7 @@
|
||||
#define SKJSONCANVAS_ATTRIBUTE_PATH "path"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_TEXT "text"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_COLOR "color"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_ALPHA "alpha"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_STYLE "style"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH "strokeWidth"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_STROKEMITER "strokeMiter"
|
||||
@ -86,6 +87,7 @@
|
||||
#define SKJSONCANVAS_ATTRIBUTE_MASKFILTER "maskFilter"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_XFERMODE "xfermode"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_BACKDROP "backdrop"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_IMAGEFILTER "imagefilter"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_IMAGE "image"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_BITMAP "bitmap"
|
||||
#define SKJSONCANVAS_ATTRIBUTE_SRC "src"
|
||||
@ -136,6 +138,18 @@
|
||||
#define SKJSONCANVAS_CAP_ROUND "round"
|
||||
#define SKJSONCANVAS_CAP_SQUARE "square"
|
||||
|
||||
#define SKJSONCANVAS_COLORTYPE_ARGB4444 "ARGB4444"
|
||||
#define SKJSONCANVAS_COLORTYPE_RGBA8888 "RGBA8888"
|
||||
#define SKJSONCANVAS_COLORTYPE_BGRA8888 "BGRA8888"
|
||||
#define SKJSONCANVAS_COLORTYPE_565 "565"
|
||||
#define SKJSONCANVAS_COLORTYPE_GRAY8 "Gray8"
|
||||
#define SKJSONCANVAS_COLORTYPE_INDEX8 "Index8"
|
||||
#define SKJSONCANVAS_COLORTYPE_ALPHA8 "Alpha8"
|
||||
|
||||
#define SKJSONCANVAS_ALPHATYPE_OPAQUE "opaque"
|
||||
#define SKJSONCANVAS_ALPHATYPE_PREMUL "premul"
|
||||
#define SKJSONCANVAS_ALPHATYPE_UNPREMUL "unpremul"
|
||||
|
||||
/*
|
||||
* Implementation of SkCanvas which writes JSON when drawn to. The JSON describes all of the draw
|
||||
* commands issued to the canvas, and can later be turned back into draw commands using
|
||||
|
@ -159,6 +159,7 @@ static SkFlattenable* load_flattenable(Json::Value jsonFlattenable) {
|
||||
const char* name = jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_NAME].asCString();
|
||||
SkFlattenable::Factory factory = SkFlattenable::NameToFactory(name);
|
||||
if (factory == nullptr) {
|
||||
SkDebugf("no factory for loading '%s'\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
void* data;
|
||||
@ -167,14 +168,56 @@ static SkFlattenable* load_flattenable(Json::Value jsonFlattenable) {
|
||||
SkFlattenable* result = factory(buffer);
|
||||
free(data);
|
||||
if (!buffer.isValid()) {
|
||||
SkDebugf("invalid buffer loading flattenable\n");
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static SkColorType colortype_from_name(const char* name) {
|
||||
if (!strcmp(name, SKJSONCANVAS_COLORTYPE_ARGB4444)) {
|
||||
return kARGB_4444_SkColorType;
|
||||
}
|
||||
else if (!strcmp(name, SKJSONCANVAS_COLORTYPE_RGBA8888)) {
|
||||
return kRGBA_8888_SkColorType;
|
||||
}
|
||||
else if (!strcmp(name, SKJSONCANVAS_COLORTYPE_BGRA8888)) {
|
||||
return kBGRA_8888_SkColorType;
|
||||
}
|
||||
else if (!strcmp(name, SKJSONCANVAS_COLORTYPE_565)) {
|
||||
return kRGB_565_SkColorType;
|
||||
}
|
||||
else if (!strcmp(name, SKJSONCANVAS_COLORTYPE_GRAY8)) {
|
||||
return kGray_8_SkColorType;
|
||||
}
|
||||
else if (!strcmp(name, SKJSONCANVAS_COLORTYPE_INDEX8)) {
|
||||
return kIndex_8_SkColorType;
|
||||
}
|
||||
else if (!strcmp(name, SKJSONCANVAS_COLORTYPE_ALPHA8)) {
|
||||
return kAlpha_8_SkColorType;
|
||||
}
|
||||
SkASSERT(false);
|
||||
return kN32_SkColorType;
|
||||
}
|
||||
|
||||
static SkBitmap* convert_colortype(SkBitmap* bitmap, SkColorType colorType) {
|
||||
if (bitmap->colorType() == colorType ) {
|
||||
return bitmap;
|
||||
}
|
||||
SkBitmap* dst = new SkBitmap();
|
||||
if (bitmap->copyTo(dst, colorType)) {
|
||||
delete bitmap;
|
||||
return dst;
|
||||
}
|
||||
SkASSERT(false);
|
||||
delete dst;
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
// caller is responsible for freeing return value
|
||||
static SkBitmap* load_bitmap(Json::Value jsonBitmap) {
|
||||
static SkBitmap* load_bitmap(const Json::Value& jsonBitmap) {
|
||||
if (!jsonBitmap.isMember(SKJSONCANVAS_ATTRIBUTE_BYTES)) {
|
||||
SkDebugf("invalid bitmap\n");
|
||||
return nullptr;
|
||||
}
|
||||
void* data;
|
||||
@ -187,20 +230,27 @@ static SkBitmap* load_bitmap(Json::Value jsonBitmap) {
|
||||
free(decoder);
|
||||
if (result != SkImageDecoder::kFailure) {
|
||||
free(data);
|
||||
if (jsonBitmap.isMember(SKJSONCANVAS_ATTRIBUTE_COLOR)) {
|
||||
const char* ctName = jsonBitmap[SKJSONCANVAS_ATTRIBUTE_COLOR].asCString();
|
||||
SkColorType ct = colortype_from_name(ctName);
|
||||
if (ct != kIndex_8_SkColorType) {
|
||||
bitmap = convert_colortype(bitmap, ct);
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
SkDebugf("image decode failed");
|
||||
SkDebugf("image decode failed\n");
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static SkImage* load_image(Json::Value jsonImage) {
|
||||
static SkImage* load_image(const Json::Value& jsonImage) {
|
||||
SkBitmap* bitmap = load_bitmap(jsonImage);
|
||||
if (bitmap == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
SkImage* result = SkImage::NewFromBitmap(*bitmap);
|
||||
free(bitmap);
|
||||
delete bitmap;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -248,6 +298,17 @@ static void apply_paint_xfermode(Json::Value& jsonPaint, SkPaint* target) {
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_paint_imagefilter(Json::Value& jsonPaint, SkPaint* target) {
|
||||
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_IMAGEFILTER)) {
|
||||
Json::Value jsonImageFilter = jsonPaint[SKJSONCANVAS_ATTRIBUTE_IMAGEFILTER];
|
||||
SkImageFilter* imageFilter = (SkImageFilter*) load_flattenable(jsonImageFilter);
|
||||
if (imageFilter != nullptr) {
|
||||
target->setImageFilter(imageFilter);
|
||||
imageFilter->unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_paint_style(Json::Value& jsonPaint, SkPaint* target) {
|
||||
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_STYLE)) {
|
||||
const char* style = jsonPaint[SKJSONCANVAS_ATTRIBUTE_STYLE].asCString();
|
||||
@ -400,6 +461,7 @@ void Renderer::getPaint(Json::Value& command, SkPaint* result) {
|
||||
apply_paint_patheffect(jsonPaint, result);
|
||||
apply_paint_maskfilter(jsonPaint, result);
|
||||
apply_paint_xfermode(jsonPaint, result);
|
||||
apply_paint_imagefilter(jsonPaint, result);
|
||||
apply_paint_style(jsonPaint, result);
|
||||
apply_paint_strokewidth(jsonPaint, result);
|
||||
apply_paint_strokemiter(jsonPaint, result);
|
||||
|
Loading…
Reference in New Issue
Block a user