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