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 void FinishGetImageBytes(
32 net::DrainableIOBuffer
* buffer
,
33 media::DataSource
* source
,
34 const base::Callback
<void(net::DrainableIOBuffer
*)>& callback
,
36 if (bytes_read
== media::DataSource::kReadError
) {
41 buffer
->DidConsume(bytes_read
);
42 // Didn't get the whole file. Continue reading to get the rest.
43 if (buffer
->BytesRemaining() > 0) {
44 source
->Read(0, buffer
->BytesRemaining(),
45 reinterpret_cast<uint8
*>(buffer
->data()),
46 base::Bind(&FinishGetImageBytes
, make_scoped_refptr(buffer
),
47 base::Unretained(source
), callback
));
52 callback
.Run(make_scoped_refptr(buffer
));
56 media::DataSource
* source
,
57 const base::Callback
<void(net::DrainableIOBuffer
*)>& callback
) {
59 if (!source
->GetSize(&size64
) ||
60 base::saturated_cast
<size_t>(size64
) > kMaxBufferSize
) {
61 return callback
.Run(NULL
);
63 int size
= base::checked_cast
<int>(size64
);
65 scoped_refptr
<net::DrainableIOBuffer
> buffer(
66 new net::DrainableIOBuffer(new net::IOBuffer(size
), size
));
67 source
->Read(0, buffer
->BytesRemaining(),
68 reinterpret_cast<uint8
*>(buffer
->data()),
69 base::Bind(&FinishGetImageBytes
, buffer
,
70 base::Unretained(source
), callback
));
75 ExifFunctions() : exif_loader_write_func_(NULL
),
76 exif_loader_new_func_(NULL
),
77 exif_loader_unref_func_(NULL
),
78 exif_loader_get_data_func_(NULL
),
79 exif_data_free_func_(NULL
),
80 exif_data_get_byte_order_func_(NULL
),
81 exif_get_short_func_(NULL
),
82 exif_get_long_func_(NULL
),
83 exif_get_rational_func_(NULL
),
84 exif_entry_get_value_func_(NULL
),
85 exif_content_get_entry_func_(NULL
) {
88 bool Initialize(const base::FilePath
& module_dir
) {
89 if (exif_lib_
.is_valid())
93 base::FilePath module_path
= module_dir
.AppendASCII("libexif.dll");
94 #elif defined(OS_MACOSX)
95 base::FilePath module_path
= module_dir
.AppendASCII("exif.so");
96 #elif defined(OS_CHROMEOS)
97 // On ChromeOS, we build and distribute our own version of libexif.
98 base::FilePath module_path
= module_dir
.AppendASCII("libexif.so");
100 // On Linux-like systems, we use the system libexif.
101 base::FilePath module_path
= base::FilePath().AppendASCII("libexif.so.12");
104 base::ScopedNativeLibrary
lib(base::LoadNativeLibrary(module_path
, NULL
));
105 if (!lib
.is_valid()) {
106 LOG(ERROR
) << "Couldn't load libexif.";
110 if (!GetFunctionPointer(lib
, &exif_loader_write_func_
,
111 "exif_loader_write") ||
112 !GetFunctionPointer(lib
, &exif_loader_new_func_
, "exif_loader_new") ||
113 !GetFunctionPointer(lib
, &exif_loader_unref_func_
,
114 "exif_loader_unref") ||
115 !GetFunctionPointer(lib
, &exif_loader_get_data_func_
,
116 "exif_loader_get_data") ||
117 !GetFunctionPointer(lib
, &exif_data_free_func_
, "exif_data_free") ||
118 !GetFunctionPointer(lib
, &exif_data_get_byte_order_func_
,
119 "exif_data_get_byte_order") ||
120 !GetFunctionPointer(lib
, &exif_get_short_func_
, "exif_get_short") ||
121 !GetFunctionPointer(lib
, &exif_get_long_func_
, "exif_get_long") ||
122 !GetFunctionPointer(lib
, &exif_get_rational_func_
,
123 "exif_get_rational") ||
124 !GetFunctionPointer(lib
, &exif_entry_get_value_func_
,
125 "exif_entry_get_value") ||
126 !GetFunctionPointer(lib
, &exif_content_get_entry_func_
,
127 "exif_content_get_entry")) {
131 exif_lib_
.Reset(lib
.Release());
135 ExifData
* ParseExifFromBuffer(unsigned char* buffer
, unsigned int size
) {
136 DCHECK(exif_lib_
.is_valid());
137 ExifLoader
* loader
= exif_loader_new_func_();
138 exif_loader_write_func_(loader
, buffer
, size
);
140 ExifData
* data
= exif_loader_get_data_func_(loader
);
142 exif_loader_unref_func_(loader
);
148 void ExifDataFree(ExifData
* data
) {
149 DCHECK(exif_lib_
.is_valid());
150 return exif_data_free_func_(data
);
153 void ExtractInt(ExifData
* data
, ExifTag tag
, int* result
) {
154 DCHECK(exif_lib_
.is_valid());
157 ExifEntry
* entry
= ExifContentGetEntry(data
, tag
);
161 ExifByteOrder order
= exif_data_get_byte_order_func_(data
);
162 switch (entry
->format
) {
163 case EXIF_FORMAT_SHORT
: {
164 ExifShort v
= exif_get_short_func_(entry
->data
, order
);
165 *result
= base::checked_cast
<int>(v
);
168 case EXIF_FORMAT_LONG
: {
169 ExifLong v
= exif_get_long_func_(entry
->data
, order
);
170 // Ignore values that don't fit in a signed int - likely invalid data.
171 if (base::IsValueInRangeForNumericType
<int>(v
))
172 *result
= base::checked_cast
<int>(v
);
176 // Ignore all other entry formats.
181 void ExtractDouble(ExifData
* data
, ExifTag tag
, double* result
) {
182 DCHECK(exif_lib_
.is_valid());
185 ExifEntry
* entry
= ExifContentGetEntry(data
, tag
);
189 ExifByteOrder order
= exif_data_get_byte_order_func_(data
);
191 if (entry
->format
== EXIF_FORMAT_RATIONAL
) {
192 ExifRational v
= exif_get_rational_func_(entry
->data
, order
);
193 *result
= base::checked_cast
<double>(v
.numerator
) /
194 base::checked_cast
<double>(v
.denominator
);
198 void ExtractString(ExifData
* data
, ExifTag tag
, std::string
* result
) {
199 DCHECK(exif_lib_
.is_valid());
202 ExifEntry
* entry
= ExifContentGetEntry(data
, tag
);
207 exif_entry_get_value_func_(entry
, buf
, sizeof(buf
));
212 // Exported by libexif.
213 typedef unsigned char (*ExifLoaderWriteFunc
)(
214 ExifLoader
*eld
, unsigned char *buf
, unsigned int len
);
215 typedef ExifLoader
* (*ExifLoaderNewFunc
)();
216 typedef void (*ExifLoaderUnrefFunc
)(ExifLoader
* loader
);
217 typedef ExifData
* (*ExifLoaderGetDataFunc
)(ExifLoader
* loader
);
218 typedef void (*ExifDataFreeFunc
)(ExifData
* data
);
219 typedef ExifByteOrder (*ExifDataGetByteOrderFunc
)(ExifData
* data
);
220 typedef ExifShort (*ExifGetShortFunc
)(const unsigned char *buf
,
221 ExifByteOrder order
);
222 typedef ExifLong (*ExifGetLongFunc
)(const unsigned char *buf
,
223 ExifByteOrder order
);
224 typedef ExifRational (*ExifGetRationalFunc
)(const unsigned char *buf
,
225 ExifByteOrder order
);
226 typedef const char* (*ExifEntryGetValueFunc
)(ExifEntry
*e
, char *val
,
227 unsigned int maxlen
);
228 typedef ExifEntry
* (*ExifContentGetEntryFunc
)(ExifContent
* content
,
231 template<typename FunctionType
>
232 bool GetFunctionPointer(const base::ScopedNativeLibrary
& lib
,
233 FunctionType
* function
, const char* name
) {
234 DCHECK(lib
.is_valid());
236 DCHECK(!(*function
));
237 *function
= reinterpret_cast<FunctionType
>(
238 lib
.GetFunctionPointer(name
));
239 DLOG_IF(WARNING
, !(*function
)) << "Missing " << name
;
240 return *function
!= NULL
;
243 // Redefines exif_content_get_entry macro in terms of function pointer.
244 ExifEntry
* ExifContentGetEntry(ExifData
* data
, ExifTag tag
) {
245 DCHECK(exif_lib_
.is_valid());
246 const ExifIfd ifds
[] =
247 { EXIF_IFD_0
, EXIF_IFD_1
, EXIF_IFD_EXIF
, EXIF_IFD_GPS
};
249 for (size_t i
= 0; i
< arraysize(ifds
); ++i
) {
250 ExifEntry
* entry
= exif_content_get_entry_func_(data
->ifd
[ifds
[i
]], tag
);
258 ExifLoaderWriteFunc exif_loader_write_func_
;
259 ExifLoaderNewFunc exif_loader_new_func_
;
260 ExifLoaderUnrefFunc exif_loader_unref_func_
;
261 ExifLoaderGetDataFunc exif_loader_get_data_func_
;
262 ExifDataFreeFunc exif_data_free_func_
;
263 ExifDataGetByteOrderFunc exif_data_get_byte_order_func_
;
264 ExifGetShortFunc exif_get_short_func_
;
265 ExifGetLongFunc exif_get_long_func_
;
266 ExifGetRationalFunc exif_get_rational_func_
;
267 ExifEntryGetValueFunc exif_entry_get_value_func_
;
268 ExifContentGetEntryFunc exif_content_get_entry_func_
;
270 base::ScopedNativeLibrary exif_lib_
;
271 DISALLOW_COPY_AND_ASSIGN(ExifFunctions
);
274 static base::LazyInstance
<ExifFunctions
> g_exif_lib
= LAZY_INSTANCE_INITIALIZER
;
279 bool ImageMetadataExtractor::InitializeLibrary() {
280 base::FilePath media_path
;
281 if (!PathService::Get(content::DIR_MEDIA_LIBS
, &media_path
))
283 return g_exif_lib
.Get().Initialize(media_path
);
287 bool ImageMetadataExtractor::InitializeLibraryForTesting() {
288 base::FilePath module_dir
;
289 if (!PathService::Get(base::DIR_EXE
, &module_dir
))
291 return g_exif_lib
.Get().Initialize(module_dir
);
294 ImageMetadataExtractor::ImageMetadataExtractor()
301 exposure_time_sec_(-1),
304 focal_length_mm_(-1),
305 iso_equivalent_(-1) {
308 ImageMetadataExtractor::~ImageMetadataExtractor() {
311 void ImageMetadataExtractor::Extract(media::DataSource
* source
,
312 const DoneCallback
& callback
) {
315 GetImageBytes(source
, base::Bind(&ImageMetadataExtractor::FinishExtraction
,
316 base::Unretained(this), callback
));
320 int ImageMetadataExtractor::width() const {
325 int ImageMetadataExtractor::height() const {
330 int ImageMetadataExtractor::rotation() const {
335 double ImageMetadataExtractor::x_resolution() const {
337 return x_resolution_
;
340 double ImageMetadataExtractor::y_resolution() const {
342 return y_resolution_
;
345 const std::string
& ImageMetadataExtractor::date() const {
350 const std::string
& ImageMetadataExtractor::camera_make() const {
355 const std::string
& ImageMetadataExtractor::camera_model() const {
357 return camera_model_
;
360 double ImageMetadataExtractor::exposure_time_sec() const {
362 return exposure_time_sec_
;
365 bool ImageMetadataExtractor::flash_fired() const {
370 double ImageMetadataExtractor::f_number() const {
375 double ImageMetadataExtractor::focal_length_mm() const {
377 return focal_length_mm_
;
380 int ImageMetadataExtractor::iso_equivalent() const {
382 return iso_equivalent_
;
385 void ImageMetadataExtractor::FinishExtraction(
386 const DoneCallback
& callback
, net::DrainableIOBuffer
* buffer
) {
392 ExifData
* data
= g_exif_lib
.Get().ParseExifFromBuffer(
393 reinterpret_cast<unsigned char*>(buffer
->data()),
394 buffer
->BytesRemaining());
401 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_IMAGE_WIDTH
, &width_
);
402 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_IMAGE_LENGTH
, &height_
);
404 // We ignore the mirrored-aspect of the mirrored-orientations and just
405 // indicate the rotation. Mirrored-orientations are very rare.
407 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_ORIENTATION
, &orientation
);
408 switch (orientation
) {
427 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_X_RESOLUTION
, &x_resolution_
);
428 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_Y_RESOLUTION
, &y_resolution_
);
430 g_exif_lib
.Get().ExtractString(data
, EXIF_TAG_DATE_TIME
, &date_
);
432 g_exif_lib
.Get().ExtractString(data
, EXIF_TAG_MAKE
, &camera_make_
);
433 g_exif_lib
.Get().ExtractString(data
, EXIF_TAG_MODEL
, &camera_model_
);
434 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_EXPOSURE_TIME
,
435 &exposure_time_sec_
);
437 int flash_value
= -1;
438 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_FLASH
, &flash_value
);
439 if (flash_value
>= 0) {
440 flash_fired_
= (flash_value
& 0x1) != 0;
443 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_FNUMBER
, &f_number_
);
444 g_exif_lib
.Get().ExtractDouble(data
, EXIF_TAG_FOCAL_LENGTH
,
446 g_exif_lib
.Get().ExtractInt(data
, EXIF_TAG_ISO_SPEED_RATINGS
,
449 g_exif_lib
.Get().ExifDataFree(data
);
456 } // namespace metadata