Flutter Engine
The Flutter Engine
Functions
JpegGainmapTest.cpp File Reference
#include "include/codec/SkAndroidCodec.h"
#include "include/codec/SkCodec.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkImage.h"
#include "include/core/SkShader.h"
#include "include/core/SkSize.h"
#include "include/core/SkStream.h"
#include "include/core/SkTypes.h"
#include "include/encode/SkJpegEncoder.h"
#include "include/private/SkGainmapInfo.h"
#include "include/private/SkGainmapShader.h"
#include "include/private/SkJpegGainmapEncoder.h"
#include "src/codec/SkJpegCodec.h"
#include "src/codec/SkJpegConstants.h"
#include "src/codec/SkJpegMultiPicture.h"
#include "src/codec/SkJpegSegmentScan.h"
#include "src/codec/SkJpegSourceMgr.h"
#include "src/codec/SkTiffUtility.h"
#include "tests/Test.h"
#include "tools/Resources.h"
#include <cstdint>
#include <cstring>
#include <memory>
#include <utility>
#include <vector>

Go to the source code of this file.

Functions

 DEF_TEST (Codec_jpegSegmentScan, r)
 
static bool find_mp_params_segment (SkStream *stream, std::unique_ptr< SkJpegMultiPictureParameters > *outMpParams, SkJpegSegment *outMpParamsSegment)
 
 DEF_TEST (Codec_multiPictureParams, r)
 
 DEF_TEST (Codec_jpegMultiPicture, r)
 
template<typename Reporter >
void decode_all (Reporter &r, std::unique_ptr< SkStream > stream, SkBitmap &baseBitmap, SkBitmap &gainmapBitmap, SkGainmapInfo &gainmapInfo)
 
 DEF_TEST (AndroidCodec_jpegGainmapDecode, r)
 
 DEF_TEST (AndroidCodec_jpegNoGainmap, r)
 
 DEF_TEST (AndroidCodec_gainmapInfoEncode, r)
 
static SkBitmap render_gainmap (const SkImageInfo &renderInfo, float renderHdrRatio, const SkBitmap &baseBitmap, const SkBitmap &gainmapBitmap, const SkGainmapInfo &gainmapInfo, int x, int y)
 
static SkColor4f render_gainmap_pixel (float renderHdrRatio, const SkBitmap &baseBitmap, const SkBitmap &gainmapBitmap, const SkGainmapInfo &gainmapInfo, int x, int y)
 
 DEF_TEST (AndroidCodec_jpegGainmapTranscode, r)
 
static sk_sp< SkDataget_mp_image (sk_sp< SkData > imageData, size_t imageNumber)
 
static std::unique_ptr< SkTiff::ImageFileDirectoryget_ifd (sk_sp< SkData > imageData, uint8_t marker, const void *sig, size_t sigSize, size_t pad)
 
static std::unique_ptr< SkTiff::ImageFileDirectoryget_mpf_ifd (sk_sp< SkData > imageData)
 
static std::unique_ptr< SkTiff::ImageFileDirectoryget_exif_ifd (sk_sp< SkData > imageData)
 
 DEF_TEST (AndroidCodec_mpfParse, r)
 
 DEF_TEST (AndroidCodec_gainmapInfoParse, r)
 

Function Documentation

◆ decode_all()

template<typename Reporter >
void decode_all ( Reporter &  r,
std::unique_ptr< SkStream stream,
SkBitmap baseBitmap,
SkBitmap gainmapBitmap,
SkGainmapInfo gainmapInfo 
)

Definition at line 486 of file JpegGainmapTest.cpp.

490 {
491 // Decode the base bitmap.
493 std::unique_ptr<SkCodec> baseCodec = SkJpegCodec::MakeFromStream(std::move(stream), &result);
494 REPORTER_ASSERT(r, baseCodec);
495 baseBitmap.allocPixels(baseCodec->getInfo());
497 SkCodec::kSuccess == baseCodec->getPixels(baseBitmap.info(),
498 baseBitmap.getPixels(),
499 baseBitmap.rowBytes()));
500 std::unique_ptr<SkAndroidCodec> androidCodec =
501 SkAndroidCodec::MakeFromCodec(std::move(baseCodec));
502 REPORTER_ASSERT(r, androidCodec);
503
504 // Extract the gainmap info and stream.
505 std::unique_ptr<SkStream> gainmapStream;
506 REPORTER_ASSERT(r, androidCodec->getAndroidGainmap(&gainmapInfo, &gainmapStream));
507 REPORTER_ASSERT(r, gainmapStream);
508
509 // Decode the gainmap bitmap.
510 std::unique_ptr<SkCodec> gainmapCodec = SkCodec::MakeFromStream(std::move(gainmapStream));
511 REPORTER_ASSERT(r, gainmapCodec);
512 SkBitmap bm;
513 bm.allocPixels(gainmapCodec->getInfo());
514 gainmapBitmap.allocPixels(gainmapCodec->getInfo());
516 SkCodec::kSuccess == gainmapCodec->getPixels(gainmapBitmap.info(),
517 gainmapBitmap.getPixels(),
518 gainmapBitmap.rowBytes()));
519}
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
static std::unique_ptr< SkAndroidCodec > MakeFromCodec(std::unique_ptr< SkCodec >)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
size_t rowBytes() const
Definition: SkBitmap.h:238
void * getPixels() const
Definition: SkBitmap.h:283
const SkImageInfo & info() const
Definition: SkBitmap.h:139
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, SkSpan< const SkCodecs::Decoder > decoders, Result *=nullptr, SkPngChunkReader *=nullptr, SelectionPolicy selectionPolicy=SelectionPolicy::kPreferStillImage)
Definition: SkCodec.cpp:163
Result
Definition: SkCodec.h:76
@ kSuccess
Definition: SkCodec.h:80
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, Result *)
GAsyncResult * result

◆ DEF_TEST() [1/9]

DEF_TEST ( AndroidCodec_gainmapInfoEncode  ,
 
)

Definition at line 673 of file JpegGainmapTest.cpp.

