| /* |
| * Copyright 2024 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/encode/SkPngRustEncoder.h" |
| |
| #include "include/codec/SkAndroidCodec.h" |
| #include "include/codec/SkCodec.h" |
| #include "include/core/SkBitmap.h" |
| #include "include/core/SkColor.h" |
| #include "include/core/SkColorSpace.h" |
| #include "include/core/SkPixmap.h" |
| #include "include/core/SkStream.h" |
| #include "include/private/SkGainmapInfo.h" |
| #include "tests/GainmapTestCommon.h" |
| #include "tests/Test.h" |
| #include "tools/DecodeUtils.h" |
| #include "tools/ToolUtils.h" |
| |
| DEF_TEST(RustEncodePng_smoke_test, r) { |
| SkBitmap bitmap; |
| bool success = ToolUtils::GetResourceAsBitmap("images/mandrill_128.png", &bitmap); |
| if (!success) { |
| return; |
| } |
| |
| SkPixmap src; |
| success = bitmap.peekPixels(&src); |
| REPORTER_ASSERT(r, success); |
| if (!success) { |
| return; |
| } |
| |
| SkDynamicMemoryWStream dst; |
| SkPngRustEncoder::Options options; |
| success = SkPngRustEncoder::Encode(&dst, src, options); |
| REPORTER_ASSERT(r, success); |
| if (!success) { |
| return; |
| } |
| |
| SkBitmap roundtrip; |
| success = ToolUtils::DecodeDataToBitmap(dst.detachAsData(), &roundtrip); |
| REPORTER_ASSERT(r, success); |
| if (!success) { |
| return; |
| } |
| |
| success = ToolUtils::equal_pixels(bitmap, roundtrip); |
| REPORTER_ASSERT(r, success); |
| } |
| |
| #ifdef SK_CODEC_USES_PNG_WITH_RUST_FOR_ANDROID |
| DEF_TEST(RustEncodePng_gainmap, r) { |
| SkColorType colorTypes[] = { |
| kRGBA_8888_SkColorType, |
| kAlpha_8_SkColorType, |
| }; |
| |
| for (const auto& colorType : colorTypes) { |
| SkDynamicMemoryWStream stream; |
| SkGainmapInfo sourceGainmapInfo; |
| sourceGainmapInfo.fGainmapRatioMin = {1.f, 1.f, 1.f, 1.f}; |
| sourceGainmapInfo.fGainmapRatioMax = {5.f, 5.f, 5.f, 1.f}; |
| sourceGainmapInfo.fGainmapGamma = {1.f, 1.f, 1.f, 1.f}; |
| sourceGainmapInfo.fEpsilonSdr = {0.01f, 0.01f, 0.01f, 0.01f}; |
| sourceGainmapInfo.fEpsilonHdr = {0.001f, 0.001f, 0.001f, 0.001f}; |
| sourceGainmapInfo.fDisplayRatioSdr = 1.f; |
| sourceGainmapInfo.fDisplayRatioHdr = 3.f; |
| sourceGainmapInfo.fGainmapMathColorSpace = SkColorSpace::MakeSRGB(); |
| SkBitmap sourceBase; |
| sourceBase.allocPixels( |
| SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kOpaque_SkAlphaType)); |
| sourceBase.eraseColor(SK_ColorRED); |
| SkBitmap sourceGainmap; |
| sourceGainmap.allocPixels(SkImageInfo::Make(4, 4, colorType, kOpaque_SkAlphaType)); |
| sourceGainmap.eraseColor(SK_ColorGREEN); |
| |
| SkPngRustEncoder::Options options; |
| options.fGainmap = &(sourceGainmap.pixmap()); |
| options.fGainmapInfo = &sourceGainmapInfo; |
| REPORTER_ASSERT(r, SkPngRustEncoder::Encode(&stream, sourceBase.pixmap(), options)); |
| |
| SkCodec::Result result = SkCodec::kSuccess; |
| std::unique_ptr<SkCodec> baseCodec = |
| SkCodec::MakeFromStream(stream.detachAsStream(), &result); |
| REPORTER_ASSERT(r, baseCodec); |
| if (!baseCodec) { |
| continue; |
| } |
| |
| SkBitmap baseBitmap; |
| baseBitmap.allocPixels(baseCodec->getInfo()); |
| REPORTER_ASSERT(r, |
| SkCodec::kSuccess == baseCodec->getPixels(baseBitmap.info(), |
| baseBitmap.getPixels(), |
| baseBitmap.rowBytes())); |
| |
| std::unique_ptr<SkAndroidCodec> androidCodec = |
| SkAndroidCodec::MakeFromCodec(std::move(baseCodec)); |
| REPORTER_ASSERT(r, androidCodec); |
| if (!androidCodec) { |
| continue; |
| } |
| |
| SkGainmapInfo gainmapInfo; |
| std::unique_ptr<SkAndroidCodec> gainmapCodec; |
| bool decodedGainmap = androidCodec->getGainmapAndroidCodec(&gainmapInfo, &gainmapCodec); |
| REPORTER_ASSERT(r, decodedGainmap); |
| REPORTER_ASSERT(r, gainmapCodec); |
| if (!gainmapCodec) { |
| continue; |
| } |
| SkBitmap gainmapBitmap; |
| gainmapBitmap.allocPixels(gainmapCodec->getInfo()); |
| REPORTER_ASSERT( |
| r, |
| SkCodec::kSuccess == gainmapCodec->getAndroidPixels(gainmapBitmap.info(), |
| gainmapBitmap.getPixels(), |
| gainmapBitmap.rowBytes())); |
| |
| REPORTER_ASSERT(r, baseBitmap.dimensions().fHeight == 16); |
| REPORTER_ASSERT(r, baseBitmap.dimensions().fWidth == 16); |
| REPORTER_ASSERT(r, baseBitmap.getColor(0, 0) == SK_ColorRED); |
| |
| REPORTER_ASSERT(r, gainmapBitmap.dimensions().fHeight == 4); |
| REPORTER_ASSERT(r, gainmapBitmap.dimensions().fWidth == 4); |
| |
| if (colorType == kAlpha_8_SkColorType) { |
| REPORTER_ASSERT(r, gainmapBitmap.getColor(0, 0) == SK_ColorBLACK); |
| } else { |
| REPORTER_ASSERT(r, gainmapBitmap.getColor(0, 0) == SK_ColorGREEN); |
| } |
| |
| if (colorType == kAlpha_8_SkColorType) { |
| sourceGainmapInfo.fGainmapMathColorSpace = nullptr; |
| } |
| |
| skiatest::ExpectApproxEqInfo(r, sourceGainmapInfo, gainmapInfo); |
| } |
| } |
| |
| DEF_TEST(RustEncodePng_sBIT, r) { |
| // Test kRGB_565_SkColorType |
| { |
| SkBitmap source; |
| source.allocPixels(SkImageInfo::Make(16, 16, kRGB_565_SkColorType, kOpaque_SkAlphaType)); |
| source.eraseColor(SK_ColorRED); |
| |
| SkDynamicMemoryWStream stream; |
| REPORTER_ASSERT(r, SkPngRustEncoder::Encode(&stream, source.pixmap(), {})); |
| |
| SkCodec::Result result = SkCodec::kSuccess; |
| std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(stream.detachAsStream(), &result); |
| REPORTER_ASSERT(r, codec); |
| if (codec) { |
| // Verify that the decoder recommends kRGB_565_SkColorType because of the sBIT chunk. |
| REPORTER_ASSERT(r, codec->getInfo().colorType() == kRGB_565_SkColorType); |
| } |
| } |
| |
| // Test kAlpha_8_SkColorType |
| { |
| SkBitmap source; |
| source.allocPixels(SkImageInfo::Make(16, 16, kAlpha_8_SkColorType, kPremul_SkAlphaType)); |
| source.eraseColor(SK_ColorTRANSPARENT); // Alpha 8 only cares about alpha channel |
| |
| SkDynamicMemoryWStream stream; |
| REPORTER_ASSERT(r, SkPngRustEncoder::Encode(&stream, source.pixmap(), {})); |
| |
| SkCodec::Result result = SkCodec::kSuccess; |
| std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(stream.detachAsStream(), &result); |
| REPORTER_ASSERT(r, codec); |
| if (codec) { |
| // Verify that the decoder recommends kAlpha_8_SkColorType because of the sBIT chunk. |
| REPORTER_ASSERT(r, codec->getInfo().colorType() == kAlpha_8_SkColorType); |
| } |
| } |
| } |
| #endif |