1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm.h"
9
10#include "Resources.h"
11#include "SkCanvas.h"
12#include "SkCodec.h"
13#include "SkData.h"
14#include "SkImage.h"
15#include "SkImageEncoderPriv.h"
16#include "SkJpegEncoder.h"
17#include "SkPngEncoder.h"
18#include "SkPM4f.h"
19#include "SkSRGB.h"
20#include "SkWebpEncoder.h"
21
22namespace skiagm {
23
24static const int imageWidth = 128;
25static const int imageHeight = 128;
26
27sk_sp<SkColorSpace> fix_for_colortype(sk_sp<SkColorSpace> colorSpace, SkColorType colorType) {
28    if (kRGBA_F16_SkColorType == colorType) {
29        if (!colorSpace) {
30            return SkColorSpace::MakeSRGBLinear();
31        }
32
33        return colorSpace->makeLinearGamma();
34    }
35
36    return colorSpace;
37}
38
39static void make(SkBitmap* bitmap, SkColorType colorType, SkAlphaType alphaType,
40                 sk_sp<SkColorSpace> colorSpace) {
41    const char* resource;
42    switch (colorType) {
43        case kGray_8_SkColorType:
44            resource = "images/grayscale.jpg";
45            alphaType = kOpaque_SkAlphaType;
46            break;
47        case kRGB_565_SkColorType:
48            resource = "images/color_wheel.jpg";
49            alphaType = kOpaque_SkAlphaType;
50            break;
51        default:
52            resource = (kOpaque_SkAlphaType == alphaType) ? "images/color_wheel.jpg"
53                                                          : "images/color_wheel.png";
54            break;
55    }
56
57    sk_sp<SkData> data = GetResourceAsData(resource);
58    std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(data);
59    SkImageInfo dstInfo = codec->getInfo().makeColorType(colorType)
60                                          .makeAlphaType(alphaType)
61                                          .makeColorSpace(fix_for_colortype(colorSpace, colorType));
62    bitmap->allocPixels(dstInfo);
63    codec->getPixels(dstInfo, bitmap->getPixels(), bitmap->rowBytes());
64}
65
66static sk_sp<SkData> encode_data(const SkBitmap& bitmap, SkEncodedImageFormat format) {
67    SkPixmap src;
68    if (!bitmap.peekPixels(&src)) {
69        return nullptr;
70    }
71    SkDynamicMemoryWStream buf;
72
73    SkPngEncoder::Options pngOptions;
74    SkWebpEncoder::Options webpOptions;
75    SkTransferFunctionBehavior behavior = bitmap.colorSpace()
76            ? SkTransferFunctionBehavior::kRespect : SkTransferFunctionBehavior::kIgnore;
77    pngOptions.fUnpremulBehavior = behavior;
78    webpOptions.fUnpremulBehavior = behavior;
79
80    switch (format) {
81        case SkEncodedImageFormat::kPNG:
82            SkAssertResult(SkPngEncoder::Encode(&buf, src, pngOptions));
83            break;
84        case SkEncodedImageFormat::kWEBP:
85            SkAssertResult(SkWebpEncoder::Encode(&buf, src, webpOptions));
86            break;
87        case SkEncodedImageFormat::kJPEG:
88            SkAssertResult(SkJpegEncoder::Encode(&buf, src, SkJpegEncoder::Options()));
89            break;
90        default:
91            break;
92    }
93    return buf.detachAsData();
94}
95
96class EncodeSRGBGM : public GM {
97public:
98    EncodeSRGBGM(SkEncodedImageFormat format)
99        : fEncodedFormat(format)
100    {}
101
102protected:
103    SkString onShortName() override {
104        const char* format = nullptr;
105        switch (fEncodedFormat) {
106            case SkEncodedImageFormat::kPNG:
107                format = "png";
108                break;
109            case SkEncodedImageFormat::kWEBP:
110                format = "webp";
111                break;
112            case SkEncodedImageFormat::kJPEG:
113                format = "jpg";
114                break;
115            default:
116                break;
117        }
118        return SkStringPrintf("encode-srgb-%s", format);
119    }
120
121    SkISize onISize() override {
122        return SkISize::Make(imageWidth * 2, imageHeight * 15);
123    }
124
125    void onDraw(SkCanvas* canvas) override {
126        const SkColorType colorTypes[] = {
127            kN32_SkColorType, kRGBA_F16_SkColorType, kGray_8_SkColorType, kRGB_565_SkColorType,
128        };
129        const SkAlphaType alphaTypes[] = {
130            kUnpremul_SkAlphaType, kPremul_SkAlphaType, kOpaque_SkAlphaType,
131        };
132        const sk_sp<SkColorSpace> colorSpaces[] = {
133            nullptr, SkColorSpace::MakeSRGB(),
134        };
135
136        SkBitmap bitmap;
137        for (SkColorType colorType : colorTypes) {
138            for (SkAlphaType alphaType : alphaTypes) {
139                canvas->save();
140                for (sk_sp<SkColorSpace> colorSpace : colorSpaces) {
141                    make(&bitmap, colorType, alphaType, colorSpace);
142                    auto image = SkImage::MakeFromEncoded(encode_data(bitmap, fEncodedFormat));
143                    canvas->drawImage(image.get(), 0.0f, 0.0f);
144                    canvas->translate((float) imageWidth, 0.0f);
145                }
146                canvas->restore();
147                canvas->translate(0.0f, (float) imageHeight);
148            }
149        }
150    }
151
152private:
153    SkEncodedImageFormat fEncodedFormat;
154
155    typedef GM INHERITED;
156};
157
158DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kPNG); )
159DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kWEBP); )
160DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kJPEG); )
161}
162