xref: /aosp_15_r20/external/image_io/src/gcontainer/gcontainer.cc (revision ca0779eb572efbbfda2e47f806647c3c7eeea8c3)
1*ca0779ebSJerome Gaillard #include "image_io/gcontainer/gcontainer.h"
2*ca0779ebSJerome Gaillard 
3*ca0779ebSJerome Gaillard #include <fstream>
4*ca0779ebSJerome Gaillard 
5*ca0779ebSJerome Gaillard #include "image_io/base/data_segment.h"
6*ca0779ebSJerome Gaillard #include "image_io/base/data_segment_data_source.h"
7*ca0779ebSJerome Gaillard #include "image_io/base/istream_data_source.h"
8*ca0779ebSJerome Gaillard #include "image_io/base/message_handler.h"
9*ca0779ebSJerome Gaillard #include "image_io/base/ostream_data_destination.h"
10*ca0779ebSJerome Gaillard #include "image_io/jpeg/jpeg_info.h"
11*ca0779ebSJerome Gaillard #include "image_io/jpeg/jpeg_info_builder.h"
12*ca0779ebSJerome Gaillard #include "image_io/jpeg/jpeg_scanner.h"
13*ca0779ebSJerome Gaillard #include "image_io/utils/file_utils.h"
14*ca0779ebSJerome Gaillard 
15*ca0779ebSJerome Gaillard namespace photos_editing_formats {
16*ca0779ebSJerome Gaillard namespace image_io {
17*ca0779ebSJerome Gaillard namespace gcontainer {
18*ca0779ebSJerome Gaillard namespace {
19*ca0779ebSJerome Gaillard 
20*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::DataRange;
21*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::DataSegment;
22*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::DataSegmentDataSource;
23*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::IStreamRefDataSource;
24*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::JpegInfoBuilder;
25*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::JpegScanner;
26*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::Message;
27*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::MessageHandler;
28*ca0779ebSJerome Gaillard using photos_editing_formats::image_io::OStreamDataDestination;
29*ca0779ebSJerome Gaillard using std::string;
30*ca0779ebSJerome Gaillard 
31*ca0779ebSJerome Gaillard // Populates first_image_range with the first image (from the header metadata
32*ca0779ebSJerome Gaillard // to the EOI marker) present in the JPEG file input_file_name. Returns true if
33*ca0779ebSJerome Gaillard // such a first image is found, false otherwise.
34*ca0779ebSJerome Gaillard //
35*ca0779ebSJerome Gaillard // input_jpeg_stream must be a JPEG stream.
36*ca0779ebSJerome Gaillard // image_data_segment is populated with the DataSegment for
37*ca0779ebSJerome Gaillard // input_file_name, and is populated only in the successful case.
38*ca0779ebSJerome Gaillard // first_image_range is populated with the first image found in the input file,
39*ca0779ebSJerome Gaillard // only if such an image is found.
40*ca0779ebSJerome Gaillard 
ExtractFirstImageInJpeg(std::istream & input_jpeg_stream,MessageHandler * message_handler,DataRange * first_image_range)41*ca0779ebSJerome Gaillard bool ExtractFirstImageInJpeg(std::istream& input_jpeg_stream,
42*ca0779ebSJerome Gaillard                              MessageHandler* message_handler,
43*ca0779ebSJerome Gaillard                              DataRange* first_image_range) {
44*ca0779ebSJerome Gaillard   if (first_image_range == nullptr) {
45*ca0779ebSJerome Gaillard     return false;
46*ca0779ebSJerome Gaillard   }
47*ca0779ebSJerome Gaillard 
48*ca0779ebSJerome Gaillard   // Get the input and output setup.
49*ca0779ebSJerome Gaillard   if (message_handler) {
50*ca0779ebSJerome Gaillard     message_handler->ClearMessages();
51*ca0779ebSJerome Gaillard   }
52*ca0779ebSJerome Gaillard 
53*ca0779ebSJerome Gaillard   // Get the jpeg info and first image range from the input.
54*ca0779ebSJerome Gaillard   IStreamRefDataSource data_source(input_jpeg_stream);
55*ca0779ebSJerome Gaillard   JpegInfoBuilder jpeg_info_builder;
56*ca0779ebSJerome Gaillard   jpeg_info_builder.SetImageLimit(1);
57*ca0779ebSJerome Gaillard   JpegScanner jpeg_scanner(message_handler);
58*ca0779ebSJerome Gaillard   jpeg_scanner.Run(&data_source, &jpeg_info_builder);
59*ca0779ebSJerome Gaillard   data_source.Reset();
60*ca0779ebSJerome Gaillard 
61*ca0779ebSJerome Gaillard   if (jpeg_scanner.HasError()) {
62*ca0779ebSJerome Gaillard     return false;
63*ca0779ebSJerome Gaillard   }
64*ca0779ebSJerome Gaillard 
65*ca0779ebSJerome Gaillard   const auto& jpeg_info = jpeg_info_builder.GetInfo();
66*ca0779ebSJerome Gaillard   const auto& image_ranges = jpeg_info.GetImageRanges();
67*ca0779ebSJerome Gaillard   if (image_ranges.empty()) {
68*ca0779ebSJerome Gaillard     if (message_handler) {
69*ca0779ebSJerome Gaillard       message_handler->ReportMessage(Message::kPrematureEndOfDataError,
70*ca0779ebSJerome Gaillard                                      "No Images Found");
71*ca0779ebSJerome Gaillard     }
72*ca0779ebSJerome Gaillard     return false;
73*ca0779ebSJerome Gaillard   }
74*ca0779ebSJerome Gaillard 
75*ca0779ebSJerome Gaillard   *first_image_range = image_ranges[0];
76*ca0779ebSJerome Gaillard   return true;
77*ca0779ebSJerome Gaillard }
78*ca0779ebSJerome Gaillard 
79*ca0779ebSJerome Gaillard }  // namespace
80*ca0779ebSJerome Gaillard 
WriteImageAndFiles(const string & input_file_name,const std::vector<string> & other_files,const string & output_file_name)81*ca0779ebSJerome Gaillard bool WriteImageAndFiles(const string& input_file_name,
82*ca0779ebSJerome Gaillard                         const std::vector<string>& other_files,
83*ca0779ebSJerome Gaillard                         const string& output_file_name) {
84*ca0779ebSJerome Gaillard   MessageHandler message_handler;
85*ca0779ebSJerome Gaillard   auto output_stream = OpenOutputFile(output_file_name, &message_handler);
86*ca0779ebSJerome Gaillard   if (!output_stream) {
87*ca0779ebSJerome Gaillard     return false;
88*ca0779ebSJerome Gaillard   }
89*ca0779ebSJerome Gaillard 
90*ca0779ebSJerome Gaillard   OStreamDataDestination output_destination(std::move(output_stream),
91*ca0779ebSJerome Gaillard                                             &message_handler);
92*ca0779ebSJerome Gaillard   output_destination.SetName(output_file_name);
93*ca0779ebSJerome Gaillard 
94*ca0779ebSJerome Gaillard   DataRange image_range;
95*ca0779ebSJerome Gaillard   std::unique_ptr<std::istream> input_stream =
96*ca0779ebSJerome Gaillard       OpenInputFile(input_file_name, &message_handler);
97*ca0779ebSJerome Gaillard 
98*ca0779ebSJerome Gaillard   if (!ExtractFirstImageInJpeg(*input_stream, &message_handler, &image_range)) {
99*ca0779ebSJerome Gaillard     return false;
100*ca0779ebSJerome Gaillard   }
101*ca0779ebSJerome Gaillard 
102*ca0779ebSJerome Gaillard   output_destination.StartTransfer();
103*ca0779ebSJerome Gaillard   IStreamDataSource data_source(
104*ca0779ebSJerome Gaillard       OpenInputFile(input_file_name, &message_handler));
105*ca0779ebSJerome Gaillard   data_source.TransferData(image_range, image_range.GetLength(),
106*ca0779ebSJerome Gaillard                            &output_destination);
107*ca0779ebSJerome Gaillard 
108*ca0779ebSJerome Gaillard   size_t bytes_transferred = image_range.GetLength();
109*ca0779ebSJerome Gaillard   for (const string& tack_on_file : other_files) {
110*ca0779ebSJerome Gaillard     if (tack_on_file.empty()) {
111*ca0779ebSJerome Gaillard       continue;
112*ca0779ebSJerome Gaillard     }
113*ca0779ebSJerome Gaillard     auto tack_on_data_segment = ReadEntireFile(tack_on_file, &message_handler);
114*ca0779ebSJerome Gaillard     if (!tack_on_data_segment) {
115*ca0779ebSJerome Gaillard       continue;
116*ca0779ebSJerome Gaillard     }
117*ca0779ebSJerome Gaillard 
118*ca0779ebSJerome Gaillard     DataSegmentDataSource tack_on_source(tack_on_data_segment);
119*ca0779ebSJerome Gaillard     DataRange tack_on_range = tack_on_data_segment->GetDataRange();
120*ca0779ebSJerome Gaillard     bytes_transferred += tack_on_range.GetLength();
121*ca0779ebSJerome Gaillard     tack_on_source.TransferData(tack_on_range, tack_on_range.GetLength(),
122*ca0779ebSJerome Gaillard                                 &output_destination);
123*ca0779ebSJerome Gaillard   }
124*ca0779ebSJerome Gaillard 
125*ca0779ebSJerome Gaillard   output_destination.FinishTransfer();
126*ca0779ebSJerome Gaillard   return output_destination.GetBytesTransferred() == bytes_transferred &&
127*ca0779ebSJerome Gaillard          !output_destination.HasError();
128*ca0779ebSJerome Gaillard }
129*ca0779ebSJerome Gaillard 
ParseFileAfterImage(const std::string & input_file_name,size_t file_start_offset,size_t file_length,std::string * out_file_contents)130*ca0779ebSJerome Gaillard bool ParseFileAfterImage(const std::string& input_file_name,
131*ca0779ebSJerome Gaillard                          size_t file_start_offset, size_t file_length,
132*ca0779ebSJerome Gaillard                          std::string* out_file_contents) {
133*ca0779ebSJerome Gaillard   std::ifstream input_stream(input_file_name);
134*ca0779ebSJerome Gaillard   if (!input_stream.is_open()) {
135*ca0779ebSJerome Gaillard     return false;
136*ca0779ebSJerome Gaillard   }
137*ca0779ebSJerome Gaillard   return ParseFileAfterImageFromStream(file_start_offset, file_length,
138*ca0779ebSJerome Gaillard                                        input_stream, out_file_contents);
139*ca0779ebSJerome Gaillard }
140*ca0779ebSJerome Gaillard 
ParseFileAfterImageFromStream(size_t start_offset,size_t length,std::istream & input_jpeg_stream,std::string * out_contents)141*ca0779ebSJerome Gaillard bool ParseFileAfterImageFromStream(size_t start_offset, size_t length,
142*ca0779ebSJerome Gaillard                                    std::istream& input_jpeg_stream,
143*ca0779ebSJerome Gaillard                                    std::string* out_contents) {
144*ca0779ebSJerome Gaillard   if (out_contents == nullptr || start_offset < 0 || length == 0) {
145*ca0779ebSJerome Gaillard     return false;
146*ca0779ebSJerome Gaillard   }
147*ca0779ebSJerome Gaillard 
148*ca0779ebSJerome Gaillard   size_t curr_posn = input_jpeg_stream.tellg();
149*ca0779ebSJerome Gaillard   input_jpeg_stream.seekg(0, input_jpeg_stream.end);
150*ca0779ebSJerome Gaillard   size_t stream_size = input_jpeg_stream.tellg();
151*ca0779ebSJerome Gaillard   input_jpeg_stream.seekg(curr_posn, input_jpeg_stream.beg);
152*ca0779ebSJerome Gaillard 
153*ca0779ebSJerome Gaillard   DataRange image_range;
154*ca0779ebSJerome Gaillard   MessageHandler message_handler;
155*ca0779ebSJerome Gaillard   if (!ExtractFirstImageInJpeg(input_jpeg_stream, &message_handler,
156*ca0779ebSJerome Gaillard                                &image_range)) {
157*ca0779ebSJerome Gaillard     return false;
158*ca0779ebSJerome Gaillard   }
159*ca0779ebSJerome Gaillard 
160*ca0779ebSJerome Gaillard   size_t image_bytes_end_offset = image_range.GetEnd();
161*ca0779ebSJerome Gaillard   size_t file_start_in_image = image_bytes_end_offset + start_offset;
162*ca0779ebSJerome Gaillard   size_t file_end_in_image = file_start_in_image + length;
163*ca0779ebSJerome Gaillard   if (stream_size < file_end_in_image) {
164*ca0779ebSJerome Gaillard     // Requested file is past the end of the image file.
165*ca0779ebSJerome Gaillard     return false;
166*ca0779ebSJerome Gaillard   }
167*ca0779ebSJerome Gaillard 
168*ca0779ebSJerome Gaillard   // Get the file's contents.
169*ca0779ebSJerome Gaillard   const DataRange file_range(file_start_in_image, file_end_in_image);
170*ca0779ebSJerome Gaillard   size_t file_range_size = file_range.GetLength();
171*ca0779ebSJerome Gaillard   // TODO(miraleung): Consider subclassing image_io/data_destination.h and
172*ca0779ebSJerome Gaillard   // transferring bytes directly into the string. TBD pending additional mime
173*ca0779ebSJerome Gaillard   // type getters.
174*ca0779ebSJerome Gaillard   input_jpeg_stream.seekg(file_range.GetBegin(), input_jpeg_stream.beg);
175*ca0779ebSJerome Gaillard   out_contents->resize(file_range_size);
176*ca0779ebSJerome Gaillard   input_jpeg_stream.read(&(*out_contents)[0], file_range_size);
177*ca0779ebSJerome Gaillard   return true;
178*ca0779ebSJerome Gaillard }
179*ca0779ebSJerome Gaillard 
180*ca0779ebSJerome Gaillard }  // namespace gcontainer
181*ca0779ebSJerome Gaillard }  // namespace image_io
182*ca0779ebSJerome Gaillard }  // namespace photos_editing_formats
183