673 {
674 SkDynamicMemoryWStream encodeStream;
675
676 constexpr size_t kNumTests = 4;
677
678 SkBitmap baseBitmap;
679 baseBitmap.allocPixels(SkImageInfo::MakeN32Premul(16, 16));
680
681 SkBitmap gainmapBitmaps[kNumTests];
682 gainmapBitmaps[0].allocPixels(SkImageInfo::MakeN32Premul(16, 16));
683 gainmapBitmaps[1].allocPixels(SkImageInfo::MakeN32Premul(8, 8));
684 gainmapBitmaps[2].allocPixels(
686 gainmapBitmaps[3].allocPixels(
688
689 SkGainmapInfo infos[kNumTests] = {
690 // Multi-channel, UltraHDR-compatible.
691 {{1.f, 2.f, 4.f, 1.f},
692 {8.f, 16.f, 32.f, 1.f},
693 {64.f, 128.f, 256.f, 1.f},
694 {1 / 10.f, 1 / 11.f, 1 / 12.f, 1.f},
695 {1 / 13.f, 1 / 14.f, 1 / 15.f, 1.f},
696 4.f,
697 32.f,
700 nullptr},
701 // Multi-channel, not UltraHDR-compatible.
702 {{1.f, 2.f, 4.f, 1.f},
703 {8.f, 16.f, 32.f, 1.f},
704 {64.f, 128.f, 256.f, 1.f},
705 {1 / 10.f, 1 / 11.f, 1 / 12.f, 1.f},
706 {1 / 13.f, 1 / 14.f, 1 / 15.f, 1.f},
707 4.f,
708 32.f,
712 // Single-channel, UltraHDR-compatible.
713 {{1.f, 1.f, 1.f, 1.f},
714 {8.f, 8.f, 8.f, 1.f},
715 {64.f, 64.f, 64.f, 1.f},
716 {1 / 128.f, 1 / 128.f, 1 / 128.f, 1.f},
717 {1 / 256.f, 1 / 256.f, 1 / 256.f, 1.f},
718 4.f,
719 32.f,
722 nullptr},
723 // Single-channel, not UltraHDR-compatible.
724 {{1.f, 1.f, 1.f, 1.f},
725 {8.f, 8.f, 8.f, 1.f},
726 {64.f, 64.f, 64.f, 1.f},
727 {1 / 128.f, 1 / 128.f, 1 / 128.f, 1.f},
728 {1 / 256.f, 1 / 256.f, 1 / 256.f, 1.f},
729 4.f,
730 32.f,
734 };
735
736 for (size_t i = 0; i < kNumTests; ++i) {
737 // Encode |gainmapInfo|.
738 bool encodeResult = SkJpegGainmapEncoder::EncodeHDRGM(&encodeStream,
739 baseBitmap.pixmap(),
741 gainmapBitmaps[i].pixmap(),
743 infos[i]);
744 REPORTER_ASSERT(r, encodeResult);
745
746 // Decode into |decodedGainmapInfo|.
747 SkGainmapInfo decodedGainmapInfo;
748 SkBitmap decodedBaseBitmap;
749 SkBitmap decodedGainmapBitmap;
750 auto decodeStream = std::make_unique<SkMemoryStream>(encodeStream.detachAsData());
751 decode_all(r,
752 std::move(decodeStream),
753 decodedBaseBitmap,
754 decodedGainmapBitmap,
755 decodedGainmapInfo);
756
757 // Verify that the decode reproducd the input.
758 expect_approx_eq_info(r, infos[i], decodedGainmapInfo);
759 }
760}
void decode_all(Reporter &r, std::unique_ptr< SkStream > stream, SkBitmap &baseBitmap, SkBitmap &gainmapBitmap, SkGainmapInfo &gainmapInfo)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition: SkColorType.h:35
const SkPixmap & pixmap() const
Definition: SkBitmap.h:133
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
sk_sp< SkData > detachAsData()
Definition: SkStream.cpp:707
static bool EncodeHDRGM(SkWStream *dst, const SkPixmap &base, const SkJpegEncoder::Options &baseOptions, const SkPixmap &gainmap, const SkJpegEncoder::Options &gainmapOptions, const SkGainmapInfo &gainmapInfo)
static constexpr skcms_Matrix3x3 kDisplayP3
Definition: SkColorSpace.h:87
static constexpr skcms_TransferFunction kSRGB
Definition: SkColorSpace.h:45
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)

◆ DEF_TEST() [2/9]

DEF_TEST ( AndroidCodec_gainmapInfoParse  ,
 
)

Definition at line 1050 of file JpegGainmapTest.cpp.

1050 {
1051 const uint8_t versionData[] = {
1052 0x00, // Minimum version
1053 0x00,
1054 0x00, // Writer version
1055 0x00,
1056 };
1057 const uint8_t data[] = {
1058 0x00, 0x00, // Minimum version
1059 0x00, 0x00, // Writer version
1060 0xc0, // Flags
1061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // Base HDR headroom
1062 0x00, 0x01, 0x45, 0x3e, 0x00, 0x00, 0x80, 0x00, // Altr HDR headroom
1063 0xfc, 0x23, 0x05, 0x14, 0x40, 0x00, 0x00, 0x00, // Red: Gainmap min
1064 0x00, 0x01, 0x1f, 0xe1, 0x00, 0x00, 0x80, 0x00, // Red: Gainmap max
1065 0x10, 0x4b, 0x9f, 0x0a, 0x40, 0x00, 0x00, 0x00, // Red: Gamma
1066 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // Red: Base offset
1067 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // Red: Altr offset
1068 0xfd, 0xdb, 0x68, 0x04, 0x40, 0x00, 0x00, 0x00, // Green: Gainmap min
1069 0x00, 0x01, 0x11, 0x68, 0x00, 0x00, 0x80, 0x00, // Green: Gainmap max
1070 0x10, 0x28, 0xf9, 0x53, 0x40, 0x00, 0x00, 0x00, // Green: Gamma
1071 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // Green: Base offset
1072 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // Green: Altr offset
1073 0xf7, 0x16, 0x7b, 0x90, 0x40, 0x00, 0x00, 0x00, // Blue: Gainmap min
1074 0x00, 0x01, 0x0f, 0x9a, 0x00, 0x00, 0x80, 0x00, // Blue: Gainmap max
1075 0x12, 0x95, 0xa8, 0x3f, 0x40, 0x00, 0x00, 0x00, // Blue: Gamma
1076 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // Blue: Base offset
1077 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // Blue: Altr offset
1078 };
1079 SkGainmapInfo kExpectedInfo = {{0.959023f, 0.977058f, 0.907989f, 1.f},
1080 {4.753710f, 4.395375f, 4.352630f, 1.f},
1081 {3.927490f, 3.960382f, 3.443712f, 1.f},
1082 {0.015625f, 0.015625f, 0.015625f, 1.f},
1083 {0.015625f, 0.015625f, 0.015625f, 1.f},
1084 1.000000f,
1085 5.819739f,
1088 nullptr};
1089 SkGainmapInfo kSingleChannelInfo = {{0.1234567e-4f, 0.1234567e-4f, 0.1234567e-4f, 1.f},
1090 {-0.1234567e-4f, -0.1234567e-4f, -0.1234567e-4f, 1.f},
1091 {0.1234567e+0f, 0.1234567e+0f, 0.1234567e+0f, 1.f},
1092 {0.1234567e+4f, 0.1234567e+4f, 0.1234567e+4f, 1.f},
1093 {0.1234567e+4f, 0.1234567e+4f, 0.1234567e+4f, 1.f},
1094 1.,
1095 4.f,
1099
1100 // Verify the version from data.
1103 SkData::MakeWithoutCopy(versionData, sizeof(versionData)).get()));
1104
1105 // Verify the SkGainmapInfo from data.
1109 expect_approx_eq_info(r, info, kExpectedInfo);
1110
1111 // Verify the parsed version.
1113
1114 // Verify the round-trip SkGainmapInfo.
1115 auto dataInfo = info.serialize();
1116 SkGainmapInfo infoRoundTrip;
1117 REPORTER_ASSERT(r, SkGainmapInfo::Parse(dataInfo.get(), infoRoundTrip));
1118 expect_approx_eq_info(r, info, infoRoundTrip);
1119
1120 // Serialize a single-channel SkGainmapInfo. The serialized data should be smaller.
1121 auto dataSingleChannelInfo = kSingleChannelInfo.serialize();
1122 REPORTER_ASSERT(r, dataSingleChannelInfo->size() < dataInfo->size());
1123 SkGainmapInfo singleChannelInfoRoundTrip;
1125 SkGainmapInfo::Parse(dataSingleChannelInfo.get(), singleChannelInfoRoundTrip));
1126 expect_approx_eq_info(r, singleChannelInfoRoundTrip, kSingleChannelInfo);
1127}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition: SkData.h:116
const myers::Point & get(const myers::Segment &)
sk_sp< SkData > serialize() const
static bool ParseVersion(const SkData *data)
static bool Parse(const SkData *data, SkGainmapInfo &info)
static sk_sp< SkData > SerializeVersion()
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ DEF_TEST() [3/9]

DEF_TEST ( AndroidCodec_jpegGainmapDecode  ,
 
)

Definition at line 521 of file JpegGainmapTest.cpp.

521 {
522 const struct Rec {
523 const char* path;
524 SkISize dimensions;
525 SkColor originColor;
526 SkColor farCornerColor;
528 } recs[] = {
529 {"images/iphone_13_pro.jpeg",
530 SkISize::Make(1512, 2016),
531 0xFF3B3B3B,
532 0xFF101010,
533 {{1.f, 1.f, 1.f, 1.f},
534 {3.482202f, 3.482202f, 3.482202f, 1.f},
535 {1.f, 1.f, 1.f, 1.f},
536 {0.f, 0.f, 0.f, 1.f},
537 {0.f, 0.f, 0.f, 1.f},
538 1.f,
539 3.482202f,
542 nullptr}},
543 {"images/iphone_15.jpeg",
544 SkISize::Make(2016, 1512),
545 0xFF5C5C5C,
546 0xFF656565,
547 {{1.f, 1.f, 1.f, 1.f},
548 {3.755272f, 3.755272f, 3.755272f, 1.f},
549 {1.f, 1.f, 1.f, 1.f},
550 {0.f, 0.f, 0.f, 1.f},
551 {0.f, 0.f, 0.f, 1.f},
552 1.f,
553 3.755272f,
556 nullptr}},
557 {"images/gainmap_gcontainer_only.jpg",
558 SkISize::Make(32, 32),
559 0xffffffff,
560 0xffffffff,
561 {{25.f, 0.5f, 1.f, 1.f},
562 {2.f, 4.f, 8.f, 1.f},
563 {0.5, 1.f, 2.f, 1.f},
564 {0.01f, 0.001f, 0.0001f, 1.f},
565 {0.0001f, 0.001f, 0.01f, 1.f},
566 2.f,
567 4.f,
570 nullptr}},
571 {"images/gainmap_iso21496_1_adobe_gcontainer.jpg",
572 SkISize::Make(32, 32),
573 0xffffffff,
574 0xff000000,
575 {{25.f, 0.5f, 1.f, 1.f},
576 {2.f, 4.f, 8.f, 1.f},
577 {0.5, 1.f, 2.f, 1.f},
578 {0.01f, 0.001f, 0.0001f, 1.f},
579 {0.0001f, 0.001f, 0.01f, 1.f},
580 2.f,
581 4.f,
584 nullptr}},
585 {"images/gainmap_iso21496_1.jpg",
586 SkISize::Make(32, 32),
587 0xffffffff,
588 0xff000000,
589 {{25.f, 0.5f, 1.f, 1.f},
590 {2.f, 4.f, 8.f, 1.f},
591 {0.5, 1.f, 2.f, 1.f},
592 {0.01f, 0.001f, 0.0001f, 1.f},
593 {0.0001f, 0.001f, 0.01f, 1.f},
594 2.f,
595 4.f,
599 };
600
601 TestStream::Type kStreamTypes[] = {
602 TestStream::Type::kUnseekable,
603 TestStream::Type::kSeekable,
604 TestStream::Type::kMemoryMapped,
605 };
606 for (const auto& streamType : kStreamTypes) {
607 bool useFileStream = streamType != TestStream::Type::kMemoryMapped;
608 for (const auto& rec : recs) {
609 auto stream = GetResourceAsStream(rec.path, useFileStream);
611 auto testStream = std::make_unique<TestStream>(streamType, stream.get());
612
613 SkBitmap baseBitmap;
614 SkBitmap gainmapBitmap;
615 SkGainmapInfo gainmapInfo;
616 decode_all(r, std::move(testStream), baseBitmap, gainmapBitmap, gainmapInfo);
617
618 // Spot-check the image size and pixels.
619 REPORTER_ASSERT(r, gainmapBitmap.dimensions() == rec.dimensions);
620 REPORTER_ASSERT(r, gainmapBitmap.getColor(0, 0) == rec.originColor);
622 r,
623 gainmapBitmap.getColor(rec.dimensions.fWidth - 1, rec.dimensions.fHeight - 1) ==
624 rec.farCornerColor);
625
626 // Verify the gainmap rendering parameters.
627 expect_approx_eq_info(r, rec.info, gainmapInfo);
628 }
629 }
630}
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition: Resources.cpp:31
uint32_t SkColor
Definition: SkColor.h:37
SkISize dimensions() const
Definition: SkBitmap.h:388
SkColor getColor(int x, int y) const
Definition: SkBitmap.h:874
static constexpr skcms_Matrix3x3 kRec2020
Definition: SkColorSpace.h:93
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20

◆ DEF_TEST() [4/9]

DEF_TEST ( AndroidCodec_jpegGainmapTranscode  ,
 
)

Definition at line 824 of file JpegGainmapTest.cpp.

824 {
825 const char* path = "images/iphone_13_pro.jpeg";
826 SkBitmap baseBitmap[2];
827 SkBitmap gainmapBitmap[2];
828 SkGainmapInfo gainmapInfo[2];
829
830 // Decode an MPF-based gainmap image.
831 decode_all(r, GetResourceAsStream(path), baseBitmap[0], gainmapBitmap[0], gainmapInfo[0]);
832
833 // This test was written before SkGainmapShader added support for kApple type. Strip the
834 // type out.
835 gainmapInfo[0].fType = SkGainmapInfo::Type::kDefault;
836
837 constexpr float kEpsilon = 1e-2f;
838 {
839 SkDynamicMemoryWStream encodeStream;
840
841 // Transcode to UltraHDR.
842 bool encodeResult = SkJpegGainmapEncoder::EncodeHDRGM(&encodeStream,
843 baseBitmap[0].pixmap(),
845 gainmapBitmap[0].pixmap(),
847 gainmapInfo[0]);
848 REPORTER_ASSERT(r, encodeResult);
849 auto encodeData = encodeStream.detachAsData();
850
851 // Decode the just-encoded image.
852 auto decodeStream = std::make_unique<SkMemoryStream>(encodeData);
853 decode_all(r, std::move(decodeStream), baseBitmap[1], gainmapBitmap[1], gainmapInfo[1]);
854
855 // HDRGM will have the same rendering parameters.
856 expect_approx_eq_info(r, gainmapInfo[0], gainmapInfo[1]);
857
858 // Render a few pixels and verify that they come out the same. Rendering requires SkSL.
859 const struct Rec {
860 int x;
861 int y;
862 float hdrRatio;
863 SkColor4f expectedColor;
864 SkColorType forcedColorType;
865 } recs[] = {
866 {1446, 1603, 1.05f, {0.984375f, 1.004883f, 1.008789f, 1.f}, kUnknown_SkColorType},
867 {1446, 1603, 100.f, {1.147461f, 1.170898f, 1.174805f, 1.f}, kUnknown_SkColorType},
868 {1446, 1603, 100.f, {1.147461f, 1.170898f, 1.174805f, 1.f}, kGray_8_SkColorType},
869 {1446, 1603, 100.f, {1.147461f, 1.170898f, 1.174805f, 1.f}, kAlpha_8_SkColorType},
870 {1446, 1603, 100.f, {1.147461f, 1.170898f, 1.174805f, 1.f}, kR8_unorm_SkColorType},
871 };
872
873 for (const auto& rec : recs) {
874 SkBitmap gainmapBitmap0;
875 SkASSERT(gainmapBitmap[0].colorType() == kGray_8_SkColorType);
876
877 // Force various different single-channel formats, to ensure that they all work. Note
878 // that when the color type is forced to kAlpha_8_SkColorType, the shader will always
879 // read (0,0,0,1) if the alpha type is kOpaque_SkAlphaType.
880 if (rec.forcedColorType == kUnknown_SkColorType) {
881 gainmapBitmap0 = gainmapBitmap[0];
882 } else {
883 gainmapBitmap0.installPixels(gainmapBitmap[0]
884 .info()
885 .makeColorType(rec.forcedColorType)
886 .makeAlphaType(kPremul_SkAlphaType),
887 gainmapBitmap[0].getPixels(),
888 gainmapBitmap[0].rowBytes());
889 }
891 rec.hdrRatio, baseBitmap[0], gainmapBitmap0, gainmapInfo[0], rec.x, rec.y);
893 rec.hdrRatio, baseBitmap[1], gainmapBitmap[1], gainmapInfo[1], rec.x, rec.y);
894
896 }
897 }
898}
static bool approx_eq(float x, float y, float epsilon)
Definition: ExifTest.cpp:81
static SkColor4f render_gainmap_pixel(float renderHdrRatio, const SkBitmap &baseBitmap, const SkBitmap &gainmapBitmap, const SkGainmapInfo &gainmapInfo, int x, int y)
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkColorType
Definition: SkColorType.h:19
@ kR8_unorm_SkColorType
Definition: SkColorType.h:54
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
static constexpr double kEpsilon
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
bool installPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, void(*releaseProc)(void *addr, void *context), void *context)
Definition: SkBitmap.cpp:323
double y
double x

