1cb93a386Sopenharmony_ci// Copyright 2015 Google Inc.
2cb93a386Sopenharmony_ci//
3cb93a386Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4cb93a386Sopenharmony_ci// you may not use this file except in compliance with the License.
5cb93a386Sopenharmony_ci// You may obtain a copy of the License at
6cb93a386Sopenharmony_ci//
7cb93a386Sopenharmony_ci//      http://www.apache.org/licenses/LICENSE-2.0
8cb93a386Sopenharmony_ci//
9cb93a386Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10cb93a386Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11cb93a386Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb93a386Sopenharmony_ci// See the License for the specific language governing permissions and
13cb93a386Sopenharmony_ci// limitations under the License.
14cb93a386Sopenharmony_ci//
15cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci#include "src/piex.h"
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ci#include <cstdint>
20cb93a386Sopenharmony_ci#include <limits>
21cb93a386Sopenharmony_ci#include <set>
22cb93a386Sopenharmony_ci#include <vector>
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci#include "src/binary_parse/range_checked_byte_ptr.h"
25cb93a386Sopenharmony_ci#include "src/image_type_recognition/image_type_recognition_lite.h"
26cb93a386Sopenharmony_ci#include "src/tiff_parser.h"
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_cinamespace piex {
29cb93a386Sopenharmony_cinamespace {
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ciusing binary_parse::RangeCheckedBytePtr;
32cb93a386Sopenharmony_ciusing image_type_recognition::RawImageTypes;
33cb93a386Sopenharmony_ciusing image_type_recognition::RecognizeRawImageTypeLite;
34cb93a386Sopenharmony_ciusing tiff_directory::Endian;
35cb93a386Sopenharmony_ciusing tiff_directory::TiffDirectory;
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ciconst std::uint32_t kRafOffsetToPreviewOffset = 84;
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_cibool GetDngInformation(const tiff_directory::TiffDirectory& tiff_directory,
40cb93a386Sopenharmony_ci                       std::uint32_t* width, std::uint32_t* height,
41cb93a386Sopenharmony_ci                       std::vector<std::uint32_t>* cfa_pattern_dim) {
42cb93a386Sopenharmony_ci  if (!GetFullDimension32(tiff_directory, width, height) || *width == 0 ||
43cb93a386Sopenharmony_ci      *height == 0) {
44cb93a386Sopenharmony_ci    return false;
45cb93a386Sopenharmony_ci  }
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci  if (!tiff_directory.Get(kTiffTagCfaPatternDim, cfa_pattern_dim) ||
48cb93a386Sopenharmony_ci      cfa_pattern_dim->size() != 2) {
49cb93a386Sopenharmony_ci    return false;
50cb93a386Sopenharmony_ci  }
51cb93a386Sopenharmony_ci  return true;
52cb93a386Sopenharmony_ci}
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_cibool GetDngInformation(const TagSet& extended_tags, StreamInterface* data,
55cb93a386Sopenharmony_ci                       std::uint32_t* width, std::uint32_t* height,
56cb93a386Sopenharmony_ci                       std::vector<std::uint32_t>* cfa_pattern_dim) {
57cb93a386Sopenharmony_ci  TagSet desired_tags = {kExifTagDefaultCropSize, kTiffTagCfaPatternDim,
58cb93a386Sopenharmony_ci                         kTiffTagExifIfd, kTiffTagSubFileType};
59cb93a386Sopenharmony_ci  desired_tags.insert(extended_tags.cbegin(), extended_tags.cend());
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci  TiffParser tiff_parser(data, 0 /* offset */);
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci  TiffContent tiff_content;
64cb93a386Sopenharmony_ci  if (!tiff_parser.Parse(desired_tags, 1, &tiff_content) ||
65cb93a386Sopenharmony_ci      tiff_content.tiff_directory.empty()) {
66cb93a386Sopenharmony_ci    return false;
67cb93a386Sopenharmony_ci  }
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci  // If IFD0 contains already the full dimensions we do not parse into the sub
70cb93a386Sopenharmony_ci  // IFD.
71cb93a386Sopenharmony_ci  const TiffDirectory& tiff_directory = tiff_content.tiff_directory[0];
72cb93a386Sopenharmony_ci  if (tiff_directory.GetSubDirectories().empty()) {
73cb93a386Sopenharmony_ci    return GetDngInformation(tiff_directory, width, height, cfa_pattern_dim);
74cb93a386Sopenharmony_ci  } else {
75cb93a386Sopenharmony_ci    return GetDngInformation(tiff_directory.GetSubDirectories()[0], width,
76cb93a386Sopenharmony_ci                             height, cfa_pattern_dim);
77cb93a386Sopenharmony_ci  }
78cb93a386Sopenharmony_ci}
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_cibool GetPreviewData(const TagSet& extended_tags,
81cb93a386Sopenharmony_ci                    const std::uint32_t tiff_offset,
82cb93a386Sopenharmony_ci                    const std::uint32_t number_of_ifds, StreamInterface* stream,
83cb93a386Sopenharmony_ci                    TiffContent* tiff_content,
84cb93a386Sopenharmony_ci                    PreviewImageData* preview_image_data) {
85cb93a386Sopenharmony_ci  TagSet desired_tags = {
86cb93a386Sopenharmony_ci      kExifTagColorSpace, kExifTagDateTimeOriginal, kExifTagExposureTime,
87cb93a386Sopenharmony_ci      kExifTagFnumber,    kExifTagFocalLength,      kExifTagGps,
88cb93a386Sopenharmony_ci      kExifTagIsoSpeed,   kTiffTagCompression,      kTiffTagDateTime,
89cb93a386Sopenharmony_ci      kTiffTagExifIfd,    kTiffTagCfaPatternDim,    kTiffTagMake,
90cb93a386Sopenharmony_ci      kTiffTagModel,      kTiffTagOrientation,      kTiffTagPhotometric};
91cb93a386Sopenharmony_ci  desired_tags.insert(extended_tags.cbegin(), extended_tags.cend());
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci  TiffParser tiff_parser(stream, tiff_offset);
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci  if (!tiff_parser.Parse(desired_tags, number_of_ifds, tiff_content)) {
96cb93a386Sopenharmony_ci    return false;
97cb93a386Sopenharmony_ci  }
98cb93a386Sopenharmony_ci  if (tiff_content->tiff_directory.empty()) {
99cb93a386Sopenharmony_ci    // Returns false if the stream does not contain any TIFF structure.
100cb93a386Sopenharmony_ci    return false;
101cb93a386Sopenharmony_ci  }
102cb93a386Sopenharmony_ci  return tiff_parser.GetPreviewImageData(*tiff_content, preview_image_data);
103cb93a386Sopenharmony_ci}
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_cibool GetPreviewData(const TagSet& extended_tags,
106cb93a386Sopenharmony_ci                    const std::uint32_t number_of_ifds, StreamInterface* stream,
107cb93a386Sopenharmony_ci                    PreviewImageData* preview_image_data) {
108cb93a386Sopenharmony_ci  const std::uint32_t kTiffOffset = 0;
109cb93a386Sopenharmony_ci  TiffContent tiff_content;
110cb93a386Sopenharmony_ci  return GetPreviewData(extended_tags, kTiffOffset, number_of_ifds, stream,
111cb93a386Sopenharmony_ci                        &tiff_content, preview_image_data);
112cb93a386Sopenharmony_ci}
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_cibool GetExifData(const std::uint32_t exif_offset, StreamInterface* stream,
115cb93a386Sopenharmony_ci                 PreviewImageData* preview_image_data) {
116cb93a386Sopenharmony_ci  const TagSet kExtendedTags = {kTiffTagJpegByteCount, kTiffTagJpegOffset};
117cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 2;
118cb93a386Sopenharmony_ci  TiffContent tiff_content;
119cb93a386Sopenharmony_ci  return GetPreviewData(kExtendedTags, exif_offset, kNumberOfIfds, stream,
120cb93a386Sopenharmony_ci                        &tiff_content, preview_image_data);
121cb93a386Sopenharmony_ci}
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci// Reads the jpeg compressed thumbnail information.
124cb93a386Sopenharmony_civoid GetThumbnailOffsetAndLength(const TagSet& extended_tags,
125cb93a386Sopenharmony_ci                                 StreamInterface* stream,
126cb93a386Sopenharmony_ci                                 PreviewImageData* preview_image_data) {
127cb93a386Sopenharmony_ci  TagSet desired_tags = {kTiffTagJpegByteCount, kTiffTagJpegOffset};
128cb93a386Sopenharmony_ci  desired_tags.insert(extended_tags.cbegin(), extended_tags.cend());
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 2;
131cb93a386Sopenharmony_ci  PreviewImageData thumbnail_data;
132cb93a386Sopenharmony_ci  if (GetPreviewData(desired_tags, kNumberOfIfds, stream, &thumbnail_data)) {
133cb93a386Sopenharmony_ci    preview_image_data->thumbnail = thumbnail_data.thumbnail;
134cb93a386Sopenharmony_ci  }
135cb93a386Sopenharmony_ci}
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_cibool GetExifIfd(const Endian endian, StreamInterface* stream,
138cb93a386Sopenharmony_ci                TiffDirectory* exif_ifd) {
139cb93a386Sopenharmony_ci  const std::uint32_t kTiffOffset = 0;
140cb93a386Sopenharmony_ci  std::uint32_t offset_to_ifd;
141cb93a386Sopenharmony_ci  if (!Get32u(stream, sizeof(offset_to_ifd), endian, &offset_to_ifd)) {
142cb93a386Sopenharmony_ci    return false;
143cb93a386Sopenharmony_ci  }
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci  std::uint32_t next_ifd_offset;
146cb93a386Sopenharmony_ci  TiffDirectory tiff_ifd(endian);
147cb93a386Sopenharmony_ci  if (!ParseDirectory(kTiffOffset, offset_to_ifd, endian, {kTiffTagExifIfd},
148cb93a386Sopenharmony_ci                      stream, &tiff_ifd, &next_ifd_offset)) {
149cb93a386Sopenharmony_ci    return false;
150cb93a386Sopenharmony_ci  }
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci  std::uint32_t exif_offset;
153cb93a386Sopenharmony_ci  if (tiff_ifd.Get(kTiffTagExifIfd, &exif_offset)) {
154cb93a386Sopenharmony_ci    return ParseDirectory(kTiffOffset, exif_offset, endian,
155cb93a386Sopenharmony_ci                          {kExifTagMakernotes}, stream, exif_ifd,
156cb93a386Sopenharmony_ci                          &next_ifd_offset);
157cb93a386Sopenharmony_ci  }
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci  return true;
160cb93a386Sopenharmony_ci}
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_cibool GetMakernoteIfd(const TiffDirectory& exif_ifd, const Endian endian,
163cb93a386Sopenharmony_ci                     const std::uint32_t skip_offset, StreamInterface* stream,
164cb93a386Sopenharmony_ci                     std::uint32_t* makernote_offset,
165cb93a386Sopenharmony_ci                     TiffDirectory* makernote_ifd) {
166cb93a386Sopenharmony_ci  std::uint32_t makernote_length;
167cb93a386Sopenharmony_ci  if (!exif_ifd.GetOffsetAndLength(kExifTagMakernotes,
168cb93a386Sopenharmony_ci                                   tiff_directory::TIFF_TYPE_UNDEFINED,
169cb93a386Sopenharmony_ci                                   makernote_offset, &makernote_length)) {
170cb93a386Sopenharmony_ci    return false;
171cb93a386Sopenharmony_ci  }
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci  std::uint32_t next_ifd_offset;
174cb93a386Sopenharmony_ci  return ParseDirectory(*makernote_offset, *makernote_offset + skip_offset,
175cb93a386Sopenharmony_ci                        endian, {kTiffTagImageWidth, kOlymTagCameraSettings,
176cb93a386Sopenharmony_ci                                 kOlymTagRawProcessing, kPentaxTagColorSpace},
177cb93a386Sopenharmony_ci                        stream, makernote_ifd, &next_ifd_offset);
178cb93a386Sopenharmony_ci}
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_cibool GetCameraSettingsIfd(const TiffDirectory& makernote_ifd,
181cb93a386Sopenharmony_ci                          const std::uint32_t makernote_offset,
182cb93a386Sopenharmony_ci                          const Endian endian, StreamInterface* stream,
183cb93a386Sopenharmony_ci                          TiffDirectory* camera_settings_ifd) {
184cb93a386Sopenharmony_ci  std::uint32_t camera_settings_offset;
185cb93a386Sopenharmony_ci  std::uint32_t camera_settings_length;
186cb93a386Sopenharmony_ci  if (!makernote_ifd.GetOffsetAndLength(
187cb93a386Sopenharmony_ci          kOlymTagCameraSettings, tiff_directory::TIFF_IFD,
188cb93a386Sopenharmony_ci          &camera_settings_offset, &camera_settings_length)) {
189cb93a386Sopenharmony_ci    return false;
190cb93a386Sopenharmony_ci  }
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci  std::uint32_t next_ifd_offset;
193cb93a386Sopenharmony_ci  if (!Get32u(stream, camera_settings_offset, endian,
194cb93a386Sopenharmony_ci              &camera_settings_offset)) {
195cb93a386Sopenharmony_ci    return false;
196cb93a386Sopenharmony_ci  }
197cb93a386Sopenharmony_ci  return ParseDirectory(makernote_offset,
198cb93a386Sopenharmony_ci                        makernote_offset + camera_settings_offset, endian,
199cb93a386Sopenharmony_ci                        {kTiffTagBitsPerSample, kTiffTagImageLength}, stream,
200cb93a386Sopenharmony_ci                        camera_settings_ifd, &next_ifd_offset);
201cb93a386Sopenharmony_ci}
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_cibool GetRawProcessingIfd(const TagSet& desired_tags,
204cb93a386Sopenharmony_ci                         const TiffDirectory& makernote_ifd,
205cb93a386Sopenharmony_ci                         const std::uint32_t makernote_offset,
206cb93a386Sopenharmony_ci                         const Endian endian, StreamInterface* stream,
207cb93a386Sopenharmony_ci                         TiffDirectory* raw_processing_ifd) {
208cb93a386Sopenharmony_ci  std::uint32_t raw_processing_offset;
209cb93a386Sopenharmony_ci  std::uint32_t raw_processing_length;
210cb93a386Sopenharmony_ci  if (!makernote_ifd.GetOffsetAndLength(
211cb93a386Sopenharmony_ci          kOlymTagRawProcessing, tiff_directory::TIFF_IFD,
212cb93a386Sopenharmony_ci          &raw_processing_offset, &raw_processing_length)) {
213cb93a386Sopenharmony_ci    return false;
214cb93a386Sopenharmony_ci  }
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci  std::uint32_t next_ifd_offset;
217cb93a386Sopenharmony_ci  if (!Get32u(stream, raw_processing_offset, endian, &raw_processing_offset)) {
218cb93a386Sopenharmony_ci    return false;
219cb93a386Sopenharmony_ci  }
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_ci  return ParseDirectory(
222cb93a386Sopenharmony_ci      makernote_offset, makernote_offset + raw_processing_offset, endian,
223cb93a386Sopenharmony_ci      desired_tags, stream, raw_processing_ifd, &next_ifd_offset);
224cb93a386Sopenharmony_ci}
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci// Retrieves the preview image offset and length from the camera settings and
227cb93a386Sopenharmony_ci// the 'full_width' and 'full_height' from the raw processing ifd in 'stream'.
228cb93a386Sopenharmony_ci// Returns false if anything is wrong.
229cb93a386Sopenharmony_cibool GetOlympusPreviewImage(StreamInterface* stream,
230cb93a386Sopenharmony_ci                            PreviewImageData* preview_image_data) {
231cb93a386Sopenharmony_ci  Endian endian;
232cb93a386Sopenharmony_ci  if (!GetEndianness(0 /* tiff offset */, stream, &endian)) {
233cb93a386Sopenharmony_ci    return false;
234cb93a386Sopenharmony_ci  }
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci  TiffDirectory exif_ifd(endian);
237cb93a386Sopenharmony_ci  if (!GetExifIfd(endian, stream, &exif_ifd)) {
238cb93a386Sopenharmony_ci    return false;
239cb93a386Sopenharmony_ci  }
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_ci  std::uint32_t makernote_offset;
242cb93a386Sopenharmony_ci  TiffDirectory makernote_ifd(endian);
243cb93a386Sopenharmony_ci  const std::uint32_t kSkipMakernoteStart = 12;
244cb93a386Sopenharmony_ci  if (!GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream,
245cb93a386Sopenharmony_ci                       &makernote_offset, &makernote_ifd)) {
246cb93a386Sopenharmony_ci    return false;
247cb93a386Sopenharmony_ci  }
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ci  const std::uint32_t kThumbnailTag = 0x0100;
250cb93a386Sopenharmony_ci  if (makernote_ifd.Has(kThumbnailTag)) {
251cb93a386Sopenharmony_ci    if (!makernote_ifd.GetOffsetAndLength(
252cb93a386Sopenharmony_ci            kThumbnailTag, tiff_directory::TIFF_TYPE_UNDEFINED,
253cb93a386Sopenharmony_ci            &preview_image_data->thumbnail.offset,
254cb93a386Sopenharmony_ci            &preview_image_data->thumbnail.length)) {
255cb93a386Sopenharmony_ci      return false;
256cb93a386Sopenharmony_ci    }
257cb93a386Sopenharmony_ci  }
258cb93a386Sopenharmony_ci
259cb93a386Sopenharmony_ci  TiffDirectory camera_settings_ifd(endian);
260cb93a386Sopenharmony_ci  if (!GetCameraSettingsIfd(makernote_ifd, makernote_offset, endian, stream,
261cb93a386Sopenharmony_ci                            &camera_settings_ifd)) {
262cb93a386Sopenharmony_ci    return false;
263cb93a386Sopenharmony_ci  }
264cb93a386Sopenharmony_ci
265cb93a386Sopenharmony_ci  const std::uint32_t kPreviewOffset = 0x0101;
266cb93a386Sopenharmony_ci  const std::uint32_t kPreviewLength = 0x0102;
267cb93a386Sopenharmony_ci  if (!camera_settings_ifd.Has(kPreviewOffset) ||
268cb93a386Sopenharmony_ci      !camera_settings_ifd.Has(kPreviewLength)) {
269cb93a386Sopenharmony_ci    return false;
270cb93a386Sopenharmony_ci  }
271cb93a386Sopenharmony_ci
272cb93a386Sopenharmony_ci  camera_settings_ifd.Get(kPreviewOffset, &preview_image_data->preview.offset);
273cb93a386Sopenharmony_ci  preview_image_data->preview.offset += makernote_offset;
274cb93a386Sopenharmony_ci  camera_settings_ifd.Get(kPreviewLength, &preview_image_data->preview.length);
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ci  // Get the crop size from the raw processing ifd.
277cb93a386Sopenharmony_ci  TiffDirectory raw_processing_ifd(endian);
278cb93a386Sopenharmony_ci  if (!GetRawProcessingIfd({kOlymTagAspectFrame}, makernote_ifd,
279cb93a386Sopenharmony_ci                           makernote_offset, endian, stream,
280cb93a386Sopenharmony_ci                           &raw_processing_ifd)) {
281cb93a386Sopenharmony_ci    return false;
282cb93a386Sopenharmony_ci  }
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci  if (raw_processing_ifd.Has(kOlymTagAspectFrame)) {
285cb93a386Sopenharmony_ci    std::vector<std::uint32_t> aspect_frame(4);
286cb93a386Sopenharmony_ci    if (raw_processing_ifd.Get(kOlymTagAspectFrame, &aspect_frame) &&
287cb93a386Sopenharmony_ci        aspect_frame[2] > aspect_frame[0] &&
288cb93a386Sopenharmony_ci        aspect_frame[3] > aspect_frame[1]) {
289cb93a386Sopenharmony_ci      preview_image_data->full_width = aspect_frame[2] - aspect_frame[0] + 1;
290cb93a386Sopenharmony_ci      preview_image_data->full_height = aspect_frame[3] - aspect_frame[1] + 1;
291cb93a386Sopenharmony_ci      if (preview_image_data->full_width < preview_image_data->full_height) {
292cb93a386Sopenharmony_ci        std::swap(preview_image_data->full_width,
293cb93a386Sopenharmony_ci                  preview_image_data->full_height);
294cb93a386Sopenharmony_ci      }
295cb93a386Sopenharmony_ci    }
296cb93a386Sopenharmony_ci  }
297cb93a386Sopenharmony_ci
298cb93a386Sopenharmony_ci  return true;
299cb93a386Sopenharmony_ci}
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_cibool PefGetColorSpace(StreamInterface* stream,
302cb93a386Sopenharmony_ci                      PreviewImageData* preview_image_data) {
303cb93a386Sopenharmony_ci  Endian endian;
304cb93a386Sopenharmony_ci  if (!GetEndianness(0 /* tiff offset */, stream, &endian)) {
305cb93a386Sopenharmony_ci    return false;
306cb93a386Sopenharmony_ci  }
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci  TiffDirectory exif_ifd(endian);
309cb93a386Sopenharmony_ci  if (!GetExifIfd(endian, stream, &exif_ifd)) {
310cb93a386Sopenharmony_ci    return false;
311cb93a386Sopenharmony_ci  }
312cb93a386Sopenharmony_ci
313cb93a386Sopenharmony_ci  std::uint32_t makernote_offset;
314cb93a386Sopenharmony_ci  TiffDirectory makernote_ifd(endian);
315cb93a386Sopenharmony_ci  const std::uint32_t kSkipMakernoteStart = 6;
316cb93a386Sopenharmony_ci  if (!GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream,
317cb93a386Sopenharmony_ci                       &makernote_offset, &makernote_ifd)) {
318cb93a386Sopenharmony_ci    return false;
319cb93a386Sopenharmony_ci  }
320cb93a386Sopenharmony_ci  if (makernote_ifd.Has(kPentaxTagColorSpace)) {
321cb93a386Sopenharmony_ci    std::uint32_t color_space;
322cb93a386Sopenharmony_ci    if (!makernote_ifd.Get(kPentaxTagColorSpace, &color_space)) {
323cb93a386Sopenharmony_ci      return false;
324cb93a386Sopenharmony_ci    }
325cb93a386Sopenharmony_ci    preview_image_data->color_space = color_space == 0
326cb93a386Sopenharmony_ci                                          ? PreviewImageData::kSrgb
327cb93a386Sopenharmony_ci                                          : PreviewImageData::kAdobeRgb;
328cb93a386Sopenharmony_ci  }
329cb93a386Sopenharmony_ci  return true;
330cb93a386Sopenharmony_ci}
331cb93a386Sopenharmony_ci
332cb93a386Sopenharmony_cibool RafGetOrientation(StreamInterface* stream, std::uint32_t* orientation) {
333cb93a386Sopenharmony_ci  // Parse the Fuji RAW header to get the offset and length of the preview
334cb93a386Sopenharmony_ci  // image, which contains the Exif information.
335cb93a386Sopenharmony_ci  const Endian endian = tiff_directory::kBigEndian;
336cb93a386Sopenharmony_ci  std::uint32_t preview_offset = 0;
337cb93a386Sopenharmony_ci  if (!Get32u(stream, kRafOffsetToPreviewOffset, endian, &preview_offset)) {
338cb93a386Sopenharmony_ci    return false;
339cb93a386Sopenharmony_ci  }
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci  const std::uint32_t exif_offset = preview_offset + 12;
342cb93a386Sopenharmony_ci  return GetExifOrientation(stream, exif_offset, orientation);
343cb93a386Sopenharmony_ci}
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_ci// Parses the Fuji Cfa header for the image width and height.
346cb93a386Sopenharmony_cibool RafGetDimension(StreamInterface* stream, std::uint32_t* width,
347cb93a386Sopenharmony_ci                     std::uint32_t* height) {
348cb93a386Sopenharmony_ci  const Endian endian = tiff_directory::kBigEndian;
349cb93a386Sopenharmony_ci  std::uint32_t cfa_header_index = 0;  // actual position in the cfa header.
350cb93a386Sopenharmony_ci  std::uint32_t cfa_header_entries = 0;
351cb93a386Sopenharmony_ci  if (!Get32u(stream, 92 /* cfa header offset */, endian, &cfa_header_index) ||
352cb93a386Sopenharmony_ci      !Get32u(stream, cfa_header_index, endian, &cfa_header_entries)) {
353cb93a386Sopenharmony_ci    return false;
354cb93a386Sopenharmony_ci  }
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci  // Add 4 to point to the actual read position in the cfa header.
357cb93a386Sopenharmony_ci  cfa_header_index += 4;
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_ci  for (std::uint32_t i = 0; i < cfa_header_entries; ++i) {
360cb93a386Sopenharmony_ci    std::uint16_t id = 0;
361cb93a386Sopenharmony_ci    std::uint16_t length = 0;
362cb93a386Sopenharmony_ci    if (!Get16u(stream, cfa_header_index, endian, &id) ||
363cb93a386Sopenharmony_ci        !Get16u(stream, cfa_header_index + 2, endian, &length)) {
364cb93a386Sopenharmony_ci      return false;
365cb93a386Sopenharmony_ci    }
366cb93a386Sopenharmony_ci
367cb93a386Sopenharmony_ci    std::uint16_t tmp_width = 0;
368cb93a386Sopenharmony_ci    std::uint16_t tmp_height = 0;
369cb93a386Sopenharmony_ci    if (id == 0x0111 /* tags the crop dimensions */ &&
370cb93a386Sopenharmony_ci        Get16u(stream, cfa_header_index + 4, endian, &tmp_height) &&
371cb93a386Sopenharmony_ci        Get16u(stream, cfa_header_index + 6, endian, &tmp_width)) {
372cb93a386Sopenharmony_ci      *width = tmp_width;
373cb93a386Sopenharmony_ci      *height = tmp_height;
374cb93a386Sopenharmony_ci      return true;
375cb93a386Sopenharmony_ci    }
376cb93a386Sopenharmony_ci    cfa_header_index += 4u + length;
377cb93a386Sopenharmony_ci  }
378cb93a386Sopenharmony_ci  return false;
379cb93a386Sopenharmony_ci}
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ciError ArwGetPreviewData(StreamInterface* stream,
382cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
383cb93a386Sopenharmony_ci  const TagSet extended_tags = {kExifTagHeight, kExifTagWidth,
384cb93a386Sopenharmony_ci                                kTiffTagJpegByteCount, kTiffTagJpegOffset,
385cb93a386Sopenharmony_ci                                kTiffTagSubIfd};
386cb93a386Sopenharmony_ci
387cb93a386Sopenharmony_ci  GetThumbnailOffsetAndLength(TagSet(), stream, preview_image_data);
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 1;
390cb93a386Sopenharmony_ci  if (GetPreviewData(extended_tags, kNumberOfIfds, stream,
391cb93a386Sopenharmony_ci                     preview_image_data)) {
392cb93a386Sopenharmony_ci    return kOk;
393cb93a386Sopenharmony_ci  }
394cb93a386Sopenharmony_ci  return kFail;
395cb93a386Sopenharmony_ci}
396cb93a386Sopenharmony_ci
397cb93a386Sopenharmony_ciError Cr2GetPreviewData(StreamInterface* stream,
398cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
399cb93a386Sopenharmony_ci  const TagSet extended_tags = {kExifTagHeight, kExifTagWidth,
400cb93a386Sopenharmony_ci                                kTiffTagStripByteCounts, kTiffTagStripOffsets};
401cb93a386Sopenharmony_ci
402cb93a386Sopenharmony_ci  GetThumbnailOffsetAndLength(TagSet(), stream, preview_image_data);
403cb93a386Sopenharmony_ci
404cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 1;
405cb93a386Sopenharmony_ci  if (GetPreviewData(extended_tags, kNumberOfIfds, stream,
406cb93a386Sopenharmony_ci                     preview_image_data)) {
407cb93a386Sopenharmony_ci    return kOk;
408cb93a386Sopenharmony_ci  }
409cb93a386Sopenharmony_ci  return kFail;
410cb93a386Sopenharmony_ci}
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ciError DngGetPreviewData(StreamInterface* stream,
413cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
414cb93a386Sopenharmony_ci  // Some thumbnails from DngCreator are larger than the specified 256 pixel.
415cb93a386Sopenharmony_ci  const int kDngThumbnailMaxDimension = 512;
416cb93a386Sopenharmony_ci
417cb93a386Sopenharmony_ci  const TagSet extended_tags = {
418cb93a386Sopenharmony_ci      kExifTagDefaultCropSize, kTiffTagImageWidth,   kTiffTagImageLength,
419cb93a386Sopenharmony_ci      kTiffTagStripByteCounts, kTiffTagStripOffsets, kTiffTagSubIfd};
420cb93a386Sopenharmony_ci
421cb93a386Sopenharmony_ci  TiffContent tiff_content;
422cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 3;
423cb93a386Sopenharmony_ci  if (!GetPreviewData(extended_tags, 0, kNumberOfIfds, stream, &tiff_content,
424cb93a386Sopenharmony_ci                      preview_image_data)) {
425cb93a386Sopenharmony_ci    return kFail;
426cb93a386Sopenharmony_ci  }
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_ci  const TiffDirectory& tiff_directory = tiff_content.tiff_directory[0];
429cb93a386Sopenharmony_ci
430cb93a386Sopenharmony_ci  if (!GetFullCropDimension(tiff_directory, &preview_image_data->full_width,
431cb93a386Sopenharmony_ci                            &preview_image_data->full_height)) {
432cb93a386Sopenharmony_ci    return kFail;
433cb93a386Sopenharmony_ci  }
434cb93a386Sopenharmony_ci
435cb93a386Sopenharmony_ci  // Find the jpeg compressed thumbnail and preview image.
436cb93a386Sopenharmony_ci  Image preview;
437cb93a386Sopenharmony_ci  Image thumbnail;
438cb93a386Sopenharmony_ci
439cb93a386Sopenharmony_ci  // Search for images in IFD0
440cb93a386Sopenharmony_ci  Image temp_image;
441cb93a386Sopenharmony_ci  if (GetImageData(tiff_directory, stream, &temp_image)) {
442cb93a386Sopenharmony_ci    if (IsThumbnail(temp_image, kDngThumbnailMaxDimension)) {
443cb93a386Sopenharmony_ci      thumbnail = temp_image;
444cb93a386Sopenharmony_ci    } else if (temp_image.format == Image::kJpegCompressed) {
445cb93a386Sopenharmony_ci      preview = temp_image;
446cb93a386Sopenharmony_ci    }
447cb93a386Sopenharmony_ci  }
448cb93a386Sopenharmony_ci
449cb93a386Sopenharmony_ci  // Search for images in other IFDs
450cb93a386Sopenharmony_ci  for (const auto& ifd : tiff_directory.GetSubDirectories()) {
451cb93a386Sopenharmony_ci    if (GetImageData(ifd, stream, &temp_image)) {
452cb93a386Sopenharmony_ci      // Try to find the largest thumbnail/preview.
453cb93a386Sopenharmony_ci      if (IsThumbnail(temp_image, kDngThumbnailMaxDimension)) {
454cb93a386Sopenharmony_ci        if (temp_image > thumbnail) {
455cb93a386Sopenharmony_ci          thumbnail = temp_image;
456cb93a386Sopenharmony_ci        }
457cb93a386Sopenharmony_ci      } else {
458cb93a386Sopenharmony_ci        if (temp_image > preview &&
459cb93a386Sopenharmony_ci            temp_image.format == Image::kJpegCompressed) {
460cb93a386Sopenharmony_ci          preview = temp_image;
461cb93a386Sopenharmony_ci        }
462cb93a386Sopenharmony_ci      }
463cb93a386Sopenharmony_ci    }
464cb93a386Sopenharmony_ci  }
465cb93a386Sopenharmony_ci  preview_image_data->preview = preview;
466cb93a386Sopenharmony_ci  preview_image_data->thumbnail = thumbnail;
467cb93a386Sopenharmony_ci
468cb93a386Sopenharmony_ci  return kOk;
469cb93a386Sopenharmony_ci}
470cb93a386Sopenharmony_ci
471cb93a386Sopenharmony_ciError NefGetPreviewData(StreamInterface* stream,
472cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
473cb93a386Sopenharmony_ci  const TagSet extended_tags = {kTiffTagImageWidth,      kTiffTagImageLength,
474cb93a386Sopenharmony_ci                                kTiffTagJpegByteCount,   kTiffTagJpegOffset,
475cb93a386Sopenharmony_ci                                kTiffTagStripByteCounts, kTiffTagStripOffsets,
476cb93a386Sopenharmony_ci                                kTiffTagSubIfd};
477cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 2;
478cb93a386Sopenharmony_ci  if (!GetPreviewData(extended_tags, kNumberOfIfds, stream,
479cb93a386Sopenharmony_ci                      preview_image_data)) {
480cb93a386Sopenharmony_ci    return kFail;
481cb93a386Sopenharmony_ci  }
482cb93a386Sopenharmony_ci
483cb93a386Sopenharmony_ci  if (preview_image_data->thumbnail.length == 0) {
484cb93a386Sopenharmony_ci    PreviewImageData thumbnail_data;
485cb93a386Sopenharmony_ci    GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data);
486cb93a386Sopenharmony_ci    preview_image_data->thumbnail = thumbnail_data.thumbnail;
487cb93a386Sopenharmony_ci  }
488cb93a386Sopenharmony_ci
489cb93a386Sopenharmony_ci  // The Nikon RAW data provides the dimensions of the sensor image, which are
490cb93a386Sopenharmony_ci  // slightly larger than the dimensions of the preview image. In order to
491cb93a386Sopenharmony_ci  // determine the correct full width and height of the image, the preview image
492cb93a386Sopenharmony_ci  // size needs to be taken into account. Based on experiments the preview image
493cb93a386Sopenharmony_ci  // dimensions must be at least 90% of the sensor image dimensions to let it be
494cb93a386Sopenharmony_ci  // a full size preview image.
495cb93a386Sopenharmony_ci  if (preview_image_data->preview.length > 0) {  // when preview image exists
496cb93a386Sopenharmony_ci    const float kEpsilon = 0.9f;
497cb93a386Sopenharmony_ci
498cb93a386Sopenharmony_ci    std::uint16_t width;
499cb93a386Sopenharmony_ci    std::uint16_t height;
500cb93a386Sopenharmony_ci    if (!GetJpegDimensions(preview_image_data->preview.offset, stream, &width,
501cb93a386Sopenharmony_ci                           &height) ||
502cb93a386Sopenharmony_ci        preview_image_data->full_width == 0 ||
503cb93a386Sopenharmony_ci        preview_image_data->full_height == 0) {
504cb93a386Sopenharmony_ci      return kUnsupported;
505cb93a386Sopenharmony_ci    }
506cb93a386Sopenharmony_ci
507cb93a386Sopenharmony_ci    if (static_cast<float>(width) /
508cb93a386Sopenharmony_ci                static_cast<float>(preview_image_data->full_width) >
509cb93a386Sopenharmony_ci            kEpsilon ||
510cb93a386Sopenharmony_ci        static_cast<float>(height) /
511cb93a386Sopenharmony_ci                static_cast<float>(preview_image_data->full_height) >
512cb93a386Sopenharmony_ci            kEpsilon) {
513cb93a386Sopenharmony_ci      preview_image_data->full_width = width;
514cb93a386Sopenharmony_ci      preview_image_data->full_height = height;
515cb93a386Sopenharmony_ci    }
516cb93a386Sopenharmony_ci  }
517cb93a386Sopenharmony_ci  return kOk;
518cb93a386Sopenharmony_ci}
519cb93a386Sopenharmony_ci
520cb93a386Sopenharmony_ciError OrfGetPreviewData(StreamInterface* stream,
521cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
522cb93a386Sopenharmony_ci  if (!GetExifData(0, stream, preview_image_data)) {
523cb93a386Sopenharmony_ci    return kFail;
524cb93a386Sopenharmony_ci  }
525cb93a386Sopenharmony_ci  // Omit errors, because some images do not contain any preview data.
526cb93a386Sopenharmony_ci  GetOlympusPreviewImage(stream, preview_image_data);
527cb93a386Sopenharmony_ci  return kOk;
528cb93a386Sopenharmony_ci}
529cb93a386Sopenharmony_ci
530cb93a386Sopenharmony_ciError PefGetPreviewData(StreamInterface* stream,
531cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
532cb93a386Sopenharmony_ci  const TagSet extended_tags = {kTiffTagImageWidth, kTiffTagImageLength,
533cb93a386Sopenharmony_ci                                kTiffTagJpegByteCount, kTiffTagJpegOffset,
534cb93a386Sopenharmony_ci                                kTiffTagSubIfd};
535cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 3;
536cb93a386Sopenharmony_ci  if (!GetPreviewData(extended_tags, kNumberOfIfds, stream,
537cb93a386Sopenharmony_ci                      preview_image_data) ||
538cb93a386Sopenharmony_ci      !PefGetColorSpace(stream, preview_image_data)) {
539cb93a386Sopenharmony_ci    return kFail;
540cb93a386Sopenharmony_ci  }
541cb93a386Sopenharmony_ci
542cb93a386Sopenharmony_ci  PreviewImageData thumbnail_data;
543cb93a386Sopenharmony_ci  GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data);
544cb93a386Sopenharmony_ci  preview_image_data->thumbnail = thumbnail_data.thumbnail;
545cb93a386Sopenharmony_ci
546cb93a386Sopenharmony_ci  return kOk;
547cb93a386Sopenharmony_ci}
548cb93a386Sopenharmony_ci
549cb93a386Sopenharmony_ciError RafGetPreviewData(StreamInterface* stream,
550cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
551cb93a386Sopenharmony_ci  // Parse the Fuji RAW header to get the offset and length of the preview
552cb93a386Sopenharmony_ci  // image, which contains the Exif information.
553cb93a386Sopenharmony_ci  const Endian endian = tiff_directory::kBigEndian;
554cb93a386Sopenharmony_ci  std::uint32_t preview_offset = 0;
555cb93a386Sopenharmony_ci  std::uint32_t preview_length = 0;
556cb93a386Sopenharmony_ci  if (!Get32u(stream, kRafOffsetToPreviewOffset, endian, &preview_offset) ||
557cb93a386Sopenharmony_ci      !Get32u(stream, kRafOffsetToPreviewOffset + 4, endian, &preview_length)) {
558cb93a386Sopenharmony_ci    return kFail;
559cb93a386Sopenharmony_ci  }
560cb93a386Sopenharmony_ci
561cb93a386Sopenharmony_ci  if (!RafGetDimension(stream, &preview_image_data->full_width,
562cb93a386Sopenharmony_ci                       &preview_image_data->full_height)) {
563cb93a386Sopenharmony_ci    return kFail;
564cb93a386Sopenharmony_ci  }
565cb93a386Sopenharmony_ci
566cb93a386Sopenharmony_ci  if (preview_length > 0) {  // when preview image exists
567cb93a386Sopenharmony_ci    // Parse the Exif information from the preview image.
568cb93a386Sopenharmony_ci    const std::uint32_t exif_offset = preview_offset + 12;
569cb93a386Sopenharmony_ci    if (!GetExifData(exif_offset, stream, preview_image_data)) {
570cb93a386Sopenharmony_ci      return kFail;
571cb93a386Sopenharmony_ci    }
572cb93a386Sopenharmony_ci  }
573cb93a386Sopenharmony_ci
574cb93a386Sopenharmony_ci  // Merge the Exif data with the RAW data to form the preview_image_data.
575cb93a386Sopenharmony_ci  preview_image_data->thumbnail.offset += 160;  // Skip the cfa header.
576cb93a386Sopenharmony_ci  preview_image_data->preview.offset = preview_offset;
577cb93a386Sopenharmony_ci  preview_image_data->preview.length = preview_length;
578cb93a386Sopenharmony_ci  return kOk;
579cb93a386Sopenharmony_ci}
580cb93a386Sopenharmony_ci
581cb93a386Sopenharmony_ciError Rw2GetPreviewData(StreamInterface* stream,
582cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
583cb93a386Sopenharmony_ci  const TagSet extended_tags = {kPanaTagTopBorder,     kPanaTagLeftBorder,
584cb93a386Sopenharmony_ci                                kPanaTagBottomBorder,  kPanaTagRightBorder,
585cb93a386Sopenharmony_ci                                kPanaTagIso,           kPanaTagJpegImage,
586cb93a386Sopenharmony_ci                                kTiffTagJpegByteCount, kTiffTagJpegOffset};
587cb93a386Sopenharmony_ci  // Parse the RAW data to get the ISO, offset and length of the preview image,
588cb93a386Sopenharmony_ci  // which contains the Exif information.
589cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 1;
590cb93a386Sopenharmony_ci  PreviewImageData preview_data;
591cb93a386Sopenharmony_ci  if (!GetPreviewData(extended_tags, kNumberOfIfds, stream, &preview_data)) {
592cb93a386Sopenharmony_ci    return kFail;
593cb93a386Sopenharmony_ci  }
594cb93a386Sopenharmony_ci
595cb93a386Sopenharmony_ci  if (preview_data.preview.length > 0) {  // when preview image exists
596cb93a386Sopenharmony_ci    // Parse the Exif information from the preview image.
597cb93a386Sopenharmony_ci    const std::uint32_t exif_offset = preview_data.preview.offset + 12;
598cb93a386Sopenharmony_ci    if (!GetExifData(exif_offset, stream, preview_image_data)) {
599cb93a386Sopenharmony_ci      return kFail;
600cb93a386Sopenharmony_ci    }
601cb93a386Sopenharmony_ci    preview_image_data->thumbnail.offset += exif_offset;
602cb93a386Sopenharmony_ci  }
603cb93a386Sopenharmony_ci
604cb93a386Sopenharmony_ci  // Merge the Exif data with the RAW data to form the preview_image_data.
605cb93a386Sopenharmony_ci  preview_image_data->preview = preview_data.preview;
606cb93a386Sopenharmony_ci  preview_image_data->iso = preview_data.iso;
607cb93a386Sopenharmony_ci  preview_image_data->full_width = preview_data.full_width;
608cb93a386Sopenharmony_ci  preview_image_data->full_height = preview_data.full_height;
609cb93a386Sopenharmony_ci
610cb93a386Sopenharmony_ci  return kOk;
611cb93a386Sopenharmony_ci}
612cb93a386Sopenharmony_ci
613cb93a386Sopenharmony_ciError SrwGetPreviewData(StreamInterface* stream,
614cb93a386Sopenharmony_ci                        PreviewImageData* preview_image_data) {
615cb93a386Sopenharmony_ci  GetThumbnailOffsetAndLength({kTiffTagSubIfd}, stream, preview_image_data);
616cb93a386Sopenharmony_ci
617cb93a386Sopenharmony_ci  const TagSet extended_tags = {kExifTagWidth, kExifTagHeight,
618cb93a386Sopenharmony_ci                                kTiffTagJpegByteCount, kTiffTagJpegOffset,
619cb93a386Sopenharmony_ci                                kTiffTagSubIfd};
620cb93a386Sopenharmony_ci  const std::uint32_t kNumberOfIfds = 1;
621cb93a386Sopenharmony_ci  if (!GetPreviewData(extended_tags, kNumberOfIfds, stream,
622cb93a386Sopenharmony_ci                      preview_image_data)) {
623cb93a386Sopenharmony_ci    return kFail;
624cb93a386Sopenharmony_ci  }
625cb93a386Sopenharmony_ci  return kOk;
626cb93a386Sopenharmony_ci}
627cb93a386Sopenharmony_ci
628cb93a386Sopenharmony_ci}  // namespace
629cb93a386Sopenharmony_ci
630cb93a386Sopenharmony_cisize_t BytesRequiredForIsRaw() {
631cb93a386Sopenharmony_ci  return image_type_recognition::GetNumberOfBytesForIsRawLite();
632cb93a386Sopenharmony_ci}
633cb93a386Sopenharmony_ci
634cb93a386Sopenharmony_cibool IsRaw(StreamInterface* data) {
635cb93a386Sopenharmony_ci  const size_t bytes = BytesRequiredForIsRaw();
636cb93a386Sopenharmony_ci  if (data == nullptr) {
637cb93a386Sopenharmony_ci    return false;
638cb93a386Sopenharmony_ci  }
639cb93a386Sopenharmony_ci
640cb93a386Sopenharmony_ci  // Read required number of bytes into a vector.
641cb93a386Sopenharmony_ci  std::vector<std::uint8_t> file_header(bytes);
642cb93a386Sopenharmony_ci  if (data->GetData(0, file_header.size(), file_header.data()) != kOk) {
643cb93a386Sopenharmony_ci    return false;
644cb93a386Sopenharmony_ci  }
645cb93a386Sopenharmony_ci
646cb93a386Sopenharmony_ci  RangeCheckedBytePtr data_buffer(file_header.data(), file_header.size());
647cb93a386Sopenharmony_ci
648cb93a386Sopenharmony_ci  return image_type_recognition::IsRawLite(data_buffer);
649cb93a386Sopenharmony_ci}
650cb93a386Sopenharmony_ci
651cb93a386Sopenharmony_ciError GetPreviewImageData(StreamInterface* data,
652cb93a386Sopenharmony_ci                          PreviewImageData* preview_image_data) {
653cb93a386Sopenharmony_ci  const size_t bytes = BytesRequiredForIsRaw();
654cb93a386Sopenharmony_ci  if (data == nullptr || bytes == 0) {
655cb93a386Sopenharmony_ci    return kFail;
656cb93a386Sopenharmony_ci  }
657cb93a386Sopenharmony_ci
658cb93a386Sopenharmony_ci  std::vector<std::uint8_t> file_header(bytes);
659cb93a386Sopenharmony_ci  Error error = data->GetData(0, file_header.size(), file_header.data());
660cb93a386Sopenharmony_ci  if (error != kOk) {
661cb93a386Sopenharmony_ci    return error;
662cb93a386Sopenharmony_ci  }
663cb93a386Sopenharmony_ci  RangeCheckedBytePtr header_buffer(file_header.data(), file_header.size());
664cb93a386Sopenharmony_ci
665cb93a386Sopenharmony_ci  switch (RecognizeRawImageTypeLite(header_buffer)) {
666cb93a386Sopenharmony_ci    case image_type_recognition::kArwImage:
667cb93a386Sopenharmony_ci      return ArwGetPreviewData(data, preview_image_data);
668cb93a386Sopenharmony_ci    case image_type_recognition::kCr2Image:
669cb93a386Sopenharmony_ci      return Cr2GetPreviewData(data, preview_image_data);
670cb93a386Sopenharmony_ci    case image_type_recognition::kDngImage:
671cb93a386Sopenharmony_ci      return DngGetPreviewData(data, preview_image_data);
672cb93a386Sopenharmony_ci    case image_type_recognition::kNefImage:
673cb93a386Sopenharmony_ci    case image_type_recognition::kNrwImage:
674cb93a386Sopenharmony_ci      return NefGetPreviewData(data, preview_image_data);
675cb93a386Sopenharmony_ci    case image_type_recognition::kOrfImage:
676cb93a386Sopenharmony_ci      return OrfGetPreviewData(data, preview_image_data);
677cb93a386Sopenharmony_ci    case image_type_recognition::kPefImage:
678cb93a386Sopenharmony_ci      return PefGetPreviewData(data, preview_image_data);
679cb93a386Sopenharmony_ci    case image_type_recognition::kRafImage:
680cb93a386Sopenharmony_ci      return RafGetPreviewData(data, preview_image_data);
681cb93a386Sopenharmony_ci    case image_type_recognition::kRw2Image:
682cb93a386Sopenharmony_ci      return Rw2GetPreviewData(data, preview_image_data);
683cb93a386Sopenharmony_ci    case image_type_recognition::kSrwImage:
684cb93a386Sopenharmony_ci      return SrwGetPreviewData(data, preview_image_data);
685cb93a386Sopenharmony_ci    default:
686cb93a386Sopenharmony_ci      return kUnsupported;
687cb93a386Sopenharmony_ci  }
688cb93a386Sopenharmony_ci}
689cb93a386Sopenharmony_ci
690cb93a386Sopenharmony_cibool GetDngInformation(StreamInterface* data, std::uint32_t* width,
691cb93a386Sopenharmony_ci                       std::uint32_t* height,
692cb93a386Sopenharmony_ci                       std::vector<std::uint32_t>* cfa_pattern_dim) {
693cb93a386Sopenharmony_ci  // If IFD0 contains already the full dimensions we do not parse into the sub
694cb93a386Sopenharmony_ci  // IFD.
695cb93a386Sopenharmony_ci  if (!GetDngInformation({}, data, width, height, cfa_pattern_dim)) {
696cb93a386Sopenharmony_ci    return GetDngInformation({kTiffTagSubIfd}, data, width, height,
697cb93a386Sopenharmony_ci                             cfa_pattern_dim);
698cb93a386Sopenharmony_ci  }
699cb93a386Sopenharmony_ci  return true;
700cb93a386Sopenharmony_ci}
701cb93a386Sopenharmony_ci
702cb93a386Sopenharmony_cibool GetOrientation(StreamInterface* data, std::uint32_t* orientation) {
703cb93a386Sopenharmony_ci  using image_type_recognition::GetNumberOfBytesForIsOfType;
704cb93a386Sopenharmony_ci  using image_type_recognition::IsOfType;
705cb93a386Sopenharmony_ci
706cb93a386Sopenharmony_ci  std::vector<std::uint8_t> file_header(
707cb93a386Sopenharmony_ci      GetNumberOfBytesForIsOfType(image_type_recognition::kRafImage));
708cb93a386Sopenharmony_ci  if (data->GetData(0, file_header.size(), file_header.data()) != kOk) {
709cb93a386Sopenharmony_ci    return false;
710cb93a386Sopenharmony_ci  }
711cb93a386Sopenharmony_ci
712cb93a386Sopenharmony_ci  // For RAF files a special routine is necessary to get orientation. For others
713cb93a386Sopenharmony_ci  // the general approach is sufficient.
714cb93a386Sopenharmony_ci  if (IsOfType(RangeCheckedBytePtr(file_header.data(), file_header.size()),
715cb93a386Sopenharmony_ci               image_type_recognition::kRafImage)) {
716cb93a386Sopenharmony_ci    return RafGetOrientation(data, orientation);
717cb93a386Sopenharmony_ci  } else {
718cb93a386Sopenharmony_ci    return GetExifOrientation(data, 0 /* offset */, orientation);
719cb93a386Sopenharmony_ci  }
720cb93a386Sopenharmony_ci}
721cb93a386Sopenharmony_ci
722cb93a386Sopenharmony_cistd::vector<std::string> SupportedExtensions() {
723cb93a386Sopenharmony_ci  return {"ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "PEF", "RAF", "RW2", "SRW"};
724cb93a386Sopenharmony_ci}
725cb93a386Sopenharmony_ci
726cb93a386Sopenharmony_ci}  // namespace piex
727