• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/utility/media_galleries/image_metadata_extractor.h"
6 
7 #include "base/bind.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"
19 
20 extern "C" {
21 #include <libexif/exif-data.h>
22 #include <libexif/exif-loader.h>
23 }  // extern "C"
24 
25 namespace metadata {
26 
27 namespace {
28 
29 const size_t kMaxBufferSize = 50 * 1024 * 1024;  // Arbitrary maximum of 50MB.
30 
FinishGetImageBytes(net::DrainableIOBuffer * buffer,media::DataSource * source,const base::Callback<void (net::DrainableIOBuffer *)> & callback,int bytes_read)31 void FinishGetImageBytes(
32     net::DrainableIOBuffer* buffer,
33     media::DataSource* source,
34     const base::Callback<void(net::DrainableIOBuffer*)>& callback,
35     int bytes_read) {
36   if (bytes_read == media::DataSource::kReadError) {
37     callback.Run(NULL);
38     return;
39   }
40 
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));
48     return;
49   }
50 
51   buffer->SetOffset(0);
52   callback.Run(make_scoped_refptr(buffer));
53 }
54 
GetImageBytes(media::DataSource * source,const base::Callback<void (net::DrainableIOBuffer *)> & callback)55 void GetImageBytes(
56     media::DataSource* source,
57     const base::Callback<void(net::DrainableIOBuffer*)>& callback) {
58   int64 size64 = 0;
59   if (!source->GetSize(&size64) ||
60       base::saturated_cast<size_t>(size64) > kMaxBufferSize) {
61     return callback.Run(NULL);
62   }
63   int size = base::checked_cast<int>(size64);
64 
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));
71 }
72 
73 class ExifFunctions {
74  public:
ExifFunctions()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) {
86   }
87 
Initialize(const base::FilePath & module_dir)88   bool Initialize(const base::FilePath& module_dir) {
89     if (exif_lib_.is_valid())
90       return true;
91 
92 #if defined(OS_WIN)
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");
99 #else
100     // On Linux-like systems, we use the system libexif.
101     base::FilePath module_path = base::FilePath().AppendASCII("libexif.so.12");
102 #endif
103 
104     base::ScopedNativeLibrary lib(base::LoadNativeLibrary(module_path, NULL));
105     if (!lib.is_valid()) {
106       LOG(ERROR) << "Couldn't load libexif.";
107       return false;
108     }
109 
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")) {
128       return false;
129     }
130 
131     exif_lib_.Reset(lib.Release());
132     return true;
133   }
134 
ParseExifFromBuffer(unsigned char * buffer,unsigned int size)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);
139 
140     ExifData* data = exif_loader_get_data_func_(loader);
141 
142     exif_loader_unref_func_(loader);
143     loader = NULL;
144 
145     return data;
146   }
147 
ExifDataFree(ExifData * data)148   void ExifDataFree(ExifData* data) {
149     DCHECK(exif_lib_.is_valid());
150     return exif_data_free_func_(data);
151   }
152 
ExtractInt(ExifData * data,ExifTag tag,int * result)153   void ExtractInt(ExifData* data, ExifTag tag, int* result) {
154     DCHECK(exif_lib_.is_valid());
155     DCHECK(result);
156 
157     ExifEntry* entry = ExifContentGetEntry(data, tag);
158     if (!entry)
159       return;
160 
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);
166         break;
167       }
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);
173         break;
174       }
175       default: {
176         // Ignore all other entry formats.
177       }
178     }
179   }
180 
ExtractDouble(ExifData * data,ExifTag tag,double * result)181   void ExtractDouble(ExifData* data, ExifTag tag, double* result) {
182     DCHECK(exif_lib_.is_valid());
183     DCHECK(result);
184 
185     ExifEntry* entry = ExifContentGetEntry(data, tag);
186     if (!entry)
187       return;
188 
189     ExifByteOrder order = exif_data_get_byte_order_func_(data);
190 
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);
195     }
196   }
197 
ExtractString(ExifData * data,ExifTag tag,std::string * result)198   void ExtractString(ExifData* data, ExifTag tag, std::string* result) {
199     DCHECK(exif_lib_.is_valid());
200     DCHECK(result);
201 
202     ExifEntry* entry = ExifContentGetEntry(data, tag);
203     if (!entry)
204       return;
205 
206     char buf[1024];
207     exif_entry_get_value_func_(entry, buf, sizeof(buf));
208     *result = buf;
209   }
210 
211  private:
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,
229                                                 ExifTag tag);
230 
231   template<typename FunctionType>
GetFunctionPointer(const base::ScopedNativeLibrary & lib,FunctionType * function,const char * name)232   bool GetFunctionPointer(const base::ScopedNativeLibrary& lib,
233                           FunctionType* function, const char* name) {
234     DCHECK(lib.is_valid());
235     DCHECK(function);
236     DCHECK(!(*function));
237     *function = reinterpret_cast<FunctionType>(
238         lib.GetFunctionPointer(name));
239     DLOG_IF(WARNING, !(*function)) << "Missing " << name;
240     return *function != NULL;
241   }
242 
243   // Redefines exif_content_get_entry macro in terms of function pointer.
ExifContentGetEntry(ExifData * data,ExifTag tag)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 };
248 
249     for (size_t i = 0; i < arraysize(ifds); ++i) {
250       ExifEntry* entry = exif_content_get_entry_func_(data->ifd[ifds[i]], tag);
251       if (entry)
252         return entry;
253     }
254 
255     return NULL;
256   }
257 
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_;
269 
270   base::ScopedNativeLibrary exif_lib_;
271   DISALLOW_COPY_AND_ASSIGN(ExifFunctions);
272 };
273 
274 static base::LazyInstance<ExifFunctions> g_exif_lib = LAZY_INSTANCE_INITIALIZER;
275 
276 }  // namespace
277 
278 // static
InitializeLibrary()279 bool ImageMetadataExtractor::InitializeLibrary() {
280   base::FilePath media_path;
281   if (!PathService::Get(content::DIR_MEDIA_LIBS, &media_path))
282     return false;
283   return g_exif_lib.Get().Initialize(media_path);
284 }
285 
286 // static
InitializeLibraryForTesting()287 bool ImageMetadataExtractor::InitializeLibraryForTesting() {
288   base::FilePath module_dir;
289   if (!PathService::Get(base::DIR_EXE, &module_dir))
290     return false;
291   return g_exif_lib.Get().Initialize(module_dir);
292 }
293 
ImageMetadataExtractor()294 ImageMetadataExtractor::ImageMetadataExtractor()
295     : extracted_(false),
296       width_(-1),
297       height_(-1),
298       rotation_(-1),
299       x_resolution_(-1),
300       y_resolution_(-1),
301       exposure_time_sec_(-1),
302       flash_fired_(false),
303       f_number_(-1),
304       focal_length_mm_(-1),
305       iso_equivalent_(-1) {
306 }
307 
~ImageMetadataExtractor()308 ImageMetadataExtractor::~ImageMetadataExtractor() {
309 }
310 
Extract(media::DataSource * source,const DoneCallback & callback)311 void ImageMetadataExtractor::Extract(media::DataSource* source,
312                                      const DoneCallback& callback) {
313   DCHECK(!extracted_);
314 
315   GetImageBytes(source, base::Bind(&ImageMetadataExtractor::FinishExtraction,
316                                    base::Unretained(this), callback));
317 
318 }
319 
width() const320 int ImageMetadataExtractor::width() const {
321   DCHECK(extracted_);
322   return width_;
323 }
324 
height() const325 int ImageMetadataExtractor::height() const {
326   DCHECK(extracted_);
327   return height_;
328 }
329 
rotation() const330 int ImageMetadataExtractor::rotation() const {
331   DCHECK(extracted_);
332   return rotation_;
333 }
334 
x_resolution() const335 double ImageMetadataExtractor::x_resolution() const {
336   DCHECK(extracted_);
337   return x_resolution_;
338 }
339 
y_resolution() const340 double ImageMetadataExtractor::y_resolution() const {
341   DCHECK(extracted_);
342   return y_resolution_;
343 }
344 
date() const345 const std::string& ImageMetadataExtractor::date() const {
346   DCHECK(extracted_);
347   return date_;
348 }
349 
camera_make() const350 const std::string& ImageMetadataExtractor::camera_make() const {
351   DCHECK(extracted_);
352   return camera_make_;
353 }
354 
camera_model() const355 const std::string& ImageMetadataExtractor::camera_model() const {
356   DCHECK(extracted_);
357   return camera_model_;
358 }
359 
exposure_time_sec() const360 double ImageMetadataExtractor::exposure_time_sec() const {
361   DCHECK(extracted_);
362   return exposure_time_sec_;
363 }
364 
flash_fired() const365 bool ImageMetadataExtractor::flash_fired() const {
366   DCHECK(extracted_);
367   return flash_fired_;
368 }
369 
f_number() const370 double ImageMetadataExtractor::f_number() const {
371   DCHECK(extracted_);
372   return f_number_;
373 }
374 
focal_length_mm() const375 double ImageMetadataExtractor::focal_length_mm() const {
376   DCHECK(extracted_);
377   return focal_length_mm_;
378 }
379 
iso_equivalent() const380 int ImageMetadataExtractor::iso_equivalent() const {
381   DCHECK(extracted_);
382   return iso_equivalent_;
383 }
384 
FinishExtraction(const DoneCallback & callback,net::DrainableIOBuffer * buffer)385 void ImageMetadataExtractor::FinishExtraction(
386     const DoneCallback& callback, net::DrainableIOBuffer* buffer) {
387   if (!buffer) {
388     callback.Run(false);
389     return;
390   }
391 
392   ExifData* data = g_exif_lib.Get().ParseExifFromBuffer(
393       reinterpret_cast<unsigned char*>(buffer->data()),
394       buffer->BytesRemaining());
395 
396   if (!data) {
397     callback.Run(false);
398     return;
399   }
400 
401   g_exif_lib.Get().ExtractInt(data, EXIF_TAG_IMAGE_WIDTH, &width_);
402   g_exif_lib.Get().ExtractInt(data, EXIF_TAG_IMAGE_LENGTH, &height_);
403 
404   // We ignore the mirrored-aspect of the mirrored-orientations and just
405   // indicate the rotation. Mirrored-orientations are very rare.
406   int orientation = 0;
407   g_exif_lib.Get().ExtractInt(data, EXIF_TAG_ORIENTATION, &orientation);
408   switch (orientation) {
409     case 1:
410     case 2:
411       rotation_ = 0;
412       break;
413     case 3:
414     case 4:
415       rotation_ = 180;
416       break;
417     case 5:
418     case 6:
419       rotation_ = 90;
420       break;
421     case 7:
422     case 8:
423       rotation_ = 270;
424       break;
425   }
426 
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_);
429 
430   g_exif_lib.Get().ExtractString(data, EXIF_TAG_DATE_TIME, &date_);
431 
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_);
436 
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;
441   }
442 
443   g_exif_lib.Get().ExtractDouble(data, EXIF_TAG_FNUMBER, &f_number_);
444   g_exif_lib.Get().ExtractDouble(data, EXIF_TAG_FOCAL_LENGTH,
445                                  &focal_length_mm_);
446   g_exif_lib.Get().ExtractInt(data, EXIF_TAG_ISO_SPEED_RATINGS,
447                               &iso_equivalent_);
448 
449   g_exif_lib.Get().ExifDataFree(data);
450 
451   extracted_ = true;
452 
453   callback.Run(true);
454 }
455 
456 }  // namespace metadata
457