How to retrieve internal PS object properties

Photoshop Script Snippets - Note: Full Scripts go in the Photoshop Scripts Forum

Moderators: Tom, Kukurykus

xbytor

How to retrieve internal PS object properties

Post by xbytor »

This is a follow-up to a recent thread where there was someone needed to get access to an underlying property on a layer.

The code below makes it possible to access properties of Application, Document, and Layer classes without having to working about the types of the objects or properties involved. The low-level function Stdlib._getObjProperty makes it possible to access properties from other types of objects.

Internally, the code only works on the current/active object. For Application, this is not an issue. For Document and Layers, it's a big issue. If you do not have Stdlib.wrapLC or Stdlib.wrapLCLayer available, you must make sure that the document and/or layer is the current/active one.

Note that if you are wanting to access layer properties by using the internal layer index you would need to have a slightly different implementation. I'll leave that as an exercise for the reader .

Please refer to the previous thread (towards the end) for more discussion on this technique.


Code: Select allcTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
xTID = function(s) {
  if (s.constructor == Number) {
    return s;
  }
  if (s.constructor == String) {
    if (s.length != 4) return sTID(s);
    try { return cTID(s); } catch (e) { return sTID(s); }
  }
  Error.runtimeError(19, "s");  // Bad Argument
};

Stdlib = function(){};

//
// Stdlib.getObjectProperty
//   Return the value of a PS object's properties from the underlying
//     ActionDescriptor-based definition.
//   Returns 'undefined' if the property's value cannot be determined
//   This api currently only works on Application, Document, and
//   Layer-family objects.
//   Lower level apis make it possible to access other kinds of objects.
//
// Examples:
// Stdlib.getObjectProperty(doc, 'Ttl ');
// Stdlib.getObjectProperty(doc.activLayer, 'Nm  ');
// Stdlib.getObjectProperty(app, 'Path');
//
Stdlib.getObjectProperty = function(obj, prop) {
  var val = Stdlib._getObjProperty(obj, prop);

  return (val ? val.value : undefined);
};

// Stdlib.getObjectPropertyType
//   For UnitDouble, return the type
//   For Object, return the classId
//   For Enumerated, return the enumerationTypeId
//   All else, return undefined
//
Stdlib.getObjectPropertyType = function(obj, prop) {
  var val = Stdlib._getObjProperty(obj, prop);

  return (val ? val.type : undefined);
};
//
// Stdlib._getObjProperty
//   Returns an object with value and (optional) type of the property.
//   The 'typ' can be used when accessing an object type that this
//   function does not already understand
//
Stdlib._getObjProperty = function(obj, prop, typ) {
  var propId;
  var otyp;

  function _ftn() {
    var ref = new ActionReference();
    ref.putProperty(cTID("Prpr"), propId);
    ref.putEnumerated(cTID(otyp), cTID("Ordn"), cTID("Trgt") );
    var desc;
    try {
      desc = executeActionGet(ref);
    } catch (e) {
      return undefined;
    }
    var val = {};

    if (desc.hasKey(propId)) {
      var typ = desc.getType(propId);
      switch (typ) {
        case DescValueType.ALIASTYPE:
          val.value = desc.getPath(propId); break;
        case DescValueType.BOOLEANTYPE:
          val.value = desc.getBoolean(propId); break;
        case DescValueType.CLASSTYPE:
          val.value = desc.getClass(propId); break;
        case DescValueType.DOUBLETYPE:
          val.value = desc.getDouble(propId); break;
        case DescValueType.ENUMERATEDTYPE: 
          val.value = desc.getEnumeratedValue(propId);
          val.type = desc.getEnumeratedType(propId);
          break;
        case DescValueType.INTEGERTYPE:
          val.value = desc.getInteger(propId); break;
        case DescValueType.LISTTYPE:
          val.value = desc.getList(propId); break;
        case DescValueType.OBJECTTYPE:
          val.value = desc.getObjectValue(propId);
          val.type = desc.getObjectType(propId);
          break;
        case DescValueType.RAWTYPE:
          val.value = desc.getData(propId); break;
        case DescValueType.REFERENCETYPE:
          val.value = desc.getReference(propId); break;
        case DescValueType.STRINGTYPE:
          val.value = desc.getString(propId); break;
        case DescValueType.UNITDOUBLE:
          val.value = desc.getUnitDoubleValue(propId);
          val.type = desc.getUnitDoubleType(propId);
          break;
      }
    }
    return val;
  }

  if (obj == undefined) {
    Error.runtimeError(2, "object");
  }
  if (prop == undefined) {
    Error.runtimeError(2, "property");
  }

  if (prop.constructor == String) {
    propId = xTID(prop);
  } else if (prop.constructor == Number) {
    propId = prop;
  } else {
    Error.runtimeError(19, "property");
  }

  var val;

  if (typ == undefined) {
    if (obj.typename == "Document") {
      otyp = "Dcmn";
    } else if (obj.typename == "ArtLayer" || obj.typename == "LayerSet") {
      otyp = "Lyr ";
    } else if (obj.typename == "Application") {
      otyp = "capp";
    } else {
      throw ("Unable to get property from " +
             (obj.typename ? obj.typename : "unknown") +
             " type of object.");
    }
  } else {
    otyp = typ;
  }

  if (otyp == "Dcmn" && Stdlib.wrapLC) {
     
    val = Stdlib.wrapLC(obj, _ftn);

  } else if (otyp == "Lyr " && Stdlib.wrapLCLayer) {

    var p = layer.parent;
    while (p.typename != "Document") {
      p = p.parent;
    }
    val = Stdlib.wrapLCLayer(p, obj, _ftn);

  } else {
    val = _ftn();
  }

  return val;
};


