/// <summary> /// Parses the XMP file identified by resource and replaces the XMP /// tag of file by the parsed data. /// </summary> public static bool ParseXmpSidecar(this TagLib.Image.File file, TagLib.File.IFileAbstraction resource) { string xmp; try { using (var stream = resource.ReadStream) { using (var reader = new StreamReader (stream)) { xmp = reader.ReadToEnd (); } } } catch (Exception e) { Log.DebugFormat ("Sidecar cannot be read for file {0}", file.Name); Log.DebugException (e); return false; } XmpTag tag = null; try { tag = new XmpTag (xmp, file); } catch (Exception e) { Log.DebugFormat ("Metadata of Sidecar cannot be parsed for file {0}", file.Name); Log.DebugException (e); return false; } var xmp_tag = file.GetTag (TagLib.TagTypes.XMP, true) as XmpTag; xmp_tag.ReplaceFrom (tag); return true; }
private void ValidateSimpleType (XmpTag tag) { var tree = tag.NodeTree; Assert.IsTrue (tree != null); Assert.AreEqual (1, tree.Children.Count); Assert.AreEqual (XmpNodeType.Simple, tree.Children[0].Type); Assert.AreEqual (XmpTag.XAP_NS, tree.Children[0].Namespace); Assert.AreEqual ("CreateDate", tree.Children[0].Name); Assert.AreEqual ("2002-08-15T17:10:04Z", tree.Children[0].Value); }
private void AddAllQualifiersTo(XmlNode xml) { if (qualifiers == null) { return; } foreach (var collection in qualifiers.Values) { foreach (XmpNode node in collection.Values) { XmlAttribute attr = XmpTag.CreateAttribute(xml.OwnerDocument, node.Name, node.Namespace); attr.Value = node.Value; xml.Attributes.Append(attr); } } }
public static XmpTag Create ( /* * string copyright, string title, string model, string creator, * string make, double? focalLength, uint? focalLengthIn35mmFilm, * string comment, string[] keywords, uint? rating, DateTime? dateTime, * string software, double? ExposureTime, double? FNumber, uint? ISOSpeedRatings */ ) { XmpTag xmpTag = new XmpTag(); /* * xmpTag.SetLangAltNode(XmpTag.DC_NS, "rights", copyright); * xmpTag.SetLangAltNode(XmpTag.DC_NS, "title", title); * xmpTag.SetTextNode(XmpTag.TIFF_NS, "Model", model); * xmpTag.SetCollectionNode(XmpTag.DC_NS, "creator", new string[] { creator }, XmpNodeType.Seq); * xmpTag.SetTextNode(XmpTag.TIFF_NS, "Make", make); * xmpTag.SetRationalNode(XmpTag.EXIF_NS, "FocalLength", focalLength.HasValue ? (double)focalLength : 0); * xmpTag.SetTextNode(XmpTag.EXIF_NS, "FocalLengthIn35mmFilm", focalLengthIn35mmFilm.HasValue ? focalLengthIn35mmFilm.Value.ToString() : String.Empty); * xmpTag.SetLangAltNode(XmpTag.DC_NS, "description", comment); * xmpTag.SetLangAltNode(XmpTag.EXIF_NS, "UserComment", comment); * xmpTag.SetCollectionNode(XmpTag.DC_NS, "subject", keywords, XmpNodeType.Bag); * xmpTag.SetTextNode(XmpTag.XAP_NS, "Rating", rating != null ? rating.ToString() : null); * xmpTag.SetTextNode(XmpTag.XAP_NS, "CreateDate", dateTime != null ? dateTime.ToString() : null); * xmpTag.SetTextNode (XmpTag.XAP_NS, "CreatorTool", software); * xmpTag.SetRationalNode(XmpTag.EXIF_NS, "ExposureTime", ExposureTime.HasValue ? (double)ExposureTime : 0); * xmpTag.SetRationalNode(XmpTag.EXIF_NS, "FNumber", FNumber.HasValue ? (double)FNumber : 0); * xmpTag.SetCollectionNode(XmpTag.EXIF_NS, "ISOSpeedRatings", new string[] { ISOSpeedRatings.ToString() }, XmpNodeType.Seq); */ return(xmpTag); // TODO: Edit factory method of XmpTag // This method should be able to configure the object in all possible ways. // Add as many parameters as needed, // and assign their values to each field by using the API. }
/// <summary> /// Loads all metadata found in the XMP file. /// </summary> /// <example>LoadXmplFile("c:\dir\metadata.xmp")</example> public void LoadXmpFile(string path) { if(!File.Exists(path)) throw new FileNotFoundException(path); var xmp = new XmpTag(File.ReadAllText(path, Encoding.UTF8), null); LoadProperties(xmp, this); }
/// <summary> /// Saves all the metadata that fits in XMP to a file. /// </summary> /// <example>SaveXmplFile("c:\dir\metadata.xmp")</example> public void SaveXmpFile(string path) { var tag = new XmpTag(); SaveInImageTag(tag); File.WriteAllText(path, tag.Render(), Encoding.UTF8); }
static string GetRights(XmpTag xmp) { var rightsNode = xmp.FindNode("http://purl.org/dc/elements/1.1/", "rights"); if (rightsNode == null) return null; foreach (var child in rightsNode.Children) { if (child.Namespace == "http://www.w3.org/1999/02/22-rdf-syntax-ns#" && child.Name == "li" && HasLangQualifier(child, "en")) { return child.Value; } } return null; }
void SetRights(XmpTag xmp, string rights) { var rightsNode = xmp.FindNode("http://purl.org/dc/elements/1.1/", "rights"); if (rightsNode == null) { if (string.IsNullOrEmpty(rights)) return; // leave it missing. // No existing rights node, and we have some. We use (default lang) rights for copyright too, and there seems to be no way to // make the base node without setting that. So set it to something meaningless. // This will typically never happen, since our dialog requires a non-empty copyright. // I'm not entirely happy with it, but as far as I can discover the current version of taglib cannot // set the 'en' alternative of dc:rights without setting the default alternative. In fact, I'm not sure the // result of doing so would technically be valid xmp; the standard calls for every langauge alternation // to have a default. xmp.SetLangAltNode("http://purl.org/dc/elements/1.1/", "rights", "Unknown"); rightsNode = xmp.FindNode("http://purl.org/dc/elements/1.1/", "rights"); } foreach (var child in rightsNode.Children) { if (child.Namespace == "http://www.w3.org/1999/02/22-rdf-syntax-ns#" && child.Name == "li" && HasLangQualifier(child, "en")) { if (string.IsNullOrEmpty(rights)) { rightsNode.RemoveChild(child); // enhance: possibly we should remove rightsNode, if it now has no children, and if taglib can. // However, we always require a copyright, so this will typically not happen. } else child.Value = rights; return; } } // Didn't find an existing rights:en node. if (string.IsNullOrEmpty(rights)) return; // leave it missing. var childNode = new XmpNode(XmpTag.RDF_NS, "li", rights); childNode.AddQualifier(new XmpNode(XmpTag.XML_NS, "lang", "en")); rightsNode.AddChild(childNode); }
/// <summary> /// Renders the current instance as child of the given node to the /// given <see cref="XmlNode"/> /// </summary> /// <param name="parent"> /// A <see cref="XmlNode"/> to render the current instance as child of. /// </param> public void RenderInto(XmlNode parent) { if (IsRootNode) { AddAllChildrenTo(parent); } else if (IsReallySimpleType && parent.Attributes.GetNamedItem(XmpTag.PARSE_TYPE_URI, XmpTag.RDF_NS) == null) { // Simple values can be added as attributes of the parent node. Not allowed when the parent has an rdf:parseType. XmlAttribute attr = XmpTag.CreateAttribute(parent.OwnerDocument, Name, Namespace); attr.Value = Value; parent.Attributes.Append(attr); } else if (Type == XmpNodeType.Simple || Type == XmpNodeType.Struct) { var node = XmpTag.CreateNode(parent.OwnerDocument, Name, Namespace); node.InnerText = Value; if (Type == XmpNodeType.Struct) { // Structured types are always handled as a parseType=Resource node. This way, IsReallySimpleType will // not match for child nodes, which makes sure they are added as extra nodes to this node. Does the // trick well, unit tests that prove this are in XmpSpecTest. XmlAttribute attr = XmpTag.CreateAttribute(parent.OwnerDocument, XmpTag.PARSE_TYPE_URI, XmpTag.RDF_NS); attr.Value = "Resource"; node.Attributes.Append(attr); } AddAllQualifiersTo(node); AddAllChildrenTo(node); parent.AppendChild(node); } else if (Type == XmpNodeType.Bag) { var node = XmpTag.CreateNode(parent.OwnerDocument, Name, Namespace); if (QualifierCount > 0) { throw new NotImplementedException(); } var bag = XmpTag.CreateNode(parent.OwnerDocument, XmpTag.BAG_URI, XmpTag.RDF_NS); foreach (var child in Children) { child.RenderInto(bag); } node.AppendChild(bag); parent.AppendChild(node); } else if (Type == XmpNodeType.Alt) { var node = XmpTag.CreateNode(parent.OwnerDocument, Name, Namespace); if (QualifierCount > 0) { throw new NotImplementedException(); } var bag = XmpTag.CreateNode(parent.OwnerDocument, XmpTag.ALT_URI, XmpTag.RDF_NS); foreach (var child in Children) { child.RenderInto(bag); } node.AppendChild(bag); parent.AppendChild(node); } else if (Type == XmpNodeType.Seq) { var node = XmpTag.CreateNode(parent.OwnerDocument, Name, Namespace); if (QualifierCount > 0) { throw new NotImplementedException(); } var bag = XmpTag.CreateNode(parent.OwnerDocument, XmpTag.SEQ_URI, XmpTag.RDF_NS); foreach (var child in Children) { child.RenderInto(bag); } node.AppendChild(bag); parent.AppendChild(node); } else { // Probably some combination of things we don't fully cover yet. Dump(); throw new NotImplementedException(); } }
private void TestRender(XmpTag tag, XmpValidator validator) { string xmp = tag.Render (); var parsed_tag = new XmpTag (xmp, null); validator (parsed_tag); }
private XmpTag TestParse(string metadata, XmpValidator validator) { var tag = new XmpTag (metadata, null); validator (tag); return tag; }
public void RenderInto(XmlNode parent) { if (IsRootNode) { AddAllChildrenTo(parent); } else if (IsReallySimpleType && parent.Attributes.GetNamedItem(XmpTag.PARSE_TYPE_URI, XmpTag.RDF_NS) == null) { XmlAttribute attr = XmpTag.CreateAttribute(parent.OwnerDocument, Name, Namespace); attr.Value = Value; parent.Attributes.Append(attr); } else if (Type == XmpNodeType.Simple || Type == XmpNodeType.Struct) { var node = XmpTag.CreateNode(parent.OwnerDocument, Name, Namespace); node.InnerText = Value; if (Type == XmpNodeType.Struct) { XmlAttribute attr = XmpTag.CreateAttribute(parent.OwnerDocument, XmpTag.PARSE_TYPE_URI, XmpTag.RDF_NS); attr.Value = "Resource"; node.Attributes.Append(attr); } AddAllQualifiersTo(node); AddAllChildrenTo(node); parent.AppendChild(node); } else if (Type == XmpNodeType.Bag) { var node = XmpTag.CreateNode(parent.OwnerDocument, Name, Namespace); if (QualifierCount > 0) { throw new NotImplementedException(); } var bag = XmpTag.CreateNode(parent.OwnerDocument, XmpTag.BAG_URI, XmpTag.RDF_NS); foreach (var child in Children) { child.RenderInto(bag); } node.AppendChild(bag); parent.AppendChild(node); } else if (Type == XmpNodeType.Alt) { var node = XmpTag.CreateNode(parent.OwnerDocument, Name, Namespace); if (QualifierCount > 0) { throw new NotImplementedException(); } var bag = XmpTag.CreateNode(parent.OwnerDocument, XmpTag.ALT_URI, XmpTag.RDF_NS); foreach (var child in Children) { child.RenderInto(bag); } node.AppendChild(bag); parent.AppendChild(node); } else if (Type == XmpNodeType.Seq) { var node = XmpTag.CreateNode(parent.OwnerDocument, Name, Namespace); if (QualifierCount > 0) { throw new NotImplementedException(); } var bag = XmpTag.CreateNode(parent.OwnerDocument, XmpTag.SEQ_URI, XmpTag.RDF_NS); foreach (var child in Children) { child.RenderInto(bag); } node.AppendChild(bag); parent.AppendChild(node); } else { Dump(); throw new NotImplementedException(); } }
private void TestBagNode(XmpTag tag, string ns, string name, string[] values) { var node = tag.FindNode(ns, name); Assert.IsFalse(node == null); Assert.AreEqual(XmpNodeType.Bag, node.Type); Assert.AreEqual(values.Length, node.Children.Count); int i = 0; foreach (var childNode in node.Children) { Assert.AreEqual(values[i], childNode.Value); Assert.AreEqual(0, childNode.Children.Count); i++; } }
public NodeIndexVisitor(XmpTag tag) { this.tag = tag; }
public void ReplaceFrom(XmpTag tag) { NodeTree = tag.NodeTree; nodes = new Dictionary <string, Dictionary <string, XmpNode> >(); AcceptVisitors(); }
public NodeIndexVisitor (XmpTag tag) { this.tag = tag; }
/// <summary> /// Replace the current tag with the given one. /// </summary> /// <param name="tag"> /// The tag from which the data should be copied. /// </param> public void ReplaceFrom (XmpTag tag) { NodeTree = tag.NodeTree; nodes = new Dictionary<string, Dictionary<string, XmpNode>> (); AcceptVisitors (); }
private void ValidateStructuredType(XmpTag tag) { var tree = tag.NodeTree; var PG_NS = "http://ns.adobe.com/xap/1.0/t/pg/"; var DIM_NS = "http://ns.adobe.com/xap/1.0/sType/Dimensions#"; Assert.IsTrue (tree != null); Assert.AreEqual (1, tree.Children.Count); var node = tree.Children[0]; Assert.AreEqual (XmpNodeType.Struct, node.Type); Assert.AreEqual (PG_NS, node.Namespace); Assert.AreEqual ("MaxPageSize", node.Name); Assert.AreEqual (3, node.Children.Count); Assert.AreEqual (DIM_NS, node.Children[0].Namespace); Assert.AreEqual ("w", node.Children[0].Name); Assert.AreEqual ("4", node.Children[0].Value); Assert.AreEqual (0, node.Children[0].Children.Count); Assert.AreEqual (DIM_NS, node.Children[1].Namespace); Assert.AreEqual ("h", node.Children[1].Name); Assert.AreEqual ("3", node.Children[1].Value); Assert.AreEqual (0, node.Children[1].Children.Count); Assert.AreEqual (DIM_NS, node.Children[2].Namespace); Assert.AreEqual ("unit", node.Children[2].Name); Assert.AreEqual ("inch", node.Children[2].Value); Assert.AreEqual (0, node.Children[2].Children.Count); }
/// <summary> /// Gets a tag of a specified type from the current instance, /// optionally creating a new tag if possible. /// </summary> /// <param name="type"> /// A <see cref="TagLib.TagTypes" /> value indicating the /// type of tag to read. /// </param> /// <param name="create"> /// A <see cref="bool" /> value specifying whether or not to /// try and create the tag if one is not found. /// </param> /// <returns> /// A <see cref="Tag" /> object containing the tag that was /// found in or added to the current instance. If no /// matching tag was found and none was created, <see /// langword="null" /> is returned. /// </returns> public override TagLib.Tag GetTag (TagLib.TagTypes type, bool create) { foreach (Tag tag in ImageTag.AllTags) { if ((tag.TagTypes & type) == type) return tag; } if (!create || (type & ImageTag.AllowedTypes) == 0) return null; ImageTag new_tag = null; switch (type) { case TagTypes.JpegComment: new_tag = new JpegCommentTag (); break; case TagTypes.GifComment: new_tag = new GifCommentTag (); break; case TagTypes.Png: new_tag = new PngTag (); break; case TagTypes.TiffIFD: new_tag = new IFDTag (); break; case TagTypes.XMP: new_tag = new XmpTag (); break; } if (new_tag != null) { ImageTag.AddTag (new_tag); return new_tag; } throw new NotImplementedException (String.Format ("Adding tag of type {0} not supported!", type)); }
/// <summary> /// Update the value of the specified node, or create it. /// Seems SetTextNode should work whether or not is already exists, but in some cases it doesn't. /// </summary> /// <param name="tag"></param> /// <param name="ns"></param> /// <param name="name"></param> /// <param name="val"></param> void AddOrModify(XmpTag tag, string ns, string name, string val) { var node = tag.FindNode(ns, name); if (node != null) node.Value = val; else tag.SetTextNode(ns, name, val); }