xref: /aosp_15_r20/external/skia/tests/SkJpegXmpTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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