Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkXmp.cpp
Go to the documentation of this file.
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
9
11#include "include/core/SkData.h"
17#include "src/xml/SkDOM.h"
18
19#include <cmath>
20#include <cstdint>
21#include <cstring>
22#include <string>
23#include <vector>
24#include <utility>
25
26////////////////////////////////////////////////////////////////////////////////////////////////////
27// XMP parsing helper functions
28
29const char* kXmlnsPrefix = "xmlns:";
30const size_t kXmlnsPrefixLength = 6;
31
32static const char* get_namespace_prefix(const char* name) {
33 if (strlen(name) <= kXmlnsPrefixLength) {
34 return nullptr;
35 }
36 return name + kXmlnsPrefixLength;
37}
38
39/*
40 * Given a node, see if that node has only one child with the indicated name. If so, see if that
41 * child has only a single child of its own, and that child is text. If all of that is the case
42 * then return the text, otherwise return nullptr.
43 *
44 * In the following example, innerText will be returned.
45 * <node><childName>innerText</childName></node>
46 *
47 * In the following examples, nullptr will be returned (because there are multiple children with
48 * childName in the first case, and because the child has children of its own in the second).
49 * <node><childName>innerTextA</childName><childName>innerTextB</childName></node>
50 * <node><childName>innerText<otherGrandChild/></childName></node>
51 */
52static const char* get_unique_child_text(const SkDOM& dom,
53 const SkDOM::Node* node,
54 const std::string& childName) {
55 // Fail if there are multiple children with childName.
56 if (dom.countChildren(node, childName.c_str()) != 1) {
57 return nullptr;
58 }
59 const auto* child = dom.getFirstChild(node, childName.c_str());
60 if (!child) {
61 return nullptr;
62 }
63 // Fail if the child has any children besides text.
64 if (dom.countChildren(child) != 1) {
65 return nullptr;
66 }
67 const auto* grandChild = dom.getFirstChild(child);
68 if (dom.getType(grandChild) != SkDOM::kText_Type) {
69 return nullptr;
70 }
71 // Return the text.
72 return dom.getName(grandChild);
73}
74
75/*
76 * Given a node, find a child node of the specified type.
77 *
78 * If there exists a child node with name |prefix| + ":" + |type|, then return that child.
79 *
80 * If there exists a child node with name "rdf:type" that has attribute "rdf:resource" with value
81 * of |type|, then if there also exists a child node with name "rdf:value" with attribute
82 * "rdf:parseType" of "Resource", then return that child node with name "rdf:value". See Example
83 * 3 in section 7.9.2.5: RDF Typed Nodes.
84 * TODO(ccameron): This should also accept a URI for the type.
85 */
86static const SkDOM::Node* get_typed_child(const SkDOM* dom,
87 const SkDOM::Node* node,
88 const std::string& prefix,
89 const std::string& type) {
90 const auto name = prefix + std::string(":") + type;
91 const SkDOM::Node* child = dom->getFirstChild(node, name.c_str());
92 if (child) {
93 return child;
94 }
95
96 const SkDOM::Node* typeChild = dom->getFirstChild(node, "rdf:type");
97 if (!typeChild) {
98 return nullptr;
99 }
100 const char* typeChildResource = dom->findAttr(typeChild, "rdf:resource");
101 if (!typeChildResource || typeChildResource != type) {
102 return nullptr;
103 }
104
105 const SkDOM::Node* valueChild = dom->getFirstChild(node, "rdf:value");
106 if (!valueChild) {
107 return nullptr;
108 }
109 const char* valueChildParseType = dom->findAttr(valueChild, "rdf:parseType");
110 if (!valueChildParseType || strcmp(valueChildParseType, "Resource") != 0) {
111 return nullptr;
112 }
113 return valueChild;
114}
115
116/*
117 * Given a node, return its value for the specified attribute.
118 *
119 * This will first look for an attribute with the name |prefix| + ":" + |key|, and return the value
120 * for that attribute.
121 *
122 * This will then look for a child node of name |prefix| + ":" + |key|, and return the field value
123 * for that child.
124 */
125static const char* get_attr(const SkDOM* dom,
126 const SkDOM::Node* node,
127 const std::string& prefix,
128 const std::string& key) {
129 const auto name = prefix + ":" + key;
130 const char* attr = dom->findAttr(node, name.c_str());
131 if (attr) {
132 return attr;
133 }
134 return get_unique_child_text(*dom, node, name);
135}
136
137// Perform get_attr and parse the result as a bool.
138static bool get_attr_bool(const SkDOM* dom,
139 const SkDOM::Node* node,
140 const std::string& prefix,
141 const std::string& key,
142 bool* outValue) {
143 const char* attr = get_attr(dom, node, prefix, key);
144 if (!attr) {
145 return false;
146 }
147 switch (SkParse::FindList(attr, "False,True")) {
148 case 0:
149 *outValue = false;
150 return true;
151 case 1:
152 *outValue = true;
153 return true;
154 default:
155 break;
156 }
157 return false;
158}
159
160// Perform get_attr and parse the result as an int32_t.
161static bool get_attr_int32(const SkDOM* dom,
162 const SkDOM::Node* node,
163 const std::string& prefix,
164 const std::string& key,
165 int32_t* value) {
166 const char* attr = get_attr(dom, node, prefix, key);
167 if (!attr) {
168 return false;
169 }
170 if (!SkParse::FindS32(attr, value)) {
171 return false;
172 }
173 return true;
174}
175
176// Perform get_attr and parse the result as a float.
177static bool get_attr_float(const SkDOM* dom,
178 const SkDOM::Node* node,
179 const std::string& prefix,
180 const std::string& key,
181 float* outValue) {
182 const char* attr = get_attr(dom, node, prefix, key);
183 if (!attr) {
184 return false;
185 }
186 SkScalar value = 0.f;
187 if (SkParse::FindScalar(attr, &value)) {
188 *outValue = value;
189 return true;
190 }
191 return false;
192}
193
194// Perform get_attr and parse the result as three comma-separated floats. Return the result as an
195// SkColor4f with the alpha component set to 1.
197 const SkDOM::Node* node,
198 const std::string& prefix,
199 const std::string& key,
200 SkColor4f* outValue) {
201 const auto name = prefix + ":" + key;
202
203 // Fail if there are multiple children with childName.
204 if (dom->countChildren(node, name.c_str()) != 1) {
205 return false;
206 }
207 // Find the child.
208 const auto* child = dom->getFirstChild(node, name.c_str());
209 if (!child) {
210 return false;
211 }
212
213 // Search for the rdf:Seq child.
214 const auto* seq = dom->getFirstChild(child, "rdf:Seq");
215 if (!seq) {
216 return false;
217 }
218
219 size_t count = 0;
220 SkScalar values[3] = {0.f, 0.f, 0.f};
221 for (const auto* liNode = dom->getFirstChild(seq, "rdf:li"); liNode;
222 liNode = dom->getNextSibling(liNode, "rdf:li")) {
223 if (count > 2) {
224 SkCodecPrintf("Too many items in list.\n");
225 return false;
226 }
227 if (dom->countChildren(liNode) != 1) {
228 SkCodecPrintf("Item can only have one child.\n");
229 return false;
230 }
231 const auto* liTextNode = dom->getFirstChild(liNode);
232 if (dom->getType(liTextNode) != SkDOM::kText_Type) {
233 SkCodecPrintf("Item's only child must be text.\n");
234 return false;
235 }
236 const char* liText = dom->getName(liTextNode);
237 if (!liText) {
238 SkCodecPrintf("Failed to get item's text.\n");
239 return false;
240 }
241 if (!SkParse::FindScalar(liText, values + count)) {
242 SkCodecPrintf("Failed to parse item's text to float.\n");
243 return false;
244 }
245 count += 1;
246 }
247 if (count < 3) {
248 SkCodecPrintf("List didn't have enough items.\n");
249 return false;
250 }
251 *outValue = {values[0], values[1], values[2], 1.f};
252 return true;
253}
254
255static bool get_attr_float3(const SkDOM* dom,
256 const SkDOM::Node* node,
257 const std::string& prefix,
258 const std::string& key,
259 SkColor4f* outValue) {
260 if (get_attr_float3_as_list(dom, node, prefix, key, outValue)) {
261 return true;
262 }
263 SkScalar value = -1.0;
264 if (get_attr_float(dom, node, prefix, key, &value)) {
265 *outValue = {value, value, value, 1.f};
266 return true;
267 }
268 return false;
269}
270
271static void find_uri_namespaces(const SkDOM& dom,
272 const SkDOM::Node* node,
273 size_t count,
274 const char* uris[],
275 const char* outNamespaces[]) {
276 // Search all attributes for xmlns:NAMESPACEi="URIi".
277 for (const auto* attr = dom.getFirstAttr(node); attr; attr = dom.getNextAttr(node, attr)) {
278 const char* attrName = dom.getAttrName(node, attr);
279 const char* attrValue = dom.getAttrValue(node, attr);
280 if (!attrName || !attrValue) {
281 continue;
282 }
283 // Make sure the name starts with "xmlns:".
284 if (strlen(attrName) <= kXmlnsPrefixLength) {
285 continue;
286 }
287 if (memcmp(attrName, kXmlnsPrefix, kXmlnsPrefixLength) != 0) {
288 continue;
289 }
290 // Search for a requested URI that matches.
291 for (size_t i = 0; i < count; ++i) {
292 if (strcmp(attrValue, uris[i]) != 0) {
293 continue;
294 }
295 outNamespaces[i] = attrName;
296 }
297 }
298}
299
300// See SkXmp::findUriNamespaces. This function has the same behavior, but only searches
301// a single SkDOM.
303 size_t count,
304 const char* uris[],
305 const char* outNamespaces[]) {
306 const SkDOM::Node* root = dom.getRootNode();
307 if (!root) {
308 return nullptr;
309 }
310
311 // Ensure that the root node identifies itself as XMP metadata.
312 const char* rootName = dom.getName(root);
313 if (!rootName || strcmp(rootName, "x:xmpmeta") != 0) {
314 return nullptr;
315 }
316
317 // Iterate the children with name rdf:RDF.
318 const char* kRdf = "rdf:RDF";
319 for (const auto* rdf = dom.getFirstChild(root, kRdf); rdf;
320 rdf = dom.getNextSibling(rdf, kRdf)) {
321 std::vector<const char*> rdfNamespaces(count, nullptr);
322 find_uri_namespaces(dom, rdf, count, uris, rdfNamespaces.data());
323
324 // Iterate the children with name rdf::Description.
325 const char* kDesc = "rdf:Description";
326 for (const auto* desc = dom.getFirstChild(rdf, kDesc); desc;
327 desc = dom.getNextSibling(desc, kDesc)) {
328 std::vector<const char*> descNamespaces = rdfNamespaces;
329 find_uri_namespaces(dom, desc, count, uris, descNamespaces.data());
330
331 // If we have a match for all the requested URIs, return.
332 bool foundAllUris = true;
333 for (size_t i = 0; i < count; ++i) {
334 if (!descNamespaces[i]) {
335 foundAllUris = false;
336 break;
337 }
338 }
339 if (foundAllUris) {
340 for (size_t i = 0; i < count; ++i) {
341 outNamespaces[i] = descNamespaces[i];
342 }
343 return desc;
344 }
345 }
346 }
347 return nullptr;
348}
349
350////////////////////////////////////////////////////////////////////////////////////////////////////
351// SkXmpImpl
352
353class SkXmpImpl final : public SkXmp {
354public:
355 SkXmpImpl() = default;
356
357 bool getGainmapInfoHDRGM(SkGainmapInfo* info) const override;
358 bool getGainmapInfoHDRGainMap(SkGainmapInfo* info) const override;
359 bool getContainerGainmapLocation(size_t* offset, size_t* size) const override;
360 const char* getExtendedXmpGuid() const override;
361 // Parse the given xmp data and store it into either the standard (main) DOM or the extended
362 // DOM. Returns true on successful parsing.
363 bool parseDom(sk_sp<SkData> xmpData, bool extended);
364
365private:
366 bool findUriNamespaces(size_t count,
367 const char* uris[],
368 const char* outNamespaces[],
369 const SkDOM** outDom,
370 const SkDOM::Node** outNode) const;
371
372 SkDOM fStandardDOM;
373 SkDOM fExtendedDOM;
374};
375
376const char* SkXmpImpl::getExtendedXmpGuid() const {
377 const char* namespaces[1] = {nullptr};
378 const char* uris[1] = {"http://ns.adobe.com/xmp/note/"};
379 const auto* extendedNode = find_uri_namespaces(fStandardDOM, 1, uris, namespaces);
380 if (!extendedNode) {
381 return nullptr;
382 }
383 const auto xmpNotePrefix = get_namespace_prefix(namespaces[0]);
384 // Extract the GUID (the MD5 hash) of the extended metadata.
385 return get_attr(&fStandardDOM, extendedNode, xmpNotePrefix, "HasExtendedXMP");
386}
387
388bool SkXmpImpl::findUriNamespaces(size_t count,
389 const char* uris[],
390 const char* outNamespaces[],
391 const SkDOM** outDom,
392 const SkDOM::Node** outNode) const {
393 // See XMP Specification Part 3: Storage in files, Section 1.1.3.1: Extended XMP in JPEG:
394 // A JPEG reader must recompose the StandardXMP and ExtendedXMP into a single data model tree
395 // containing all of the XMP for the JPEG file, and remove the xmpNote:HasExtendedXMP property.
396 // This code does not do that. Instead, it maintains the two separate trees and searches them
397 // sequentially.
398 *outNode = find_uri_namespaces(fStandardDOM, count, uris, outNamespaces);
399 if (*outNode) {
400 *outDom = &fStandardDOM;
401 return true;
402 }
403 *outNode = find_uri_namespaces(fExtendedDOM, count, uris, outNamespaces);
404 if (*outNode) {
405 *outDom = &fExtendedDOM;
406 return true;
407 }
408 *outDom = nullptr;
409 return false;
410}
411
412bool SkXmpImpl::getContainerGainmapLocation(size_t* outOffset, size_t* outSize) const {
413 // Find a node that matches the requested namespaces and URIs.
414 const char* namespaces[2] = {nullptr, nullptr};
415 const char* uris[2] = {"http://ns.google.com/photos/1.0/container/",
416 "http://ns.google.com/photos/1.0/container/item/"};
417 const SkDOM* dom = nullptr;
418 const SkDOM::Node* node = nullptr;
419 if (!findUriNamespaces(2, uris, namespaces, &dom, &node)) {
420 return false;
421 }
422 const char* containerPrefix = get_namespace_prefix(namespaces[0]);
423 const char* itemPrefix = get_namespace_prefix(namespaces[1]);
424
425 // The node must have a Container:Directory child.
426 const auto* directory = get_typed_child(dom, node, containerPrefix, "Directory");
427 if (!directory) {
428 SkCodecPrintf("Missing Container Directory");
429 return false;
430 }
431
432 // That Container:Directory must have a sequence of items.
433 const auto* seq = dom->getFirstChild(directory, "rdf:Seq");
434 if (!seq) {
435 SkCodecPrintf("Missing rdf:Seq");
436 return false;
437 }
438
439 // Iterate through the items in the Container:Directory's sequence. Keep a running sum of the
440 // Item:Length of all items that appear before the GainMap.
441 bool isFirstItem = true;
442 size_t offset = 0;
443 for (const auto* li = dom->getFirstChild(seq, "rdf:li"); li;
444 li = dom->getNextSibling(li, "rdf:li")) {
445 // Each list item must contain a Container:Item.
446 const auto* item = get_typed_child(dom, li, containerPrefix, "Item");
447 if (!item) {
448 SkCodecPrintf("List item does not have container Item.\n");
449 return false;
450 }
451 // A Semantic is required for every item.
452 const char* itemSemantic = get_attr(dom, item, itemPrefix, "Semantic");
453 if (!itemSemantic) {
454 SkCodecPrintf("Item is missing Semantic.\n");
455 return false;
456 }
457 // A Mime is required for every item.
458 const char* itemMime = get_attr(dom, item, itemPrefix, "Mime");
459 if (!itemMime) {
460 SkCodecPrintf("Item is missing Mime.\n");
461 return false;
462 }
463
464 if (isFirstItem) {
465 isFirstItem = false;
466 // The first item must be Primary.
467 if (strcmp(itemSemantic, "Primary") != 0) {
468 SkCodecPrintf("First item is not Primary.\n");
469 return false;
470 }
471 // The first item has mime type image/jpeg (we are decoding a jpeg).
472 if (strcmp(itemMime, "image/jpeg") != 0) {
473 SkCodecPrintf("Primary does not report that it is image/jpeg.\n");
474 return false;
475 }
476 // The first media item can contain a Padding attribute, which specifies additional
477 // padding between the end of the encoded primary image and the beginning of the next
478 // media item. Only the first media item can contain a Padding attribute.
479 int32_t padding = 0;
480 if (get_attr_int32(dom, item, itemPrefix, "Padding", &padding)) {
481 if (padding < 0) {
482 SkCodecPrintf("Item padding must be non-negative.");
483 return false;
484 }
485 offset += padding;
486 }
487 } else {
488 // A Length is required for all non-Primary items.
489 int32_t length = 0;
490 if (!get_attr_int32(dom, item, itemPrefix, "Length", &length)) {
491 SkCodecPrintf("Item length is absent.");
492 return false;
493 }
494 if (length < 0) {
495 SkCodecPrintf("Item length must be non-negative.");
496 return false;
497 }
498 // If this is not the recovery map, then read past it.
499 if (strcmp(itemSemantic, "GainMap") != 0) {
500 offset += length;
501 continue;
502 }
503 // The recovery map must have mime type image/jpeg in this implementation.
504 if (strcmp(itemMime, "image/jpeg") != 0) {
505 SkCodecPrintf("GainMap does not report that it is image/jpeg.\n");
506 return false;
507 }
508
509 // Populate the location in the file at which to find the gainmap image.
510 *outOffset = offset;
511 *outSize = length;
512 return true;
513 }
514 }
515 return false;
516}
517
518// Return true if the specified XMP metadata identifies this image as an HDR gainmap.
520 // Find a node that matches the requested namespaces and URIs.
521 const char* namespaces[2] = {nullptr, nullptr};
522 const char* uris[2] = {"http://ns.apple.com/pixeldatainfo/1.0/",
523 "http://ns.apple.com/HDRGainMap/1.0/"};
524 const SkDOM* dom = nullptr;
525 const SkDOM::Node* node = nullptr;
526 if (!findUriNamespaces(2, uris, namespaces, &dom, &node)) {
527 return false;
528 }
529 const char* adpiPrefix = get_namespace_prefix(namespaces[0]);
530 const char* hdrGainMapPrefix = get_namespace_prefix(namespaces[1]);
531
532 const char* auxiliaryImageType = get_attr(dom, node, adpiPrefix, "AuxiliaryImageType");
533 if (!auxiliaryImageType) {
534 SkCodecPrintf("Did not find AuxiliaryImageType.\n");
535 return false;
536 }
537 if (strcmp(auxiliaryImageType, "urn:com:apple:photo:2020:aux:hdrgainmap") != 0) {
538 SkCodecPrintf("AuxiliaryImageType was not HDR gain map.\n");
539 return false;
540 }
541
542 int32_t version = 0;
543 if (!get_attr_int32(dom, node, hdrGainMapPrefix, "HDRGainMapVersion", &version)) {
544 SkCodecPrintf("Did not find HDRGainMapVersion.\n");
545 return false;
546 }
547 if (version != 65536) {
548 SkCodecPrintf("HDRGainMapVersion was not 65536.\n");
549 return false;
550 }
551
552 // This node will often have StoredFormat and NativeFormat children that have inner text that
553 // specifies the integer 'L008' (also known as kCVPixelFormatType_OneComponent8).
554 const float kRatioMax = std::exp(1.f);
555 info->fGainmapRatioMin = {1.f, 1.f, 1.f, 1.f};
556 info->fGainmapRatioMax = {kRatioMax, kRatioMax, kRatioMax, 1.f};
557 info->fGainmapGamma = {1.f, 1.f, 1.f, 1.f};
558 info->fEpsilonSdr = {0.f, 0.f, 0.f, 1.f};
559 info->fEpsilonHdr = {0.f, 0.f, 0.f, 1.f};
560 info->fDisplayRatioSdr = 1.f;
561 info->fDisplayRatioHdr = kRatioMax;
563 return true;
564}
565
567 // Find a node that matches the requested namespace and URI.
568 const char* namespaces[1] = {nullptr};
569 const char* uris[1] = {"http://ns.adobe.com/hdr-gain-map/1.0/"};
570 const SkDOM* dom = nullptr;
571 const SkDOM::Node* node = nullptr;
572 if (!findUriNamespaces(1, uris, namespaces, &dom, &node)) {
573 return false;
574 }
575 const char* hdrgmPrefix = get_namespace_prefix(namespaces[0]);
576
577 // Require that hdrgm:Version="1.0" be present.
578 const char* version = get_attr(dom, node, hdrgmPrefix, "Version");
579 if (!version) {
580 SkCodecPrintf("Version attribute is absent.\n");
581 return false;
582 }
583 if (strcmp(version, "1.0") != 0) {
584 SkCodecPrintf("Version is \"%s\", not \"1.0\".\n", version);
585 return false;
586 }
587
588 // Initialize the parameters to their defaults.
589 bool baseRenditionIsHDR = false;
590 SkColor4f gainMapMin = {0.f, 0.f, 0.f, 1.f}; // log2 value
591 SkColor4f gainMapMax = {1.f, 1.f, 1.f, 1.f}; // log2 value
592 SkColor4f gamma = {1.f, 1.f, 1.f, 1.f};
593 SkColor4f offsetSdr = {1.f / 64.f, 1.f / 64.f, 1.f / 64.f, 0.f};
594 SkColor4f offsetHdr = {1.f / 64.f, 1.f / 64.f, 1.f / 64.f, 0.f};
595 SkScalar hdrCapacityMin = 0.f; // log2 value
596 SkScalar hdrCapacityMax = 1.f; // log2 value
597
598 // Read all parameters that are present.
599 get_attr_bool(dom, node, hdrgmPrefix, "BaseRenditionIsHDR", &baseRenditionIsHDR);
600 get_attr_float3(dom, node, hdrgmPrefix, "GainMapMin", &gainMapMin);
601 get_attr_float3(dom, node, hdrgmPrefix, "GainMapMax", &gainMapMax);
602 get_attr_float3(dom, node, hdrgmPrefix, "Gamma", &gamma);
603 get_attr_float3(dom, node, hdrgmPrefix, "OffsetSDR", &offsetSdr);
604 get_attr_float3(dom, node, hdrgmPrefix, "OffsetHDR", &offsetHdr);
605 get_attr_float(dom, node, hdrgmPrefix, "HDRCapacityMin", &hdrCapacityMin);
606 get_attr_float(dom, node, hdrgmPrefix, "HDRCapacityMax", &hdrCapacityMax);
607
608 // Translate all parameters to SkGainmapInfo's expected format.
609 const float kLog2 = std::log(2.f);
610 outGainmapInfo->fGainmapRatioMin = {std::exp(gainMapMin.fR * kLog2),
611 std::exp(gainMapMin.fG * kLog2),
612 std::exp(gainMapMin.fB * kLog2),
613 1.f};
614 outGainmapInfo->fGainmapRatioMax = {std::exp(gainMapMax.fR * kLog2),
615 std::exp(gainMapMax.fG * kLog2),
616 std::exp(gainMapMax.fB * kLog2),
617 1.f};
618 outGainmapInfo->fGainmapGamma = {1.f / gamma.fR, 1.f / gamma.fG, 1.f / gamma.fB, 1.f};
619 outGainmapInfo->fEpsilonSdr = offsetSdr;
620 outGainmapInfo->fEpsilonHdr = offsetHdr;
621 outGainmapInfo->fDisplayRatioSdr = std::exp(hdrCapacityMin * kLog2);
622 outGainmapInfo->fDisplayRatioHdr = std::exp(hdrCapacityMax * kLog2);
623 if (baseRenditionIsHDR) {
625 } else {
627 }
628 return true;
629}
630
632 SkDOM* dom = extended ? &fExtendedDOM : &fStandardDOM;
633 auto xmpdStream = SkMemoryStream::Make(std::move(xmpData));
634 if (!dom->build(*xmpdStream)) {
635 SkCodecPrintf("Failed to parse XMP %s metadata.\n", extended ? "extended" : "standard");
636 return false;
637 }
638 return true;
639}
640
641////////////////////////////////////////////////////////////////////////////////////////////////////
642// SkXmp
643
644std::unique_ptr<SkXmp> SkXmp::Make(sk_sp<SkData> xmpData) {
645 std::unique_ptr<SkXmpImpl> xmp(new SkXmpImpl);
646 if (!xmp->parseDom(std::move(xmpData), /*extended=*/false)) {
647 return nullptr;
648 }
649 return xmp;
650}
651
652std::unique_ptr<SkXmp> SkXmp::Make(sk_sp<SkData> xmpStandard, sk_sp<SkData> xmpExtended) {
653 std::unique_ptr<SkXmpImpl> xmp(new SkXmpImpl);
654 if (!xmp->parseDom(std::move(xmpStandard), /*extended=*/false)) {
655 return nullptr;
656 }
657 // Try to parse extended xmp but ignore the return value: if parsing fails, we'll still return
658 // the standard xmp.
659 (void)xmp->parseDom(std::move(xmpExtended), /*extended=*/true);
660 return xmp;
661}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
int count
#define SkCodecPrintf(...)
Definition SkCodecPriv.h:23
static void find_uri_namespaces(const SkDOM &dom, const SkDOM::Node *node, size_t count, const char *uris[], const char *outNamespaces[])
Definition SkXmp.cpp:271
static bool get_attr_float3_as_list(const SkDOM *dom, const SkDOM::Node *node, const std::string &prefix, const std::string &key, SkColor4f *outValue)
Definition SkXmp.cpp:196
const size_t kXmlnsPrefixLength
Definition SkXmp.cpp:30
static const char * get_unique_child_text(const SkDOM &dom, const SkDOM::Node *node, const std::string &childName)
Definition SkXmp.cpp:52
static const char * get_attr(const SkDOM *dom, const SkDOM::Node *node, const std::string &prefix, const std::string &key)
Definition SkXmp.cpp:125
static bool get_attr_bool(const SkDOM *dom, const SkDOM::Node *node, const std::string &prefix, const std::string &key, bool *outValue)
Definition SkXmp.cpp:138
static bool get_attr_float3(const SkDOM *dom, const SkDOM::Node *node, const std::string &prefix, const std::string &key, SkColor4f *outValue)
Definition SkXmp.cpp:255
static const char * get_namespace_prefix(const char *name)
Definition SkXmp.cpp:32
static bool get_attr_int32(const SkDOM *dom, const SkDOM::Node *node, const std::string &prefix, const std::string &key, int32_t *value)
Definition SkXmp.cpp:161
const char * kXmlnsPrefix
Definition SkXmp.cpp:29
static const SkDOM::Node * get_typed_child(const SkDOM *dom, const SkDOM::Node *node, const std::string &prefix, const std::string &type)
Definition SkXmp.cpp:86
static bool get_attr_float(const SkDOM *dom, const SkDOM::Node *node, const std::string &prefix, const std::string &key, float *outValue)
Definition SkXmp.cpp:177
Definition SkDOM.h:24
@ kText_Type
Definition SkDOM.h:44
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition SkStream.cpp:314
static const char * FindScalar(const char str[], SkScalar *value)
Definition SkParse.cpp:216
static const char * FindS32(const char str[], int32_t *value)
Definition SkParse.cpp:143
static int FindList(const char str[], const char list[])
Definition SkParse.cpp:278
const char * getExtendedXmpGuid() const override
Definition SkXmp.cpp:376
bool parseDom(sk_sp< SkData > xmpData, bool extended)
Definition SkXmp.cpp:631
bool getGainmapInfoHDRGM(SkGainmapInfo *info) const override
Definition SkXmp.cpp:566
bool getGainmapInfoHDRGainMap(SkGainmapInfo *info) const override
Definition SkXmp.cpp:519
SkXmpImpl()=default
bool getContainerGainmapLocation(size_t *offset, size_t *size) const override
Definition SkXmp.cpp:412
Definition SkXmp.h:23
static std::unique_ptr< SkXmp > Make(sk_sp< SkData > xmpData)
Definition SkXmp.cpp:644
float SkScalar
Definition extension.cpp:12
uint8_t value
const char * name
Definition fuchsia.cc:50
size_t length
Definition dom.py:1
Point offset
SkColor4f fGainmapRatioMax
SkColor4f fEpsilonSdr
SkColor4f fGainmapGamma
SkColor4f fGainmapRatioMin
BaseImageType fBaseImageType
float fDisplayRatioSdr
SkColor4f fEpsilonHdr
float fDisplayRatioHdr