1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/utility/media_galleries/image_metadata_extractor.h"
8 #include "base/callback.h"
9 #include "base/files/file_path.h"
10 #include "base/lazy_instance.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/numerics/safe_conversions.h"
13 #include "base/path_service.h"
14 #include "base/scoped_native_library.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "content/public/common/content_paths.h"
17 #include "media/base/data_source.h"
18 #include "net/base/io_buffer.h"
21 #include <libexif/exif-data.h>
22 #include <libexif/exif-loader.h>
29 const size_t kMaxBufferSize
= 50 * 1024 * 1024; // Arbitrary maximum of 50MB.
31 typedef base::Callback
<void(const scoped_refptr
<net::DrainableIOBuffer
>&)>
34 void FinishGetImageBytes(
35 const scoped_refptr
<net::DrainableIOBuffer
>& buffer
,
36 media::DataSource
* source
,
37 const GotImageCallback
& callback
,
39 if (bytes_read
== media::DataSource::kReadError
) {
44 buffer
->DidConsume(bytes_read
);
45 // Didn't get the whole file. Continue reading to get the rest.
46 if (buffer
->BytesRemaining() > 0) {
49 buffer
->BytesRemaining(),
50 reinterpret_cast<uint8
*>(buffer
->data()),
52 &FinishGetImageBytes
, buffer
, base::Unretained(source
), callback
));
61 media::DataSource
* source
,
62 const GotImageCallback
& callback
) {
64 if (!source
->GetSize(&size64
) ||
65 base::saturated_cast
<size_t>(size64
) > kMaxBufferSize
) {
66 return callback
.Run(NULL
);
68 int size
= base::checked_cast
<int>(size64
);
70 scoped_refptr
<net::DrainableIOBuffer
> buffer(
71 new net::DrainableIOBuffer(new net::IOBuffer(size
), size
));
72 source
->Read(0, buffer
->BytesRemaining(),
73 reinterpret_cast<uint8
*>(buffer
->data()),
74 base::Bind(&FinishGetImageBytes
, buffer
,
75 base::Unretained(source
), callback
));
80 ExifFunctions() : exif_loader_write_func_(NULL
),
81 exif_loader_new_func_(NULL
),
82 exif_loader_unref_func_(NULL
),
83 exif_loader_get_data_func_(NULL
),
84 exif_data_free_func_(NULL
),
85 exif_data_get_byte_order_func_(NULL
),
86 exif_get_short_func_(NULL
),
87 exif_get_long_func_(NULL
),
88 exif_get_rational_func_(NULL
),
89 exif_entry_get_value_func_(NULL
),
90 exif_content_get_entry_func_(NULL
) {
93 bool Initialize(const base::FilePath
& module_dir
) {
94 if (exif_lib_
.is_valid())
98 base::FilePath module_path
= module_dir
.AppendASCII("libexif.dll");
99 #elif defined(OS_MACOSX)
100 base::FilePath module_path
= module_dir
.AppendASCII("exif.so");
101 #elif defined(OS_CHROMEOS)
102 // On ChromeOS, we build and distribute our own version of libexif.
103 base::FilePath module_path
= module_dir
.AppendASCII("libexif.so");
105 // On Linux-like systems, we use the system libexif.
106 base::FilePath module_path
= base::FilePath().AppendASCII("libexif.so.12");
109 base::ScopedNativeLibrary
lib(base::LoadNativeLibrary(module_path
, NULL
));
110 if (!lib
.is_valid()) {
111 LOG(ERROR
) << "Couldn't load libexif.";
115 if (!GetFunctionPointer(lib
, &exif_loader_write_func_
,
116 "exif_loader_write") ||
117 !GetFunctionPointer(lib
, &exif_loader_new_func_
, "exif_loader_new") ||
118 !GetFunctionPointer(lib
, &exif_loader_unref_func_
,
119 "exif_loader_unref") ||
120 !GetFunctionPointer(lib
, &exif_loader_get_data_func_
,
121 "exif_loader_get_data") ||
122 !GetFunctionPointer(lib
, &exif_data_free_func_
, "exif_data_free") ||
123 !GetFunctionPointer(lib
, &exif_data_get_byte_order_func_
,
124 "exif_data_get_byte_order") ||
125 !GetFunctionPointer(lib
, &exif_get_short_func_
, "exif_get_short") ||
126 !GetFunctionPointer(lib
, &exif_get_long_func_
, "exif_get_long") ||
127 !GetFunctionPointer(lib
, &exif_get_rational_func_
,
128 "exif_get_rational") ||
129 !GetFunctionPointer(lib
, &exif_entry_get_value_func_
,
130 "exif_entry_get_value") ||
131 !GetFunctionPointer(lib
, &exif_content_get_entry_func_
,
132 "exif_content_get_entry")) {
136 exif_lib_
.Reset(lib
.Release());
140 ExifData
* ParseExifFromBuffer(unsigned char* buffer
, unsigned int size
) {
141 DCHECK(exif_lib_
.is_valid());
142 ExifLoader
* loader
= exif_loader_new_func_();
143 exif_loader_write_func_(loader
, buffer
, size
);
145 ExifData
* data
= exif_loader_get_data_func_(loader
);
147 exif_loader_unref_func_(loader
);
153 void ExifDataFree(ExifData
* data
) {
154 DCHECK(exif_lib_
.is_valid());
155 return exif_data_free_func_(data
);
158 void ExtractInt(ExifData
* data
, ExifTag tag
, int* result
) {
159 DCHECK(exif_lib_
.is_valid());
162 ExifEntry
* entry
= ExifContentGetEntry(data
, tag
);
166 ExifByteOrder order
= exif_data_get_byte_order_func_(data
);
167 switch (entry
->format
) {
168 case EXIF_FORMAT_SHORT
: {
169 ExifShort v
= exif_get_short_func_(entry
->data
, order
);
170 *result
= base::checked_cast
<int>(v
);
173 case EXIF_FORMAT_LONG
: {
174 ExifLong v
= exif_get_long_func_(entry
->data
, order
);
175 // Ignore values that don't fit in a signed int - likely invalid data.
176 if (base::IsValueInRangeForNumericType
<int>(v
))
177 *result
= base::checked_cast
<int>(v
);
181 // Ignore all other entry formats.
186 void ExtractDouble(ExifData
* data
, ExifTag tag
, double* result
) {
187 DCHECK(exif_lib_
.is_valid());
190 ExifEntry
* entry
= ExifContentGetEntry(data
, tag
);
194 ExifByteOrder order
= exif_data_get_byte_order_func_(data
);
196 if (entry
->format
== EXIF_FORMAT_RATIONAL
) {
197 ExifRational v
= exif_get_rational_func_(entry
->data
, order
);
198 *result
= base::checked_cast
<double>(v
.numerator
) /
199 base::checked_cast
<double>(v
.denominator
);
203 void ExtractString(ExifData
* data
, ExifTag tag
, std::string
* result
) {
204 DCHECK(exif_lib_
.is_valid());
207 ExifEntry
* entry
= ExifContentGetEntry(data
, tag
);
212 exif_entry_get_value_func_(entry
, buf
, sizeof(buf
));
217 // Exported by libexif.
218 typedef unsigned char (*ExifLoaderWriteFunc
)(
219 ExifLoader
*eld
, unsigned char *buf
, unsigned int len
);
220 typedef ExifLoader
* (*ExifLoaderNewFunc
)();
221 typedef void (*ExifLoaderUnrefFunc
)(ExifLoader
* loader
);
222 typedef ExifData
* (*ExifLoaderGetDataFunc
)(ExifLoader
* loader
);
223 typedef void (*ExifDataFreeFunc
)(ExifData
* data
);
224 typedef ExifByteOrder (*ExifDataGetByteOrderFunc
)(ExifData
* data
);
225 typedef ExifShort (*ExifGetShortFunc
)(const unsigned char *buf
,
226 ExifByteOrder order
);
227 typedef ExifLong (*ExifGetLongFunc
)(const unsigned char *buf
,
228 ExifByteOrder order
);
229 typedef ExifRational (*ExifGetRationalFunc
)(const unsigned char *buf
,
230 ExifByteOrder order
);
231 typedef const char* (*ExifEntryGetValueFunc
)(ExifEntry
*e
, char *val
,
232 unsigned int maxlen
);
233 typedef ExifEntry
* (*ExifContentGetEntryFunc
)(ExifContent
* content
,
236 template<typename FunctionType
>
237 bool GetFunctionPointer(const base::ScopedNativeLibrary
& lib
,
238 FunctionType
* function
, const char* name
) {
239 DCHECK(lib
.is_valid());
241 DCHECK(!(*function
));
242 *function
= reinterpret_cast<FunctionType
>(
243 lib
.GetFunctionPointer(name
));
244 DLOG_IF(WARNING
, !(*function
)) << "Missing " << name
;
245 return *function
!= NULL
;
248 // Redefines exif_content_get_entry macro in terms of function pointer.
249 ExifEntry
* ExifContentGetEntry(ExifData
* data
, ExifTag tag
) {
250 DCHECK(exif_lib_
.is_valid());
251 const ExifIfd ifds
[] =
252 { EXIF_IFD_0
, EXIF_IFD_1
, EXIF_IFD_EXIF
, EXIF_IFD_GPS
};
254 for (size_t i
= 0; i
< arraysize(ifds
); ++i
) {
255 ExifEntry
* entry
= exif_content_get_entry_func_(data
->ifd
[ifds
[i
]], tag
);
263 ExifLoaderWriteFunc exif_loader_write_func_
;
264 ExifLoaderNewFunc exif_loader_new_func_
;
265 ExifLoaderUnrefFunc exif_loader_unref_func_
;
266 ExifLoaderGetDataFunc exif_loader_get_data_func_
;
267 ExifDataFreeFunc exif_data_free_func_
;
268 ExifDataGetByteOrderFunc exif_data_get_byte_order_func_
;
269 ExifGetShortFunc exif_get_short_func_
;
270 ExifGetLongFunc exif_get_long_func_
;
271 ExifGetRationalFunc exif_get_rational_func_
;
272 ExifEntryGetValueFunc exif_entry_get_value_func_
;
273 ExifContentGetEntryFunc exif_content_get_entry_func_
;
275 base::ScopedNativeLibrary exif_lib_
;
276 DISALLOW_COPY_AND_ASSIGN(ExifFunctions
);
279 static base::LazyInstance
<ExifFunctions
> g_exif_lib
= LAZY_INSTANCE_INITIALIZER
;
284 bool ImageMetadataExtractor::InitializeLibrary() {
285 base::FilePath media_path
;
286 if (!PathService::Get(content::DIR_MEDIA_LIBS
, &media_path
))
288 return g_exif_lib
.Get().Initialize(media_path
);
292 bool ImageMetadataExtractor::InitializeLibraryForTesting() {
293 base::FilePath module_dir
;
294 if (!PathService::Get(base::DIR_EXE
, &module_dir
))
296 return g_exif_lib
.Get().Initialize(module_dir
);
299 ImageMetadataExtractor::ImageMetadataExtractor()
306 exposure_time_sec_(-1),
309 focal_length_mm_(-1),
310 iso_equivalent_(-1) {
313 ImageMetadataExtractor::~ImageMetadataExtractor() {
316 void ImageMetadataExtractor::Extract(media::DataSource
* source
,
317 const DoneCallback
& callback
) {
320 GetImageBytes(source
, base::Bind(&ImageMetadataExtractor::FinishExtraction
,
321 base::Unretained(this), callback
));
325 int ImageMetadataExtractor::width() const {
330 int ImageMetadataExtractor::height() const {
335 int ImageMetadataExtractor::rotation() const {
340 double ImageMetadataExtractor::x_resolution() const {
342 return x_resolution_
;
345 double ImageMetadataExtractor::y_resolution() const {
347 return y_resolution_
;
350 const std::string
& ImageMetadataExtractor::date() const {
355 const std::string
& ImageMetadataExtractor::camera_make() const {
360 const std::string
& ImageMetadataExtractor::camera_model() const {
362 return camera_model_
;
365 double ImageMetadataExtractor::exposure_time_sec() const {
367 return exposure_time_sec_
;
370 bool ImageMetadataExtractor::flash_fired() const {
375 double ImageMetadataExtractor::f_number() const {
380 double ImageMetadataExtractor::focal_length_mm() const {
382 return focal_length_mm_
;
385 int ImageMetadataExtractor::iso_equivalent() const {
387 return iso_equivalent_
;
390 void ImageMetadataExtractor::FinishExtraction(
391 const DoneCallback
& callback
,
392 const scoped_refptr
<net::DrainableIOBuffer
>& buffer
) {
398 ExifData
* data
= g_exif_lib
.Get().ParseExifFromBuffer(
399 reinterpret_cast<unsigned char*>(buffer
->data()),
400 buffer
->BytesRemaining());
407 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_IMAGE_WIDTH
, &width_
);
408 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_IMAGE_LENGTH
, &height_
);
410 // We ignore the mirrored-aspect of the mirrored-orientations and just
411 // indicate the rotation. Mirrored-orientations are very rare.
413 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_ORIENTATION
, &orientation
);
414 switch (orientation
) {
433 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_X_RESOLUTION
, &x_resolution_
);
434 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_Y_RESOLUTION
, &y_resolution_
);
436 g_exif_lib
.Get().ExtractString(data
, EXIF_TAG_DATE_TIME
, &date_
);
438 g_exif_lib
.Get().ExtractString(data
, EXIF_TAG_MAKE
, &camera_make_
);
439 g_exif_lib
.Get().ExtractString(data
, EXIF_TAG_MODEL
, &camera_model_
);
440 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_EXPOSURE_TIME
,
441 &exposure_time_sec_
);
443 int flash_value
= -1;
444 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_FLASH
, &flash_value
);
445 if (flash_value
>= 0) {
446 flash_fired_
= (flash_value
& 0x1) != 0;
449 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_FNUMBER
, &f_number_
);
450 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_FOCAL_LENGTH
,
452 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_ISO_SPEED_RATINGS
,
455 g_exif_lib
.Get().ExifDataFree(data
);
462 } // namespace metadata