summaryrefslogtreecommitdiff
path: root/src/gcontainer/gcontainer.cc
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2018-11-15 16:07:46 -0800
committerEino-Ville Talvala <etalvala@google.com>2018-11-15 16:07:46 -0800
commit2d6d3250dcb304c8ad081dedc8eef6ea48fd669d (patch)
tree68cc8d5a9bf5a558f46025d740c47cb292eea9f0 /src/gcontainer/gcontainer.cc
parent840fc3b66a9e6593d542ada6fe14d91107fab98d (diff)
downloadimage_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.cc163
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