Skip to main content
Participating Frequently
November 6, 2008
Question

[CS3 JS] Possible to Inspect Custom XMP Metadata With JavaScript?

  • November 6, 2008
  • 10 replies
  • 5439 views
I am using custom XMP metadata in InCopy and InDesign docs in CS3 to hold custom metadata that can vary wildly. I know the full set of possible items but not what values will be in a particular document.

Short of writing the XMP to a file and then processing that from my script, is there a way to inspect the custom properties from JavaScript. I didn't see a way to do it from the data model.

Thanks,

Eliot
This topic has been closed for replies.

10 replies

Inspiring
November 29, 2008
Here is another script to catch MetaData, some more than the basic:


// metaDataOfLinks.jsx
//DESCRIPTION: Catches MetaData of linked images and creates a report at the DeskTop.
// Martin Fischer 10/2008

var myLinkXmpArray = ["author", "copyrightInfoURL", "copyrightNotice", "copyrightStatus ", "creationDate", "creator", "description", "documentTitle", "format", "jobName", "keywords", "modificationDate", "serverURL"];
var myIPTCArray = ["CiAdrCity", "CiAdrCtry", "CiAdrExtadr", "CiAdrPcode", "CiAdrRegion", "CiEmailWork", "CiTelWork", "City", "CiUrlWork", "CopyrightNotice", "Country", "CountryCode", "Creator", "CreatorContactInfo", "CreatorJobtitle", "DateCreated", "Description", "DescriptionWriter", "Headline", "Instructions", "IntellectualGenre", "JobID", "Keywords", "Location", "Provider", "Province-State", "RightsUsageTerms", "Scene", "Source", "SubjectCode", "Title"];
var myPSArray = ["photoshop:AuthorsPosition", "photoshop:CaptionWriter", "photoshop:Category", "photoshop:City", "photoshop:Country", "photoshop:Credit", "photoshop:DateCreated", "photoshop:Headline", "photoshop:Instructions", "photoshop:Source", "photoshop:State", "photoshop:SupplementalCategories", "photoshop:TransmissionReference", "photoshop:Urgency"];//var myPSArray = ["photoshop:AuthorsPosition", "CaptionWriter", "Category", "City", "Country", "Credit", "DateCreated", "Headline", "Instructions", "Source", "State", "SupplementalCategories", "TransmissionReference", "Urgency"];
var myTiffArray = ["tiff:ImageWidth", "tiff:ImageLength", "tiff:BitsPerSample", "tiff:Compression", "tiff:PhotometricInterpretation", "tiff:Orientation", "tiff:SamplesPerPixel", "tiff:PlanarConfiguration", "tiff:YCbCrSubSampling", "tiff:YCbCrPositioning", "tiff:XResolution", "tiff:YResolution", "tiff:ResolutionUnit", "tiff:TransferFunction", "tiff:WhitePoint", "tiff:PrimaryChromaticities", "tiff:YCbCrCoefficients", "tiff:ReferenceBlackWhite", "tiff:DateTime", "tiff:ImageDescription", "tiff:MakeProperName", "tiff:Model", "tiff:Software", "tiff:Artist", "tiff:Copyright"];
var myExifArray = ["exif:ExifVersion", "exif:FlashpixVersion", "exif:ColorSpace", "exif:ComponentsConfiguration", "exif:CompressedBitsPerPixel", "exif:PixelXDimension", "exif:PixelYDimension", "exif:UserComment", "exif:RelatedSoundFile", "exif:DateTimeOriginal", "exif:DateTimeDigitized", "exif:ExposureTime", "exif:FNumber", "exif:ExposureProgram", "exif:SpectralSensitivity", "exif:ISOSpeedRatings", "exif:OECF", "exif:ShutterSpeedValue", "exif:ApertureValue", "exif:BrightnessValue", "exif:ExposureBiasValue", "exif:MaxApertureValue", "exif:SubjectDistance", "exif:MeteringMode", "exif:LightSource", "exif:Flash", "exif:FocalLength", "exif:SubjectArea", "exif:FlashEnergy", "exif:SpatialFrequencyResponse", "exif:FocalPlaneXResolution", "exif:FocalPlaneYResolution", "exif:FocalPlaneResolutionUnit", "exif:SubjectLocation", "exif:ExposureIndex", "exif:SensingMethod", "exif:FileSource", "exif:SceneType", "exif:CFAPattern", "exif:CustomRendered", "exif:ExposureMode", "exif:WhiteBalance", "exif:DigitalZoomRatio", "exif:FocalLengthIn35mmFilm", "exif:SceneCaptureType", "exif:GainControl", "exif:Contrast", "exif:Saturation", "exif:Sharpness", "exif:DeviceSettingDescription", "exif:SubjectDistanceRange", "exif:ImageUniqueID", "exif:GPSVersionID", "exif:GPSLatitude", "exif:GPSLongitude", "exif:GPSAltitudeRef", "exif:GPSAltitude", "exif:GPSTimeStamp", "exif:DateTimeOriginal,", "exif:DateTimeDigitized.", "exif:GPSTimeStamp", "exif:GPSSatellites", "exif:GPSStatus", "exif:GPSMeasureMode", "exif:GPSDOP", "exif:GPSSpeedRef", "exif:GPSSpeed", "exif:GPSTrackRef", "exif:GPSTrack", "exif:GPSImgDirectionRef", "exif:GPSImgDirection", "exif:GPSMapDatum", "exif:GPSDestLatitude", "exif:GPSDestLongitude", "exif:GPSDestBearingRef", "exif:GPSDestBearing", "exif:GPSDestDistanceRef", "exif:GPSDestDistance", "exif:GPSProcessingMethod", "exif:GPSAreaInformation"];
var myCameraRawArray = ["crs:AutoBrightness", "crs:AutoContrast", "crs:AutoExposure", "crs:AutoShadows", "crs:BlueHue", "crs:BlueSaturation", "crs:Brightness", "crs:CameraProfile", "crs:ChromaticAberrationB", "crs:ChromaticAberrationR", "crs:ColorNoiseReduction", "crs:Contrast", "crs:CropTop", "crs:CropLeft", "crs:CropBottom", "crs:CropRight", "crs:CropAngle", "crs:CropWidth", "crs:CropHeight", "crs:CropUnits", "crs:Exposure", "crs:GreenHue", "crs:GreenSaturation", "crs:HasCrop", "crs:HasSettings", "crs:LuminanceSmoothing", "crs:RawFileName", "crs:RedHue", "crs:RedSaturation", "crs:Saturation", "crs:Shadows", "crs:ShadowTint", "crs:Sharpness", "crs:Temperature", "crs:Tint", "crs:ToneCurve", "crs:ToneCurveName", "crs:Version", "crs:VignetteAmount", "crs:VignetteMidpoint", "crs:WhiteBalance"];

