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 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 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: 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 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 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 148 void ExifDataFree(ExifData* data) { 149 DCHECK(exif_lib_.is_valid()); 150 return exif_data_free_func_(data); 151 } 152 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 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 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> 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. 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 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 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 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 308 ImageMetadataExtractor::~ImageMetadataExtractor() { 309 } 310 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 320 int ImageMetadataExtractor::width() const { 321 DCHECK(extracted_); 322 return width_; 323 } 324 325 int ImageMetadataExtractor::height() const { 326 DCHECK(extracted_); 327 return height_; 328 } 329 330 int ImageMetadataExtractor::rotation() const { 331 DCHECK(extracted_); 332 return rotation_; 333 } 334 335 double ImageMetadataExtractor::x_resolution() const { 336 DCHECK(extracted_); 337 return x_resolution_; 338 } 339 340 double ImageMetadataExtractor::y_resolution() const { 341 DCHECK(extracted_); 342 return y_resolution_; 343 } 344 345 const std::string& ImageMetadataExtractor::date() const { 346 DCHECK(extracted_); 347 return date_; 348 } 349 350 const std::string& ImageMetadataExtractor::camera_make() const { 351 DCHECK(extracted_); 352 return camera_make_; 353 } 354 355 const std::string& ImageMetadataExtractor::camera_model() const { 356 DCHECK(extracted_); 357 return camera_model_; 358 } 359 360 double ImageMetadataExtractor::exposure_time_sec() const { 361 DCHECK(extracted_); 362 return exposure_time_sec_; 363 } 364 365 bool ImageMetadataExtractor::flash_fired() const { 366 DCHECK(extracted_); 367 return flash_fired_; 368 } 369 370 double ImageMetadataExtractor::f_number() const { 371 DCHECK(extracted_); 372 return f_number_; 373 } 374 375 double ImageMetadataExtractor::focal_length_mm() const { 376 DCHECK(extracted_); 377 return focal_length_mm_; 378 } 379 380 int ImageMetadataExtractor::iso_equivalent() const { 381 DCHECK(extracted_); 382 return iso_equivalent_; 383 } 384 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