aboutsummaryrefslogtreecommitdiffstats
path: root/gm/makecolorspace.cpp
blob: aa28efd0a32f70b489ba2b62119024ad9e60fad1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * 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);
        }
    }
}