var myInfo = new Array;
var myDoc = app.activeDocument;
var myLinks = app.documents[0].links;

for ( i = 0; i < myLinks.length; i++)
getMetaData ( myLinks );

writeData ( 'Metadaten zu ' + myDoc.name + '\r-----------\r\r' + myInfo.join ( '\r\r'), File ('~/Desktop/Metadaten_' + myDoc.name.replace(/.indd$/, '') + '.txt'));

// ===============================================================
// Funktionen
// ===============================================================
function getMetaData ( aLink )
{
var myLinkXmp = aLink.linkXmp.properties.toSource().replace( /^\(\{/,'' ).replace (/\)\}$/,'').replace( /parent.+$/,'').replace(/:/g, ':\t').split( ', ');
var myString = aLink.name;
myString += loopLinkXmp ( aLink, myLinkXmpArray );
myString += loopArray ( aLink, "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/", "Iptc4xmpCore:CreatorContactInfo/Iptc4xmpCore:", myIPTCArray);
myString += loopArray ( aLink, "http://ns.adobe.com/photoshop/1.0/", "", myPSArray );
myString += loopArray ( aLink, "http://ns.adobe.com/tiff/1.0/", "", myTiffArray );
myString += loopArray ( aLink, "http://ns.adobe.com/exif/1.0/", "", myExifArray );
myString += loopArray ( aLink, "http://ns.adobe.com/camera-raw-settings/1.0/", "", myCameraRawArray );
myInfo.push( myString.replace( /, $/,'') );
}

function loopArray( aLink, s1, s2, anArray )
{
var temp = '\r\t--- ' + s1 + ' ---\r\t';
for ( var a = 0; a < anArray.length; a++)
{
try {
var theEvalString = 'aLink.linkXmp.getProperty(\"' + s1 + '\", \"' + s2 + anArray + '\")';
var myCode = eval( theEvalString );
if ( myCode != '' )
temp += '[' + anArray
+ ']\t' + myCode + '\r\t';
} catch (e){ //temp +=e + '\r'
}
}
return temp;
}

function loopLinkXmp( aLink, anArray )
{
var temp = '\r\t--- LinkMetadata ---\r\t';
for ( var a = 0; a < anArray.length; a++)
{
try {
var theEvalString = 'aLink.linkXmp.' + anArray
;
var myCode = eval( theEvalString );
if ( myCode != '' )
temp += '[' + anArray
+ ']\t' + myCode + '\r\t';
} catch (e){ //temp +=e + '\r'
}
}
return temp;
}

function writeData ( aData, theFile )
{
theFile.open ( 'w', 'Text', 'R*ch' );
theFile.encoding = 'UTF-8';
theFile.write ( aData );
theFile.close ();
}


Ressources:
Adobe XMP Developer Center: http://www.adobe.com/devnet/xmp/
XMP Specification: http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf

