2021-01-07 16:50:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copyright 2021 Google Inc.
|
|
|
|
|
*
|
|
|
|
|
* 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/core/SkCanvas.h"
|
2022-03-31 19:07:44 +00:00
|
|
|
|
#include "include/core/SkColorSpace.h"
|
2021-01-07 16:50:01 +00:00
|
|
|
|
#include "include/core/SkFont.h"
|
2021-01-08 16:25:38 +00:00
|
|
|
|
#include "include/core/SkSurface.h"
|
2021-01-07 16:50:01 +00:00
|
|
|
|
#include "tools/Resources.h"
|
|
|
|
|
|
|
|
|
|
static const skcms_TransferFunction gTFs[] = {
|
|
|
|
|
SkNamedTransferFn::kSRGB,
|
|
|
|
|
SkNamedTransferFn::k2Dot2,
|
|
|
|
|
SkNamedTransferFn::kLinear,
|
|
|
|
|
SkNamedTransferFn::kRec2020,
|
|
|
|
|
SkNamedTransferFn::kPQ,
|
|
|
|
|
SkNamedTransferFn::kHLG,
|
|
|
|
|
{-3.0f, 2.0f, 2.0f, 1/0.17883277f, 0.28466892f, 0.55991073f, 3.0f }, // HLG scaled 4x
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const skcms_Matrix3x3 gGamuts[] = {
|
|
|
|
|
SkNamedGamut::kSRGB,
|
|
|
|
|
SkNamedGamut::kAdobeRGB,
|
|
|
|
|
SkNamedGamut::kDisplayP3,
|
|
|
|
|
SkNamedGamut::kRec2020,
|
|
|
|
|
SkNamedGamut::kXYZ,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const int W = 128,
|
|
|
|
|
H = 128;
|
|
|
|
|
|
2021-01-08 16:25:38 +00:00
|
|
|
|
// These GMs demonstrate that our color space management is self-consistent.
|
2021-01-07 16:50:01 +00:00
|
|
|
|
// (Important to note, self-consistent, not necessarily correct in an objective sense.)
|
|
|
|
|
//
|
|
|
|
|
// Let's let,
|
|
|
|
|
//
|
|
|
|
|
// SkColorSpace* imgCS = img->colorSpace();
|
|
|
|
|
// SkColorSpace* dstCS = canvas->imageInfo().colorSpace();
|
|
|
|
|
//
|
|
|
|
|
// Ordinarily we'd just
|
|
|
|
|
//
|
|
|
|
|
// canvas->drawImage(img, 0,0);
|
|
|
|
|
//
|
|
|
|
|
// which would convert that img's pixels from imgCS to dstCS while drawing.
|
|
|
|
|
//
|
2021-01-08 16:25:38 +00:00
|
|
|
|
// But before we draw in these GMs, we convert the image to an arbitrarily different color space,
|
2021-01-07 16:50:01 +00:00
|
|
|
|
// letting midCS range over the cross-product gTFs × gGamuts:
|
|
|
|
|
//
|
|
|
|
|
// canvas->drawImage(img->makeColorSpace(midCS), 0,0);
|
|
|
|
|
//
|
|
|
|
|
// This converts img first from imgCS to midCS, treating midCS as a destination color space,
|
|
|
|
|
// and then draws that midCS image to the dstCS canvas, treating midCS as a source color space.
|
|
|
|
|
// This should draw a grid of images that look identical except for small precision loss.
|
2021-01-08 16:25:38 +00:00
|
|
|
|
//
|
|
|
|
|
// If instead of calling SkImage::makeColorSpace() we use SkCanvas::makeSurface() to create a
|
|
|
|
|
// midCS offscreen, we construct the same logical imgCS -> midCS -> dstCS transform chain while
|
|
|
|
|
// exercising different drawing code paths. Both strategies should draw roughly the same.
|
2021-01-07 16:50:01 +00:00
|
|
|
|
|
2021-01-08 16:25:38 +00:00
|
|
|
|
namespace {
|
|
|
|
|
enum Strategy { SkImage_makeColorSpace, SkCanvas_makeSurface };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void draw_colorspace_gm(Strategy strategy, SkCanvas* canvas) {
|
2021-01-07 16:50:01 +00:00
|
|
|
|
if (!canvas->imageInfo().colorSpace()) {
|
|
|
|
|
canvas->drawString("This GM only makes sense with color-managed drawing.",
|
|
|
|
|
W,H, SkFont{}, SkPaint{});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sk_sp<SkImage> img = GetResourceAsImage("images/mandrill_128.png");
|
|
|
|
|
if (!img) {
|
|
|
|
|
canvas->drawString("Could not load our test image!",
|
|
|
|
|
W,H, SkFont{}, SkPaint{});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SkASSERT(img->width() == W);
|
|
|
|
|
SkASSERT(img->height() == H);
|
|
|
|
|
SkASSERT(img->colorSpace());
|
|
|
|
|
|
|
|
|
|
for (skcms_Matrix3x3 gamut : gGamuts) {
|
|
|
|
|
canvas->save();
|
|
|
|
|
for (skcms_TransferFunction tf : gTFs) {
|
|
|
|
|
sk_sp<SkColorSpace> midCS = SkColorSpace::MakeRGB(tf, gamut);
|
2021-01-08 16:25:38 +00:00
|
|
|
|
|
|
|
|
|
switch (strategy) {
|
|
|
|
|
case SkImage_makeColorSpace: {
|
|
|
|
|
canvas->drawImage(img->makeColorSpace(midCS), 0,0);
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case SkCanvas_makeSurface: {
|
|
|
|
|
sk_sp<SkSurface> offscreen =
|
|
|
|
|
canvas->makeSurface(canvas->imageInfo().makeColorSpace(midCS));
|
2021-01-08 20:01:36 +00:00
|
|
|
|
if (!offscreen) {
|
|
|
|
|
canvas->drawString("Could not allocate offscreen surface!",
|
|
|
|
|
W,H, SkFont{}, SkPaint{});
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-01-08 16:25:38 +00:00
|
|
|
|
offscreen->getCanvas()->drawImage(img, 0,0);
|
|
|
|
|
canvas->drawImage(offscreen->makeImageSnapshot(), 0,0);
|
|
|
|
|
} break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-07 16:50:01 +00:00
|
|
|
|
canvas->translate(W, 0);
|
|
|
|
|
}
|
|
|
|
|
canvas->restore();
|
|
|
|
|
canvas->translate(0, H);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-08 16:25:38 +00:00
|
|
|
|
|
|
|
|
|
DEF_SIMPLE_GM(colorspace, canvas, W*SK_ARRAY_COUNT(gTFs), H*SK_ARRAY_COUNT(gGamuts)) {
|
|
|
|
|
draw_colorspace_gm(SkImage_makeColorSpace, canvas);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEF_SIMPLE_GM(colorspace2, canvas, W*SK_ARRAY_COUNT(gTFs), H*SK_ARRAY_COUNT(gGamuts)) {
|
|
|
|
|
draw_colorspace_gm(SkCanvas_makeSurface, canvas);
|
|
|
|
|
}
|