◆ DEF_TEST() [5/9]

DEF_TEST ( AndroidCodec_jpegNoGainmap  ,
 
)

Definition at line 632 of file JpegGainmapTest.cpp.

632 {
633 // This test image has a large APP16 segment that will stress the various SkJpegSourceMgrs'
634 // data skipping paths.
635 const char* path = "images/icc-v2-gbr.jpg";
636
637 TestStream::Type kStreamTypes[] = {
638 TestStream::Type::kUnseekable,
639 TestStream::Type::kSeekable,
640 TestStream::Type::kMemoryMapped,
641 };
642 for (const auto& streamType : kStreamTypes) {
643 bool useFileStream = streamType != TestStream::Type::kMemoryMapped;
644 auto stream = GetResourceAsStream(path, useFileStream);
646 auto testStream = std::make_unique<TestStream>(streamType, stream.get());
647
648 // Decode the base bitmap.
650 std::unique_ptr<SkCodec> baseCodec =
651 SkJpegCodec::MakeFromStream(std::move(testStream), &result);
652 REPORTER_ASSERT(r, baseCodec);
653 SkBitmap baseBitmap;
654 baseBitmap.allocPixels(baseCodec->getInfo());
656 SkCodec::kSuccess == baseCodec->getPixels(baseBitmap.info(),
657 baseBitmap.getPixels(),
658 baseBitmap.rowBytes()));
659
660 std::unique_ptr<SkAndroidCodec> androidCodec =
661 SkAndroidCodec::MakeFromCodec(std::move(baseCodec));
662 REPORTER_ASSERT(r, androidCodec);
663
664 // Try to extract the gainmap info and stream. It should fail.
665 SkGainmapInfo gainmapInfo;
666 std::unique_ptr<SkStream> gainmapStream;
667 REPORTER_ASSERT(r, !androidCodec->getAndroidGainmap(&gainmapInfo, &gainmapStream));
668 }
669}

