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