128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan/* 228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * Copyright 2017 The Chromium OS Authors. All rights reserved. 328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * Use of this source code is governed by a BSD-style license that can be 428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * found in the LICENSE file. 528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan */ 628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan#include "arc/exif_utils.h" 828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan#include <cstdlib> 1028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan#include <ctime> 1128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 1228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan#include <libyuv.h> 1328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 1428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan#include "arc/common.h" 1528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 1628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathannamespace std { 1728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 1828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathantemplate <> 1928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanstruct default_delete<ExifEntry> { 2028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan inline void operator()(ExifEntry* entry) const { exif_entry_unref(entry); } 2128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan}; 2228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 2328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} // namespace std 2428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 2528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathannamespace arc { 2628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 2728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan// This comes from the Exif Version 2.3 standard table 9. 2828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanconst uint8_t gExifAsciiPrefix[] = {0x41, 0x53, 0x43, 0x49, 2928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 0x49, 0x0, 0x0, 0x0}; 3028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 3128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanstatic void SetLatitudeOrLongitudeData(unsigned char* data, double num) { 3228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // Take the integer part of |num|. 3328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifLong degrees = static_cast<ExifLong>(num); 3428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees)); 3528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifLong microseconds = 3628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0)); 3728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1}); 3828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, 3928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan {minutes, 1}); 4028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, 4128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan {microseconds, 1000000}); 4228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 4328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 4428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth SwaminathanExifUtils::ExifUtils() 4528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan : yu12_buffer_(nullptr), 4628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_width_(0), 4728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_height_(0), 4828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_width_(0), 4928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_height_(0), 5028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_(nullptr), 5128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan app1_buffer_(nullptr), 5228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan app1_length_(0) {} 5328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 5428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth SwaminathanExifUtils::~ExifUtils() { Reset(); } 5528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 5628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::Initialize(const uint8_t* buffer, uint16_t width, 5728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan uint16_t height, int quality) { 5828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan Reset(); 5928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 6028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (width % 2 != 0 || height % 2 != 0) { 6128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "invalid image size " << width << "x" << height; 6228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 6328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 6428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (quality < 1 || quality > 100) { 6528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "invalid jpeg quality " << quality; 6628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 6728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 6828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_jpeg_quality_ = quality; 6928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_buffer_ = buffer; 7028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_width_ = width; 7128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_height_ = height; 7228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 7328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_ = exif_data_new(); 7428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (exif_data_ == nullptr) { 7528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "allocate memory for exif_data_ failed"; 7628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 7728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 7828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // Set the image options. 7928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_set_option(exif_data_, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); 8028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_set_data_type(exif_data_, EXIF_DATA_TYPE_COMPRESSED); 8128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_set_byte_order(exif_data_, EXIF_BYTE_ORDER_INTEL); 8228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 8328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // Set image width and length. 8428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan SetImageWidth(width); 8528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan SetImageLength(height); 8628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 8728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 8828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 8928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 9028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetMaker(const std::string& maker) { 9128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan size_t entrySize = maker.length() + 1; 9228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 9328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, entrySize, entrySize); 9428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 9528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding Make exif entry failed"; 9628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 9728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 9828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(entry->data, maker.c_str(), entrySize); 9928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 10028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 10128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 10228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetModel(const std::string& model) { 10328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan size_t entrySize = model.length() + 1; 10428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 10528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, entrySize, entrySize); 10628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 10728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding Model exif entry failed"; 10828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 10928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 11028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(entry->data, model.c_str(), entrySize); 11128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 11228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 11328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 11428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetDateTime(const struct tm& t) { 11528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // The length is 20 bytes including NULL for termination in Exif standard. 11628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan char str[20]; 11728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i", 11828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, 11928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan t.tm_min, t.tm_sec); 12028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (result != sizeof(str) - 1) { 12128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(WARNING) << "Input time is invalid"; 12228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 12328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 12428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = 12528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan AddVariableLengthEntry(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, 12628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan sizeof(str), sizeof(str)); 12728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 12828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding DateTime exif entry failed"; 12928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 13028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 13128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(entry->data, str, sizeof(str)); 13228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 13328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 13428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 13528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetFocalLength(uint32_t numerator, uint32_t denominator) { 13628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = 13728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan AddEntry(EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH); 13828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 13928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding FocalLength exif entry failed"; 14028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 14128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 14228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, 14328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan {numerator, denominator}); 14428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 14528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 14628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 14728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetGpsLatitude(double latitude) { 14828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan const ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF); 14928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> refEntry = 15028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan AddVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2); 15128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!refEntry) { 15228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSLatitudeRef exif entry failed"; 15328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 15428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 15528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (latitude >= 0) { 15628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(refEntry->data, "N", sizeof("N")); 15728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } else { 15828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(refEntry->data, "S", sizeof("S")); 15928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan latitude *= -1; 16028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 16128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 16228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan const ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE); 16328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 16428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational)); 16528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 16628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get()); 16728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSLatitude exif entry failed"; 16828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 16928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 17028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan SetLatitudeOrLongitudeData(entry->data, latitude); 17128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 17228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 17328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 17428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 17528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetGpsLongitude(double longitude) { 17628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF); 17728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> refEntry = 17828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan AddVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2); 17928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!refEntry) { 18028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSLongitudeRef exif entry failed"; 18128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 18228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 18328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (longitude >= 0) { 18428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(refEntry->data, "E", sizeof("E")); 18528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } else { 18628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(refEntry->data, "W", sizeof("W")); 18728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan longitude *= -1; 18828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 18928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 19028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE); 19128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 19228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational)); 19328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 19428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get()); 19528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSLongitude exif entry failed"; 19628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 19728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 19828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan SetLatitudeOrLongitudeData(entry->data, longitude); 19928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 20028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 20128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 20228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 20328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetGpsAltitude(double altitude) { 20428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF); 20528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> refEntry = 20628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan AddVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_BYTE, 1, 1); 20728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!refEntry) { 20828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSAltitudeRef exif entry failed"; 20928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 21028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 21128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (altitude >= 0) { 21228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan *refEntry->data = 0; 21328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } else { 21428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan *refEntry->data = 1; 21528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan altitude *= -1; 21628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 21728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 21828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE); 21928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 22028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 1, sizeof(ExifRational)); 22128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 22228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get()); 22328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSAltitude exif entry failed"; 22428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 22528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 22628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, 22728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan {static_cast<ExifLong>(altitude * 1000), 1000}); 22828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 22928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 23028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 23128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 23228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetGpsTimestamp(const struct tm& t) { 23328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP); 23428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan const size_t kGpsDateStampSize = 11; 23528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = 23628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan AddVariableLengthEntry(EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII, 23728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan kGpsDateStampSize, kGpsDateStampSize); 23828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 23928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSDateStamp exif entry failed"; 24028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 24128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 24228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan int result = 24328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize, 24428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan "%04i:%02i:%02i", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday); 24528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (result != kGpsDateStampSize - 1) { 24628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(WARNING) << "Input time is invalid"; 24728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 24828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 24928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 25028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP); 25128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan entry = AddVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3, 25228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 3 * sizeof(ExifRational)); 25328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 25428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSTimeStamp exif entry failed"; 25528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 25628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 25728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, 25828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan {static_cast<ExifLong>(t.tm_hour), 1}); 25928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, 26028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan {static_cast<ExifLong>(t.tm_min), 1}); 26128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_rational(entry->data + 2 * sizeof(ExifRational), 26228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan EXIF_BYTE_ORDER_INTEL, 26328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan {static_cast<ExifLong>(t.tm_sec), 1}); 26428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 26528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 26628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 26728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 26828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetGpsProcessingMethod(const std::string& method) { 26928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD); 27028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan size_t size = sizeof(gExifAsciiPrefix) + method.length(); 27128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = AddVariableLengthEntry( 27228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan EXIF_IFD_GPS, tag, EXIF_FORMAT_UNDEFINED, size, size); 27328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 27428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding GPSProcessingMethod exif entry failed"; 27528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 27628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 27728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(entry->data, gExifAsciiPrefix, sizeof(gExifAsciiPrefix)); 27828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // Since the exif format is undefined, NULL termination is not necessary. 27928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan memcpy(entry->data + sizeof(gExifAsciiPrefix), method.c_str(), 28028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan method.length()); 28128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 28228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 28328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 28428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 28528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetThumbnailSize(uint16_t width, uint16_t height) { 28628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (width % 2 != 0 || height % 2 != 0) { 28728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Invalid thumbnail size " << width << "x" << height; 28828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 28928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 29028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_width_ = width; 29128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_height_ = height; 29228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 29328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 29428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 29528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetOrientation(uint16_t orientation) { 29628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = AddEntry(EXIF_IFD_0, EXIF_TAG_ORIENTATION); 29728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 29828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding Orientation exif entry failed"; 29928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 30028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 30128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan /* 30228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * Orientation value: 30328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * 1 2 3 4 5 6 7 8 30428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * 30528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * 888888 888888 88 88 8888888888 88 88 8888888888 30628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * 88 88 88 88 88 88 88 88 88 88 88 88 30728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * 8888 8888 8888 8888 88 8888888888 8888888888 88 30828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * 88 88 88 88 30928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * 88 88 888888 888888 31028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan */ 31128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan int value = 1; 31228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan switch (orientation) { 31328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan case 90: 31428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan value = 6; 31528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan break; 31628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan case 180: 31728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan value = 3; 31828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan break; 31928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan case 270: 32028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan value = 8; 32128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan break; 32228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan default: 32328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan break; 32428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 32528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, value); 32628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 32728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 32828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 32928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::GenerateApp1() { 33028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan DestroyApp1(); 33128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (thumbnail_width_ > 0 && thumbnail_height_ > 0) { 33228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!GenerateThumbnail()) { 33328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Generate thumbnail image failed"; 33428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 33528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 33628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_->data = const_cast<uint8_t*>( 33728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan static_cast<const uint8_t*>(compressor_.GetCompressedImagePtr())); 33828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_->size = compressor_.GetCompressedImageSize(); 33928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 34028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // Save the result into |app1_buffer_|. 34128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_save_data(exif_data_, &app1_buffer_, &app1_length_); 34228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!app1_length_) { 34328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Allocate memory for app1_buffer_ failed"; 34428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 34528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 34628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan /* 34728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * The JPEG segment size is 16 bits in spec. The size of APP1 segment should 34828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * be smaller than 65533 because there are two bytes for segment size field. 34928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan */ 35028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (app1_length_ > 65533) { 35128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan DestroyApp1(); 35228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "The size of APP1 segment is too large"; 35328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 35428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 35528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 35628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 35728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 35828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanconst uint8_t* ExifUtils::GetApp1Buffer() { return app1_buffer_; } 35928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 36028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanunsigned int ExifUtils::GetApp1Length() { return app1_length_; } 36128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 36228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanvoid ExifUtils::Reset() { 36328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_buffer_ = nullptr; 36428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_width_ = 0; 36528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_height_ = 0; 36628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_width_ = 0; 36728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_height_ = 0; 36828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan DestroyApp1(); 36928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (exif_data_) { 37028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan /* 37128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * Since we decided to ignore the original APP1, we are sure that there is 37228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * no thumbnail allocated by libexif. |exif_data_->data| is actually 37328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * allocated by JpegCompressor. Sets |exif_data_->data| to nullptr to 37428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * prevent exif_data_unref() destroy it incorrectly. 37528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan */ 37628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_->data = nullptr; 37728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_->size = 0; 37828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_unref(exif_data_); 37928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_data_ = nullptr; 38028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 38128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 38228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 38328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanstd::unique_ptr<ExifEntry> ExifUtils::AddVariableLengthEntry( 38428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifIfd ifd, ExifTag tag, ExifFormat format, uint64_t components, 38528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan unsigned int size) { 38628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // Remove old entry if exists. 38728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_content_remove_entry(exif_data_->ifd[ifd], 38828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_content_get_entry(exif_data_->ifd[ifd], tag)); 38928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan ExifMem* mem = exif_mem_new_default(); 39028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!mem) { 39128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Allocate memory for exif entry failed"; 39228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return nullptr; 39328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 39428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry(exif_entry_new_mem(mem)); 39528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 39628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Allocate memory for exif entry failed"; 39728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_mem_unref(mem); 39828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return nullptr; 39928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 40028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan void* tmpBuffer = exif_mem_alloc(mem, size); 40128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!tmpBuffer) { 40228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Allocate memory for exif entry failed"; 40328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_mem_unref(mem); 40428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return nullptr; 40528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 40628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 40728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan entry->data = static_cast<unsigned char*>(tmpBuffer); 40828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan entry->tag = tag; 40928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan entry->format = format; 41028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan entry->components = components; 41128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan entry->size = size; 41228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 41328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_content_add_entry(exif_data_->ifd[ifd], entry.get()); 41428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_mem_unref(mem); 41528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 41628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return entry; 41728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 41828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 41928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanstd::unique_ptr<ExifEntry> ExifUtils::AddEntry(ExifIfd ifd, ExifTag tag) { 42028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry( 42128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_content_get_entry(exif_data_->ifd[ifd], tag)); 42228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (entry) { 42328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // exif_content_get_entry() won't ref the entry, so we ref here. 42428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_entry_ref(entry.get()); 42528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return entry; 42628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 42728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan entry.reset(exif_entry_new()); 42828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 42928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Allocate memory for exif entry failed"; 43028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return nullptr; 43128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 43228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan entry->tag = tag; 43328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_content_add_entry(exif_data_->ifd[ifd], entry.get()); 43428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_entry_initialize(entry.get(), tag); 43528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return entry; 43628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 43728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 43828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetImageWidth(uint16_t width) { 43928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = AddEntry(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH); 44028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 44128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding ImageWidth exif entry failed"; 44228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 44328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 44428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, width); 44528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 44628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 44728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 44828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::SetImageLength(uint16_t length) { 44928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::unique_ptr<ExifEntry> entry = 45028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan AddEntry(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH); 45128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!entry) { 45228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Adding ImageLength exif entry failed"; 45328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 45428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 45528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, length); 45628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 45728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 45828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 45928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::GenerateThumbnail() { 46028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // Resize yuv image to |thumbnail_width_| x |thumbnail_height_|. 46128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan std::vector<uint8_t> scaled_buffer; 46228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!GenerateYuvThumbnail(&scaled_buffer)) { 46328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Generate YUV thumbnail failed"; 46428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 46528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 46628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 46728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan // Compress thumbnail to JPEG. 46828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (!compressor_.CompressImage(scaled_buffer.data(), thumbnail_width_, 46928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_height_, thumbnail_jpeg_quality_, 47028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan NULL, 0)) { 47128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Compress thumbnail failed"; 47228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 47328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 47428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 47528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 47628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 47728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanbool ExifUtils::GenerateYuvThumbnail(std::vector<uint8_t>* scaled_buffer) { 47828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan size_t y_plane_size = yu12_width_ * yu12_height_; 47928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan const uint8* y_plane = yu12_buffer_; 48028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan const uint8* u_plane = y_plane + y_plane_size; 48128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan const uint8* v_plane = u_plane + y_plane_size / 4; 48228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 48328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan size_t scaled_y_plane_size = thumbnail_width_ * thumbnail_height_; 48428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan scaled_buffer->resize(scaled_y_plane_size * 3 / 2); 48528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan uint8* scaled_y_plane = scaled_buffer->data(); 48628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan uint8* scaled_u_plane = scaled_y_plane + scaled_y_plane_size; 48728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan uint8* scaled_v_plane = scaled_u_plane + scaled_y_plane_size / 4; 48828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 48928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan int result = libyuv::I420Scale( 49028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan y_plane, yu12_width_, u_plane, yu12_width_ / 2, v_plane, yu12_width_ / 2, 49128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan yu12_width_, yu12_height_, scaled_y_plane, thumbnail_width_, 49228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan scaled_u_plane, thumbnail_width_ / 2, scaled_v_plane, 49328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan thumbnail_width_ / 2, thumbnail_width_, thumbnail_height_, 49428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan libyuv::kFilterNone); 49528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan if (result != 0) { 49628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan LOGF(ERROR) << "Scale I420 image failed"; 49728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return false; 49828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan } 49928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan return true; 50028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 50128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 50228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanvoid ExifUtils::DestroyApp1() { 50328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan /* 50428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * Since there is no API to access ExifMem in ExifData->priv, we use free 50528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * here, which is the default free function in libexif. See 50628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan * exif_data_save_data() for detail. 50728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan */ 50828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan free(app1_buffer_); 50928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan app1_buffer_ = nullptr; 51028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan app1_length_ = 0; 51128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} 51228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan 51328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan} // namespace arc 514