◆ DEF_TEST() [6/9]

DEF_TEST ( AndroidCodec_mpfParse  ,
 
)

Definition at line 952 of file JpegGainmapTest.cpp.

952 {
953 sk_sp<SkData> inputData = GetResourceAsData("images/iphone_13_pro.jpeg");
954
955 {
956 // The MPF in iPhone images has 3 entries: version, image count, and the MP entries.
957 auto ifd = get_mpf_ifd(inputData);
958 REPORTER_ASSERT(r, ifd);
959 REPORTER_ASSERT(r, ifd->getNumEntries() == 3);
960 REPORTER_ASSERT(r, ifd->getEntryTag(0) == 0xB000);
961 REPORTER_ASSERT(r, ifd->getEntryTag(1) == 0xB001);
962 REPORTER_ASSERT(r, ifd->getEntryTag(2) == 0xB002);
963
964 // There is no attribute IFD.
965 REPORTER_ASSERT(r, !ifd->nextIfdOffset());
966 }
967
968 {
969 // The gainmap images have version and image count.
970 auto ifd = get_mpf_ifd(get_mp_image(inputData, 1));
971 REPORTER_ASSERT(r, ifd);
972
973 REPORTER_ASSERT(r, ifd->getNumEntries() == 2);
974 REPORTER_ASSERT(r, ifd->getEntryTag(0) == 0xB000);
975 REPORTER_ASSERT(r, ifd->getEntryTag(1) == 0xB001);
976 uint32_t value = 0;
977 REPORTER_ASSERT(r, ifd->getEntryUnsignedLong(1, 1, &value));
978 REPORTER_ASSERT(r, value == 3);
979
980 // There is no further IFD.
981 REPORTER_ASSERT(r, !ifd->nextIfdOffset());
982 }
983
984 // Replace |inputData| with its transcoded version.
985 {
986 SkBitmap baseBitmap;
987 SkBitmap gainmapBitmap;
988 SkGainmapInfo gainmapInfo;
989 decode_all(r,
990 std::make_unique<SkMemoryStream>(inputData),
991 baseBitmap,
992 gainmapBitmap,
993 gainmapInfo);
995 SkDynamicMemoryWStream encodeStream;
996 bool encodeResult = SkJpegGainmapEncoder::EncodeHDRGM(&encodeStream,
997 baseBitmap.pixmap(),
999 gainmapBitmap.pixmap(),
1001 gainmapInfo);
1002 REPORTER_ASSERT(r, encodeResult);
1003 inputData = encodeStream.detachAsData();
1004 }
1005
1006 {
1007 // Exif should be present and valid.
1008 auto ifd = get_exif_ifd(inputData);
1009 REPORTER_ASSERT(r, ifd);
1010 REPORTER_ASSERT(r, ifd->getNumEntries() == 1);
1011 constexpr uint16_t kSubIFDOffsetTag = 0x8769;
1012 REPORTER_ASSERT(r, ifd->getEntryTag(0) == kSubIFDOffsetTag);
1013 }
1014
1015 {
1016 // The MPF in encoded images has 3 entries: version, image count, and the MP entries.
1017 auto ifd = get_mpf_ifd(inputData);
1018 REPORTER_ASSERT(r, ifd);
1019 REPORTER_ASSERT(r, ifd->getNumEntries() == 3);
1020 REPORTER_ASSERT(r, ifd->getEntryTag(0) == 0xB000);
1021 REPORTER_ASSERT(r, ifd->getEntryTag(1) == 0xB001);
1022 REPORTER_ASSERT(r, ifd->getEntryTag(2) == 0xB002);
1023
1024 // There is no attribute IFD.
1025 REPORTER_ASSERT(r, !ifd->nextIfdOffset());
1026 }
1027
1028 {
1029 // The MPF in encoded gainmap images has 2 entries: Version and number of images.
1030 auto ifd = get_mpf_ifd(get_mp_image(inputData, 1));
1031 REPORTER_ASSERT(r, ifd);
1032
1033 REPORTER_ASSERT(r, ifd->getNumEntries() == 1);
1034 REPORTER_ASSERT(r, ifd->getEntryTag(0) == 0xB000);
1035
1036 // Verify the version data (don't verify the version in the primary image, because if that
1037 // were broken all MPF images would be broken).
1038 sk_sp<SkData> versionData = ifd->getEntryUndefinedData(0);
1039 REPORTER_ASSERT(r, versionData);
1040 REPORTER_ASSERT(r, versionData->bytes()[0] == '0');
1041 REPORTER_ASSERT(r, versionData->bytes()[1] == '1');
1042 REPORTER_ASSERT(r, versionData->bytes()[2] == '0');
1043 REPORTER_ASSERT(r, versionData->bytes()[3] == '0');
1044
1045 // There is no further IFD.
1046 REPORTER_ASSERT(r, !ifd->nextIfdOffset());
1047 }
1048}
static sk_sp< SkData > get_mp_image(sk_sp< SkData > imageData, size_t imageNumber)
static std::unique_ptr< SkTiff::ImageFileDirectory > get_exif_ifd(sk_sp< SkData > imageData)
static std::unique_ptr< SkTiff::ImageFileDirectory > get_mpf_ifd(sk_sp< SkData > imageData)
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition: Resources.cpp:42
const uint8_t * bytes() const
Definition: SkData.h:43
uint8_t value
constexpr uint16_t kSubIFDOffsetTag
Definition: SkExif.cpp:22

