Flutter Engine
The Flutter Engine
ExifTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2016 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
12#include "include/core/SkSize.h"
15#include "tests/Test.h"
16#include "tools/Resources.h"
17
18#include <memory>
19#include <tuple>
20#include <utility>
21
22DEF_TEST(ExifOrientation, r) {
23 std::unique_ptr<SkStream> stream(GetResourceAsStream("images/exif-orientation-2-ur.jpg"));
24 REPORTER_ASSERT(r, nullptr != stream);
25 if (!stream) {
26 return;
27 }
28
29 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
30 REPORTER_ASSERT(r, nullptr != codec);
31 SkEncodedOrigin origin = codec->getOrigin();
33
34 codec = SkCodec::MakeFromStream(GetResourceAsStream("images/mandrill_512_q075.jpg"));
35 REPORTER_ASSERT(r, nullptr != codec);
36 origin = codec->getOrigin();
38}
39
40DEF_TEST(GetImageRespectsExif, r) {
41 std::unique_ptr<SkStream> stream(GetResourceAsStream("images/orientation/6.webp"));
42 REPORTER_ASSERT(r, nullptr != stream);
43 if (!stream) {
44 return;
45 }
46
47 std::unique_ptr<SkCodec> codec(SkWebpDecoder::Decode(std::move(stream), nullptr));
48 REPORTER_ASSERT(r, nullptr != codec);
49 SkEncodedOrigin origin = codec->getOrigin();
51 "Actual origin %d", origin);
52
53 auto result = codec->getImage();
55 "Not success %d", std::get<1>(result));
58 SkISize dims = frame->dimensions();
59 REPORTER_ASSERT(r, dims.fWidth == 100, "width %d != 100", dims.fWidth);
60 REPORTER_ASSERT(r, dims.fHeight == 80, "height %d != 80", dims.fHeight);
61}
62
63DEF_TEST(ExifOrientationInExif, r) {
64 std::unique_ptr<SkStream> stream(GetResourceAsStream("images/orientation/exif.jpg"));
65
66 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream));
67 REPORTER_ASSERT(r, nullptr != codec);
68 SkEncodedOrigin origin = codec->getOrigin();
70}
71
72DEF_TEST(ExifOrientationInSubIFD, r) {
73 std::unique_ptr<SkStream> stream(GetResourceAsStream("images/orientation/subifd.jpg"));
74
75 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream));
76 REPORTER_ASSERT(r, nullptr != codec);
77 SkEncodedOrigin origin = codec->getOrigin();
79}
80
81static bool approx_eq(float x, float y, float epsilon) { return std::abs(x - y) < epsilon; }
82
83DEF_TEST(ExifParse, r) {
84 const float kEpsilon = 0.001f;
85
86 {
87 sk_sp<SkData> data = GetResourceAsData("images/test0-hdr.exif");
88 REPORTER_ASSERT(r, nullptr != data);
90 SkExif::Parse(exif, data.get());
91 REPORTER_ASSERT(r, exif.fHdrHeadroom.has_value());
92 REPORTER_ASSERT(r, approx_eq(exif.fHdrHeadroom.value(), 3.755296f, kEpsilon));
93
94 REPORTER_ASSERT(r, exif.fResolutionUnit.has_value());
95 REPORTER_ASSERT(r, 2 == exif.fResolutionUnit.value());
96 REPORTER_ASSERT(r, exif.fXResolution.has_value());
97 REPORTER_ASSERT(r, 72.f == exif.fXResolution.value());
98 REPORTER_ASSERT(r, exif.fYResolution.has_value());
99 REPORTER_ASSERT(r, 72.f == exif.fYResolution.value());
100
101 REPORTER_ASSERT(r, exif.fPixelXDimension.has_value());
102 REPORTER_ASSERT(r, 4032 == exif.fPixelXDimension.value());
103 REPORTER_ASSERT(r, exif.fPixelYDimension.has_value());
104 REPORTER_ASSERT(r, 3024 == exif.fPixelYDimension.value());
105 }
106
107 {
108 sk_sp<SkData> data = GetResourceAsData("images/test1-pixel32.exif");
109 REPORTER_ASSERT(r, nullptr != data);
110 SkExif::Metadata exif;
111 SkExif::Parse(exif, data.get());
112 REPORTER_ASSERT(r, !exif.fHdrHeadroom.has_value());
113
114 REPORTER_ASSERT(r, exif.fResolutionUnit.value());
115 REPORTER_ASSERT(r, 2 == exif.fResolutionUnit.value());
116 REPORTER_ASSERT(r, exif.fXResolution.has_value());
117 REPORTER_ASSERT(r, 72.f == exif.fXResolution.value());
118 REPORTER_ASSERT(r, exif.fYResolution.has_value());
119 REPORTER_ASSERT(r, 72.f == exif.fYResolution.value());
120
121 REPORTER_ASSERT(r, exif.fPixelXDimension.has_value());
122 REPORTER_ASSERT(r, 200 == exif.fPixelXDimension.value());
123 REPORTER_ASSERT(r, exif.fPixelYDimension.has_value());
124 REPORTER_ASSERT(r, 100 == exif.fPixelYDimension.value());
125 }
126
127 {
128 sk_sp<SkData> data = GetResourceAsData("images/test2-nonuniform.exif");
129 REPORTER_ASSERT(r, nullptr != data);
130 SkExif::Metadata exif;
131 SkExif::Parse(exif, data.get());
132 REPORTER_ASSERT(r, !exif.fHdrHeadroom.has_value());
133
134 REPORTER_ASSERT(r, exif.fResolutionUnit.value());
135 REPORTER_ASSERT(r, 2 == exif.fResolutionUnit.value());
136 REPORTER_ASSERT(r, exif.fXResolution.has_value());
137 REPORTER_ASSERT(r, 144.f == exif.fXResolution.value());
138 REPORTER_ASSERT(r, exif.fYResolution.has_value());
139 REPORTER_ASSERT(r, 36.f == exif.fYResolution.value());
140
141 REPORTER_ASSERT(r, exif.fPixelXDimension.has_value());
142 REPORTER_ASSERT(r, 50 == exif.fPixelXDimension.value());
143 REPORTER_ASSERT(r, exif.fPixelYDimension.has_value());
144 REPORTER_ASSERT(r, 100 == exif.fPixelYDimension.value());
145 }
146
147 {
148 sk_sp<SkData> data = GetResourceAsData("images/test3-little-endian.exif");
149 REPORTER_ASSERT(r, nullptr != data);
150 SkExif::Metadata exif;
151 SkExif::Parse(exif, data.get());
152 REPORTER_ASSERT(r, !exif.fHdrHeadroom.has_value());
153
154 REPORTER_ASSERT(r, exif.fResolutionUnit.value());
155 REPORTER_ASSERT(r, 2 == exif.fResolutionUnit.value());
156 REPORTER_ASSERT(r, exif.fXResolution.has_value());
157 REPORTER_ASSERT(r, 350.f == exif.fXResolution.value());
158 REPORTER_ASSERT(r, exif.fYResolution.has_value());
159 REPORTER_ASSERT(r, 350.f == exif.fYResolution.value());
160
161 REPORTER_ASSERT(r, !exif.fPixelXDimension.has_value());
162 REPORTER_ASSERT(r, !exif.fPixelYDimension.has_value());
163 }
164
165 {
166 sk_sp<SkData> data = GetResourceAsData("images/test0-hdr.exif");
167
168 // Zero out the denominators of signed and unsigned rationals, to verify that we do not
169 // divide by zero.
170 data = SkData::MakeWithCopy(data->bytes(), data->size());
171 memset(static_cast<uint8_t*>(data->writable_data()) + 186, 0, 4);
172 memset(static_cast<uint8_t*>(data->writable_data()) + 2171, 0, 4);
173 memset(static_cast<uint8_t*>(data->writable_data()) + 2240, 0, 4);
174
175 // Parse the corrupted Exif.
176 SkExif::Metadata exif;
177 SkExif::Parse(exif, data.get());
178
179 // HDR headroom signed denominators are destroyed.
180 REPORTER_ASSERT(r, exif.fHdrHeadroom.has_value());
181 REPORTER_ASSERT(r, approx_eq(exif.fHdrHeadroom.value(), 3.482202f, kEpsilon));
182
183 // The X resolution should be zero.
184 REPORTER_ASSERT(r, exif.fXResolution.has_value());
185 REPORTER_ASSERT(r, 0.f == exif.fXResolution.value());
186 REPORTER_ASSERT(r, exif.fYResolution.has_value());
187 REPORTER_ASSERT(r, 72.f == exif.fYResolution.value());
188 }
189}
190
191DEF_TEST(ExifTruncate, r) {
192 sk_sp<SkData> data = GetResourceAsData("images/test0-hdr.exif");
193
194 // At 545 bytes, we do not have either value yet.
195 {
196 SkExif::Metadata exif;
197 SkExif::Parse(exif, SkData::MakeWithCopy(data->bytes(), 545).get());
198 REPORTER_ASSERT(r, !exif.fPixelXDimension.has_value());
199 REPORTER_ASSERT(r, !exif.fPixelYDimension.has_value());
200 }
201
202 // At 546 bytes, we have one.
203 {
204 SkExif::Metadata exif;
205 SkExif::Parse(exif, SkData::MakeWithCopy(data->bytes(), 546).get());
206 REPORTER_ASSERT(r, exif.fPixelXDimension.has_value());
207 REPORTER_ASSERT(r, !exif.fPixelYDimension.has_value());
208 }
209
210 // At 558 bytes (12 bytes later, one tag), we have both.
211 {
212 SkExif::Metadata exif;
213 SkExif::Parse(exif, SkData::MakeWithCopy(data->bytes(), 558).get());
214 REPORTER_ASSERT(r, exif.fPixelXDimension.has_value());
215 REPORTER_ASSERT(r, exif.fPixelYDimension.has_value());
216 }
217}
DEF_TEST(ExifOrientation, r)
Definition: ExifTest.cpp:22
static bool approx_eq(float x, float y, float epsilon)
Definition: ExifTest.cpp:81
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition: Resources.cpp:31
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition: Resources.cpp:42
SkEncodedOrigin
@ kTopRight_SkEncodedOrigin
@ kTopLeft_SkEncodedOrigin
@ kLeftBottom_SkEncodedOrigin
@ kRightTop_SkEncodedOrigin
static constexpr double kEpsilon
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, SkSpan< const SkCodecs::Decoder > decoders, Result *=nullptr, SkPngChunkReader *=nullptr, SelectionPolicy selectionPolicy=SelectionPolicy::kPreferStillImage)
Definition: SkCodec.cpp:163
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition: SkData.cpp:111
T * get() const
Definition: SkRefCnt.h:303
@ kSuccess
Definition: embedder.h:73
double frame
Definition: examples.cpp:31
GAsyncResult * result
double y
double x
void SK_API Parse(Metadata &metadata, const SkData *data)
Definition: SkExif.cpp:182
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
const myers::Point & get< 1 >(const myers::Segment &s)
Definition: Myers.h:81
const myers::Point & get< 0 >(const myers::Segment &s)
Definition: Myers.h:80
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707
std::optional< uint32_t > fPixelYDimension
Definition: SkExif.h:44
std::optional< uint32_t > fPixelXDimension
Definition: SkExif.h:43
std::optional< float > fHdrHeadroom
Definition: SkExif.h:35
std::optional< float > fYResolution
Definition: SkExif.h:40
std::optional< uint16_t > fResolutionUnit
Definition: SkExif.h:38
std::optional< float > fXResolution
Definition: SkExif.h:39
Definition: SkSize.h:16
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63