Home | History | Annotate | Download | only in dynamic_depth
      1 #include "dynamic_depth/dynamic_depth.h"
      2 
      3 #include <fstream>
      4 #include <sstream>
      5 
      6 #include "android-base/logging.h"
      7 #include "dynamic_depth/container.h"
      8 #include "dynamic_depth/item.h"
      9 #include "image_io/gcontainer/gcontainer.h"
     10 #include "xmpmeta/xmp_data.h"
     11 #include "xmpmeta/xmp_writer.h"
     12 
     13 namespace dynamic_depth {
     14 namespace {
     15 
     16 using ::dynamic_depth::xmpmeta::CreateXmpData;
     17 using ::dynamic_depth::xmpmeta::XmpData;
     18 
     19 constexpr char kImageMimePrefix[] = "image";
     20 
     21 bool IsMimeTypeImage(const string& mime) {
     22   string mime_lower = mime;
     23   std::transform(mime_lower.begin(), mime_lower.end(), mime_lower.begin(),
     24                  ::tolower);
     25   return strncmp(mime_lower.c_str(), kImageMimePrefix, mime_lower.find("/")) ==
     26          0;
     27 }
     28 
     29 }  // namespace
     30 
     31 bool WriteImageAndMetadataAndContainer(std::istream* input_jpeg_stream,
     32                                        Device* device,
     33                                        std::ostream* output_jpeg_stream) {
     34   const std::unique_ptr<XmpData> xmp_data = CreateXmpData(true);
     35   device->SerializeToXmp(xmp_data.get());
     36   bool success =
     37       WriteLeftEyeAndXmpMeta(*xmp_data, input_jpeg_stream, output_jpeg_stream);
     38 
     39   if (device->GetContainer() == nullptr) {
     40     return success;
     41   }
     42 
     43   // Append Container:Item elements' payloads.
     44   for (auto item : device->GetContainer()->GetItems()) {
     45     const string& payload = item->GetPayloadToSerialize();
     46     const unsigned int payload_size = item->GetLength();
     47     if (payload_size <= 0 || payload.empty()) {
     48       continue;
     49     }
     50     output_jpeg_stream->write(payload.c_str(), payload_size);
     51   }
     52 
     53   return success;
     54 }
     55 
     56 bool WriteImageAndMetadataAndContainer(const string& out_filename,
     57                                        const uint8_t* primary_image_bytes,
     58                                        size_t primary_image_bytes_count,
     59                                        Device* device) {
     60   std::istringstream input_jpeg_stream(
     61       std::string(reinterpret_cast<const char*>(primary_image_bytes),
     62                   primary_image_bytes_count));
     63   std::ofstream output_jpeg_stream;
     64   output_jpeg_stream.open(out_filename, std::ostream::out);
     65   bool success = WriteImageAndMetadataAndContainer(&input_jpeg_stream, device,
     66                                                    &output_jpeg_stream);
     67   output_jpeg_stream.close();
     68   return success;
     69 }
     70 
     71 bool GetItemPayload(const string& input_image_filename, const Device* device,
     72                     const string& item_uri, string* out_payload) {
     73   if (device == nullptr || device->GetContainer() == nullptr) {
     74     LOG(ERROR) << "No Container element to parse";
     75     return false;
     76   }
     77 
     78   return GetItemPayload(input_image_filename, device->GetContainer(), item_uri,
     79                         out_payload);
     80 }
     81 
     82 bool GetItemPayload(const string& input_image_filename,
     83                     const Container* container, const string& item_uri,
     84                     string* out_payload) {
     85   std::ifstream input_stream(input_image_filename);
     86   return GetItemPayload(container, item_uri, input_stream, out_payload);
     87 }
     88 
     89 bool GetItemPayload(const Container* container, const string& item_uri,
     90                     std::istream& input_jpeg_stream, string* out_payload) {
     91   if (container == nullptr) {
     92     LOG(ERROR) << "Container cannot be null";
     93     return false;
     94   }
     95 
     96   size_t file_offset = 0;
     97   size_t file_length = 0;
     98   int index = 0;
     99   bool is_mime_type_image = false;
    100   for (const auto& item : container->GetItems()) {
    101     is_mime_type_image = IsMimeTypeImage(item->GetMime());
    102 
    103     if (item_uri.compare(item->GetDataUri()) == 0) {
    104       // Found a matching item.
    105       file_length = item->GetLength();
    106       break;
    107     }
    108 
    109     file_offset += item->GetLength();
    110     index++;
    111   }
    112 
    113   if (file_length == 0) {
    114     if (index == 0 && is_mime_type_image) {
    115       LOG(INFO) << "Item references the primary image, Not populating data";
    116       return true;
    117     }
    118 
    119     // File length can be zero to indicate the primary image (checked above) or
    120     // use the last file in the list. If this check fails, it's not in this
    121     // state.
    122     if (file_offset == 0) {
    123       LOG(ERROR) << "Not using the primary image, or not image mime, or not "
    124                     "the first item, but has file offset of 0";
    125       return false;
    126     }
    127   }
    128 
    129   std::string std_payload;
    130   bool success = ::photos_editing_formats::image_io::gcontainer::
    131       ParseFileAfterImageFromStream(file_offset, file_length, input_jpeg_stream,
    132                                     &std_payload);
    133   *out_payload = std_payload;
    134   return success;
    135 }
    136 
    137 }  // namespace dynamic_depth
    138