Reading Embedded XMP Packets using ColdFusion
In working more and more on our Digital Asset Management initiatives, I've become more involved in working with XMP. Mostly as an experiment, I wanted to see if I could read and write this embedded metadata from and to a file. The Adobe XMP Toolkit indicates how this can be done based on the structure of specific types of files. It also indicates that packet scanning techniques can be used when file structure is unknown, however, is not encouraged.
I recognize it might not be the BEST way to read the XMP packet, however, all is fair in love and ColdFusion experimentation :) It's important to note that this code looks only for the FIRST instance of the string <x:xmpmeta and if there are multiple instances of XMP packets, subsequent instances are ignored. Adobe also indicates that if there are multiple packets, there is no way to know which packet is the correct one.
Needless to say, using the code below, I was able to read and parse XMP packets from all the Adobe sample files included in their toolkit. It may not be the end-all solution, and may not work for writing back to the file, but it's a start!
<cfparam name="URL.source" default="xmp-asset.jpg">
<cffile action="readbinary" file="#ExpandPath(URL.source)#" variable="data">
<!--- encode the binary data to hex --->
<cfset hex_data = BinaryEncode(data,"hex") />
<!--- string indicating beginning of packet '<x:xmpmeta' --->
<cfset xmp_string_begin = "3C783A786D706D657461" />
<!--- string indicating end of packet '</x:xmpmeta>' --->
<cfset xmp_string_end = "3C2F783A786D706D6574613E" />
<!--- find the starting index in the hex string --->
<cfset idx_start = FindNoCase(xmp_string_begin,hex_data) />
<!--- find the ending index in the hex string --->
<cfset idx_end = FindNoCase(xmp_string_end,hex_data,idx_start) + Len(xmp_string_end) />
<!--- using the start and end indices, extract the xmp packet --->
<cfset xmp_hex = Mid(hex_data,idx_start,Evaluate(idx_end-idx_start)) />
<!--- convert the hex to readable characters --->
<cfset xmp_string = ToString(BinaryDecode(xmp_hex,"hex")) />
<!--- parse the xml string to and xml structure --->
<cfset xmp_xml = XmlParse(xmp_string) />
<cfcontent type="text/xml">
<cfoutput>#xmp_string#</cfoutput>
Be sure to check out the Adobe XMP Developer Center for more information.
-rh