blob: 67b5fb4411977fe4c63a2006dfb2fb1280dbb9ea [file] [log] [blame]
#include "dynamic_depth/dynamic_depth.h"
#include <fstream>
#include <sstream>
#include "android-base/logging.h"
#include "dynamic_depth/container.h"
#include "dynamic_depth/item.h"
#include "image_io/gcontainer/gcontainer.h"
#include "xmpmeta/xmp_data.h"
#include "xmpmeta/xmp_writer.h"
namespace dynamic_depth {
namespace {
using ::dynamic_depth::xmpmeta::CreateXmpData;
using ::dynamic_depth::xmpmeta::XmpData;
constexpr char kImageMimePrefix[] = "image";
bool IsMimeTypeImage(const string& mime) {
string mime_lower = mime;
std::transform(mime_lower.begin(), mime_lower.end(), mime_lower.begin(),
::tolower);
return strncmp(mime_lower.c_str(), kImageMimePrefix, mime_lower.find("/")) ==
0;
}
} // namespace
bool WriteImageAndMetadataAndContainer(std::istream* input_jpeg_stream,
Device* device,
std::ostream* output_jpeg_stream) {
const std::unique_ptr<XmpData> xmp_data = CreateXmpData(true);
device->SerializeToXmp(xmp_data.get());
bool success =
WriteLeftEyeAndXmpMeta(*xmp_data, input_jpeg_stream, output_jpeg_stream);
if (device->GetContainer() == nullptr) {
return success;
}
// Append Container:Item elements' payloads.
for (auto item : device->GetContainer()->GetItems()) {
const string& payload = item->GetPayloadToSerialize();
const unsigned int payload_size = item->GetLength();
if (payload_size <= 0 || payload.empty()) {
continue;
}
output_jpeg_stream->write(payload.c_str(), payload_size);
}
return success;
}
bool WriteImageAndMetadataAndContainer(const string& out_filename,
const uint8_t* primary_image_bytes,
size_t primary_image_bytes_count,
Device* device) {
std::istringstream input_jpeg_stream(
std::string(reinterpret_cast<const char*>(primary_image_bytes),
primary_image_bytes_count));
std::ofstream output_jpeg_stream;
output_jpeg_stream.open(out_filename, std::ostream::out);
bool success = WriteImageAndMetadataAndContainer(&input_jpeg_stream, device,
&output_jpeg_stream);
output_jpeg_stream.close();
return success;
}
bool GetItemPayload(const string& input_image_filename, const Device* device,
const string& item_uri, string* out_payload) {
if (device == nullptr || device->GetContainer() == nullptr) {
LOG(ERROR) << "No Container element to parse";
return false;
}
return GetItemPayload(input_image_filename, device->GetContainer(), item_uri,
out_payload);
}
bool GetItemPayload(const string& input_image_filename,
const Container* container, const string& item_uri,
string* out_payload) {
std::ifstream input_stream(input_image_filename);
return GetItemPayload(container, item_uri, input_stream, out_payload);
}
bool GetItemPayload(const Container* container, const string& item_uri,
std::istream& input_jpeg_stream, string* out_payload) {
if (container == nullptr) {
LOG(ERROR) << "Container cannot be null";
return false;
}
size_t file_offset = 0;
size_t file_length = 0;
int index = 0;
bool is_mime_type_image = false;
for (const auto& item : container->GetItems()) {
is_mime_type_image = IsMimeTypeImage(item->GetMime());
if (item_uri.compare(item->GetDataUri()) == 0) {
// Found a matching item.
file_length = item->GetLength();
break;
}
file_offset += item->GetLength();
index++;
}
if (file_length == 0) {
if (index == 0 && is_mime_type_image) {
LOG(INFO) << "Item references the primary image, Not populating data";
return true;
}
// File length can be zero to indicate the primary image (checked above) or
// use the last file in the list. If this check fails, it's not in this
// state.
if (file_offset == 0) {
LOG(ERROR) << "Not using the primary image, or not image mime, or not "
"the first item, but has file offset of 0";
return false;
}
}
std::string std_payload;
bool success = ::photos_editing_formats::image_io::gcontainer::
ParseFileAfterImageFromStream(file_offset, file_length, input_jpeg_stream,
&std_payload);
*out_payload = std_payload;
return success;
}
} // namespace dynamic_depth