diff options
author | Yujie Qin <yujieqin@google.com> | 2016-01-15 16:22:20 +0100 |
---|---|---|
committer | Yujie Qin <yujieqin@google.com> | 2016-01-15 16:22:20 +0100 |
commit | 3eaa83178e9d1722c126d598d3eee7fb383c2c85 (patch) | |
tree | e281e204200ca6d10a898f1046f68ab0a76c211d /src | |
parent | 51b5fc1431c797637e4f45be97b078efabac3f4b (diff) | |
download | piex-3eaa83178e9d1722c126d598d3eee7fb383c2c85.tar.gz |
Sync to github.com/google/piex at commit cdcebd956de2dd080bc106058db3d12f8dce8ba2
Diffstat (limited to 'src')
-rw-r--r-- | src/image_type_recognition/image_type_recognition_lite.cc | 41 | ||||
-rw-r--r-- | src/image_type_recognition/image_type_recognition_lite.h | 1 | ||||
-rw-r--r-- | src/piex.cc | 117 | ||||
-rw-r--r-- | src/piex.h | 6 | ||||
-rw-r--r-- | src/piex_types.h | 4 | ||||
-rw-r--r-- | src/tiff_parser.cc | 9 | ||||
-rw-r--r-- | src/tiff_parser.h | 23 |
7 files changed, 166 insertions, 35 deletions
diff --git a/src/image_type_recognition/image_type_recognition_lite.cc b/src/image_type_recognition/image_type_recognition_lite.cc index 520688a..45429fd 100644 --- a/src/image_type_recognition/image_type_recognition_lite.cc +++ b/src/image_type_recognition/image_type_recognition_lite.cc @@ -728,6 +728,45 @@ class Rw2TypeChecker : public TypeChecker { } }; +// Samsung RAW. +class SrwTypeChecker : public TypeChecker { + public: + virtual RawImageTypes Type() const { return kSrwImage; } + + virtual size_t RequestedSize() const { return 256; } + + // Check multiple points: + // 1. valid big endianness at the beginning of the file; + // 2. magic numbers at the (offset == 2 and offset==4) positions of the file; + // 3. the signature "SAMSUNG" in the requested bytes of the file; + virtual bool IsMyType(const RangeCheckedBytePtr& source) const { + // Limits the source length to the RequestedSize(), using it guarantees that + // we will not read more than this size from the source. + RangeCheckedBytePtr limited_source = + source.pointerToSubArray(0 /* pos */, RequestedSize()); + + bool use_big_endian; + if (!DetermineEndianness(source, &use_big_endian)) { + return false; + } + + const unsigned short kTiffMagic = 0x2A; // NOLINT + const unsigned int kTiffOffset = 8; + if (!CheckUInt16Value(limited_source, 2 /* offset */, use_big_endian, + kTiffMagic) || + !CheckUInt32Value(limited_source, 4 /* offset */, use_big_endian, + kTiffOffset)) { + return false; + } + + const string kSignature("SAMSUNG"); + if (!IsSignatureFound(source, 0, RequestedSize(), kSignature, NULL)) { + return false; + } + return true; + } +}; + // Sigma / Polaroid RAW. class X3fTypeChecker : public TypeChecker { public: @@ -769,6 +808,7 @@ class TypeCheckerList { checkers_.push_back(new RafTypeChecker()); checkers_.push_back(new RawContaxNTypeChecker()); checkers_.push_back(new Rw2TypeChecker()); + checkers_.push_back(new SrwTypeChecker()); checkers_.push_back(new X3fTypeChecker()); // Sort the checkers by the ascending RequestedSize() to get better @@ -833,6 +873,7 @@ bool IsRaw(const RawImageTypes type) { case kRafImage: case kRawContaxNImage: case kRw2Image: + case kSrwImage: case kX3fImage: { return true; } diff --git a/src/image_type_recognition/image_type_recognition_lite.h b/src/image_type_recognition/image_type_recognition_lite.h index da9caf5..5b9ca64 100644 --- a/src/image_type_recognition/image_type_recognition_lite.h +++ b/src/image_type_recognition/image_type_recognition_lite.h @@ -54,6 +54,7 @@ enum RawImageTypes { kRafImage, kRawContaxNImage, kRw2Image, + kSrwImage, kX3fImage, }; diff --git a/src/piex.cc b/src/piex.cc index daef264..ed3c8f4 100644 --- a/src/piex.cc +++ b/src/piex.cc @@ -79,12 +79,15 @@ Error GetExifData(const std::uint32_t exif_offset, StreamInterface* stream, } // Reads the jpeg compressed thumbnail information. -void GetThumbnailOffsetAndLength(StreamInterface* stream, +void GetThumbnailOffsetAndLength(const TagSet& extended_tags, + StreamInterface* stream, PreviewImageData* preview_image_data) { + TagSet desired_tags = {kTiffTagJpegByteCount, kTiffTagJpegOffset}; + desired_tags.insert(extended_tags.cbegin(), extended_tags.cend()); + const std::uint32_t kNumberOfIfds = 2; - const TagSet extended_tags = {kTiffTagJpegByteCount, kTiffTagJpegOffset}; PreviewImageData thumbnail_data; - if (GetPreviewData(extended_tags, kNumberOfIfds, stream, &thumbnail_data) == + if (GetPreviewData(desired_tags, kNumberOfIfds, stream, &thumbnail_data) == kOk) { preview_image_data->thumbnail_offset = thumbnail_data.preview_offset; preview_image_data->thumbnail_length = thumbnail_data.preview_length; @@ -118,7 +121,8 @@ Error GetExifIfd(const Endian endian, StreamInterface* stream, } Error GetMakernoteIfd(const TiffDirectory& exif_ifd, const Endian endian, - StreamInterface* stream, std::uint32_t* makernote_offset, + const std::uint32_t skip_offset, StreamInterface* stream, + std::uint32_t* makernote_offset, TiffDirectory* makernote_ifd) { std::uint32_t makernote_length; if (!exif_ifd.GetOffsetAndLength(kExifTagMakernotes, @@ -128,10 +132,10 @@ Error GetMakernoteIfd(const TiffDirectory& exif_ifd, const Endian endian, } std::uint32_t next_ifd_offset; - return ParseDirectory( - *makernote_offset, *makernote_offset + 12, endian, - {kTiffTagImageWidth, kOlymTagCameraSettings, kOlymTagRawProcessing}, - stream, makernote_ifd, &next_ifd_offset); + return ParseDirectory(*makernote_offset, *makernote_offset + skip_offset, + endian, {kTiffTagImageWidth, kOlymTagCameraSettings, + kOlymTagRawProcessing, kPentaxTagColorSpace}, + stream, makernote_ifd, &next_ifd_offset); } Error GetCameraSettingsIfd(const TiffDirectory& makernote_ifd, @@ -199,8 +203,9 @@ Error GetOlympusPreviewImage(StreamInterface* stream, std::uint32_t makernote_offset; TiffDirectory makernote_ifd(endian); - error = GetMakernoteIfd(exif_ifd, endian, stream, &makernote_offset, - &makernote_ifd); + const std::uint32_t kSkipMakernoteStart = 12; + error = GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream, + &makernote_offset, &makernote_ifd); if (error != kOk) { return error; } @@ -259,6 +264,39 @@ Error GetOlympusPreviewImage(StreamInterface* stream, return kOk; } +Error PefGetColorSpace(StreamInterface* stream, + PreviewImageData* preview_image_data) { + Endian endian; + if (!GetEndianness(0 /* tiff offset */, stream, &endian)) { + return kFail; + } + + TiffDirectory exif_ifd(endian); + Error error = GetExifIfd(endian, stream, &exif_ifd); + if (error != kOk) { + return error; + } + + std::uint32_t makernote_offset; + TiffDirectory makernote_ifd(endian); + const std::uint32_t kSkipMakernoteStart = 6; + error = GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream, + &makernote_offset, &makernote_ifd); + if (error != kOk) { + return error; + } + if (makernote_ifd.Has(kPentaxTagColorSpace)) { + std::uint32_t color_space; + if (!makernote_ifd.Get(kPentaxTagColorSpace, &color_space)) { + return kFail; + } + preview_image_data->color_space = color_space == 0 + ? PreviewImageData::kSrgb + : PreviewImageData::kAdobeRgb; + } + return kOk; +} + // Parses the Fuji Cfa header for the image width and height. bool RafGetDimension(StreamInterface* stream, std::uint32_t* width, std::uint32_t* height) { @@ -301,7 +339,7 @@ Error ArwGetPreviewData(StreamInterface* stream, kTiffTagJpegByteCount, kTiffTagJpegOffset, kTiffTagSubIfd}; - GetThumbnailOffsetAndLength(stream, preview_image_data); + GetThumbnailOffsetAndLength(TagSet(), stream, preview_image_data); const std::uint32_t kNumberOfIfds = 1; return GetPreviewData(extended_tags, kNumberOfIfds, stream, @@ -313,7 +351,7 @@ Error Cr2GetPreviewData(StreamInterface* stream, const TagSet extended_tags = {kExifTagHeight, kExifTagWidth, kTiffTagStripByteCounts, kTiffTagStripOffsets}; - GetThumbnailOffsetAndLength(stream, preview_image_data); + GetThumbnailOffsetAndLength(TagSet(), stream, preview_image_data); const std::uint32_t kNumberOfIfds = 1; return GetPreviewData(extended_tags, kNumberOfIfds, stream, @@ -388,7 +426,7 @@ Error NefGetPreviewData(StreamInterface* stream, } PreviewImageData thumbnail_data; - GetThumbnailOffsetAndLength(stream, &thumbnail_data); + GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data); preview_image_data->thumbnail_offset = thumbnail_data.thumbnail_offset; preview_image_data->thumbnail_length = thumbnail_data.thumbnail_length; @@ -434,6 +472,31 @@ Error OrfGetPreviewData(StreamInterface* stream, return GetOlympusPreviewImage(stream, preview_image_data); } +Error PefGetPreviewData(StreamInterface* stream, + PreviewImageData* preview_image_data) { + const TagSet extended_tags = {kTiffTagImageWidth, kTiffTagImageLength, + kTiffTagJpegByteCount, kTiffTagJpegOffset, + kTiffTagSubIfd}; + const std::uint32_t kNumberOfIfds = 3; + Error error = + GetPreviewData(extended_tags, kNumberOfIfds, stream, preview_image_data); + if (error != kOk) { + return error; + } + + error = PefGetColorSpace(stream, preview_image_data); + if (error != kOk) { + return error; + } + + PreviewImageData thumbnail_data; + GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data); + preview_image_data->thumbnail_offset = thumbnail_data.thumbnail_offset; + preview_image_data->thumbnail_length = thumbnail_data.thumbnail_length; + + return kOk; +} + Error RafGetPreviewData(StreamInterface* stream, PreviewImageData* preview_image_data) { // Parse the Fuji RAW header to get the offset and length of the preview @@ -464,6 +527,7 @@ Error RafGetPreviewData(StreamInterface* stream, // The preview offset and length extracted from the Exif data are actually // the thumbnail offset and length. preview_image_data->thumbnail_offset = preview_image_data->preview_offset; + preview_image_data->thumbnail_offset += 160; // Skip the cfa header. preview_image_data->thumbnail_length = preview_image_data->preview_length; preview_image_data->preview_offset = preview_offset; preview_image_data->preview_length = preview_length; @@ -493,13 +557,14 @@ Error Rw2GetPreviewData(StreamInterface* stream, if (GetExifData(exif_offset, stream, preview_image_data) == kFail) { return kFail; } + // The preview offset and length extracted from the Exif data are actually + // the thumbnail offset and length. + preview_image_data->thumbnail_offset = + exif_offset + preview_image_data->preview_offset; + preview_image_data->thumbnail_length = preview_image_data->preview_length; } // Merge the Exif data with the RAW data to form the preview_image_data. - // The preview offset and length extracted from the Exif data are actually - // the thumbnail offset and length. - preview_image_data->thumbnail_offset = preview_image_data->preview_offset; - preview_image_data->thumbnail_length = preview_image_data->preview_length; preview_image_data->preview_offset = preview_data.preview_offset; preview_image_data->preview_length = preview_data.preview_length; preview_image_data->iso = preview_data.iso; @@ -509,6 +574,18 @@ Error Rw2GetPreviewData(StreamInterface* stream, return kOk; } +Error SrwGetPreviewData(StreamInterface* stream, + PreviewImageData* preview_image_data) { + GetThumbnailOffsetAndLength({kTiffTagSubIfd}, stream, preview_image_data); + + const TagSet extended_tags = {kExifTagWidth, kExifTagHeight, + kTiffTagJpegByteCount, kTiffTagJpegOffset, + kTiffTagSubIfd}; + const std::uint32_t kNumberOfIfds = 1; + return GetPreviewData(extended_tags, kNumberOfIfds, stream, + preview_image_data); +} + } // namespace size_t BytesRequiredForIsRaw() { @@ -558,10 +635,14 @@ Error GetPreviewImageData(StreamInterface* data, return NefGetPreviewData(data, preview_image_data); case image_type_recognition::kOrfImage: return OrfGetPreviewData(data, preview_image_data); + case image_type_recognition::kPefImage: + return PefGetPreviewData(data, preview_image_data); case image_type_recognition::kRafImage: return RafGetPreviewData(data, preview_image_data); case image_type_recognition::kRw2Image: return Rw2GetPreviewData(data, preview_image_data); + case image_type_recognition::kSrwImage: + return SrwGetPreviewData(data, preview_image_data); default: return kUnsupported; } @@ -575,8 +656,10 @@ std::vector<std::string> SupportedExtensions() { extensions.push_back("NEF"); extensions.push_back("NRW"); extensions.push_back("ORF"); + extensions.push_back("PEF"); extensions.push_back("RAF"); extensions.push_back("RW2"); + extensions.push_back("SRW"); return extensions; } @@ -42,7 +42,7 @@ // // Uncompress the JPEG as usual, e.g. on Android with the BitmapFactory: // // In Java // Bitmap bitmap = BitmapFactory.decodeByteArray( -// file.at(image_data.jpeg_offset), image_data.jpeg_length); +// file.at(image_data.preview_offset), image_data.preview_length); #ifndef PIEX_PIEX_H_ #define PIEX_PIEX_H_ @@ -69,8 +69,8 @@ bool IsRaw(StreamInterface* data); // Returns 'kFail' when something with the data is wrong. // Returns 'kUnsupported' if file format is not supported. // -// One could check the "preview_image_data->jpeg_length != 0" for the existance -// of a preview image. +// One could check the "preview_image_data->preview_length != 0" for the +// existance of a preview image. Error GetPreviewImageData(StreamInterface* data, PreviewImageData* preview_image_data); diff --git a/src/piex_types.h b/src/piex_types.h index a180d87..f0c216a 100644 --- a/src/piex_types.h +++ b/src/piex_types.h @@ -29,8 +29,8 @@ enum Error { kUnsupported, }; -// Contains relevant image information as well as the 'jpeg_offset' and the -// 'jpeg_length' which are used to obtain the JPEG compressed preview image. +// Contains relevant image information as well as the 'preview_offset' and the +// 'preview_length' which are used to obtain the JPEG compressed preview image. // 'full_width' and 'full_height' are correctly cropped but not rotated. struct PreviewImageData { enum ColorSpace { diff --git a/src/tiff_parser.cc b/src/tiff_parser.cc index a36d5c8..cad5bc4 100644 --- a/src/tiff_parser.cc +++ b/src/tiff_parser.cc @@ -162,7 +162,7 @@ void FillGpsPreviewImageData(const TiffDirectory& gps_directory, Error FillPreviewImageData(const TiffDirectory& tiff_directory, PreviewImageData* preview_image_data) { bool success = true; - // Get jpeg_offset and jpeg_length + // Get preview_offset and preview_length if (tiff_directory.Has(kTiffTagStripOffsets) && tiff_directory.Has(kTiffTagStripByteCounts)) { std::vector<std::uint32_t> strip_offsets; @@ -190,8 +190,9 @@ Error FillPreviewImageData(const TiffDirectory& tiff_directory, } } - // Get exif_orientation - if (tiff_directory.Has(kTiffTagOrientation)) { + // Get exif_orientation if it was not set already. + if (tiff_directory.Has(kTiffTagOrientation) && + preview_image_data->exif_orientation == 1) { success &= tiff_directory.Get(kTiffTagOrientation, &preview_image_data->exif_orientation); } @@ -202,7 +203,7 @@ Error FillPreviewImageData(const TiffDirectory& tiff_directory, success &= tiff_directory.Get(kExifTagColorSpace, &color_space); if (color_space == 1) { preview_image_data->color_space = PreviewImageData::kSrgb; - } else if (color_space == 65535) { + } else if (color_space == 65535 || color_space == 2) { preview_image_data->color_space = PreviewImageData::kAdobeRgb; } } diff --git a/src/tiff_parser.h b/src/tiff_parser.h index 087844d..88b4006 100644 --- a/src/tiff_parser.h +++ b/src/tiff_parser.h @@ -28,7 +28,18 @@ namespace piex { // Specifies all tags that might be of interest to get the preview data. -enum Tags { +enum GpsTags { + kGpsTagLatitudeRef = 1, + kGpsTagLatitude = 2, + kGpsTagLongitudeRef = 3, + kGpsTagLongitude = 4, + kGpsTagAltitudeRef = 5, + kGpsTagAltitude = 6, + kGpsTagTimeStamp = 7, + kGpsTagDateStamp = 29, +}; + +enum TiffTags { kExifTagColorSpace = 0xA001, kExifTagDateTimeOriginal = 0x9003, kExifTagDefaultCropSize = 0xC620, @@ -40,14 +51,6 @@ enum Tags { kExifTagIsoSpeed = 0x8827, kExifTagMakernotes = 0x927C, kExifTagWidth = 0xA002, - kGpsTagLatitudeRef = 1, - kGpsTagLatitude = 2, - kGpsTagLongitudeRef = 3, - kGpsTagLongitude = 4, - kGpsTagAltitudeRef = 5, - kGpsTagAltitude = 6, - kGpsTagTimeStamp = 7, - kGpsTagDateStamp = 29, kOlymTagAspectFrame = 0x1113, kOlymTagCameraSettings = 0x2020, kOlymTagRawProcessing = 0x2040, @@ -57,6 +60,7 @@ enum Tags { kPanaTagLeftBorder = 0x0005, kPanaTagRightBorder = 0x007, kPanaTagTopBorder = 0x0004, + kPentaxTagColorSpace = 0x0037, kTiffTagArtist = 0x013B, kTiffTagBitsPerSample = 0x0102, kTiffTagCompression = 0x0103, @@ -87,6 +91,7 @@ enum Tags { kTiffTagYresolution = 0x011B, }; +typedef int Tags; typedef std::set<Tags> TagSet; typedef std::vector<tiff_directory::TiffDirectory> IfdVector; |