diff options
author | Eino-Ville Talvala <etalvala@google.com> | 2018-11-15 16:07:46 -0800 |
---|---|---|
committer | Eino-Ville Talvala <etalvala@google.com> | 2018-11-15 16:07:46 -0800 |
commit | 2d6d3250dcb304c8ad081dedc8eef6ea48fd669d (patch) | |
tree | 68cc8d5a9bf5a558f46025d740c47cb292eea9f0 /src/gcontainer/gcontainer.cc | |
parent | 840fc3b66a9e6593d542ada6fe14d91107fab98d (diff) | |
download | image_io-2d6d3250dcb304c8ad081dedc8eef6ea48fd669d.tar.gz |
Initial commit of libimage_io
Image_io is a library for manipulating image files, especially XMP
metadata within them.
Test: m libimage_io
Bug: 109735087
Bug: 119211681
Change-Id: I657f307be0459fe40154806c7cd388b97bcb0ea5
Diffstat (limited to 'src/gcontainer/gcontainer.cc')
-rw-r--r-- | src/gcontainer/gcontainer.cc | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/gcontainer/gcontainer.cc b/src/gcontainer/gcontainer.cc new file mode 100644 index 0000000..1179778 --- /dev/null +++ b/src/gcontainer/gcontainer.cc @@ -0,0 +1,163 @@ +#include "image_io/gcontainer/gcontainer.h" + +#include <fstream> + +#include "image_io/base/data_segment.h" +#include "image_io/base/data_segment_data_source.h" +#include "image_io/base/message_handler.h" +#include "image_io/base/ostream_data_destination.h" +#include "image_io/jpeg/jpeg_info.h" +#include "image_io/jpeg/jpeg_info_builder.h" +#include "image_io/jpeg/jpeg_scanner.h" +#include "image_io/utils/file_utils.h" + +namespace photos_editing_formats { +namespace image_io { +namespace gcontainer { +namespace { + +using photos_editing_formats::image_io::DataRange; +using photos_editing_formats::image_io::DataSegment; +using photos_editing_formats::image_io::DataSegmentDataSource; +using photos_editing_formats::image_io::JpegInfoBuilder; +using photos_editing_formats::image_io::JpegScanner; +using photos_editing_formats::image_io::Message; +using photos_editing_formats::image_io::MessageHandler; +using photos_editing_formats::image_io::OStreamDataDestination; +using photos_editing_formats::image_io::ReportErrorPolicy; +using std::string; + +// Populates first_image_range with the first image (from the header metadata +// to the EOI marker) present in the JPEG file input_file_name. Returns true if +// such a first image is found, false otherwise. +// +// input_file_name must be a JPEG file. +// image_data_segment is populated with the DataSegment for +// input_file_name, and is populated only in the successful case. +// first_image_range is populated with the first image found in the input file, +// only if such an image is found. +bool ExtractFirstImageInJpeg(const string& input_file_name, + std::shared_ptr<DataSegment>* image_data_segment, + DataRange* first_image_range) { + if (first_image_range == nullptr) { + return false; + } + + // Get the input and output setup. + MessageHandler::Get()->ClearMessages(); + auto data_segment = + ReadEntireFile(input_file_name, ReportErrorPolicy::kReportError); + if (!data_segment) { + return false; + } + + // Get the jpeg info and first image range from the input. + DataSegmentDataSource data_source(data_segment); + JpegInfoBuilder jpeg_info_builder; + jpeg_info_builder.SetImageLimit(1); + JpegScanner jpeg_scanner; + jpeg_scanner.Run(&data_source, &jpeg_info_builder); + if (jpeg_scanner.HasError()) { + return false; + } + + const auto& jpeg_info = jpeg_info_builder.GetInfo(); + const auto& image_ranges = jpeg_info.GetImageRanges(); + if (image_ranges.empty()) { + MessageHandler::Get()->ReportMessage(Message::kPrematureEndOfDataError, + "No Images Found"); + return false; + } + + *image_data_segment = data_segment; + *first_image_range = image_ranges[0]; + return true; +} + +} // namespace + +bool WriteImageAndFiles(const string& input_file_name, + const std::vector<string>& other_files, + const string& output_file_name) { + auto output_stream = + OpenOutputFile(output_file_name, ReportErrorPolicy::kReportError); + if (!output_stream) { + return false; + } + + OStreamDataDestination output_destination(std::move(output_stream)); + output_destination.SetName(output_file_name); + + DataRange image_range; + std::shared_ptr<DataSegment> data_segment; + if (!ExtractFirstImageInJpeg(input_file_name, &data_segment, &image_range)) { + return false; + } + + output_destination.StartTransfer(); + DataSegmentDataSource data_source(data_segment); + data_source.TransferData(image_range, image_range.GetLength(), + &output_destination); + + size_t bytes_transferred = image_range.GetLength(); + for (const string& tack_on_file : other_files) { + if (tack_on_file.empty()) { + continue; + } + auto tack_on_data_segment = + ReadEntireFile(tack_on_file, ReportErrorPolicy::kReportError); + if (!tack_on_data_segment) { + continue; + } + + DataSegmentDataSource tack_on_source(tack_on_data_segment); + DataRange tack_on_range = tack_on_data_segment->GetDataRange(); + bytes_transferred += tack_on_range.GetLength(); + tack_on_source.TransferData(tack_on_range, tack_on_range.GetLength(), + &output_destination); + } + + output_destination.FinishTransfer(); + return output_destination.GetBytesTransferred() == bytes_transferred && + !output_destination.HasError(); +} + +bool ParseFileAfterImage(const string& input_file_name, + size_t file_start_offset, size_t file_length, + string* out_file_contents) { + if (out_file_contents == nullptr || file_start_offset < 0 || + file_length == 0) { + return false; + } + + DataRange image_range; + std::shared_ptr<DataSegment> data_segment; + if (!ExtractFirstImageInJpeg(input_file_name, &data_segment, &image_range)) { + return false; + } + + size_t image_bytes_end_offset = image_range.GetEnd(); + size_t image_file_end = data_segment->GetEnd(); + size_t file_start_in_image = image_bytes_end_offset + file_start_offset; + size_t file_end_in_image = file_start_in_image + file_length; + if (image_file_end < file_end_in_image) { + // Requested file is past the end of the image file. + return false; + } + + // Get the file's contents. + const DataRange file_range(file_start_in_image, file_end_in_image); + size_t file_range_size = file_range.GetLength(); + // TODO(miraleung): Consider subclassing image_io/data_destination.h and + // transferring bytes directly into the string. TBD pending additional mime + // type getters. + std::ifstream input_file_stream(input_file_name); + input_file_stream.seekg(file_range.GetBegin()); + out_file_contents->resize(file_range_size); + input_file_stream.read(&(*out_file_contents)[0], file_range_size); + return true; +} + +} // namespace gcontainer +} // namespace image_io +} // namespace photos_editing_formats |