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