Martin Fischer
tomaxxi
Inspiring
August 17, 2010

Hey!

I know it's old post, but I wrote two interesting articles about Adobe XMP.


Extract Metadata with Adobe XMP [Part 1]

Extract Metadata with Adobe XMP [Part 2]

--

tomaxxi

http://indisnip.wordpress.com/

Loic.Aigon
Legend
November 29, 2008
I believe this subject has been already discussed by here. Have a look on the archives via the search function of this forum. I am quite sure you will find good infos.
Loic
Participant
November 29, 2008
hi iam new to XMP . please tell me How to develop XMp in .net

Rami Reddy.b
bandiramireddy@aol.com
Known Participant
November 13, 2008
Hi venkan,

There are examples of both in the "Working with Documents" chapter of the InDesign Scripting Guide.

Thanks,

Ole
Participant
November 13, 2008
Did anybody give the basics things of XMP Metadata

1) How to create?
2) How to import in the InDesign?
Participant
November 13, 2008
Did anybody say about the basics of XMP Metadata
ekimberAuthor
Participating Frequently
November 7, 2008
Right--the problem is that I don't know what might be there in a given document instance.

The argument that not allowing inspection somehow protects somebody is pretty bogus given that I can save the entire XMP data to a file from a script using one line of code, or just inspect the INCX or INX document.

Also, the document properties dialog shows all the custom metadata, so there must be C++ code that can access it. Just not script code. So the argument is doubly bogus. Hmph.

In any case, since I'm generating the INCX from XML I just added a script label to the Story object that lists the custom metadata fields I add as part of the INCX generation. Then my script can just iterate over the list and get the stuff out.

The only problem with that solution is when I need to start from a blank document and still allow authors to add custom metadata from InCopy (where I will be creating my own dialog for inspecting and setting custom metadata).

On the subject of Bridge--if a user only has InCopy and not InDesign, would they still have Bridge? That is, for InCopy-only users, can I even depend on the presence of Bridge?

Thanks,

Eliot
Known Participant
November 7, 2008
X wrote: "In Bridge, you can use the Metadata object to poke around provided you know the namespace and the property names."

That's the trouble--you have to know where things are. I think that the original poster was looking for a way to browse the XMP without knowing the namespace/container names. XMP doesn't want people to be able to do that for some reason (probably having to do with intellectual property protection, etc.).

You can browse standard fields, of course--but the custom ones won't even tell you if they're present or not--they'll just return an empty string when you try to retrieve the data.

Thanks,

Ole
Known Participant
November 7, 2008
> That's the trouble--you have to know where things are. I think that the original poster was looking for a way to browse the XMP without knowing the namespace/container names. XMP doesn't want people to be able to do that for some reason (probably having to do with intellectual property protection, etc.).
>

XMPScript does have an iterator object which may address this shortcoming though
I haven't tested it yet.

XMPIterator object
Created by a call to XMPMeta.iterator(). Walks recursively through the
properties and qualifiers of an XMPMeta object, and returns them as
XMPProperty objects.

-X
ekimberAuthor
Participating Frequently
November 6, 2008
Hmm, not discoverable by design. That seems a little odd.

Unfortunately, I don't know where the data is (or rather, I do know where the data is, I just don't know how much of it there might be).

I guess that leaves with saving the XMP to a file and processing it separately, which isn't that big a deal but still.

Thanks,

Eliot
Known Participant
November 7, 2008
> I guess that leaves with saving the XMP to a file and processing it separately, which isn't that big a deal but still.

The other alternative is to have some script code that calls Bridge to get at
the metadata. In Bridge, you can use the Metadata object to poke around provided
you know the namespace and the property names. The XMPScript lib is also an
option in Bridge CS3, but it references only metadata stored in the XMP packet
in the file. It does not handle derived/implicit metadata, like the EXIF data
that is a part of images. A lot of my Photoshop work relies heavily on metadata
so I've got this all worked out fairly well, including rough 'parsing' for
canonical XMP format and Metadata.serialize() format.

-X
Known Participant
November 6, 2008
Hi Eliot,

Getting custom XMP data is not discoverable by design (I disagree with the design of XMP on this matter, but that's the way it is). But if you know where the data is, it's relatively easy. Take a look at the example script Metadata.jsx that goes with the Scripting Guide--it creates a custom XMP field "email". In short, it looks like this:

//Create a custom XMP container, "email"

var myString = "http://ns.adobe.com/xap/1.0/";
var myNewContainer = myDocument.metadataPreferences.createContainerItem(myString, "email");
myDocument.metadataPreferences.setProperty(myString, "email/*[1]", "someone@adobe.com");
//Retrieve the value from the XMP container:
myString = myDocument.metadataPreferences.getProperty("http://ns.adobe.com/xap/1.0/","email/*[1]");


Thanks,

Ole