-X
xbytor

How to retrieve internal PS object properties

Post by xbytor »

Here's the expanded bug-reduced version:
Code: Select all//
// Stdlib.getObjectProperty
//   Return the value of a PS object's properties from the underlying
//     ActionDescriptor-based definition.
//   Returns 'undefined' if the property's value cannot be determined
//   This api currently only works on Application, Document, and
//   Layer-family objects.
//   Lower level apis make it possible to access other kinds of objects.
//
// Examples:
// var str = Stdlib.getObjectProperty(0, "Nm  ", "Lyr ")
// var bool = Stdlib.getObjectProperty(doc.activeLayer, "Vsbl", "Lyr ")
// var str = Stdlib.getObjectProperty(doc, 'Ttl ');
// var file = Stdlib.getObjectProperty(app, 'Path');
// var clrDesc = Stdlib.getObjectProperty(app, 'FrgC');
//
Stdlib.getObjectProperty = function(obj, prop, typ) {
  var val = Stdlib._getObjProperty(obj, prop, typ);

  return (val ? val.value : undefined);
};

// Stdlib.getObjectPropertyType
//   For UnitDouble, return the type
//   For Object, return the classId
//   For Enumerated, return the enumerationTypeId
//   All else, return undefined
//
Stdlib.getObjectPropertyType = function(obj, prop, typ) {
  var val = Stdlib._getObjProperty(obj, prop, typ);

  return (val ? val.type : undefined);
};
//
// Stdlib._getObjProperty
//   Returns an object with value and (optional) type of the property.
//   The 'typ' can be used when accessing an object type that this
//   function does not already understand
//
Stdlib._getObjProperty = function(obj, prop, typ) {
  var propId;
  var otyp;

  function _ftn(obj, propId, otyp) {
    var ref = new ActionReference();
    ref.putProperty(cTID("Prpr"), propId);

    if (typeof(obj) == "number") {
      ref.putIndex(cTID(otyp), obj);
    } else {
      ref.putEnumerated(cTID(otyp), cTID("Ordn"), cTID("Trgt") );
    }

    var desc;
    try {
      desc = executeActionGet(ref);
    } catch (e) {
      return undefined;
    }
    var val = {};

    if (desc.hasKey(propId)) {
      var typ = desc.getType(propId);
      switch (typ) {
        case DescValueType.ALIASTYPE:
          val.value = desc.getPath(propId); break;
        case DescValueType.BOOLEANTYPE:
          val.value = desc.getBoolean(propId); break;
        case DescValueType.CLASSTYPE:
          val.value = desc.getClass(propId); break;
        case DescValueType.DOUBLETYPE:
          val.value = desc.getDouble(propId); break;
        case DescValueType.ENUMERATEDTYPE: 
          val.value = desc.getEnumeratedValue(propId);
          val.type = desc.getEnumeratedType(propId);
          break;o
        case DescValueType.INTEGERTYPE:
          val.value = desc.getInteger(propId); break;
        case DescValueType.LISTTYPE:
          val.value = desc.getList(propId); break;
        case DescValueType.OBJECTTYPE:
          val.value = desc.getObjectValue(propId);
          val.type = desc.getObjectType(propId);
          break;
        case DescValueType.RAWTYPE:
          val.value = desc.getData(propId); break;
        case DescValueType.REFERENCETYPE:
          val.value = desc.getReference(propId); break;
        case DescValueType.STRINGTYPE:
          val.value = desc.getString(propId); break;
        case DescValueType.UNITDOUBLE:
          val.value = desc.getUnitDoubleValue(propId);
          val.type = desc.getUnitDoubleType(propId);
          break;
      }
    }
    return val;
  }

  if (obj == undefined) {
    Error.runtimeError(2, "object");
  }
  if (prop == undefined) {
    Error.runtimeError(2, "property");
  }

  if (prop.constructor == String) {
    propId = xTID(prop);
  } else if (prop.constructor == Number) {
    propId = prop;
  } else {
    Error.runtimeError(19, "property");
  }

  var val; // {value: undefind, type: undefined}

  //$.level = 1; debugger;

  if (app.documents.length > 0) {
    var o_doc = app.activeDocument;   // active doc before this function
    var o_layer = o_doc.activeLayer;  // active layer before this function
  }

  if (typeof(obj) == "object") {
    if (typ == "Dcmn" || obj.typename == "Document") {
      otyp = "Dcmn";
      if (app.activeDocument != obj) {
        o_doc = app.activeDocument;
        app.activeDocument = obj;
      }

    } else if (typ == "Lyr " || obj.typename == "ArtLayer"
               || obj.typename == "LayerSet") {
      otyp = "Lyr ";
      var layer = obj;
      while(layer.parent != undefined &&
            layer.parent.typename != "Document") {
        layer = layer.parent;
      }
      if (app.activeDocument != layer.parent) {
        app.activeDocument = layer.parent;
      }
      if (layer.parent.activeLayer != layer) {
        layer.parent.activeLayer = layer;
      }
       
    } else if (typ == "capp" || obj.typename == "Application") {
      otyp = "capp";

    } else {
      throw ("Unable to get property from " +
             (obj.typename ? obj.typename : "unknown") +
             " type of object.");
    }
  } else if (typeof(obj) == "number") {
    if (!typ) {
      throw ("Unable to get property from unknown type of object");
    }
    if (typ != "Lyr " && typ != "Dcmn") {
      throw "Indexed app operations are not yet supported.";
    }
    otyp = typ;
  }

  var val = _ftn(obj, propId, otyp);

  if (app.documents.length > 0) {
    if (o_doc.activeLayer != o_layer) {
      o_doc.activeLayer = o_layer;
    }
    if (app.activeDocument != o_doc) {
      app.activeDocument = o_doc;
    }
  }

  return val;
};

Stdlib.getLayerProperty = function(index, propSym) {
  return Stdlib.getObjectProperty(index, propSym, 'Lyr ');
};
Stdlib.getDocumentProperty = function(index, propSym) {
  return Stdlib.getObjectProperty(index, propSym, 'Dcmn');
};
Stdlib.getApplicationProperty = function(propSym) {
  return Stdlib.getObjectProperty(app, propSym);
};


The previous versions had problems if the document or layer was not the active one when this was called.

-X
-X
Larry Ligon

How to retrieve internal PS object properties

Post by Larry Ligon »

I don't need no exercise!!!
xbytor

How to retrieve internal PS object properties

Post by xbytor »

The updated version will work with layer and document objects or their indexes.

Code: Select allStdlib.getLayerProperty(1, "Nm ");
Stdlib.getLayerProperty(doc.activeLayer, "Nm  ");
Stdlib.getDocumentProperty(1, "Ttl ");
Stdlib.getDocumentProperty(doc, "Ttl ");

I already did the exercise for you

-X
Larry Ligon

How to retrieve internal PS object properties

Post by Larry Ligon »

Thanks! I had my 60th birthday on March 15. I'm beyond exercise now!