blob: 60c8758da6ad81fc249358e435f54032482ff205 [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm/gm.h"
#include "include/codec/SkEncodedImageFormat.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkData.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkSurface.h"
#include "include/encode/SkWebpEncoder.h"
#include "tools/DecodeUtils.h"
#include "tools/Resources.h"
namespace skiagm {
static const int imageWidth = 128;
static const int imageHeight = 128;
static sk_sp<SkImage> make_image(SkColorType colorType, SkAlphaType alphaType) {
const char* resource;
switch (colorType) {
case kGray_8_SkColorType:
if (alphaType != kOpaque_SkAlphaType) {
return nullptr;
}
resource = "images/grayscale.jpg";
break;
case kRGB_565_SkColorType:
case kRGB_888x_SkColorType:
case kRGB_101010x_SkColorType:
case kBGR_101010x_SkColorType:
if (alphaType != kOpaque_SkAlphaType) {
return nullptr;
}
resource = "images/color_wheel.jpg";
break;
default:
resource = (kOpaque_SkAlphaType == alphaType) ? "images/color_wheel.jpg"
: "images/rainbow-gradient.png";
break;
}
auto image = ToolUtils::GetResourceAsImage(resource);
if (!image) {
return nullptr;
}
auto surface = SkSurfaces::Raster(SkImageInfo::Make(
image->width(), image->height(), colorType, alphaType, image->refColorSpace()));
surface->getCanvas()->drawImage(image, 0, 0);
return surface->makeImageSnapshot();
}
// This GM looks different depending on the colortype used, so we use different
// names to treat them as different GMs.
// All Variants draw images in pairs:
// - First as an image of the SkColorType of the destination
// - Next as the result of encoding and decoding the first image
enum class Variant {
// One pair, using an opaque image.
kOpaque,
// One pair, using a grayscale image.
kGray,
// An opaque pair followed by two more for premul and unpremul.
kNormal,
};
class EncodeColorTypesGM : public GM {
public:
EncodeColorTypesGM(SkEncodedImageFormat format, int quality, Variant variant, const char* name)
: fFormat(format)
, fQuality(quality)
, fVariant(variant)
, fName(name)
{}
protected:
SkString getName() const override {
const char* variant = fVariant == Variant::kOpaque ? "opaque-":
fVariant == Variant::kGray ? "gray-" :
"" ;
return SkStringPrintf("encode-%scolor-types-%s", variant, fName);
}
SkISize getISize() override {
const int width = fVariant == Variant::kNormal ? imageWidth * 7 : imageWidth * 2;
return SkISize::Make(width, imageHeight);
}
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
const auto colorType = canvas->imageInfo().colorType();
switch (fVariant) {
case Variant::kGray:
if (colorType != kGray_8_SkColorType) {
return DrawResult::kSkip;
}
break;
case Variant::kOpaque:
if (colorType != kRGB_565_SkColorType &&
colorType != kRGB_888x_SkColorType &&
colorType != kRGB_101010x_SkColorType &&
colorType != kBGR_101010x_SkColorType)
{
return DrawResult::kSkip;
}
break;
case Variant::kNormal:
if (colorType != kARGB_4444_SkColorType &&
colorType != kRGBA_8888_SkColorType &&
colorType != kBGRA_8888_SkColorType &&
colorType != kRGBA_1010102_SkColorType &&
colorType != kBGRA_1010102_SkColorType &&
colorType != kRGBA_F16Norm_SkColorType &&
colorType != kRGBA_F16_SkColorType &&
colorType != kRGBA_F32_SkColorType)
{
return DrawResult::kSkip;
}
break;
}
const SkAlphaType alphaTypes[] = {
kOpaque_SkAlphaType, kPremul_SkAlphaType, kUnpremul_SkAlphaType,
};
for (SkAlphaType alphaType : alphaTypes) {
auto src = make_image(colorType, alphaType);
if (!src) {
break;
}
SkASSERT_RELEASE(fFormat == SkEncodedImageFormat::kWEBP);
SkWebpEncoder::Options options;
if (fQuality < 100) {
options.fCompression = SkWebpEncoder::Compression::kLossy;
options.fQuality = fQuality;
} else {
options.fCompression = SkWebpEncoder::Compression::kLossless;
// in lossless mode, this is effort. 70 is the default effort in SkImageEncoder,
// which follows Blink and WebPConfigInit.
options.fQuality = 70;
}
auto data = SkWebpEncoder::Encode(nullptr, src.get(), options);
SkASSERT(data);
auto decoded = SkImages::DeferredFromEncodedData(data);
if (!decoded) {
break;
}
canvas->drawImage(src, 0.0f, 0.0f);
canvas->translate((float) imageWidth, 0.0f);
canvas->drawImage(decoded, 0.0f, 0.0f);
canvas->translate((float) imageWidth * 1.5, 0.0f);
}
return DrawResult::kOk;
}
private:
const SkEncodedImageFormat fFormat;
const int fQuality;
const Variant fVariant;
const char* fName;
using INHERITED = GM;
};
#define DEF_ENCODE_GM(format, quality, variant, name) \
static skiagm::GMRegistry SK_MACRO_CONCAT(SK_MACRO_APPEND_LINE(REG_), variant)(\
[](){return std::unique_ptr<skiagm::GM>([](){\
return new EncodeColorTypesGM(format, quality, Variant::variant, name);\
}());});
#define DEF_VARIANTS(format, quality, name) \
DEF_ENCODE_GM(format, quality, kNormal, name); \
DEF_ENCODE_GM(format, quality, kOpaque, name); \
DEF_ENCODE_GM(format, quality, kGray, name);
DEF_VARIANTS(SkEncodedImageFormat::kWEBP, 100, "webp-lossless")
DEF_VARIANTS(SkEncodedImageFormat::kWEBP, 80, "webp-lossy")
} // namespace skiagm