1 /* 2 * Copyright 2017 The Chromium OS Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 */ 6 7 #include "arc/exif_utils.h" 8 9 #include <cstdlib> 10 #include <ctime> 11 12 #include <libyuv.h> 13 14 #include "arc/common.h" 15 16 namespace std { 17 18 template <> 19 struct default_delete<ExifEntry> { 20 inline void operator()(ExifEntry* entry) const { exif_entry_unref(entry); } 21 }; 22 23 } // namespace std 24 25 namespace arc { 26 27 // This comes from the Exif Version 2.3 standard table 9. 28 const uint8_t gExifAsciiPrefix[] = {0x41, 0x53, 0x43, 0x49, 29 0x49, 0x0, 0x0, 0x0}; 30 31 static void SetLatitudeOrLongitudeData(unsigned char* data, double num) { 32 // Take the integer part of |num|. 33 ExifLong degrees = static_cast<ExifLong>(num); 34 ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees)); 35 ExifLong microseconds = 36 static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0)); 37 exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1}); 38 exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, 39 {minutes, 1}); 40 exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, 41 {microseconds, 1000000}); 42 } 43 44 ExifUtils::ExifUtils() 45 : yu12_buffer_(nullptr), 46 yu12_width_(0), 47 yu12_height_(0), 48 thumbnail_width_(0), 49 thumbnail_height_(0), 50 exif_data_(nullptr), 51 app1_buffer_(nullptr), 52 app1_length_(0) {} 53 54 ExifUtils::~ExifUtils() { Reset(); } 55 56 bool ExifUtils::Initialize(const uint8_t* buffer, uint16_t width, 57 uint16_t height, int quality) { 58 Reset(); 59 60 if (width % 2 != 0 || height % 2 != 0) { 61 LOGF(ERROR) << "invalid image size " << width << "x" << height; 62 return false; 63 } 64 if (quality < 1 || quality > 100) { 65 LOGF(ERROR) << "invalid jpeg quality " << quality; 66 return false; 67 } 68 thumbnail_jpeg_quality_ = quality; 69 yu12_buffer_ = buffer; 70 yu12_width_ = width; 71 yu12_height_ = height; 72 73 exif_data_ = exif_data_new(); 74 if (exif_data_ == nullptr) { 75 LOGF(ERROR) << "allocate memory for exif_data_ failed"; 76 return false; 77 } 78 // Set the image options. 79 exif_data_set_option(exif_data_, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); 80 exif_data_set_data_type(exif_data_, EXIF_DATA_TYPE_COMPRESSED); 81 exif_data_set_byte_order(exif_data_, EXIF_BYTE_ORDER_INTEL); 82 83 // Set image width and length. 84 SetImageWidth(width); 85 SetImageLength(height); 86 87 return true; 88 } 89 90 bool ExifUtils::SetMaker(const std::string& maker) { 91 size_t entrySize = maker.length() + 1; 92 std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 93 EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, entrySize, entrySize); 94 if (!entry) { 95 LOGF(ERROR) << "Adding Make exif entry failed"; 96 return false; 97 } 98 memcpy(entry->data, maker.c_str(), entrySize); 99 return true; 100 } 101 102 bool ExifUtils::SetModel(const std::string& model) { 103 size_t entrySize = model.length() + 1; 104 std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 105 EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, entrySize, entrySize); 106 if (!entry) { 107 LOGF(ERROR) << "Adding Model exif entry failed"; 108 return false; 109 } 110 memcpy(entry->data, model.c_str(), entrySize); 111 return true; 112 } 113 114 bool ExifUtils::SetDateTime(const struct tm& t) { 115 // The length is 20 bytes including NULL for termination in Exif standard. 116 char str[20]; 117 int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i", 118 t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, 119 t.tm_min, t.tm_sec); 120 if (result != sizeof(str) - 1) { 121 LOGF(WARNING) << "Input time is invalid"; 122 return false; 123 } 124 std::unique_ptr<ExifEntry> entry = 125 AddVariableLengthEntry(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, 126 sizeof(str), sizeof(str)); 127 if (!entry) { 128 LOGF(ERROR) << "Adding DateTime exif entry failed"; 129 return false; 130 } 131 memcpy(entry->data, str, sizeof(str)); 132 return true; 133 } 134 135 bool ExifUtils::SetFocalLength(uint32_t numerator, uint32_t denominator) { 136 std::unique_ptr<ExifEntry> entry = 137 AddEntry(EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH); 138 if (!entry) { 139 LOGF(ERROR) << "Adding FocalLength exif entry failed"; 140 return false; 141 } 142 exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, 143 {numerator, denominator}); 144 return true; 145 } 146 147 bool ExifUtils::SetGpsLatitude(double latitude) { 148 const ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF); 149 std::unique_ptr<ExifEntry> refEntry = 150 AddVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2); 151 if (!refEntry) { 152 LOGF(ERROR) << "Adding GPSLatitudeRef exif entry failed"; 153 return false; 154 } 155 if (latitude >= 0) { 156 memcpy(refEntry->data, "N", sizeof("N")); 157 } else { 158 memcpy(refEntry->data, "S", sizeof("S")); 159 latitude *= -1; 160 } 161 162 const ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE); 163 std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 164 EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational)); 165 if (!entry) { 166 exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get()); 167 LOGF(ERROR) << "Adding GPSLatitude exif entry failed"; 168 return false; 169 } 170 SetLatitudeOrLongitudeData(entry->data, latitude); 171 172 return true; 173 } 174 175 bool ExifUtils::SetGpsLongitude(double longitude) { 176 ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF); 177 std::unique_ptr<ExifEntry> refEntry = 178 AddVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2); 179 if (!refEntry) { 180 LOGF(ERROR) << "Adding GPSLongitudeRef exif entry failed"; 181 return false; 182 } 183 if (longitude >= 0) { 184 memcpy(refEntry->data, "E", sizeof("E")); 185 } else { 186 memcpy(refEntry->data, "W", sizeof("W")); 187 longitude *= -1; 188 } 189 190 ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE); 191 std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 192 EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational)); 193 if (!entry) { 194 exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get()); 195 LOGF(ERROR) << "Adding GPSLongitude exif entry failed"; 196 return false; 197 } 198 SetLatitudeOrLongitudeData(entry->data, longitude); 199 200 return true; 201 } 202 203 bool ExifUtils::SetGpsAltitude(double altitude) { 204 ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF); 205 std::unique_ptr<ExifEntry> refEntry = 206 AddVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_BYTE, 1, 1); 207 if (!refEntry) { 208 LOGF(ERROR) << "Adding GPSAltitudeRef exif entry failed"; 209 return false; 210 } 211 if (altitude >= 0) { 212 *refEntry->data = 0; 213 } else { 214 *refEntry->data = 1; 215 altitude *= -1; 216 } 217 218 ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE); 219 std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 220 EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 1, sizeof(ExifRational)); 221 if (!entry) { 222 exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get()); 223 LOGF(ERROR) << "Adding GPSAltitude exif entry failed"; 224 return false; 225 } 226 exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, 227 {static_cast<ExifLong>(altitude * 1000), 1000}); 228 229 return true; 230 } 231 232 bool ExifUtils::SetGpsTimestamp(const struct tm& t) { 233 const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP); 234 const size_t kGpsDateStampSize = 11; 235 std::unique_ptr<ExifEntry> entry = 236 AddVariableLengthEntry(EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII, 237 kGpsDateStampSize, kGpsDateStampSize); 238 if (!entry) { 239 LOGF(ERROR) << "Adding GPSDateStamp exif entry failed"; 240 return false; 241 } 242 int result = 243 snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize, 244 "%04i:%02i:%02i", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday); 245 if (result != kGpsDateStampSize - 1) { 246 LOGF(WARNING) << "Input time is invalid"; 247 return false; 248 } 249 250 const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP); 251 entry = AddVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3, 252 3 * sizeof(ExifRational)); 253 if (!entry) { 254 LOGF(ERROR) << "Adding GPSTimeStamp exif entry failed"; 255 return false; 256 } 257 exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, 258 {static_cast<ExifLong>(t.tm_hour), 1}); 259 exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, 260 {static_cast<ExifLong>(t.tm_min), 1}); 261 exif_set_rational(entry->data + 2 * sizeof(ExifRational), 262 EXIF_BYTE_ORDER_INTEL, 263 {static_cast<ExifLong>(t.tm_sec), 1}); 264 265 return true; 266 } 267 268 bool ExifUtils::SetGpsProcessingMethod(const std::string& method) { 269 ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD); 270 size_t size = sizeof(gExifAsciiPrefix) + method.length(); 271 std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 272 EXIF_IFD_GPS, tag, EXIF_FORMAT_UNDEFINED, size, size); 273 if (!entry) { 274 LOGF(ERROR) << "Adding GPSProcessingMethod exif entry failed"; 275 return false; 276 } 277 memcpy(entry->data, gExifAsciiPrefix, sizeof(gExifAsciiPrefix)); 278 // Since the exif format is undefined, NULL termination is not necessary. 279 memcpy(entry->data + sizeof(gExifAsciiPrefix), method.c_str(), 280 method.length()); 281 282 return true; 283 } 284 285 bool ExifUtils::SetThumbnailSize(uint16_t width, uint16_t height) { 286 if (width % 2 != 0 || height % 2 != 0) { 287 LOGF(ERROR) << "Invalid thumbnail size " << width << "x" << height; 288 return false; 289 } 290 thumbnail_width_ = width; 291 thumbnail_height_ = height; 292 return true; 293 } 294 295 bool ExifUtils::SetOrientation(uint16_t orientation) { 296 std::unique_ptr<ExifEntry> entry = AddEntry(EXIF_IFD_0, EXIF_TAG_ORIENTATION); 297 if (!entry) { 298 LOGF(ERROR) << "Adding Orientation exif entry failed"; 299 return false; 300 } 301 /* 302 * Orientation value: 303 * 1 2 3 4 5 6 7 8 304 * 305 * 888888 888888 88 88 8888888888 88 88 8888888888 306 * 88 88 88 88 88 88 88 88 88 88 88 88 307 * 8888 8888 8888 8888 88 8888888888 8888888888 88 308 * 88 88 88 88 309 * 88 88 888888 888888 310 */ 311 int value = 1; 312 switch (orientation) { 313 case 90: 314 value = 6; 315 break; 316 case 180: 317 value = 3; 318 break; 319 case 270: 320 value = 8; 321 break; 322 default: 323 break; 324 } 325 exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, value); 326 return true; 327 } 328 329 bool ExifUtils::GenerateApp1() { 330 DestroyApp1(); 331 if (thumbnail_width_ > 0 && thumbnail_height_ > 0) { 332 if (!GenerateThumbnail()) { 333 LOGF(ERROR) << "Generate thumbnail image failed"; 334 return false; 335 } 336 exif_data_->data = const_cast<uint8_t*>( 337 static_cast<const uint8_t*>(compressor_.GetCompressedImagePtr())); 338 exif_data_->size = compressor_.GetCompressedImageSize(); 339 } 340 // Save the result into |app1_buffer_|. 341 exif_data_save_data(exif_data_, &app1_buffer_, &app1_length_); 342 if (!app1_length_) { 343 LOGF(ERROR) << "Allocate memory for app1_buffer_ failed"; 344 return false; 345 } 346 /* 347 * The JPEG segment size is 16 bits in spec. The size of APP1 segment should 348 * be smaller than 65533 because there are two bytes for segment size field. 349 */ 350 if (app1_length_ > 65533) { 351 DestroyApp1(); 352 LOGF(ERROR) << "The size of APP1 segment is too large"; 353 return false; 354 } 355 return true; 356 } 357 358 const uint8_t* ExifUtils::GetApp1Buffer() { return app1_buffer_; } 359 360 unsigned int ExifUtils::GetApp1Length() { return app1_length_; } 361 362 void ExifUtils::Reset() { 363 yu12_buffer_ = nullptr; 364 yu12_width_ = 0; 365 yu12_height_ = 0; 366 thumbnail_width_ = 0; 367 thumbnail_height_ = 0; 368 DestroyApp1(); 369 if (exif_data_) { 370 /* 371 * Since we decided to ignore the original APP1, we are sure that there is 372 * no thumbnail allocated by libexif. |exif_data_->data| is actually 373 * allocated by JpegCompressor. Sets |exif_data_->data| to nullptr to 374 * prevent exif_data_unref() destroy it incorrectly. 375 */ 376 exif_data_->data = nullptr; 377 exif_data_->size = 0; 378 exif_data_unref(exif_data_); 379 exif_data_ = nullptr; 380 } 381 } 382 383 std::unique_ptr<ExifEntry> ExifUtils::AddVariableLengthEntry( 384 ExifIfd ifd, ExifTag tag, ExifFormat format, uint64_t components, 385 unsigned int size) { 386 // Remove old entry if exists. 387 exif_content_remove_entry(exif_data_->ifd[ifd], 388 exif_content_get_entry(exif_data_->ifd[ifd], tag)); 389 ExifMem* mem = exif_mem_new_default(); 390 if (!mem) { 391 LOGF(ERROR) << "Allocate memory for exif entry failed"; 392 return nullptr; 393 } 394 std::unique_ptr<ExifEntry> entry(exif_entry_new_mem(mem)); 395 if (!entry) { 396 LOGF(ERROR) << "Allocate memory for exif entry failed"; 397 exif_mem_unref(mem); 398 return nullptr; 399 } 400 void* tmpBuffer = exif_mem_alloc(mem, size); 401 if (!tmpBuffer) { 402 LOGF(ERROR) << "Allocate memory for exif entry failed"; 403 exif_mem_unref(mem); 404 return nullptr; 405 } 406 407 entry->data = static_cast<unsigned char*>(tmpBuffer); 408 entry->tag = tag; 409 entry->format = format; 410 entry->components = components; 411 entry->size = size; 412 413 exif_content_add_entry(exif_data_->ifd[ifd], entry.get()); 414 exif_mem_unref(mem); 415 416 return entry; 417 } 418 419 std::unique_ptr<ExifEntry> ExifUtils::AddEntry(ExifIfd ifd, ExifTag tag) { 420 std::unique_ptr<ExifEntry> entry( 421 exif_content_get_entry(exif_data_->ifd[ifd], tag)); 422 if (entry) { 423 // exif_content_get_entry() won't ref the entry, so we ref here. 424 exif_entry_ref(entry.get()); 425 return entry; 426 } 427 entry.reset(exif_entry_new()); 428 if (!entry) { 429 LOGF(ERROR) << "Allocate memory for exif entry failed"; 430 return nullptr; 431 } 432 entry->tag = tag; 433 exif_content_add_entry(exif_data_->ifd[ifd], entry.get()); 434 exif_entry_initialize(entry.get(), tag); 435 return entry; 436 } 437 438 bool ExifUtils::SetImageWidth(uint16_t width) { 439 std::unique_ptr<ExifEntry> entry = AddEntry(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH); 440 if (!entry) { 441 LOGF(ERROR) << "Adding ImageWidth exif entry failed"; 442 return false; 443 } 444 exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, width); 445 return true; 446 } 447 448 bool ExifUtils::SetImageLength(uint16_t length) { 449 std::unique_ptr<ExifEntry> entry = 450 AddEntry(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH); 451 if (!entry) { 452 LOGF(ERROR) << "Adding ImageLength exif entry failed"; 453 return false; 454 } 455 exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, length); 456 return true; 457 } 458 459 bool ExifUtils::GenerateThumbnail() { 460 // Resize yuv image to |thumbnail_width_| x |thumbnail_height_|. 461 std::vector<uint8_t> scaled_buffer; 462 if (!GenerateYuvThumbnail(&scaled_buffer)) { 463 LOGF(ERROR) << "Generate YUV thumbnail failed"; 464 return false; 465 } 466 467 // Compress thumbnail to JPEG. 468 if (!compressor_.CompressImage(scaled_buffer.data(), thumbnail_width_, 469 thumbnail_height_, thumbnail_jpeg_quality_, 470 NULL, 0)) { 471 LOGF(ERROR) << "Compress thumbnail failed"; 472 return false; 473 } 474 return true; 475 } 476 477 bool ExifUtils::GenerateYuvThumbnail(std::vector<uint8_t>* scaled_buffer) { 478 size_t y_plane_size = yu12_width_ * yu12_height_; 479 const uint8* y_plane = yu12_buffer_; 480 const uint8* u_plane = y_plane + y_plane_size; 481 const uint8* v_plane = u_plane + y_plane_size / 4; 482 483 size_t scaled_y_plane_size = thumbnail_width_ * thumbnail_height_; 484 scaled_buffer->resize(scaled_y_plane_size * 3 / 2); 485 uint8* scaled_y_plane = scaled_buffer->data(); 486 uint8* scaled_u_plane = scaled_y_plane + scaled_y_plane_size; 487 uint8* scaled_v_plane = scaled_u_plane + scaled_y_plane_size / 4; 488 489 int result = libyuv::I420Scale( 490 y_plane, yu12_width_, u_plane, yu12_width_ / 2, v_plane, yu12_width_ / 2, 491 yu12_width_, yu12_height_, scaled_y_plane, thumbnail_width_, 492 scaled_u_plane, thumbnail_width_ / 2, scaled_v_plane, 493 thumbnail_width_ / 2, thumbnail_width_, thumbnail_height_, 494 libyuv::kFilterNone); 495 if (result != 0) { 496 LOGF(ERROR) << "Scale I420 image failed"; 497 return false; 498 } 499 return true; 500 } 501 502 void ExifUtils::DestroyApp1() { 503 /* 504 * Since there is no API to access ExifMem in ExifData->priv, we use free 505 * here, which is the default free function in libexif. See 506 * exif_data_save_data() for detail. 507 */ 508 free(app1_buffer_); 509 app1_buffer_ = nullptr; 510 app1_length_ = 0; 511 } 512 513 } // namespace arc 514