C++程序  |  208行  |  6.7 KB

/*
 * Copyright 2016 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 "SkCanvas.h"
#include "SkCodec.h"
#include "SkColorSpace_Base.h"
#include "SkData.h"
#include "SkImageEncoderPriv.h"
#include "SkPM4f.h"
#include "SkSRGB.h"

namespace skiagm {

static const int imageWidth = 128;
static const int imageHeight = 128;

static inline int div_round_up(int a, int b) {
    return (a + b - 1) / b;
}

sk_sp<SkColorSpace> fix_for_colortype(sk_sp<SkColorSpace> colorSpace, SkColorType colorType) {
    if (kRGBA_F16_SkColorType == colorType) {
        if (!colorSpace) {
            return SkColorSpace::MakeSRGBLinear();
        }

        return as_CSB(colorSpace)->makeLinearGamma();
    }

    return colorSpace;
}

static void make_index8(SkBitmap* bitmap, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
    const SkColor colors[] = {
            0x800000FF, 0x8000FF00, 0x80FF0000, 0x80FFFF00,
    };

    auto toPMColor = [alphaType, colorSpace](SkColor color) {
        // In the opaque/unpremul case, just convert to SkPMColor ordering.
        if (kPremul_SkAlphaType != alphaType) {
            return SkSwizzle_BGRA_to_PMColor(color);
        }

        // Linear premultiply.
        if (colorSpace) {
            uint32_t result;
            Sk4f pmFloat = SkColor4f::FromColor(color).premul().to4f_pmorder();
            SkNx_cast<uint8_t>(sk_linear_to_srgb_needs_trunc(pmFloat)).store(&result);
            result = (result & 0x00FFFFFF) | (color & 0xFF000000);
            return result;
        }

        // Legacy premultiply.
        return SkPreMultiplyColor(color);
    };

    // Note that these are not necessarily premultiplied, but they are platform byte ordering.
    SkPMColor pmColors[SK_ARRAY_COUNT(colors)];
    for (int i = 0; i < (int) SK_ARRAY_COUNT(colors); i++) {
        pmColors[i] = toPMColor(colors[i]);
    }

    sk_sp<SkColorTable> colorTable(new SkColorTable(pmColors, SK_ARRAY_COUNT(pmColors)));
    SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kIndex_8_SkColorType,
                                         alphaType, colorSpace);
    bitmap->allocPixels(info, nullptr, colorTable.get());
    for (int y = 0; y < imageHeight; y++) {
        for (int x = 0; x < imageWidth; x++) {
            *bitmap->getAddr8(x, y) = (x / div_round_up(imageWidth, 2)) +
                                      (y / div_round_up(imageHeight, 3));
        }
    }
}

static void make(SkBitmap* bitmap, SkColorType colorType, SkAlphaType alphaType,
                 sk_sp<SkColorSpace> colorSpace) {
    const char* resource;
    switch (colorType) {
        case kIndex_8_SkColorType:
            make_index8(bitmap, alphaType, colorSpace);
            return;
        case kGray_8_SkColorType:
            resource = "grayscale.jpg";
            alphaType = kOpaque_SkAlphaType;
            break;
        case kRGB_565_SkColorType:
            resource = "color_wheel.jpg";
            alphaType = kOpaque_SkAlphaType;
            break;
        default:
            resource = (kOpaque_SkAlphaType == alphaType) ? "color_wheel.jpg"
                                                          : "color_wheel.png";
            break;
    }

    sk_sp<SkData> data = GetResourceAsData(resource);
    std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
    SkImageInfo dstInfo = codec->getInfo().makeColorType(colorType)
                                          .makeAlphaType(alphaType)
                                          .makeColorSpace(fix_for_colortype(colorSpace, colorType));
    bitmap->allocPixels(dstInfo);
    codec->getPixels(dstInfo, bitmap->getPixels(), bitmap->rowBytes());
}

static sk_sp<SkData> encode_data(const SkBitmap& bitmap, SkEncodedImageFormat format) {
    SkAutoLockPixels autoLockPixels(bitmap);
    SkPixmap src;
    if (!bitmap.peekPixels(&src)) {
        return nullptr;
    }
    SkDynamicMemoryWStream buf;

    SkEncodeOptions options;
    if (bitmap.colorSpace()) {
        options.fUnpremulBehavior = SkTransferFunctionBehavior::kRespect;
    }

    switch (format) {
        case SkEncodedImageFormat::kPNG:
            SkAssertResult(SkEncodeImageAsPNG(&buf, src, options));
            break;
        case SkEncodedImageFormat::kWEBP:
            SkAssertResult(SkEncodeImageAsWEBP(&buf, src, options));
            break;
        case SkEncodedImageFormat::kJPEG:
            SkAssertResult(SkEncodeImageAsJPEG(&buf, src, options));
            break;
        default:
            break;
    }
    return buf.detachAsData();
}

class EncodeSRGBGM : public GM {
public:
    EncodeSRGBGM(SkEncodedImageFormat format)
        : fEncodedFormat(format)
    {}

protected:
    SkString onShortName() override {
        const char* format = nullptr;
        switch (fEncodedFormat) {
            case SkEncodedImageFormat::kPNG:
                format = "png";
                break;
            case SkEncodedImageFormat::kWEBP:
                format = "webp";
                break;
            case SkEncodedImageFormat::kJPEG:
                format = "jpg";
                break;
            default:
                break;
        }
        return SkStringPrintf("encode-srgb-%s", format);
    }

    SkISize onISize() override {
        return SkISize::Make(imageWidth * 2, imageHeight * 15);
    }

    void onDraw(SkCanvas* canvas) override {
        const SkColorType colorTypes[] = {
                kN32_SkColorType, kRGBA_F16_SkColorType, kIndex_8_SkColorType, kGray_8_SkColorType,
                kRGB_565_SkColorType,
        };
        const SkAlphaType alphaTypes[] = {
                kUnpremul_SkAlphaType, kPremul_SkAlphaType, kOpaque_SkAlphaType,
        };
        const sk_sp<SkColorSpace> colorSpaces[] = {
                nullptr, SkColorSpace::MakeSRGB(),
        };

        SkBitmap bitmap;
        for (SkColorType colorType : colorTypes) {
            for (SkAlphaType alphaType : alphaTypes) {
                canvas->save();
                for (sk_sp<SkColorSpace> colorSpace : colorSpaces) {
                    make(&bitmap, colorType, alphaType, colorSpace);
                    auto image = SkImage::MakeFromEncoded(encode_data(bitmap, fEncodedFormat));
                    canvas->drawImage(image.get(), 0.0f, 0.0f);
                    canvas->translate((float) imageWidth, 0.0f);
                }
                canvas->restore();
                canvas->translate(0.0f, (float) imageHeight);
            }
        }
    }

private:
    SkEncodedImageFormat fEncodedFormat;

    typedef GM INHERITED;
};

DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kPNG); )
DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kWEBP); )
DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kJPEG); )
}