1 /*
2 * Copyright 2023 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkData.h"
9 #include "include/private/SkGainmapInfo.h"
10 #include "src/codec/SkJpegXmp.h"
11 #include "src/core/SkMD5.h"
12 #include "tests/Test.h"
13
14 #include <iomanip>
15 #include <iostream>
16 #include <regex>
17 #include <sstream>
18
DEF_TEST(SkJpegXmp_standardXmp,r)19 DEF_TEST(SkJpegXmp_standardXmp, r) {
20 const char xmpData[] =
21 "http://ns.adobe.com/xap/1.0/\0"
22 R"(
23 <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
24 <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
25 xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/">
26 <rdf:Description rdf:about="">
27 <hdrgm:Version>1.0</hdrgm:Version>
28 <hdrgm:GainMapMax>3</hdrgm:GainMapMax>
29 <hdrgm:HDRCapacityMax>4</hdrgm:HDRCapacityMax>
30 </rdf:Description>
31 </rdf:RDF>
32 </x:xmpmeta>)";
33
34 std::vector<sk_sp<SkData>> app1Params;
35 app1Params.push_back(SkData::MakeWithoutCopy(xmpData, sizeof(xmpData) - 1));
36
37 auto xmp = SkJpegMakeXmp(app1Params);
38 REPORTER_ASSERT(r, xmp);
39
40 SkGainmapInfo info;
41 REPORTER_ASSERT(r, xmp->getGainmapInfoHDRGM(&info));
42 REPORTER_ASSERT(r, info.fGainmapRatioMax.fR == 8.f);
43 REPORTER_ASSERT(r, info.fDisplayRatioHdr == 16.f);
44 }
45
46 DEF_TEST(SkJpegXmp_defaultValues, r) {
47 const char xmpData[] =
48 "http://ns.adobe.com/xap/1.0/\0"
49 R"(
50 <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
51 <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
52 xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/">
53 <rdf:Description rdf:about="" hdrgm:Version="1.0">
54 </rdf:Description>
55 </rdf:RDF>
56 </x:xmpmeta>)";
57
58 std::vector<sk_sp<SkData>> app1Params;
59 app1Params.push_back(SkData::MakeWithoutCopy(xmpData, sizeof(xmpData) - 1));
60
61 auto xmp = SkJpegMakeXmp(app1Params);
62 REPORTER_ASSERT(r, xmp);
63
64 SkGainmapInfo info;
65 REPORTER_ASSERT(r, xmp->getGainmapInfoHDRGM(&info));
66 REPORTER_ASSERT(r, info.fGainmapRatioMin.fR == 1.f);
67 REPORTER_ASSERT(r, info.fGainmapRatioMin.fG == 1.f);
68 REPORTER_ASSERT(r, info.fGainmapRatioMin.fB == 1.f);
69 REPORTER_ASSERT(r, info.fGainmapRatioMax.fR == 2.f);
70 REPORTER_ASSERT(r, info.fGainmapRatioMax.fG == 2.f);
71 REPORTER_ASSERT(r, info.fGainmapRatioMax.fB == 2.f);
72 REPORTER_ASSERT(r, info.fGainmapGamma.fR == 1.f);
73 REPORTER_ASSERT(r, info.fGainmapGamma.fG == 1.f);
74 REPORTER_ASSERT(r, info.fGainmapGamma.fB == 1.f);
75 REPORTER_ASSERT(r, info.fEpsilonSdr.fR == 1.f / 64.f);
76 REPORTER_ASSERT(r, info.fEpsilonSdr.fG == 1.f / 64.f);
77 REPORTER_ASSERT(r, info.fEpsilonSdr.fB == 1.f / 64.f);
78 REPORTER_ASSERT(r, info.fEpsilonHdr.fG == 1.f / 64.f);
79 REPORTER_ASSERT(r, info.fEpsilonHdr.fR == 1.f / 64.f);
80 REPORTER_ASSERT(r, info.fEpsilonHdr.fB == 1.f / 64.f);
81 REPORTER_ASSERT(r, info.fDisplayRatioSdr == 1.f);
82 REPORTER_ASSERT(r, info.fDisplayRatioHdr == 2.f);
83 }
84
85 static std::string uint32_to_string(uint32_t v) {
86 const char c[4] = {static_cast<char>((v >> 24) & 0xff),
87 static_cast<char>((v >> 16) & 0xff),
88 static_cast<char>((v >> 8) & 0xff),
89 static_cast<char>(v & 0xff)};
90 return std::string(c, 4);
91 }
92
93 static std::string standard_xmp_with_header(const SkMD5::Digest& digest, const std::string& data) {
94 const std::string guid = digest.toHexString().c_str();
95 const std::string dataWithGuid = std::regex_replace(data, std::regex("\\$GUID"), guid);
96 return std::string("http://ns.adobe.com/xap/1.0/") + '\0' + dataWithGuid;
97 }
98
extended_xmp_with_header(const SkMD5::Digest & digest,uint32_t size,uint32_t offset,const std::string & data)99 static std::string extended_xmp_with_header(const SkMD5::Digest& digest,
100 uint32_t size,
101 uint32_t offset,
102 const std::string& data) {
103 return std::string("http://ns.adobe.com/xmp/extension/") + '\0' + digest.toHexString().c_str() +
104 uint32_to_string(size) + uint32_to_string(offset) + data;
105 }
106
DEF_TEST(SkJpegXmp_readExtendedXmp,r)107 DEF_TEST(SkJpegXmp_readExtendedXmp, r) {
108 const std::string standardXmpData = R"(
109 <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
110 <rdf:RDF xmlns:xmpNote="http://ns.adobe.com/xmp/note/">
111 <rdf:Description rdf:about="">
112 <xmpNote:HasExtendedXMP>$GUID</xmpNote:HasExtendedXMP>
113 </rdf:Description>
114 </rdf:RDF>
115 </x:xmpmeta>)";
116
117 const std::string extendedXmpData1 = R"(
118 <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
119 <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
120 xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/">
121 <rdf:Description rdf:about="">
122 <hdrgm:Version>1.0</hdrgm:Version>
123 <hdrgm:GainMapMax>3</hdrgm:GainMapMax>
124 <hdrgm:HDRCapacityMax>4</hdrgm:HDRCapacityMax>)";
125 const std::string extendedXmpData2 = R"(
126 </rdf:Description>
127 </rdf:RDF>
128 </x:xmpmeta>)";
129
130 const uint32_t totalExtendedXmpSize = extendedXmpData1.size() + extendedXmpData2.size();
131 SkMD5 md5;
132 md5.write(extendedXmpData1.data(), extendedXmpData1.length());
133 md5.write(extendedXmpData2.data(), extendedXmpData2.length());
134 const SkMD5::Digest digest = md5.finish();
135
136 const std::string standardXmpDataWithHeader = standard_xmp_with_header(digest, standardXmpData);
137
138 const uint32_t offset1 = 0;
139 const std::string extendedXmpData1WithHeader =
140 extended_xmp_with_header(digest, totalExtendedXmpSize, offset1, extendedXmpData1);
141
142 const uint32_t offset2 = extendedXmpData1.size();
143 const std::string extendedXmpData2WithHeader =
144 extended_xmp_with_header(digest, totalExtendedXmpSize, offset2, extendedXmpData2);
145
146 std::vector<sk_sp<SkData>> app1Params;
147 app1Params.push_back(SkData::MakeWithoutCopy(standardXmpDataWithHeader.data(),
148 standardXmpDataWithHeader.length()));
149 app1Params.push_back(SkData::MakeWithoutCopy(extendedXmpData1WithHeader.data(),
150 extendedXmpData1WithHeader.length()));
151 app1Params.push_back(SkData::MakeWithoutCopy(extendedXmpData2WithHeader.data(),
152 extendedXmpData2WithHeader.length()));
153
154 auto xmp = SkJpegMakeXmp(app1Params);
155 REPORTER_ASSERT(r, xmp);
156
157 SkGainmapInfo info;
158 REPORTER_ASSERT(r, xmp->getGainmapInfoHDRGM(&info));
159 REPORTER_ASSERT(r, info.fGainmapRatioMax.fR == 8.f);
160 REPORTER_ASSERT(r, info.fDisplayRatioHdr == 16.f);
161 }
162