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