1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h" 9cb93a386Sopenharmony_ci#include "include/core/SkPixmap.h" 10cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 11cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 12cb93a386Sopenharmony_ci#include "src/core/SkAutoMalloc.h" 13cb93a386Sopenharmony_ci#include "tests/Test.h" 14cb93a386Sopenharmony_ci#include "tools/Resources.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_cistatic void codec_yuv(skiatest::Reporter* reporter, 17cb93a386Sopenharmony_ci const char path[], 18cb93a386Sopenharmony_ci const SkYUVAInfo* expectedInfo) { 19cb93a386Sopenharmony_ci std::unique_ptr<SkStream> stream(GetResourceAsStream(path)); 20cb93a386Sopenharmony_ci if (!stream) { 21cb93a386Sopenharmony_ci return; 22cb93a386Sopenharmony_ci } 23cb93a386Sopenharmony_ci std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream))); 24cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, codec); 25cb93a386Sopenharmony_ci if (!codec) { 26cb93a386Sopenharmony_ci return; 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci // Test queryYUBAInfo() 30cb93a386Sopenharmony_ci SkYUVAPixmapInfo yuvaPixmapInfo; 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci static constexpr auto kAllTypes = SkYUVAPixmapInfo::SupportedDataTypes::All(); 33cb93a386Sopenharmony_ci static constexpr auto kNoTypes = SkYUVAPixmapInfo::SupportedDataTypes(); 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci // SkYUVAInfo param is required to be non-null. 36cb93a386Sopenharmony_ci bool success = codec->queryYUVAInfo(kAllTypes, nullptr); 37cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !success); 38cb93a386Sopenharmony_ci // Fails when there is no support for YUVA planes. 39cb93a386Sopenharmony_ci success = codec->queryYUVAInfo(kNoTypes, &yuvaPixmapInfo); 40cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !success); 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci success = codec->queryYUVAInfo(kAllTypes, &yuvaPixmapInfo); 43cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkToBool(expectedInfo) == success); 44cb93a386Sopenharmony_ci if (!success) { 45cb93a386Sopenharmony_ci return; 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, *expectedInfo == yuvaPixmapInfo.yuvaInfo()); 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci int numPlanes = yuvaPixmapInfo.numPlanes(); 50cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, numPlanes <= SkYUVAInfo::kMaxPlanes); 51cb93a386Sopenharmony_ci for (int i = 0; i < numPlanes; ++i) { 52cb93a386Sopenharmony_ci const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i); 53cb93a386Sopenharmony_ci SkColorType planeCT = planeInfo.colorType(); 54cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !planeInfo.isEmpty()); 55cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, planeCT != kUnknown_SkColorType); 56cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, planeInfo.validRowBytes(yuvaPixmapInfo.rowBytes(i))); 57cb93a386Sopenharmony_ci // Currently all planes must share a data type, gettable as SkYUVAPixmapInfo::dataType(). 58cb93a386Sopenharmony_ci auto [numChannels, planeDataType] = SkYUVAPixmapInfo::NumChannelsAndDataType(planeCT); 59cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, planeDataType == yuvaPixmapInfo.dataType()); 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) { 62cb93a386Sopenharmony_ci const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i); 63cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, planeInfo.dimensions().isEmpty()); 64cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, planeInfo.colorType() == kUnknown_SkColorType); 65cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, yuvaPixmapInfo.rowBytes(i) == 0); 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci // Allocate the memory for the YUV decode. 69cb93a386Sopenharmony_ci auto pixmaps = SkYUVAPixmaps::Allocate(yuvaPixmapInfo); 70cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pixmaps.isValid()); 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci for (int i = 0; i < SkYUVAPixmaps::kMaxPlanes; ++i) { 73cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pixmaps.plane(i).info() == yuvaPixmapInfo.planeInfo(i)); 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) { 76cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pixmaps.plane(i).rowBytes() == 0); 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci // Test getYUVAPlanes() 80cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->getYUVAPlanes(pixmaps)); 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ciDEF_TEST(Jpeg_YUV_Codec, r) { 84cb93a386Sopenharmony_ci auto setExpectations = [](SkISize dims, SkYUVAInfo::Subsampling subsampling) { 85cb93a386Sopenharmony_ci return SkYUVAInfo(dims, 86cb93a386Sopenharmony_ci SkYUVAInfo::PlaneConfig::kY_U_V, 87cb93a386Sopenharmony_ci subsampling, 88cb93a386Sopenharmony_ci kJPEG_Full_SkYUVColorSpace, 89cb93a386Sopenharmony_ci kTopLeft_SkEncodedOrigin, 90cb93a386Sopenharmony_ci SkYUVAInfo::Siting::kCentered, 91cb93a386Sopenharmony_ci SkYUVAInfo::Siting::kCentered); 92cb93a386Sopenharmony_ci }; 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci SkYUVAInfo expectations = setExpectations({128, 128}, SkYUVAInfo::Subsampling::k420); 95cb93a386Sopenharmony_ci codec_yuv(r, "images/color_wheel.jpg", &expectations); 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci // H2V2 98cb93a386Sopenharmony_ci expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k420); 99cb93a386Sopenharmony_ci codec_yuv(r, "images/mandrill_512_q075.jpg", &expectations); 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci // H1V1 102cb93a386Sopenharmony_ci expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444); 103cb93a386Sopenharmony_ci codec_yuv(r, "images/mandrill_h1v1.jpg", &expectations); 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci // H2V1 106cb93a386Sopenharmony_ci expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k422); 107cb93a386Sopenharmony_ci codec_yuv(r, "images/mandrill_h2v1.jpg", &expectations); 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci // Non-power of two dimensions 110cb93a386Sopenharmony_ci expectations = setExpectations({439, 154}, SkYUVAInfo::Subsampling::k420); 111cb93a386Sopenharmony_ci codec_yuv(r, "images/cropped_mandrill.jpg", &expectations); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci expectations = setExpectations({8, 8}, SkYUVAInfo::Subsampling::k420); 114cb93a386Sopenharmony_ci codec_yuv(r, "images/randPixels.jpg", &expectations); 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci // Progressive images 117cb93a386Sopenharmony_ci expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444); 118cb93a386Sopenharmony_ci codec_yuv(r, "images/brickwork-texture.jpg", &expectations); 119cb93a386Sopenharmony_ci codec_yuv(r, "images/brickwork_normal-map.jpg", &expectations); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci // A CMYK encoded image should fail. 122cb93a386Sopenharmony_ci codec_yuv(r, "images/CMYK.jpg", nullptr); 123cb93a386Sopenharmony_ci // A grayscale encoded image should fail. 124cb93a386Sopenharmony_ci codec_yuv(r, "images/grayscale.jpg", nullptr); 125cb93a386Sopenharmony_ci // A PNG should fail. 126cb93a386Sopenharmony_ci codec_yuv(r, "images/arrow.png", nullptr); 127cb93a386Sopenharmony_ci} 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci#include "include/effects/SkColorMatrix.h" 130cb93a386Sopenharmony_ci#include "src/core/SkYUVMath.h" 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci// Be sure that the two matrices are inverses of each other 133cb93a386Sopenharmony_ci// (i.e. rgb2yuv and yuv2rgb 134cb93a386Sopenharmony_ciDEF_TEST(YUVMath, reporter) { 135cb93a386Sopenharmony_ci const SkYUVColorSpace spaces[] = { 136cb93a386Sopenharmony_ci kJPEG_SkYUVColorSpace, 137cb93a386Sopenharmony_ci kRec601_SkYUVColorSpace, 138cb93a386Sopenharmony_ci kRec709_SkYUVColorSpace, 139cb93a386Sopenharmony_ci kBT2020_SkYUVColorSpace, 140cb93a386Sopenharmony_ci kIdentity_SkYUVColorSpace, 141cb93a386Sopenharmony_ci }; 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci // Not sure what the theoretical precision we can hope for is, so pick a big value that 144cb93a386Sopenharmony_ci // passes (when I think we're correct). 145cb93a386Sopenharmony_ci const float tolerance = 1.0f/(1 << 18); 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci for (auto cs : spaces) { 148cb93a386Sopenharmony_ci SkColorMatrix r2ym = SkColorMatrix::RGBtoYUV(cs), 149cb93a386Sopenharmony_ci y2rm = SkColorMatrix::YUVtoRGB(cs); 150cb93a386Sopenharmony_ci r2ym.postConcat(y2rm); 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci float tmp[20]; 153cb93a386Sopenharmony_ci r2ym.getRowMajor(tmp); 154cb93a386Sopenharmony_ci for (int i = 0; i < 20; ++i) { 155cb93a386Sopenharmony_ci float expected = 0; 156cb93a386Sopenharmony_ci if (i % 6 == 0) { // diagonal 157cb93a386Sopenharmony_ci expected = 1; 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkScalarNearlyEqual(tmp[i], expected, tolerance)); 160cb93a386Sopenharmony_ci } 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci} 163