| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/codec/SkCodec.h" |
| #include "include/codec/SkEncodedOrigin.h" |
| #include "include/codec/SkWebpDecoder.h" |
| #include "include/core/SkImage.h" |
| #include "include/core/SkSize.h" |
| #include "include/core/SkStream.h" |
| #include "include/private/SkExif.h" |
| #include "tests/Test.h" |
| #include "tools/Resources.h" |
| |
| #include <memory> |
| #include <tuple> |
| #include <utility> |
| |
| DEF_TEST(ExifOrientation, r) { |
| std::unique_ptr<SkStream> stream(GetResourceAsStream("images/exif-orientation-2-ur.jpg")); |
| REPORTER_ASSERT(r, nullptr != stream); |
| if (!stream) { |
| return; |
| } |
| |
| std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream))); |
| REPORTER_ASSERT(r, nullptr != codec); |
| SkEncodedOrigin origin = codec->getOrigin(); |
| REPORTER_ASSERT(r, kTopRight_SkEncodedOrigin == origin); |
| |
| codec = SkCodec::MakeFromStream(GetResourceAsStream("images/mandrill_512_q075.jpg")); |
| REPORTER_ASSERT(r, nullptr != codec); |
| origin = codec->getOrigin(); |
| REPORTER_ASSERT(r, kTopLeft_SkEncodedOrigin == origin); |
| } |
| |
| DEF_TEST(GetImageRespectsExif, r) { |
| std::unique_ptr<SkStream> stream(GetResourceAsStream("images/orientation/6.webp")); |
| REPORTER_ASSERT(r, nullptr != stream); |
| if (!stream) { |
| return; |
| } |
| |
| std::unique_ptr<SkCodec> codec(SkWebpDecoder::Decode(std::move(stream), nullptr)); |
| REPORTER_ASSERT(r, nullptr != codec); |
| SkEncodedOrigin origin = codec->getOrigin(); |
| REPORTER_ASSERT(r, kRightTop_SkEncodedOrigin == origin, |
| "Actual origin %d", origin); |
| |
| auto result = codec->getImage(); |
| REPORTER_ASSERT(r, std::get<1>(result) == SkCodec::Result::kSuccess, |
| "Not success %d", std::get<1>(result)); |
| sk_sp<SkImage> frame = std::get<0>(result); |
| REPORTER_ASSERT(r, frame); |
| SkISize dims = frame->dimensions(); |
| REPORTER_ASSERT(r, dims.fWidth == 100, "width %d != 100", dims.fWidth); |
| REPORTER_ASSERT(r, dims.fHeight == 80, "height %d != 80", dims.fHeight); |
| } |
| |
| DEF_TEST(ExifOrientationInExif, r) { |
| std::unique_ptr<SkStream> stream(GetResourceAsStream("images/orientation/exif.jpg")); |
| |
| std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream)); |
| REPORTER_ASSERT(r, nullptr != codec); |
| SkEncodedOrigin origin = codec->getOrigin(); |
| REPORTER_ASSERT(r, kLeftBottom_SkEncodedOrigin == origin); |
| } |
| |
| DEF_TEST(ExifOrientationInSubIFD, r) { |
| std::unique_ptr<SkStream> stream(GetResourceAsStream("images/orientation/subifd.jpg")); |
| |
| std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream)); |
| REPORTER_ASSERT(r, nullptr != codec); |
| SkEncodedOrigin origin = codec->getOrigin(); |
| REPORTER_ASSERT(r, kLeftBottom_SkEncodedOrigin == origin); |
| } |
| |
| static bool approx_eq(float x, float y, float epsilon) { return std::abs(x - y) < epsilon; } |
| |
| DEF_TEST(ExifParse, r) { |
| const float kEpsilon = 0.001f; |
| |
| { |
| sk_sp<SkData> data = GetResourceAsData("images/test0-hdr.exif"); |
| REPORTER_ASSERT(r, nullptr != data); |
| SkExifMetadata exif(data); |
| float hdrHeadroom = 0.f; |
| REPORTER_ASSERT(r, exif.getHdrHeadroom(&hdrHeadroom)); |
| REPORTER_ASSERT(r, approx_eq(hdrHeadroom, 3.755296f, kEpsilon)); |
| |
| uint16_t resolutionUnit = 0; |
| float xResolution = 0.f; |
| float yResolution = 0.f; |
| REPORTER_ASSERT(r, exif.getResolutionUnit(&resolutionUnit)); |
| REPORTER_ASSERT(r, 2 == resolutionUnit); |
| REPORTER_ASSERT(r, exif.getXResolution(&xResolution)); |
| REPORTER_ASSERT(r, 72.f == xResolution); |
| REPORTER_ASSERT(r, exif.getYResolution(&yResolution)); |
| REPORTER_ASSERT(r, 72.f == yResolution); |
| |
| uint32_t pixelXDimension = 0; |
| uint32_t pixelYDimension = 0; |
| REPORTER_ASSERT(r, exif.getPixelXDimension(&pixelXDimension)); |
| REPORTER_ASSERT(r, 4032 == pixelXDimension); |
| REPORTER_ASSERT(r, exif.getPixelYDimension(&pixelYDimension)); |
| REPORTER_ASSERT(r, 3024 == pixelYDimension); |
| } |
| |
| { |
| sk_sp<SkData> data = GetResourceAsData("images/test1-pixel32.exif"); |
| REPORTER_ASSERT(r, nullptr != data); |
| SkExifMetadata exif(data); |
| float hdrHeadroom = 0.f; |
| REPORTER_ASSERT(r, !exif.getHdrHeadroom(&hdrHeadroom)); |
| |
| uint16_t resolutionUnit = 0; |
| float xResolution = 0.f; |
| float yResolution = 0.f; |
| REPORTER_ASSERT(r, exif.getResolutionUnit(&resolutionUnit)); |
| REPORTER_ASSERT(r, 2 == resolutionUnit); |
| REPORTER_ASSERT(r, exif.getXResolution(&xResolution)); |
| REPORTER_ASSERT(r, 72.f == xResolution); |
| REPORTER_ASSERT(r, exif.getYResolution(&yResolution)); |
| REPORTER_ASSERT(r, 72.f == yResolution); |
| |
| uint32_t pixelXDimension = 0; |
| uint32_t pixelYDimension = 0; |
| REPORTER_ASSERT(r, exif.getPixelXDimension(&pixelXDimension)); |
| REPORTER_ASSERT(r, 200 == pixelXDimension); |
| REPORTER_ASSERT(r, exif.getPixelYDimension(&pixelYDimension)); |
| REPORTER_ASSERT(r, 100 == pixelYDimension); |
| } |
| |
| { |
| sk_sp<SkData> data = GetResourceAsData("images/test2-nonuniform.exif"); |
| REPORTER_ASSERT(r, nullptr != data); |
| SkExifMetadata exif(data); |
| float hdrHeadroom = 0.f; |
| REPORTER_ASSERT(r, !exif.getHdrHeadroom(&hdrHeadroom)); |
| |
| uint16_t resolutionUnit = 0; |
| float xResolution = 0.f; |
| float yResolution = 0.f; |
| REPORTER_ASSERT(r, exif.getResolutionUnit(&resolutionUnit)); |
| REPORTER_ASSERT(r, 2 == resolutionUnit); |
| REPORTER_ASSERT(r, exif.getXResolution(&xResolution)); |
| REPORTER_ASSERT(r, 144.f == xResolution); |
| REPORTER_ASSERT(r, exif.getYResolution(&yResolution)); |
| REPORTER_ASSERT(r, 36.f == yResolution); |
| |
| uint32_t pixelXDimension = 0; |
| uint32_t pixelYDimension = 0; |
| REPORTER_ASSERT(r, exif.getPixelXDimension(&pixelXDimension)); |
| REPORTER_ASSERT(r, 50 == pixelXDimension); |
| REPORTER_ASSERT(r, exif.getPixelYDimension(&pixelYDimension)); |
| REPORTER_ASSERT(r, 100 == pixelYDimension); |
| } |
| |
| { |
| sk_sp<SkData> data = GetResourceAsData("images/test3-little-endian.exif"); |
| REPORTER_ASSERT(r, nullptr != data); |
| SkExifMetadata exif(data); |
| float hdrHeadroom = 0.f; |
| REPORTER_ASSERT(r, !exif.getHdrHeadroom(&hdrHeadroom)); |
| |
| uint16_t resolutionUnit = 0; |
| float xResolution = 0.f; |
| float yResolution = 0.f; |
| REPORTER_ASSERT(r, exif.getResolutionUnit(&resolutionUnit)); |
| REPORTER_ASSERT(r, 2 == resolutionUnit); |
| REPORTER_ASSERT(r, exif.getXResolution(&xResolution)); |
| REPORTER_ASSERT(r, 350.f == xResolution); |
| REPORTER_ASSERT(r, exif.getYResolution(&yResolution)); |
| REPORTER_ASSERT(r, 350.f == yResolution); |
| |
| uint32_t pixelXDimension = 0; |
| uint32_t pixelYDimension = 0; |
| REPORTER_ASSERT(r, !exif.getPixelXDimension(&pixelXDimension)); |
| REPORTER_ASSERT(r, !exif.getPixelYDimension(&pixelYDimension)); |
| } |
| |
| { |
| sk_sp<SkData> data = GetResourceAsData("images/test0-hdr.exif"); |
| |
| // Zero out the denominators of signed and unsigned rationals, to verify that we do not |
| // divide by zero. |
| data = SkData::MakeWithCopy(data->bytes(), data->size()); |
| memset(static_cast<uint8_t*>(data->writable_data()) + 186, 0, 4); |
| memset(static_cast<uint8_t*>(data->writable_data()) + 2171, 0, 4); |
| memset(static_cast<uint8_t*>(data->writable_data()) + 2240, 0, 4); |
| |
| // Parse the corrupted Exif. |
| SkExifMetadata exif(data); |
| |
| // HDR headroom signed denominators are destroyed. |
| float hdrHeadroom = 0.f; |
| REPORTER_ASSERT(r, exif.getHdrHeadroom(&hdrHeadroom)); |
| REPORTER_ASSERT(r, approx_eq(hdrHeadroom, 3.482202f, kEpsilon)); |
| |
| // The X resolution should be zero. |
| float xResolution = 0.f; |
| float yResolution = 0.f; |
| REPORTER_ASSERT(r, exif.getXResolution(&xResolution)); |
| REPORTER_ASSERT(r, 0.f == xResolution); |
| REPORTER_ASSERT(r, exif.getYResolution(&yResolution)); |
| REPORTER_ASSERT(r, 72.f == yResolution); |
| } |
| } |