Generate xml
Bug: b/252835416
Test: use sample code in ag/20349112, output xmp metadata should be identical to the sample
Change-Id: I1fa8d40c3fab1a8e3ebe70db42582d632bcdb7d5
diff --git a/libs/jpegrecoverymap/Android.bp b/libs/jpegrecoverymap/Android.bp
index 3ab2ba8..a9248ab 100644
--- a/libs/jpegrecoverymap/Android.bp
+++ b/libs/jpegrecoverymap/Android.bp
@@ -23,7 +23,7 @@
cc_library_static {
name: "libjpegrecoverymap",
- vendor_available: true,
+ host_supported: true,
export_include_dirs: ["include"],
local_include_dirs: ["include"],
@@ -33,6 +33,7 @@
],
shared_libs: [
+ "libimage_io",
"libutils",
],
}
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
index 15eca1e..aa580cc 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
@@ -168,6 +168,47 @@
status_t appendRecoveryMap(void* compressed_jpeg_image,
jr_compressed_ptr compressed_recovery_map,
void* dest);
+
+ /*
+ * This method generates XMP metadata.
+ *
+ * below is an example of the XMP metadata that this function generates where
+ * secondary_image_length = 1000
+ * hdr_ratio = 1.25
+ *
+ * <x:xmpmeta
+ * xmlns:x="adobe:ns:meta/"
+ * x:xmptk="Adobe XMP Core 5.1.2">
+ * <rdf:RDF
+ * xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ * <rdf:Description
+ * xmlns:GContainer="http://ns.google.com/photos/1.0/container/">
+ * <GContainer:Version>1</GContainer:Version>
+ * <GContainer:HdrRatio>1.25</GContainer:HdrRatio>
+ * <GContainer:Directory>
+ * <rdf:Seq>
+ * <rdf:li>
+ * <GContainer:Item
+ * Item:Semantic="Primary"
+ * Item:Mime="image/jpeg"/>
+ * </rdf:li>
+ * <rdf:li>
+ * <GContainer:Item
+ * Item:Semantic="RecoveryMap"
+ * Item:Mime="image/jpeg"
+ * Item:Length="1000"/>
+ * </rdf:li>
+ * </rdf:Seq>
+ * </GContainer:Directory>
+ * </rdf:Description>
+ * </rdf:RDF>
+ * </x:xmpmeta>
+ *
+ * @param secondary_image_length length of secondary image
+ * @param hdr_ratio hdr ratio
+ * @return XMP metadata in type of string
+ */
+ std::string generateXmp(int secondary_image_length, float hdr_ratio);
};
} // namespace android::recoverymap
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
index 5d25722..8d3cd00 100644
--- a/libs/jpegrecoverymap/recoverymap.cpp
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -14,10 +14,29 @@
* limitations under the License.
*/
+#include "image_io/xml/xml_writer.h"
+
#include <jpegrecoverymap/recoverymap.h>
+#include <sstream>
+#include <string>
+
+using namespace std;
namespace android::recoverymap {
+/*
+ * Helper function used for generating XMP metadata.
+ *
+ * @param prefix The prefix part of the name.
+ * @param suffix The suffix part of the name.
+ * @return A name of the form "prefix:suffix".
+ */
+string Name(const string &prefix, const string &suffix) {
+ std::stringstream ss;
+ ss << prefix << ":" << suffix;
+ return ss.str();
+}
+
status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
jr_uncompressed_ptr uncompressed_yuv_420_image,
void* dest) {
@@ -137,4 +156,53 @@
return NO_ERROR;
}
+string RecoveryMap::generateXmp(int secondary_image_length, float hdr_ratio) {
+ const string kContainerPrefix = "GContainer";
+ const string kContainerUri = "http://ns.google.com/photos/1.0/container/";
+ const string kItemPrefix = "Item";
+ const string kRecoveryMap = "RecoveryMap";
+ const string kDirectory = "Directory";
+ const string kImageJpeg = "image/jpeg";
+ const string kItem = "Item";
+ const string kLength = "Length";
+ const string kMime = "Mime";
+ const string kPrimary = "Primary";
+ const string kSemantic = "Semantic";
+ const string kVersion = "Version";
+ const int kVersionValue = 1;
+
+ const string kConDir = Name(kContainerPrefix, kDirectory);
+ const string kContainerItem = Name(kContainerPrefix, kItem);
+ const string kItemLength = Name(kItemPrefix, kLength);
+ const string kItemMime = Name(kItemPrefix, kMime);
+ const string kItemSemantic = Name(kItemPrefix, kSemantic);
+
+ const vector<string> kConDirSeq({kConDir, string("rdf:Seq")});
+ const vector<string> kLiItem({string("rdf:li"), kContainerItem});
+
+ std::stringstream ss;
+ photos_editing_formats::image_io::XmlWriter writer(ss);
+ writer.StartWritingElement("x:xmpmeta");
+ writer.WriteXmlns("x", "adobe:ns:meta/");
+ writer.WriteAttributeNameAndValue("x:xmptk", "Adobe XMP Core 5.1.2");
+ writer.StartWritingElement("rdf:RDF");
+ writer.WriteXmlns("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+ writer.StartWritingElement("rdf:Description");
+ writer.WriteXmlns(kContainerPrefix, kContainerUri);
+ writer.WriteElementAndContent(Name(kContainerPrefix, kVersion), kVersionValue);
+ writer.WriteElementAndContent(Name(kContainerPrefix, "HdrRatio"), hdr_ratio);
+ writer.StartWritingElements(kConDirSeq);
+ size_t item_depth = writer.StartWritingElements(kLiItem);
+ writer.WriteAttributeNameAndValue(kItemSemantic, kPrimary);
+ writer.WriteAttributeNameAndValue(kItemMime, kImageJpeg);
+ writer.FinishWritingElementsToDepth(item_depth);
+ writer.StartWritingElements(kLiItem);
+ writer.WriteAttributeNameAndValue(kItemSemantic, kRecoveryMap);
+ writer.WriteAttributeNameAndValue(kItemMime, kImageJpeg);
+ writer.WriteAttributeNameAndValue(kItemLength, secondary_image_length);
+ writer.FinishWriting();
+
+ return ss.str();
+}
+
} // namespace android::recoverymap