summaryrefslogtreecommitdiff
path: root/src/jpeg/jpeg_image_extractor.cc
blob: 82f8fce9fb7d7a72fc6b7fa09e8459bcc601956e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include "image_io/jpeg/jpeg_image_extractor.h"

#include <sstream>

#include "image_io/base/data_range_tracking_destination.h"
#include "image_io/base/message_handler.h"
#include "image_io/extras/base64_decoder_data_destination.h"
#include "image_io/jpeg/jpeg_segment.h"
#include "image_io/jpeg/jpeg_xmp_data_extractor.h"

/// Set this macro to 1 for debug output.
#define PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_IMAGE_EXTRACTOR_DEBUG 0

namespace photos_editing_formats {
namespace image_io {

using std::vector;

namespace {

/// The optimim size to use for the DataSource::TransferData() function.
constexpr size_t kBestDataSize = 0x10000;

}  // namespace

bool JpegImageExtractor::ExtractAppleDepthImage(
    DataDestination* image_destination) {
  bool succeeded =
      ExtractImage(jpeg_info_.GetAppleDepthImageRange(), image_destination);
  return jpeg_info_.HasAppleDepth() && succeeded;
}

bool JpegImageExtractor::ExtractAppleMatteImage(
    DataDestination* image_destination) {
  bool succeeded =
      ExtractImage(jpeg_info_.GetAppleMatteImageRange(), image_destination);
  return jpeg_info_.HasAppleMatte() && succeeded;
}

bool JpegImageExtractor::ExtractImage(const DataRange& image_range,
                                      DataDestination* image_destination) {
  DataRangeTrackingDestination data_range_destination(image_destination);
  bool has_errors = false;
  data_range_destination.StartTransfer();
  if (image_range.IsValid()) {
    DataSource::TransferDataResult result = data_source_->TransferData(
        image_range, kBestDataSize, &data_range_destination);
    if (result == DataSource::kTransferDataError) {
      has_errors = true;
    } else if (result == DataSource::kTransferDataNone ||
               data_range_destination.HasDisjointTransferRanges() ||
               data_range_destination.GetTrackedDataRange() != image_range) {
      has_errors = true;
      MessageHandler::Get()->ReportMessage(Message::kPrematureEndOfDataError,
                                           "");
    }
  }
  data_range_destination.FinishTransfer();
  return !has_errors;
}

bool JpegImageExtractor::ExtractGDepthImage(
    DataDestination* image_destination) {
  return ExtractImage(JpegXmpInfo::kGDepthInfoType, image_destination);
}

bool JpegImageExtractor::ExtractGImageImage(
    DataDestination* image_destination) {
  return ExtractImage(JpegXmpInfo::kGImageInfoType, image_destination);
}

bool JpegImageExtractor::ExtractImage(JpegXmpInfo::Type xmp_info_type,
                                      DataDestination* image_destination) {
  bool has_errors = false;
  const bool has_image = jpeg_info_.HasImage(xmp_info_type);
  Base64DecoderDataDestination base64_decoder(image_destination);
  const vector<DataRange>& data_ranges =
      jpeg_info_.GetSegmentDataRanges(xmp_info_type);
  size_t data_ranges_count = data_ranges.size();
  JpegXmpDataExtractor xmp_data_extractor(xmp_info_type, data_ranges_count,
                                          &base64_decoder);
  xmp_data_extractor.StartTransfer();
  if (has_image) {
    for (size_t index = 0; index < data_ranges_count; ++index) {
      const DataRange& data_range = data_ranges[index];
      xmp_data_extractor.SetSegmentIndex(index);
#if PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_IMAGE_EXTRACTOR_DEBUG
      std::stringstream sstream;
      sstream << "Segment " << index << " from " << data_range.GetBegin()
              << " to " << data_range.GetEnd();
      MessageHandler::Get()->ReportMessage(Message::kStatus, sstream.str());
#endif  // PHOTOS_EDITING_FORMATS_IMAGE_IO_JPEG_JPEG_IMAGE_EXTRACTOR_DEBUG
      DataSource::TransferDataResult result = data_source_->TransferData(
          data_range, kBestDataSize, &xmp_data_extractor);
      if (result == DataSource::kTransferDataError) {
        has_errors = true;
        break;
      } else if (result == DataSource::kTransferDataNone) {
        has_errors = true;
        MessageHandler::Get()->ReportMessage(Message::kPrematureEndOfDataError,
                                             "");
      }
    }
  }
  xmp_data_extractor.FinishTransfer();
  return has_image && !has_errors;
}

}  // namespace image_io
}  // namespace photos_editing_formats