◆ DEF_TEST() [7/9]

DEF_TEST ( Codec_jpegMultiPicture  ,
 
)

Definition at line 392 of file JpegGainmapTest.cpp.

392 {
393 const char* path = "images/iphone_13_pro.jpeg";
396
397 // Search and parse the MPF header.
398 std::unique_ptr<SkJpegMultiPictureParameters> mpParams;
399 SkJpegSegment mpParamsSegment;
400 REPORTER_ASSERT(r, find_mp_params_segment(stream.get(), &mpParams, &mpParamsSegment));
401
402 // Verify that we get the same parameters when we re-serialize and de-serialize them
403 {
404 auto mpParamsSerialized = mpParams->serialize(0);
405 REPORTER_ASSERT(r, mpParamsSerialized);
406 auto mpParamsRoundTripped = SkJpegMultiPictureParameters::Make(mpParamsSerialized);
407 REPORTER_ASSERT(r, mpParamsRoundTripped);
408 REPORTER_ASSERT(r, mpParamsRoundTripped->images.size() == mpParams->images.size());
409 for (size_t i = 0; i < mpParamsRoundTripped->images.size(); ++i) {
410 REPORTER_ASSERT(r, mpParamsRoundTripped->images[i].size == mpParams->images[i].size);
412 r,
413 mpParamsRoundTripped->images[i].dataOffset == mpParams->images[i].dataOffset);
414 }
415 }
416
417 const struct Rec {
418 const TestStream::Type streamType;
419 const bool skipFirstImage;
420 const size_t bufferSize;
421 } recs[] = {
422 {TestStream::Type::kMemoryMapped, false, 1024},
423 {TestStream::Type::kMemoryMapped, true, 1024},
424 {TestStream::Type::kSeekable, false, 1024},
425 {TestStream::Type::kSeekable, true, 1024},
426 {TestStream::Type::kSeekable, false, 7},
427 {TestStream::Type::kSeekable, true, 13},
428 {TestStream::Type::kSeekable, true, 1024 * 1024 * 16},
429 {TestStream::Type::kUnseekable, false, 1024},
430 {TestStream::Type::kUnseekable, true, 1024},
431 {TestStream::Type::kUnseekable, false, 1},
432 {TestStream::Type::kUnseekable, true, 1},
433 {TestStream::Type::kUnseekable, false, 7},
434 {TestStream::Type::kUnseekable, true, 13},
435 {TestStream::Type::kUnseekable, false, 1024 * 1024 * 16},
436 {TestStream::Type::kUnseekable, true, 1024 * 1024 * 16},
437 };
438 for (const auto& rec : recs) {
439 stream->rewind();
440 TestStream testStream(rec.streamType, stream.get());
441 auto sourceMgr = SkJpegSourceMgr::Make(&testStream, rec.bufferSize);
442
443 // Decode the images into bitmaps.
444 size_t numberOfImages = mpParams->images.size();
445 std::vector<SkBitmap> bitmaps(numberOfImages);
446 for (size_t i = 0; i < numberOfImages; ++i) {
447 if (i == 0) {
448 REPORTER_ASSERT(r, mpParams->images[i].dataOffset == 0);
449 continue;
450 }
451 if (i == 1 && rec.skipFirstImage) {
452 continue;
453 }
454 auto imageData = sourceMgr->getSubsetData(
456 mpParams->images[i].dataOffset, mpParamsSegment.offset),
457 mpParams->images[i].size);
458 REPORTER_ASSERT(r, imageData);
459
460 std::unique_ptr<SkCodec> codec =
462 REPORTER_ASSERT(r, codec);
463
464 SkBitmap bm;
465 bm.allocPixels(codec->getInfo());
468 codec->getPixels(bm.info(), bm.getPixels(), bm.rowBytes()));
469 bitmaps[i] = bm;
470 }
471
472 // Spot-check the image size and pixels.
473 if (!rec.skipFirstImage) {
474 REPORTER_ASSERT(r, bitmaps[1].dimensions() == SkISize::Make(1512, 2016));
475 REPORTER_ASSERT(r, bitmaps[1].getColor(0, 0) == 0xFF3B3B3B);
476 REPORTER_ASSERT(r, bitmaps[1].getColor(1511, 2015) == 0xFF101010);
477 }
478 REPORTER_ASSERT(r, bitmaps[2].dimensions() == SkISize::Make(576, 768));
479 REPORTER_ASSERT(r, bitmaps[2].getColor(0, 0) == 0xFF010101);
480 REPORTER_ASSERT(r, bitmaps[2].getColor(575, 767) == 0xFFB5B5B5);
481 }
482}
static bool find_mp_params_segment(SkStream *stream, std::unique_ptr< SkJpegMultiPictureParameters > *outMpParams, SkJpegSegment *outMpParamsSegment)
static std::unique_ptr< SkJpegSourceMgr > Make(SkStream *stream, size_t bufferSize=1024)
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition: SkStream.cpp:314
static size_t GetImageAbsoluteOffset(uint32_t dataOffset, size_t mpSegmentOffset)
static std::unique_ptr< SkJpegMultiPictureParameters > Make(const sk_sp< const SkData > &segmentParameters)

