skia2/gm/makecolorspace.cpp
Brian Osman f48c9965ec Revert "Revert "Add SkImage::makeColorTypeAndColorSpace""
This reverts commit 9a97c96c9c.

This works like makeColorSpace, but allows changing color type as well.
Added a GM to test, although the GM demonstrates several ways this can
fail (especially when using this on lazy images).

For simple use-cases (8888 <-> F16), everything should be fine.

For the reland, add logic to the GM to guard against context abandon
failures, and to ensure that lazy images can be decoded (by calling
makeRasterImage) before trying to draw them. That prevents the DDL
recorder from seeing them.

Bug: skia:
Change-Id: Ibc7b07c3399979b1a44d85a38424e5487e606607
Reviewed-on: https://skia-review.googlesource.com/c/183800
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
2019-01-14 18:01:15 +00:00

133 lines
5.1 KiB
C++

/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "Resources.h"
#include "SkCodec.h"
#include "SkColorSpace.h"
#include "SkImage.h"
#include "SkImagePriv.h"
sk_sp<SkImage> make_raster_image(const char* path) {
sk_sp<SkData> resourceData = GetResourceAsData(path);
std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(resourceData);
SkBitmap bitmap;
bitmap.allocPixels(codec->getInfo());
codec->getPixels(codec->getInfo(), bitmap.getPixels(), bitmap.rowBytes());
return SkImage::MakeFromBitmap(bitmap);
}
sk_sp<SkImage> make_color_space(sk_sp<SkImage> orig, sk_sp<SkColorSpace> colorSpace) {
sk_sp<SkImage> xform = orig->makeColorSpace(colorSpace);
// Assign an sRGB color space on the xformed image, so we can see the effects of the xform
// when we draw.
sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
if (colorSpace->gammaIsLinear()) {
srgb = SkColorSpace::MakeSRGBLinear();
}
return SkImageMakeRasterCopyAndAssignColorSpace(xform.get(), srgb.get());
}
class MakeCSGM : public skiagm::GM {
public:
MakeCSGM() {}
protected:
SkString onShortName() override {
return SkString("makecolorspace");
}
SkISize onISize() override {
return SkISize::Make(128*3, 128*4);
}
void onDraw(SkCanvas* canvas) override {
sk_sp<SkColorSpace> wideGamut = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
SkNamedGamut::kAdobeRGB);
sk_sp<SkColorSpace> wideGamutLinear = wideGamut->makeLinearGamma();
// Lazy images
sk_sp<SkImage> opaqueImage = GetResourceAsImage("images/mandrill_128.png");
sk_sp<SkImage> premulImage = GetResourceAsImage("images/color_wheel.png");
if (!opaqueImage || !premulImage) {
return;
}
canvas->drawImage(opaqueImage, 0.0f, 0.0f);
canvas->drawImage(make_color_space(opaqueImage, wideGamut), 128.0f, 0.0f);
canvas->drawImage(make_color_space(opaqueImage, wideGamutLinear), 256.0f, 0.0f);
canvas->drawImage(premulImage, 0.0f, 128.0f);
canvas->drawImage(make_color_space(premulImage, wideGamut), 128.0f, 128.0f);
canvas->drawImage(make_color_space(premulImage, wideGamutLinear), 256.0f, 128.0f);
canvas->translate(0.0f, 256.0f);
// Raster images
opaqueImage = make_raster_image("images/mandrill_128.png");
premulImage = make_raster_image("images/color_wheel.png");
canvas->drawImage(opaqueImage, 0.0f, 0.0f);
canvas->drawImage(make_color_space(opaqueImage, wideGamut), 128.0f, 0.0f);
canvas->drawImage(make_color_space(opaqueImage, wideGamutLinear), 256.0f, 0.0f);
canvas->drawImage(premulImage, 0.0f, 128.0f);
canvas->drawImage(make_color_space(premulImage, wideGamut), 128.0f, 128.0f);
canvas->drawImage(make_color_space(premulImage, wideGamutLinear), 256.0f, 128.0f);
}
private:
typedef skiagm::GM INHERITED;
};
DEF_GM(return new MakeCSGM;)
DEF_SIMPLE_GM_BG(makecolortypeandspace, canvas, 128 * 3, 128 * 4, SK_ColorWHITE) {
sk_sp<SkImage> images[] = {
GetResourceAsImage("images/mandrill_128.png"),
GetResourceAsImage("images/color_wheel.png"),
};
auto rec2020 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kRec2020);
// Use the lazy images on the first iteration, and concrete (raster/GPU) images on the second
for (bool lazy : {true, false}) {
for (int j = 0; j < 2; ++j) {
const SkImage* image = images[j].get();
if (!image) {
// Can happen on bots that abandon the GPU context
continue;
}
// Unmodified
canvas->drawImage(image, 0, 0);
// Change the color type/space of the image in a couple ways. In both cases, codec
// may fail, because we refude to decode transparent sources to opaque color types.
// Guard against that, to avoid cascading failures in DDL.
// 565 in a wide color space (should be visibly quantized). Fails with the color_wheel,
// because of the codec issues mentioned above.
auto image565 = image->makeColorTypeAndColorSpace(kRGB_565_SkColorType, rec2020);
if (!lazy || image565->makeRasterImage()) {
canvas->drawImage(image565, 128, 0);
}
// Grayscale in the original color space. This fails in even more cases, due to the
// above opaque issue, and because Ganesh doesn't support drawing to gray, at all.
auto imageGray = image->makeColorTypeAndColorSpace(kGray_8_SkColorType,
image->refColorSpace());
if (!lazy || imageGray->makeRasterImage()) {
canvas->drawImage(imageGray, 256, 0);
}
images[j] = canvas->getGrContext()
? image->makeTextureImage(canvas->getGrContext(), nullptr)
: image->makeRasterImage();
canvas->translate(0, 128);
}
}
}