1 // Copyright 2023 Google LLC
2 // SPDX-License-Identifier: BSD-2-Clause
3
4 #include <string>
5
6 #include "avif/avif.h"
7 #include "aviftest_helpers.h"
8 #include "gtest/gtest.h"
9
10 namespace avif {
11 namespace {
12
13 // Used to pass the data folder path to the GoogleTest suites.
14 const char* data_path = nullptr;
15
TEST(GainMapTest,DecodeGainMapGrid)16 TEST(GainMapTest, DecodeGainMapGrid) {
17 const std::string path =
18 std::string(data_path) + "color_grid_gainmap_different_grid.avif";
19 DecoderPtr decoder(avifDecoderCreate());
20 ASSERT_NE(decoder, nullptr);
21 decoder->imageContentToDecode |= AVIF_IMAGE_CONTENT_GAIN_MAP;
22
23 avifResult result = avifDecoderSetIOFile(decoder.get(), path.c_str());
24 ASSERT_EQ(result, AVIF_RESULT_OK)
25 << avifResultToString(result) << " " << decoder->diag.error;
26
27 // Just parse the image first.
28 result = avifDecoderParse(decoder.get());
29 ASSERT_EQ(result, AVIF_RESULT_OK)
30 << avifResultToString(result) << " " << decoder->diag.error;
31 EXPECT_EQ(decoder->compressionFormat, COMPRESSION_FORMAT_AVIF);
32 avifImage* decoded = decoder->image;
33 ASSERT_NE(decoded, nullptr);
34
35 // Verify that the gain map is present and matches the input.
36 EXPECT_NE(decoder->image->gainMap, nullptr);
37 // Color+alpha: 4x3 grid of 128x200 tiles.
38 EXPECT_EQ(decoded->width, 128u * 4u);
39 EXPECT_EQ(decoded->height, 200u * 3u);
40 EXPECT_EQ(decoded->depth, 10u);
41 ASSERT_NE(decoded->gainMap->image, nullptr);
42 // Gain map: 2x2 grid of 64x80 tiles.
43 EXPECT_EQ(decoded->gainMap->image->width, 64u * 2u);
44 EXPECT_EQ(decoded->gainMap->image->height, 80u * 2u);
45 EXPECT_EQ(decoded->gainMap->image->depth, 8u);
46 EXPECT_EQ(decoded->gainMap->baseHdrHeadroom.n, 6u);
47 EXPECT_EQ(decoded->gainMap->baseHdrHeadroom.d, 2u);
48
49 // Decode the image.
50 result = avifDecoderNextImage(decoder.get());
51 ASSERT_EQ(result, AVIF_RESULT_OK)
52 << avifResultToString(result) << " " << decoder->diag.error;
53 }
54
TEST(GainMapTest,DecodeOriented)55 TEST(GainMapTest, DecodeOriented) {
56 const std::string path = std::string(data_path) + "gainmap_oriented.avif";
57 DecoderPtr decoder(avifDecoderCreate());
58 ASSERT_NE(decoder, nullptr);
59 decoder->imageContentToDecode |= AVIF_IMAGE_CONTENT_GAIN_MAP;
60 ASSERT_EQ(avifDecoderSetIOFile(decoder.get(), path.c_str()), AVIF_RESULT_OK);
61 ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK);
62
63 // Verify that the transformative properties were kept.
64 EXPECT_EQ(decoder->image->transformFlags,
65 AVIF_TRANSFORM_IROT | AVIF_TRANSFORM_IMIR);
66 EXPECT_EQ(decoder->image->irot.angle, 1);
67 EXPECT_EQ(decoder->image->imir.axis, 0);
68 EXPECT_EQ(decoder->image->gainMap->image->transformFlags,
69 AVIF_TRANSFORM_NONE);
70 }
71
TEST(GainMapTest,IgnoreGainMapButReadMetadata)72 TEST(GainMapTest, IgnoreGainMapButReadMetadata) {
73 const std::string path =
74 std::string(data_path) + "seine_sdr_gainmap_srgb.avif";
75 DecoderPtr decoder(avifDecoderCreate());
76 ASSERT_NE(decoder, nullptr);
77
78 avifResult result = avifDecoderSetIOFile(decoder.get(), path.c_str());
79 ASSERT_EQ(result, AVIF_RESULT_OK)
80 << avifResultToString(result) << " " << decoder->diag.error;
81 result = avifDecoderParse(decoder.get());
82 ASSERT_EQ(result, AVIF_RESULT_OK)
83 << avifResultToString(result) << " " << decoder->diag.error;
84 avifImage* decoded = decoder->image;
85 ASSERT_NE(decoded, nullptr);
86
87 // Verify that the gain map was detected...
88 EXPECT_NE(decoder->image->gainMap, nullptr);
89 // ... but not decoded because enableDecodingGainMap is false by default.
90 EXPECT_EQ(decoded->gainMap->image, nullptr);
91 // Check that the gain map metadata WAS populated.
92 EXPECT_EQ(decoded->gainMap->alternateHdrHeadroom.n, 13);
93 EXPECT_EQ(decoded->gainMap->alternateHdrHeadroom.d, 10);
94 }
95
TEST(GainMapTest,IgnoreColorAndAlpha)96 TEST(GainMapTest, IgnoreColorAndAlpha) {
97 const std::string path =
98 std::string(data_path) + "seine_sdr_gainmap_srgb.avif";
99 DecoderPtr decoder(avifDecoderCreate());
100 ASSERT_NE(decoder, nullptr);
101 decoder->imageContentToDecode = AVIF_IMAGE_CONTENT_GAIN_MAP;
102
103 avifResult result = avifDecoderSetIOFile(decoder.get(), path.c_str());
104 ASSERT_EQ(result, AVIF_RESULT_OK)
105 << avifResultToString(result) << " " << decoder->diag.error;
106 result = avifDecoderParse(decoder.get());
107 ASSERT_EQ(result, AVIF_RESULT_OK)
108 << avifResultToString(result) << " " << decoder->diag.error;
109 result = avifDecoderNextImage(decoder.get());
110 ASSERT_EQ(result, AVIF_RESULT_OK)
111 << avifResultToString(result) << " " << decoder->diag.error;
112 avifImage* decoded = decoder->image;
113 ASSERT_NE(decoded, nullptr);
114
115 // Main image metadata is available.
116 EXPECT_EQ(decoded->width, 400u);
117 EXPECT_EQ(decoded->height, 300u);
118 // But pixels are not.
119 EXPECT_EQ(decoded->yuvRowBytes[0], 0u);
120 EXPECT_EQ(decoded->yuvRowBytes[1], 0u);
121 EXPECT_EQ(decoded->yuvRowBytes[2], 0u);
122 EXPECT_EQ(decoded->alphaRowBytes, 0u);
123 // The gain map was decoded.
124 EXPECT_NE(decoder->image->gainMap, nullptr);
125 ASSERT_NE(decoded->gainMap->image, nullptr);
126 // Including pixels.
127 EXPECT_GT(decoded->gainMap->image->yuvRowBytes[0], 0u);
128 }
129
TEST(GainMapTest,IgnoreAll)130 TEST(GainMapTest, IgnoreAll) {
131 const std::string path =
132 std::string(data_path) + "seine_sdr_gainmap_srgb.avif";
133 DecoderPtr decoder(avifDecoderCreate());
134 ASSERT_NE(decoder, nullptr);
135 decoder->imageContentToDecode = AVIF_IMAGE_CONTENT_NONE;
136
137 avifResult result = avifDecoderSetIOFile(decoder.get(), path.c_str());
138 ASSERT_EQ(result, AVIF_RESULT_OK)
139 << avifResultToString(result) << " " << decoder->diag.error;
140 result = avifDecoderParse(decoder.get());
141 ASSERT_EQ(result, AVIF_RESULT_OK)
142 << avifResultToString(result) << " " << decoder->diag.error;
143 avifImage* decoded = decoder->image;
144 ASSERT_NE(decoded, nullptr);
145
146 EXPECT_NE(decoder->image->gainMap, nullptr);
147 ASSERT_EQ(decoder->image->gainMap->image, nullptr);
148
149 // But trying to access the next image should give an error because both
150 // ignoreColorAndAlpha and enableDecodingGainMap are set.
151 ASSERT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_NO_CONTENT);
152 }
153
154 // The following two functions use avifDecoderReadFile which is not supported in
155 // CAPI yet.
156
157 /*
158 TEST(GainMapTest, DecodeColorGridGainMapNoGrid) {
159 const std::string path =
160 std::string(data_path) + "color_grid_alpha_grid_gainmap_nogrid.avif";
161 ImagePtr decoded(avifImageCreateEmpty());
162 ASSERT_NE(decoded, nullptr);
163 DecoderPtr decoder(avifDecoderCreate());
164 ASSERT_NE(decoder, nullptr);
165 decoder->enableDecodingGainMap = true;
166 decoder->enableParsingGainMapMetadata = true;
167 ASSERT_EQ(avifDecoderReadFile(decoder.get(), decoded.get(), path.c_str()),
168 AVIF_RESULT_OK);
169
170 // Color+alpha: 4x3 grid of 128x200 tiles.
171 EXPECT_EQ(decoded->width, 128u * 4u);
172 EXPECT_EQ(decoded->height, 200u * 3u);
173 ASSERT_NE(decoded->gainMap, nullptr);
174 ASSERT_NE(decoded->gainMap->image, nullptr);
175 // Gain map: single image of size 64x80.
176 EXPECT_EQ(decoded->gainMap->image->width, 64u);
177 EXPECT_EQ(decoded->gainMap->image->height, 80u);
178 EXPECT_EQ(decoded->gainMap->baseHdrHeadroom.n, 6u);
179 EXPECT_EQ(decoded->gainMap->baseHdrHeadroom.d, 2u);
180 }
181
182 TEST(GainMapTest, DecodeColorNoGridGainMapGrid) {
183 const std::string path =
184 std::string(data_path) + "color_nogrid_alpha_nogrid_gainmap_grid.avif";
185 ImagePtr decoded(avifImageCreateEmpty());
186 ASSERT_NE(decoded, nullptr);
187 DecoderPtr decoder(avifDecoderCreate());
188 ASSERT_NE(decoder, nullptr);
189 decoder->enableDecodingGainMap = true;
190 decoder->enableParsingGainMapMetadata = true;
191 ASSERT_EQ(avifDecoderReadFile(decoder.get(), decoded.get(), path.c_str()),
192 AVIF_RESULT_OK);
193
194 // Color+alpha: single image of size 128x200 .
195 EXPECT_EQ(decoded->width, 128u);
196 EXPECT_EQ(decoded->height, 200u);
197 ASSERT_NE(decoded->gainMap, nullptr);
198 ASSERT_NE(decoded->gainMap->image, nullptr);
199 // Gain map: 2x2 grid of 64x80 tiles.
200 EXPECT_EQ(decoded->gainMap->image->width, 64u * 2u);
201 EXPECT_EQ(decoded->gainMap->image->height, 80u * 2u);
202 EXPECT_EQ(decoded->gainMap->baseHdrHeadroom.n, 6u);
203 EXPECT_EQ(decoded->gainMap->baseHdrHeadroom.d, 2u);
204 }
205 */
206
207 } // namespace
208 } // namespace avif
209
main(int argc,char ** argv)210 int main(int argc, char** argv) {
211 ::testing::InitGoogleTest(&argc, argv);
212 if (argc != 2) {
213 std::cerr << "There must be exactly one argument containing the path to "
214 "the test data folder"
215 << std::endl;
216 return 1;
217 }
218 avif::data_path = argv[1];
219 return RUN_ALL_TESTS();
220 }
221