◆ DEF_TEST() [8/9]

DEF_TEST ( Codec_jpegSegmentScan  ,
 
)

Definition at line 172 of file JpegGainmapTest.cpp.

172 {
173 const struct Rec {
174 const char* path;
175 size_t sosSegmentCount;
176 size_t eoiSegmentCount;
177 size_t testSegmentIndex;
178 uint8_t testSegmentMarker;
179 size_t testSegmentOffset;
180 uint16_t testSegmentParameterLength;
181 } recs[] = {
182 {"images/wide_gamut_yellow_224_224_64.jpeg", 11, 15, 10, 0xda, 9768, 12},
183 {"images/CMYK.jpg", 7, 8, 1, 0xee, 2, 14},
184 {"images/b78329453.jpeg", 10, 23, 3, 0xe2, 154, 540},
185 {"images/brickwork-texture.jpg", 8, 28, 12, 0xc4, 34183, 42},
186 {"images/brickwork_normal-map.jpg", 8, 28, 27, 0xd9, 180612, 0},
187 {"images/cmyk_yellow_224_224_32.jpg", 19, 23, 2, 0xed, 854, 2828},
188 {"images/color_wheel.jpg", 10, 11, 2, 0xdb, 20, 67},
189 {"images/cropped_mandrill.jpg", 10, 11, 4, 0xc0, 158, 17},
190 {"images/dog.jpg", 10, 11, 5, 0xc4, 177, 28},
191 {"images/ducky.jpg", 12, 13, 10, 0xc4, 3718, 181},
192 {"images/exif-orientation-2-ur.jpg", 11, 12, 2, 0xe1, 20, 130},
193 {"images/flutter_logo.jpg", 9, 27, 21, 0xda, 5731, 8},
194 {"images/grayscale.jpg", 6, 16, 9, 0xda, 327, 8},
195 {"images/icc-v2-gbr.jpg", 12, 25, 24, 0xd9, 43832, 0},
196 {"images/mandrill_512_q075.jpg", 10, 11, 7, 0xc4, 393, 31},
197 {"images/mandrill_cmyk.jpg", 19, 35, 16, 0xdd, 574336, 4},
198 {"images/mandrill_h1v1.jpg", 10, 11, 1, 0xe0, 2, 16},
199 {"images/mandrill_h2v1.jpg", 10, 11, 0, 0xd8, 0, 0},
200 {"images/randPixels.jpg", 10, 11, 6, 0xc4, 200, 30},
201 {"images/wide_gamut_yellow_224_224_64.jpeg", 11, 15, 10, 0xda, 9768, 12},
202 };
203
204 for (const auto& rec : recs) {
205 auto stream = GetResourceAsStream(rec.path);
206 if (!stream) {
207 continue;
208 }
209
210 // Scan all the way to EndOfImage.
211 auto sourceMgr = SkJpegSourceMgr::Make(stream.get());
212 const auto& segments = sourceMgr->getAllSegments();
213
214 // Verify we got the expected number of segments at EndOfImage
215 REPORTER_ASSERT(r, rec.eoiSegmentCount == segments.size());
216
217 // Verify we got the expected number of segments before StartOfScan
218 for (size_t i = 0; i < segments.size(); ++i) {
219 if (segments[i].marker == kJpegMarkerStartOfScan) {
220 REPORTER_ASSERT(r, rec.sosSegmentCount == i + 1);
221 break;
222 }
223 }
224
225 // Verify the values for a randomly pre-selected segment index.
226 const auto& segment = segments[rec.testSegmentIndex];
227 REPORTER_ASSERT(r, rec.testSegmentMarker == segment.marker);
228 REPORTER_ASSERT(r, rec.testSegmentOffset == segment.offset);
229 REPORTER_ASSERT(r, rec.testSegmentParameterLength == segment.parameterLength);
230 }
231}
static const char marker[]
static constexpr uint8_t kJpegMarkerStartOfScan

◆ DEF_TEST() [9/9]

DEF_TEST ( Codec_multiPictureParams  ,
 
)

Definition at line 254 of file JpegGainmapTest.cpp.

