1 #include "image_io/jpeg/jpeg_image_extractor.h"
2
3 #include <sstream>
4
5 #include "image_io/base/data_range_tracking_destination.h"
6 #include "image_io/base/message_handler.h"
7 #include "image_io/extras/base64_decoder_data_destination.h"
8 #include "image_io/jpeg/jpeg_segment.h"
9 #include "image_io/jpeg/jpeg_xmp_data_extractor.h"
10
11 /// Set this macro to 1 for debug output.
12 #define PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_IMAGE_EXTRACTOR_DEBUG 0
13
14 namespace photos_editing_formats {
15 namespace image_io {
16
17 using std::vector;
18
19 namespace {
20
21 /// The optimim size to use for the DataSource::TransferData() function.
22 constexpr size_t kBestDataSize = 0x10000;
23
24 } // namespace
25
ExtractAppleDepthImage(DataDestination * image_destination)26 bool JpegImageExtractor::ExtractAppleDepthImage(
27 DataDestination* image_destination) {
28 bool succeeded =
29 ExtractImage(jpeg_info_.GetAppleDepthImageRange(), image_destination);
30 return jpeg_info_.HasAppleDepth() && succeeded;
31 }
32
ExtractAppleMatteImage(DataDestination * image_destination)33 bool JpegImageExtractor::ExtractAppleMatteImage(
34 DataDestination* image_destination) {
35 bool succeeded =
36 ExtractImage(jpeg_info_.GetAppleMatteImageRange(), image_destination);
37 return jpeg_info_.HasAppleMatte() && succeeded;
38 }
39
ExtractImage(const DataRange & image_range,DataDestination * image_destination)40 bool JpegImageExtractor::ExtractImage(const DataRange& image_range,
41 DataDestination* image_destination) {
42 DataRangeTrackingDestination data_range_destination(image_destination);
43 bool has_errors = false;
44 data_range_destination.StartTransfer();
45 if (image_range.IsValid()) {
46 DataSource::TransferDataResult result = data_source_->TransferData(
47 image_range, kBestDataSize, &data_range_destination);
48 if (result == DataSource::kTransferDataError) {
49 has_errors = true;
50 } else if (result == DataSource::kTransferDataNone ||
51 data_range_destination.HasDisjointTransferRanges() ||
52 data_range_destination.GetTrackedDataRange() != image_range) {
53 has_errors = true;
54 if (message_handler_) {
55 message_handler_->ReportMessage(Message::kPrematureEndOfDataError, "");
56 }
57 }
58 }
59 data_range_destination.FinishTransfer();
60 return !has_errors;
61 }
62
ExtractGDepthImage(DataDestination * image_destination)63 bool JpegImageExtractor::ExtractGDepthImage(
64 DataDestination* image_destination) {
65 return ExtractImage(JpegXmpInfo::kGDepthInfoType, image_destination);
66 }
67
ExtractGImageImage(DataDestination * image_destination)68 bool JpegImageExtractor::ExtractGImageImage(
69 DataDestination* image_destination) {
70 return ExtractImage(JpegXmpInfo::kGImageInfoType, image_destination);
71 }
72
ExtractImage(JpegXmpInfo::Type xmp_info_type,DataDestination * image_destination)73 bool JpegImageExtractor::ExtractImage(JpegXmpInfo::Type xmp_info_type,
74 DataDestination* image_destination) {
75 bool has_errors = false;
76 const bool has_image = jpeg_info_.HasImage(xmp_info_type);
77 Base64DecoderDataDestination base64_decoder(image_destination,
78 message_handler_);
79 const vector<DataRange>& data_ranges =
80 jpeg_info_.GetSegmentDataRanges(xmp_info_type);
81 size_t data_ranges_count = data_ranges.size();
82 JpegXmpDataExtractor xmp_data_extractor(xmp_info_type, data_ranges_count,
83 &base64_decoder, message_handler_);
84 xmp_data_extractor.StartTransfer();
85 if (has_image) {
86 for (size_t index = 0; index < data_ranges_count; ++index) {
87 const DataRange& data_range = data_ranges[index];
88 xmp_data_extractor.SetSegmentIndex(index);
89 #if PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_IMAGE_EXTRACTOR_DEBUG
90 std::stringstream sstream;
91 sstream << "Segment " << index << " from " << data_range.GetBegin()
92 << " to " << data_range.GetEnd();
93 MessageHandler::Get()->ReportMessage(Message::kStatus, sstream.str());
94 #endif // PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_IMAGE_EXTRACTOR_DEBUG
95 DataSource::TransferDataResult result = data_source_->TransferData(
96 data_range, kBestDataSize, &xmp_data_extractor);
97 if (result == DataSource::kTransferDataError) {
98 has_errors = true;
99 break;
100 } else if (result == DataSource::kTransferDataNone) {
101 has_errors = true;
102 if (message_handler_) {
103 message_handler_->ReportMessage(Message::kPrematureEndOfDataError,
104 "");
105 }
106 }
107 }
108 }
109 xmp_data_extractor.FinishTransfer();
110 return has_image && !has_errors;
111 }
112
113 } // namespace image_io
114 } // namespace photos_editing_formats
115