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