254 {
255 // Little-endian test.
256 {
257 const uint8_t bytes[] = {
258 0x4d, 0x50, 0x46, 0x00, 0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03,
259 0x00, 0x00, 0xb0, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x31, 0x30, 0x30,
260 0x01, 0xb0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
261 0xb0, 0x07, 0x00, 0x20, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
262 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x20, 0xcf, 0x49, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x28, 0x01, 0x00,
264 0xf9, 0xb7, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
265 };
266 auto mpParams =
268 REPORTER_ASSERT(r, mpParams);
269 REPORTER_ASSERT(r, mpParams->images.size() == 2);
270 REPORTER_ASSERT(r, mpParams->images[0].dataOffset == 0);
271 REPORTER_ASSERT(r, mpParams->images[0].size == 4837152);
272 REPORTER_ASSERT(r, mpParams->images[1].dataOffset == 3979257);
273 REPORTER_ASSERT(r, mpParams->images[1].size == 76014);
274 }
275
276 // Big-endian test.
277 {
278 const uint8_t bytes[] = {
279 0x4d, 0x50, 0x46, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00,
280 0x03, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30,
281 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0xb0,
282 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
283 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x56, 0xda, 0x2f, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xc6, 0x01,
285 0x00, 0x55, 0x7c, 0x1f, 0x00, 0x00, 0x00, 0x00,
286 };
287 auto mpParams =
289 REPORTER_ASSERT(r, mpParams);
290 REPORTER_ASSERT(r, mpParams->images.size() == 2);
291 REPORTER_ASSERT(r, mpParams->images[0].dataOffset == 0);
292 REPORTER_ASSERT(r, mpParams->images[0].size == 5691951);
293 REPORTER_ASSERT(r, mpParams->images[1].dataOffset == 5602335);
294 REPORTER_ASSERT(r, mpParams->images[1].size == 1361409);
295 }
296
297 // Three entry test.
298 {
299 const uint8_t bytes[] = {
300 0x4d, 0x50, 0x46, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00,
301 0x03, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30,
302 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0xb0,
303 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x1c, 0xc2, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0xb0,
306 0x00, 0x1f, 0x12, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x96, 0x6b, 0x00, 0x22, 0x18, 0x9c, 0x00, 0x00, 0x00, 0x00,
308 };
309 auto mpParams =
311 REPORTER_ASSERT(r, mpParams);
312 REPORTER_ASSERT(r, mpParams->images.size() == 3);
313 REPORTER_ASSERT(r, mpParams->images[0].dataOffset == 0);
314 REPORTER_ASSERT(r, mpParams->images[0].size == 2038978);
315 REPORTER_ASSERT(r, mpParams->images[1].dataOffset == 2036460);
316 REPORTER_ASSERT(r, mpParams->images[1].size == 198064);
317 REPORTER_ASSERT(r, mpParams->images[2].dataOffset == 2234524);
318 REPORTER_ASSERT(r, mpParams->images[2].size == 38507);
319 }
320
321 // Inserting various corrupt values.
322 {
323 const uint8_t bytes[] = {
324 0x4d, 0x50, 0x46, 0x00, // 0: {'M', 'P', 'F', 0} signature
325 0x4d, 0x4d, 0x00, 0x2a, // 4: {'M', 'M', 0, '*'} big-endian
326 0x00, 0x00, 0x00, 0x08, // 8: Index IFD offset
327 0x00, 0x03, // 12: Number of tags
328 0xb0, 0x00, // 14: Version tag
329 0x00, 0x07, // 16: Undefined type
330 0x00, 0x00, 0x00, 0x04, // 18: Size
331 0x30, 0x31, 0x30, 0x30, // 22: Value
332 0xb0, 0x01, // 26: Number of images
333 0x00, 0x04, // 28: Unsigned long type
334 0x00, 0x00, 0x00, 0x01, // 30: Count
335 0x00, 0x00, 0x00, 0x02, // 34: Value
336 0xb0, 0x02, // 38: MP entry tag
337 0x00, 0x07, // 40: Undefined type
338 0x00, 0x00, 0x00, 0x20, // 42: Size
339 0x00, 0x00, 0x00, 0x32, // 46: Value (offset)
340 0x00, 0x00, 0x00, 0x00, // 50: Next IFD offset (null)
341 0x20, 0x03, 0x00, 0x00, // 54: MP Entry 0 attributes
342 0x00, 0x56, 0xda, 0x2f, // 58: MP Entry 0 size (5691951)
343 0x00, 0x00, 0x00, 0x00, // 62: MP Entry 0 offset (0)
344 0x00, 0x00, 0x00, 0x00, // 66: MP Entry 0 dependencies
345 0x00, 0x00, 0x00, 0x00, // 70: MP Entry 1 attributes.
346 0x00, 0x14, 0xc6, 0x01, // 74: MP Entry 1 size (1361409)
347 0x00, 0x55, 0x7c, 0x1f, // 78: MP Entry 1 offset (5602335)
348 0x00, 0x00, 0x00, 0x00, // 82: MP Entry 1 dependencies
349 };
350
351 // Verify the offsets labeled above.
352 REPORTER_ASSERT(r, bytes[22] == 0x30);
353 REPORTER_ASSERT(r, bytes[26] == 0xb0);
354 REPORTER_ASSERT(r, bytes[38] == 0xb0);
355 REPORTER_ASSERT(r, bytes[54] == 0x20);
356 REPORTER_ASSERT(r, bytes[81] == 0x1f);
357
358 {
359 // Change the version to {'0', '1', '0', '1'}.
360 auto bytesInvalid = SkData::MakeWithCopy(bytes, sizeof(bytes));
361 REPORTER_ASSERT(r, bytes[25] == '0');
362 reinterpret_cast<uint8_t*>(bytesInvalid->writable_data())[25] = '1';
363 REPORTER_ASSERT(r, SkJpegMultiPictureParameters::Make(bytesInvalid) == nullptr);
364 }
365
366 {
367 // Change the number of images to be undefined type instead of unsigned long type.
368 auto bytesInvalid = SkData::MakeWithCopy(bytes, sizeof(bytes));
369 REPORTER_ASSERT(r, bytes[29] == 0x04);
370 reinterpret_cast<uint8_t*>(bytesInvalid->writable_data())[29] = 0x07;
371 REPORTER_ASSERT(r, SkJpegMultiPictureParameters::Make(bytesInvalid) == nullptr);
372 }
373
374 {
375 // Make the MP entries point off of the end of the buffer.
376 auto bytesInvalid = SkData::MakeWithCopy(bytes, sizeof(bytes));
377 REPORTER_ASSERT(r, bytes[49] == 0x32);
378 reinterpret_cast<uint8_t*>(bytesInvalid->writable_data())[49] = 0xFE;
379 REPORTER_ASSERT(r, SkJpegMultiPictureParameters::Make(bytesInvalid) == nullptr);
380 }
381
382 {
383 // Make the MP entries too small.
384 auto bytesInvalid = SkData::MakeWithCopy(bytes, sizeof(bytes));
385 REPORTER_ASSERT(r, bytes[45] == 0x20);
386 reinterpret_cast<uint8_t*>(bytesInvalid->writable_data())[45] = 0x1F;
387 REPORTER_ASSERT(r, SkJpegMultiPictureParameters::Make(bytesInvalid) == nullptr);
388 }
389 }
390}
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition: SkData.cpp:111

◆ find_mp_params_segment()

static bool find_mp_params_segment ( SkStream stream,
std::unique_ptr< SkJpegMultiPictureParameters > *  outMpParams,
SkJpegSegment outMpParamsSegment 
)
static

Definition at line 233 of file JpegGainmapTest.cpp.

235 {
236 auto sourceMgr = SkJpegSourceMgr::Make(stream);
237 for (const auto& segment : sourceMgr->getAllSegments()) {
238 if (segment.marker != kMpfMarker) {
239 continue;
240 }
241 auto parameterData = sourceMgr->getSegmentParameters(segment);
242 if (!parameterData) {
243 continue;
244 }
245 *outMpParams = SkJpegMultiPictureParameters::Make(parameterData);
246 if (*outMpParams) {
247 *outMpParamsSegment = segment;
248 return true;
249 }
250 }
251 return false;
252}
static constexpr uint32_t kMpfMarker

◆ get_exif_ifd()

static std::unique_ptr< SkTiff::ImageFileDirectory > get_exif_ifd ( sk_sp< SkData imageData)
static

Definition at line 948 of file JpegGainmapTest.cpp.

948 {
949 return get_ifd(std::move(imageData), kExifMarker, kExifSig, sizeof(kExifSig), 1);
950}
static std::unique_ptr< SkTiff::ImageFileDirectory > get_ifd(sk_sp< SkData > imageData, uint8_t marker, const void *sig, size_t sigSize, size_t pad)
static constexpr uint32_t kExifMarker
constexpr uint8_t kExifSig[]

◆ get_ifd()

static std::unique_ptr< SkTiff::ImageFileDirectory > get_ifd ( sk_sp< SkData imageData,
uint8_t  marker,
const void *  sig,
size_t  sigSize,
size_t  pad 
)
static

Definition at line 916 of file JpegGainmapTest.cpp.

917 {
918 SkMemoryStream stream(imageData);
919 auto sourceMgr = SkJpegSourceMgr::Make(&stream);
920 for (const auto& segment : sourceMgr->getAllSegments()) {
921 if (segment.marker != marker) {
922 continue;
923 }
924 auto parameterData = sourceMgr->getSegmentParameters(segment);
925 if (!parameterData) {
926 continue;
927 }
928 if (parameterData->size() < sigSize || memcmp(sig, parameterData->data(), sigSize) != 0) {
929 continue;
930 }
931 auto ifdData = SkData::MakeSubset(
932 parameterData.get(), sigSize + pad, parameterData->size() - (sigSize + pad));
933
934 bool littleEndian = false;
935 uint32_t ifdOffset = 0;
936 if (!SkTiff::ImageFileDirectory::ParseHeader(ifdData.get(), &littleEndian, &ifdOffset)) {
937 return nullptr;
938 }
939 return SkTiff::ImageFileDirectory::MakeFromOffset(ifdData, littleEndian, ifdOffset);
940 }
941 return nullptr;
942}
static sk_sp< SkData > MakeSubset(const SkData *src, size_t offset, size_t length)
Definition: SkData.cpp:173
static bool ParseHeader(const SkData *data, bool *outLittleEndian, uint32_t *outIfdOffset)
static std::unique_ptr< ImageFileDirectory > MakeFromOffset(sk_sp< SkData > data, bool littleEndian, uint32_t ifdOffset, bool allowTruncated=false)

◆ get_mp_image()

static sk_sp< SkData > get_mp_image ( sk_sp< SkData imageData,
size_t  imageNumber 
)
static

Definition at line 900 of file JpegGainmapTest.cpp.

900 {
901 SkMemoryStream stream(imageData);
902 auto sourceMgr = SkJpegSourceMgr::Make(&stream);
903
904 std::unique_ptr<SkJpegMultiPictureParameters> mpParams;
905 SkJpegSegment mpParamsSegment;
906 if (!find_mp_params_segment(&stream, &mpParams, &mpParamsSegment)) {
907 return nullptr;
908 }
909 return SkData::MakeSubset(
910 imageData.get(),
912 mpParams->images[imageNumber].dataOffset, mpParamsSegment.offset),
913 mpParams->images[imageNumber].size);
914}
T * get() const
Definition: SkRefCnt.h:303

◆ get_mpf_ifd()

static std::unique_ptr< SkTiff::ImageFileDirectory > get_mpf_ifd ( sk_sp< SkData imageData)
static

Definition at line 944 of file JpegGainmapTest.cpp.

944 {
945 return get_ifd(std::move(imageData), kMpfMarker, kMpfSig, sizeof(kMpfSig), 0);
946}
static constexpr uint8_t kMpfSig[]

◆ render_gainmap()

static SkBitmap render_gainmap ( const SkImageInfo renderInfo,
float  renderHdrRatio,
const SkBitmap baseBitmap,
const SkBitmap gainmapBitmap,
const SkGainmapInfo gainmapInfo,
int  x,
int  y 
)
static

Definition at line 763 of file JpegGainmapTest.cpp.

769 {
770 SkRect baseRect = SkRect::MakeXYWH(x, y, renderInfo.width(), renderInfo.height());
771
772 float scaleX = gainmapBitmap.width() / static_cast<float>(baseBitmap.width());
773 float scaleY = gainmapBitmap.height() / static_cast<float>(baseBitmap.height());
774 SkRect gainmapRect = SkRect::MakeXYWH(baseRect.x() * scaleX,
775 baseRect.y() * scaleY,
776 baseRect.width() * scaleX,
777 baseRect.height() * scaleY);
778
779 SkRect dstRect = SkRect::Make(renderInfo.dimensions());
780
781 sk_sp<SkImage> baseImage = SkImages::RasterFromBitmap(baseBitmap);
782 sk_sp<SkImage> gainmapImage = SkImages::RasterFromBitmap(gainmapBitmap);
783 sk_sp<SkShader> shader = SkGainmapShader::Make(baseImage,
784 baseRect,
786 gainmapImage,
787 gainmapRect,
789 gainmapInfo,
790 dstRect,
791 renderHdrRatio,
792 renderInfo.refColorSpace());
793
795 result.allocPixels(renderInfo);
796 result.eraseColor(SK_ColorTRANSPARENT);
797 SkCanvas canvas(result);
798
800 paint.setShader(shader);
801 canvas.drawRect(dstRect, paint);
802
803 return result;
804}
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
int width() const
Definition: SkBitmap.h:149
int height() const
Definition: SkBitmap.h:158
static sk_sp< SkShader > Make(const sk_sp< const SkImage > &baseImage, const SkRect &baseRect, const SkSamplingOptions &baseSamplingOptions, const sk_sp< const SkImage > &gainmapImage, const SkRect &gainmapRect, const SkSamplingOptions &gainmapSamplingOptions, const SkGainmapInfo &gainmapInfo, const SkRect &dstRect, float dstHdrRatio, sk_sp< SkColorSpace > dstColorSpace)
const Paint & paint
Definition: color_source.cc:38
SK_API sk_sp< SkImage > RasterFromBitmap(const SkBitmap &bitmap)
SkSamplingOptions(SkFilterMode::kLinear))
sk_sp< SkColorSpace > refColorSpace() const
SkISize dimensions() const
Definition: SkImageInfo.h:421
int width() const
Definition: SkImageInfo.h:365
int height() const
Definition: SkImageInfo.h:371
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
constexpr float x() const
Definition: SkRect.h:720
constexpr float y() const
Definition: SkRect.h:727
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762

◆ render_gainmap_pixel()

static SkColor4f render_gainmap_pixel ( float  renderHdrRatio,
const SkBitmap baseBitmap,
const SkBitmap gainmapBitmap,
const SkGainmapInfo gainmapInfo,
int  x,
int  y 
)
static

Definition at line 807 of file JpegGainmapTest.cpp.

812 {
813 SkImageInfo testPixelInfo = SkImageInfo::Make(
814 /*width=*/1,
815 /*height=*/1,
819 SkBitmap testPixelBitmap = render_gainmap(
820 testPixelInfo, renderHdrRatio, baseBitmap, gainmapBitmap, gainmapInfo, x, y);
821 return testPixelBitmap.getColor4f(0, 0);
822}
static SkBitmap render_gainmap(const SkImageInfo &renderInfo, float renderHdrRatio, const SkBitmap &baseBitmap, const SkBitmap &gainmapBitmap, const SkGainmapInfo &gainmapInfo, int x, int y)
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
SkColor4f getColor4f(int x, int y) const
Definition: SkBitmap.h:893