Skip to content

Photoshop Kevlar API Additions for Generator

samgannawayA edited this page Aug 5, 2024 · 35 revisions

For more information on how to connect to Kevlar, and send ExtendScript to Photoshop over a socket connection, refer to the Photoshop CC SDK

networkEventSubscribe

Subscribe to changes, sends any relevant change info back on subscribing socket/pipe. This API existed in previous versions of Kevlar, but generator adds three new events, "imageChanged", "generatorMenuChanged" and "generatorDocActivated". When the change/event occurs, the event name followed by optional additional json or parameters is returned on the same transaction as the subscription request

  • "imageChanged"

    Subscribe to any changes to image documents in JSON format (see the JSONFormat documentation for a full explanation)

     //call Kevlar to subscribe to the message
     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
    
     //event name
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "imageChanged" ) );
    
     //JSON format version: optional, currently ignored.
     //you will always get the current version for now: "1.0.0" in Photoshop 14.1 or "1.1.0" in Photoshop 14.2
     
     desc1.putString( stringIDToTypeID( "version" ),  "1.0.0" );
    
     executeAction( idNS, desc1, DialogModes.NO );
    

    Sample notification after creating a new document (message type JavaScript):

     imageChanged
     {"id":1125,"active":true,"file":"Untitled-2"}	 
    
  • "generatorMenuChanged"

    Subscribe to selection of generator menu items

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "generatorMenuChanged" ) );
    
     //JSON format version: optional, currently ignored.
     //you will always get the current version for now: "1.0.0" in Photoshop 14.1 or "1.1.0" in Photoshop 14.2
     desc1.putString( stringIDToTypeID( "version" ),  "1.0.0" );
    
     executeAction( idNS, desc1, DialogModes.NO );
    

    Sample notification after selecting a generator menu item (message type JavaScript):

     generatorMenuChanged
     {"generatorMenuChanged":{"name":"menu1","checked":false,"enabled":true}}
    
  • "generatorDocActivated"

    Subscribe to any activate of documents with generator metadata (see "generatorSettings" below)

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "generatorDocActivated" ) );
    
     //JSON format version: optional, currently ignored.
     //you will always get the current version for now: "1.0.0" in Photoshop 14.1 or "1.1.0" in Photoshop 14.2
     desc1.putString( stringIDToTypeID( "version" ),  "1.0.0" ); 
    
     executeAction( idNS, desc1, DialogModes.NO );
    

    Sample notification after selecting a generator menu item (message type JavaScript):

     generatorDocActivated
     {"id":1125,"active":true,"file":"Untitled-2"}	 
    

Other events (present in the Photoshop Kevlar API since CS5.5)

  • "foregroundColorChanged"

    Notify when the app foreground color changes

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ),
                  stringIDToTypeID( "foregroundColorChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     foregroundColorChanged
     [color as 6 character hex value] 
    
  • "backgroundColorChanged"

    Notify when the app background color changes

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ),
                  stringIDToTypeID( "backgroundColorChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     backgroundColorChanged
     [color as 6 character hex value] 
    
  • "currentDocumentChanged"

    Notify when a different document becomes active

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), 
                            stringIDToTypeID( "currentDocumentChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     currentDocumentChanged
     [document id, if active document] 
    
  • "activeViewChanged"

    Notify when a different view becomes active

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), 
                            stringIDToTypeID( "activeViewChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     activeViewChanged
     [document id, if active document] 
    
  • "newDocumentViewCreated"

    Notify when a new view is created

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), 
                            stringIDToTypeID( "newDocumentViewCreated" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     newDocumentViewCreated
     [document id, if active document] 
    
  • "closedDocument"

    Notify when document is closed

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), 
                            stringIDToTypeID( "closedDocument" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     closedDocument
     [document id, if active document] 
    
  • "documentChanged"

    Notify when document becomes dirty

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), 
                            stringIDToTypeID( "documentChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     documentChanged
     [document id, if active document] 
    
  • "colorSettingsChanged" (no additional data returned)

    Notify when the color management preferences change

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "colorSettingsChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    
  • "keyboardShortcutsChanged" (no additional data returned)

    Notify when the keyboard shortcut preferences change

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "keyboardShortcutsChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    
  • "quickMaskStateChanged"

    Notify when the quick mask mode is entered/exited

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "quickMaskStateChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     quickMaskStateChanged
     enter 
    
     quickMaskStateChanged
     exit 
    
  • "toolChanged"

    Notify when a new tool is selected.

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "toolChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notifications sent:

     toolChanged
     [tool name] 
    
  • "workspaceChanged"

    Notify when a new workspace is selected.

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "workspaceChanged" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notification sent:

     workspaceChanged
     [workspace display name] 
    
  • 'Asrt' (eventAssert)

    Notify when an assert fails (debug builds of PS only)

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), charIDToTypeID( 'Asrt' ) );
     executeAction( idNS, desc1, DialogModes.NO );
    

    Notification sent:

     Asrt
     [assert message]
    
  • "idle"

    Notify when Photoshop is idle (no additional data sent)

     var idNS = stringIDToTypeID( "networkEventSubscribe" );
     var desc1 = new ActionDescriptor();
     desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "idle" ) );
     executeAction( idNS, desc1, DialogModes.NO );
    
  • Miscellaneous

    Notify when specified event is recorded no additional data sent) See event* for list of events in PITerminology.h imageChanged is usually more useful. as it describes exactly what changed in the document, rather than an eventID, this is just mentioned for the sake of completeness.

      var idNS = stringIDToTypeID( "networkEventSubscribe" );
      var desc1 = new ActionDescriptor();
      desc1.putClass( stringIDToTypeID( "eventIDAttr" ), charIDToTypeID( eventFourCharID ) );
      executeAction( idNS, desc1, DialogModes.NO );
    

    Notification sent:

      eventFourCharID
    

networkEventUnsubscribe

Stop receiving notifications for the specified event

var idNS = stringIDToTypeID( "networkEventUnsubscribe" );
var desc1 = new ActionDescriptor();
desc1.putClass( stringIDToTypeID( "eventIDAttr" ), stringIDToTypeID( "imageChanged" ) );
executeAction( idNS, desc1, DialogModes.NO );

sendDocumentThumbnailToNetworkClient

Send a thumbnail of a document's composite

var idNS = stringIDToTypeID( "sendDocumentThumbnailToNetworkClient" );
var desc1 = new ActionDescriptor();
desc1.putInteger( stringIDToTypeID( "documentID" ), docID ); //optional document id, uses active doc if not specified
desc1.putInteger( stringIDToTypeID( "width" ), thumbWidth ); //maximum size of thumbnail
desc1.putInteger( stringIDToTypeID( "height" ), thumbHeight );
desc1.putInteger( stringIDToTypeID( "format" ), formatIndex ); //1 is JPEG, 2 is pixmap (uncompressed w/ transparency)

// "placedID" : Photoshop 16.1 and later, optional. reference smart object(s) within the document
//series of "ID" from layer:smartObject:{} or "placedID" from "image:placed:[{}]"

//var placedList = new ActionList();
//placedList.putString( "37b45136-b6b4-1178-944f-cc2a4c1f14fc", ); 
//placedList.putString( "354d49de-b6b4-1178-944f-cc2a4c1f14fc" ); //if nested. within the previous smart object
//placedList.putString( "354d49dd-b6b4-1178-944f-cc2a4c1f14fc" ); //etc, up to 5 ids
//desc1.putList( stringIDToTypeID( "placedID" ), placedList );


executeAction( idNS, desc1, DialogModes.NO );

The thumbnail pixels are returned as message type Image in the requested format

sendLayerThumbnailToNetworkClient

Send a thumbnail of layer composite, or a range of layers, with optional settings/transform applied

var idNS = stringIDToTypeID( "sendLayerThumbnailToNetworkClient" );
var desc1 = new ActionDescriptor();
desc1.putInteger( stringIDToTypeID( "documentID" ), docID ); //optional document id, uses active doc if not specified
desc1.putInteger( stringIDToTypeID( "width" ), maxThumbWidth );
desc1.putInteger( stringIDToTypeID( "height" ), maxThumbHeight );
desc1.putInteger( stringIDToTypeID( "format" ), 2 ); //only 2 == pixmap is supported for now

// "placedID" : Photoshop 16.1 and later, optional. reference smart object(s) within the document
//series of "ID" from layer:smartObject:{} or "placedID" from "image:placed:[{}]"

//var placedList = new ActionList();
//placedList.putString( "37b45136-b6b4-1178-944f-cc2a4c1f14fc", ); 
//placedList.putString( "354d49de-b6b4-1178-944f-cc2a4c1f14fc" ); //if nested. within the previous smart object
//placedList.putString( "354d49dd-b6b4-1178-944f-cc2a4c1f14fc" ); //etc, up to 5 ids
//desc1.putList( stringIDToTypeID( "placedID" ), placedList );

//Optional: "convertToWorkingRGBProfile" 
//if present and true, the thumbnail is converted to the working RGB space in "Color Settings..."
desc1.putBoolean( stringIDToTypeID( "convertToWorkingRGBProfile" ), true );

//"useICCProfile": optional, Photoshop 16.1, and later. 
//convert to profile with this name, e.g. srgb is "sRGB IEC61966-2.1"

//desc1.putString( stringIDToTypeID( "useICCProfile" ), "sRGB IEC61966-2.1");

//Note: "interpolation", "transform", "bounds", "boundsOnly", and "thread"	
//are supported in background-only (layer-less) documents 	
//but only in version 15.0 and later.  "layerID" should be 0 in that case.	
//The other layer-related settings are ignored as there are no layers.

//Optional: "interpolation" 
//interpolation method to use for any downscaling necessary
//to fit into requested "width"/"height"
//supported interpolation types (from image size dialog/action)
// default is "bicubicSharper":
//	"nearestNeighbor", "bilinear", "bicubic",
//	"bicubicSmoother", "bicubicSharper", "bicubicAutomatic", 
//	"preserveDetailsUpscale", "automaticInterpolation"

desc1.putEnumerated( stringIDToTypeID( "interpolation" ), stringIDToTypeID( "interpolationType" ), stringIDToTypeID( thumbnailInterpolation ) );

//Optional: "transform" 
//scale/transform layers by this before building thumbnails 
//(scales original source data, such as smart obj/vectors)
//if this is specified, the thumbnail is built on a worker thread in Photoshop
//Optional: "interpolation", similar to interpolation above,
//but this is just used for the transform step (not the thumbnail),
//it defaults to Photoshop's "Image Interpolation" preference.

var transform1 = new ActionDescriptor();"
transform1.putInteger( stringIDToTypeID( "width" ), transformScaleX ); //percent, 100.0 == 1x
transform1.putInteger( stringIDToTypeID( "height" ), transformScaleY );
transform1.putEnumerated( stringIDToTypeID( "interpolation" ), stringIDToTypeID( "interpolationType" ), stringIDToTypeID( transformInterpolation ) );
transform1.putBoolean( stringIDToTypeID( "forceDumbScaling" ), true ); //For PS >= 14.2. Make smart shapes scale like non-smart shapes (round rect corners will scale), default is false
desc1.putObject( stringIDToTypeID( "transform" ), stringIDToTypeID( "transform" ), transform1 );


//which layers (use one of the following forms)
desc1.putBoolean( stringIDToTypeID( "selectedLayers" ), true );
//or 
desc1.putInteger( stringIDToTypeID( "layerID" ), layerID );
//or
desc1.putInteger( stringIDToTypeID( "firstLayer" ), firsLayerIndex );
desc1.putInteger( stringIDToTypeID( "lastLayer" ), lastLayerIndex );

//WARNING: if firstLayer, lastLayer range includes a group layer,
//it must include the corresponding hidden "divider" layer at the bottom of the group
//(and vice-versa).  
//The range can also just include layers inside a group with no group layers at all.

//firstLayer, lastLayer is a range of layers to include in the thumbnail.  If the range includes a group top layer,
//it needs to include all the group members, including one layer index below the lowest indexed group member (a hidden group bound layer)

//The firstLayer/lastLayer form supports these  optional args (see GetLayerRangeComposite in PSLAPI.h for more info)
//to modify layer/image settings before obtaining thumbnail
//layerSettings is an action list with  one action descriptor per each layer in firstLayer/lastLayer
//if the descriptor has a "layerSettings" key, the descriptor will be used to modify the layer before the thumbnail is retrieved:
//"layerSettings" keys:
//	enabled:boolean (make the layer visible/invisible)
//	blendOptions: (blending settings to use, follows same format as blendOptions imageChanged event)
//	layerEffects: (fx settings to use, follows same format as layerEffects imageChanged event)
//	offset:{horizontal:x vertical:y} (integer offset of layer)
//  vectorMask:{enabled:bool, offset:{horizontal:x vertical:y}, invert:boolean}
//  FXRefPoint:{horizontal:x vertical:y}

desc1.putObject( stringIDToTypeID( "layerSettings" ), layerSettingsList );
desc1.putObject( stringIDToTypeID( "imageSettings" ), imageSettingsObject );

//Sample of layerSettings List for layer indeces 1 to 6, that shows every other layer:
var oddDesc = new ActionDescriptor();
var evenDesc = new ActionDescriptor();
var firstLayer = 1;
var lastLayer = 6;
var evenDesc = new ActionDescriptor();
var lsID = stringIDToTypeID( "layerSettings" );
var evenDescSettings = new ActionDescriptor();
evenDescSettings.putBoolean( stringIDToTypeID( "enabled" ), false );
evenDesc.putObject( lsID, lsID, evenDescSettings );
var settingsList = new ActionList();
for (var ll = firstLayer; ll <= lastLayer; ++ll)
{settingsList.putObject( lsID, (ll & 1) ? oddDesc : evenDesc );}
desc1.putInteger( stringIDToTypeID( "firstLayer" ), firstLayer );
desc1.putInteger( stringIDToTypeID( "lastLayer" ), lastLayer );
desc1.putList( stringIDToTypeID( "layerSettings" ), settingsList );


//Optional: includeLayers, these add additional layers to the requested layer
//values are enums of type stringIDToTypeID( "includeLayers" ) with one of the following values:
// stringIDToTypeID( "includeVisible" ) , include visible layers of this type
// stringIDToTypeID( "includeNone" ) , include no layers of this type
// stringIDToTypeID( "includeAll" ) , include all layers of this type (force them visible)

//keys are one of the following values:
//includeAdjustors: adjustors above the layer, default is includeVisible
//includeAncestors: enclosing groups (includes group blending, fx, masks), default is includeAll
//includeChildren: children if layer is a group (includes group blending, fx, masks), default is includeVisible
//includeClipBase: clip base if layer is clipped.  The clip base is a layer that a clipped layer is clipped to, default is includeAll
//includeClipped: clipped layers if layer is clip base, default is includeVisible

//Notes:
//for includeAncestors:
//     includeVisible and includeAll incorporate any blending parameters/masks of the ancestor groups
//     includeVisible returns an empty thumbnail for any layer inside an invisible group
//     includeNone substitutes  default groups for any groups around the layer

desc1.putEnumerated( stringIDToTypeID( "includeAdjustors" ), stringIDToTypeID( "includeLayers" ), includeAdjustors );
desc1.putEnumerated( stringIDToTypeID( "includeAncestors" ), stringIDToTypeID( "includeLayers" ), includeAncestors );
desc1.putEnumerated( stringIDToTypeID( "includeChildren" ), stringIDToTypeID( "includeLayers" ), includeChildren );
desc1.putEnumerated( stringIDToTypeID( "includeClipBase" ), stringIDToTypeID( "includeLayers" ), includeClipBase );
desc1.putEnumerated( stringIDToTypeID( "includeClipped" ), stringIDToTypeID( "includeLayers" ),  includeClipped );

//Optional: clipToDocumentBounds
//clip the layer thumbnail to the document canvas bounds (default is false)
desc1.putBoolean( stringIDToTypeID( "clipToDocumentBounds" ), true );

//Optional: clipBounds
//clip the layer thumbnail to an arbitraryRect

var clipBounds = new ActionDescriptor();
clipBounds.putInteger(stringIDToTypeID( "top" ), top);
clipBounds.putInteger(stringIDToTypeID( "left" ), left);
clipBounds.putInteger(stringIDToTypeID( "right" ), right);
clipBounds.putInteger(stringIDToTypeID( "bottom" ), bottom);
desc1.putObject( stringIDToTypeID( "clipBounds" ), stringIDToTypeID( "clipBounds" ), clipBounds );

//Optional: bounds
//return the thumbnail bounds as JSON on same transaction. (default is false)
desc1.putBoolean( stringIDToTypeID( "bounds" ), true );

//Optional: boundsOnly
//Just return the thumbnail bounds as JSON on same transaction. (no thumbnail data) (default is false)
desc1.putBoolean( stringIDToTypeID( "boundsOnly" ), true );

//scale/transform layers by this before building thumbnails (scales original source data, such as smart obj/vectors)
//if this is specified, the thumbnail is built on a worker thread in Photoshop
//Optional: "interpolation", similar to interpolation above, but this is just used for the transform step (not the thumbnail)

//Optional: thread
//build the thumbnail on a thread.  By default, the thumbnail is threaded if there is a "transform", otherwise
//it is done on the main thread unless a user event occurs, then it is cancelled, and restarted on a thread
//thread can be used to override the default (either force the thumb to be started on the main thread or a background thread)
//it may help performance if you know that the thumbnail is either quick (best done on main thread) or slow (best done on background)
//there is a slight memory/performance penalty for threading in that the layer data must be copied before it is threaded

desc1.putBoolean( stringIDToTypeID( "thread" ), true );


//optional "compID" or "compIndex"
//layer comp id/index to use (this comp is temporarily applied before getting thumbnail)
desc1.putInteger( stringIDToTypeID( "compID" ), compID );
//or
desc1.putInteger( stringIDToTypeID( "compIndex" ), compIndex );

//15.0 and later:
//optional “allowDither” and “useColorSettingsDither”. Both default to true.
//If 
//1) “allowDither” is true
//2) and either “useColorSettingsDither” is false,
//       or dither is checked in the global color settings (Color Settings… in Photoshop)
//3) and any color/depth conversion would be “lossy” (16 to 8 bit, CMYK to RGB, etc)
//
//then dithering will occur, otherwise there will be no dithering.

//e.g. force dither off.
desc1.putBoolean( stringIDToTypeID( "allowDither" ), false ); 
desc1.putBoolean( stringIDToTypeID( "useColorSettingsDither" ), false );

executeAction( idNS, desc1, DialogModes.NO );

Thumbnail is returned as message type Image (pixmap type)

sendLayerShapeToNetworkClient

Return path/fill/strokeStyle for a shape layer(s)

var idNS = stringIDToTypeID( "sendLayerShapeToNetworkClient" );
var desc1 = new ActionDescriptor();

desc1.putInteger( stringIDToTypeID( "documentID" ), docID ); //optional document id, uses active doc if not specified

// "placedID" : Photoshop 16.1 and later, optional. reference smart object(s) within the document
//series of "ID" from layer:smartObject:{} or "placedID" from "image:placed:[{}]"

//var placedList = new ActionList();
//placedList.putString( "37b45136-b6b4-1178-944f-cc2a4c1f14fc", ); 
//placedList.putString( "354d49de-b6b4-1178-944f-cc2a4c1f14fc" ); //if nested. within the previous smart object
//placedList.putString( "354d49dd-b6b4-1178-944f-cc2a4c1f14fc" ); //etc, up to 5 ids
//desc1.putList( stringIDToTypeID( "placedID" ), placedList );

//which layers (use one of the following forms)
desc1.putBoolean( stringIDToTypeID( "selectedLayers" ), true );
//or 
desc1.putBoolean( stringIDToTypeID( "layerID" ), layerID );
//or
desc1.putBoolean( stringIDToTypeID( "firstLayer" ), firsLayerIndex );
desc1.putBoolean( stringIDToTypeID( "lastLayer" ), lastLayerIndex );
desc1.putString( stringIDToTypeID( "version" ), "1.0.0" ); //format version. Valid versions are 1.0.0 in 14.1, and 1.0, 1.0.0, 1.1, or 1.1.0 in Photoshop 14.2

executeAction( idNS, desc1, DialogModes.NO );

Path is returned as JSON (same format as image changed and doc info) containing just the path, fill, and stroke (if any) attributes:

{"path":
	{"pathComponents": // arrays of paths to be filled and boolean operators
		[{"shapeOperation": ("intersect"/"add"/"subtract"/"xor")
		"subpathListKey":[  //list of subpath objects that make up the component 
			{"closedSubpath":true, // (if subpath is closed)
			 "points": [{" // array of knot objects (anchor and control points)
				anchor:[x,y]  		//point on path
				forward:[x1,y1]		//forward bezier control
				backward:[x2,y2]	//backward bezier control
				},  //next knot...
				...]
		"origin":{"origin": ("ellipse"/"rect"/"roundedrect"/"line"/"unknown")
		"radii":  [r1,r2,r3,r4], //radii for rounded rect if any
	"bounds":["top":top,"left":left,"right":right,"bottom":bottom], //bounds of entire path
	"defaultFill":true/false}, //whether path starts out filled or not
"fill":
	{"color":{"red":red,"green":green,"blue":blue},"class":"solidColorLayer"}
	//or
	{"gradient":{(gradient object)},"class":"gradientLayer"}
	//or
	{"pattern":{(pattern object)},"class":"patternLayer"}
"strokeStyle":
	{(strokeStyle object)}
}

Sample output for a black filled ellipse:

{"path":{"pathComponents":
		[{"shapeOperation":"add",
		  "subpathListKey":[
			{"closedSubpath":true,
			 "points": [{"anchor":[234.5,36],"forward":[307.125,36],"backward":[161.875,36]},
				{"anchor":[366,167],"forward":[366,239.349],"backward":[366,94.651]},
				{"anchor":[234.5,298],"forward":[161.875,298],"backward":[307.125,298]},
				{"anchor":[103,167],"forward":[103,94.651],"backward":[103,239.349]}]
			}],
		   "origin":{"origin":"ellipse","bounds":[35,102,299,367]}
		}],
	"bounds":[35,102,299,367],
	"defaultFill":false},
"fill":{"color":{"red":0,"green":0,"blue":0},"class":"solidColorLayer"}
}

sendDocumentInfoToNetworkClient

Return complete document info in JSON format. Produces a similar response as networkEventSubscribe(imageChanged), essentially forcing all possible changes for the docs/layers/comps

// Sample code for getting document info with sendDocumentInfoToNetworkClient

var idNS = stringIDToTypeID( "sendDocumentInfoToNetworkClient" );
var desc = new ActionDescriptor();

//All parameters are optional

// "version:: optional requested version (you always get the current version back, but this does a sanity check, and errors on an incompatible version)
desc.putString( stringIDToTypeID( "version" ), "1.4.0");

// ----------------------------------------------------------------
//Target of info request (by default gets info for active document)

//"documentID" : optional document id, uses active doc if not specified
//desc.putInteger( stringIDToTypeID( "documentID" ), 42 ); 

// Photoshop 16.1 and later
// "placedID" :  optional. reference smart object(s) within the document
//list of up to five placed IDs that are a path into the smart object hierarchy (each successive id is a smart object nested
//in the previous id.  Similar to placedID in sendLayerThumbnailToNetworkClient.
// of "ID" from layer:smartObject:{} or "placedID" from "image:placed:[{}]"


//var placedList = new ActionList();
//placedList.putString( "9d79145d-ba20-1178-860a-9aaf4074c344" ); 
//desc.putList( stringIDToTypeID( "placedID" ), placedList );

//16.1 and later
// "layerID","firstLayer","lastLayer": 16.1 and later, just get info for these layers
// default is to use all layers.  Similar to sendLayerThumbnailToNetworkClient
// "selectedLayers" : default is false, just get info for the selected layer(s)

//desc.putInteger( stringIDToTypeID( "layerID" ), 5 );
//-or-
//desc.putInteger( stringIDToTypeID( "firstLayer" ), 2 );
//desc.putInteger( stringIDToTypeID( "lastLayer" ), 5 );
//-or-
desc.putBoolean( stringIDToTypeID( "selectedLayers" ), true);

// ----------------------------------------------------------------

// "expandSmartObjects": default is false, recursively get doc info for any smart objects. can be slow
desc.putBoolean( stringIDToTypeID( "expandSmartObjects" ), true);

// "getTextStyles": default is false, return more detailed text info. can be slow
//desc.putBoolean( stringIDToTypeID( "getTextStyles" ), true);

// "getFullTextStyles" : default is false, return all text information (getTextStyles must also be true)
//desc.putBoolean( stringIDToTypeID( "getFullTextStyles" ), false);

// "getDefaultLayerFX": default is false, return all layer fx even if they are disabled
desc.putBoolean( stringIDToTypeID( "getDefaultLayerFX" ), true);

// "getCompLayerSettings": default is false, enumerate layer settings in layer comps
//desc.putBoolean( stringIDToTypeID( "getCompLayerSettings" ), true);

// "getPathData": default is false, return path control points for shapes
//desc.putBoolean( stringIDToTypeID( "getPathData" ), true);

//"imageInfo": return image-wide info (size, resolution etc.), default is !"selectedLayers" (true iff selectedLayers is false or missing)
desc.putBoolean( stringIDToTypeID( "imageInfo" ), true ); 

//"compInfo": return comp info in "comps" array, default is true, default is !"selectedLayers" (true iff selectedLayers is false or missing)
desc.putBoolean( stringIDToTypeID( "compInfo" ), true );

//"layerInfo": return layer info in "layers" array, default is true
desc.putBoolean( stringIDToTypeID( "layerInfo" ), true );

//16.1 and later "includeAncestors": include surrounding layer groups if doing selected layers/range/single layer id. default is true
//should only be used with single layers (otherwise grouping may not be accurate)
//desc.putBoolean( stringIDToTypeID( "includeAncestors" ), false );

// ----------------------------------------------------------------

//"whichInfo": allows more specificity of the attributes returned
//generally follows format of the returned info (see JSON info format)
//helps to reduce the calcuation needed if you just need certain info or certain layers.

//Version notes
//In 16.0 and earlier
//  	Both "layers" and "comps" are required
//		layers:text or layers:path would force expansion (getTextStyles, getPathData to true)
//		presence of whichInfo:placed forces expandSmartObjects to true, if it's absent expandSmartObjects is forced to false
//		individual image attributes aren't supported
//		to specify a layer, layerID/firstLayer/lastLayer need to go in whichInfo->layers
//		layerID needs to be 0, or a valid layer id.
//in 16.1 and later, 
//		Both "layers" and "comps" are optional (if missing no layer or comp info is returned at all)
//		the getTextStyles/getPathData/expandSmartObjects flags are always respected for layers:text, path
//		layerID/firstLayer/lastLayer are read from top level (or from whichInfo.layers if layerID/firstLayer/lastLayer is present there)
//		layerID is optional

//examples

//get just the layer smartObject info

//whichInfo:{
//layers:{smartObject:true}
//}

//get just the comp layer settings

//whichInfo:{
//comps:{layerSettings:true}
//}

//get all info for the layer with layerID, id (you can specify layerID in the top level descriptor in 16.1 and later)
//whichInfo:{
//layers:{allInfo:true}
//}

//get just the layer text info 
//whichInfo:{
//layers:{text:true}
//}

//get just the image size
//whichInfo:{
//bounds:true
//}

//equivalent to no whichInfo (get all info)
//whichInfo:{
//
//allInfo:true
//layers:{allInfo:true}
//comps:{allInfo:true}
//}

var whichInfoDesc = new ActionDescriptor();
var layerInfoDesc = new ActionDescriptor();
var compInfoDesc = new ActionDescriptor();


//layer target qualifier
//Version 16.0 and earlier: specify the layer or layers for whichInfo in layers descriptor.
//As noted above, n 16.1 and later, you also can specify layerID/firstLayer/lastLayer in the top level descriptor
//In 16.0 and earlier, layerID must be 0 or a valid layerID
//Version 16.1: if any layerID/selectedLayers/firstLayer/lastLayer is here, it will override the top level descriptor

layerInfoDesc.putInteger( stringIDToTypeID( "layerID" ), 0 );  // 0 if multiple layers, valid id if single layer
//and
//layerInfoDesc.putBoolean( stringIDToTypeID( "selectedLayers" ), true ); 
//-or- a range:
//layerInfoDesc.putInteger( stringIDToTypeID( "firstLayer" ), 2 );
//layerInfoDesc.putInteger( stringIDToTypeID( "lastLayer" ), 5 );

//layer attributes
//Specify which info to get.  Add true for each param from JSON layer object you want
//-or- one or more individual attributes, e.g.

layerInfoDesc.putBoolean( stringIDToTypeID( "type" ), true ); 
layerInfoDesc.putBoolean( stringIDToTypeID( "name" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "protection" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "bounds" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "visible" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "clipped" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "fill" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "blendOptions" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "layerEffects" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "strokeStyle" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "mask" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "pixels" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "generatorSettings" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "path" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "text" ), true ); 
// layerInfoDesc.putBoolean( stringIDToTypeID( "smartObject" ), true ); 
layerInfoDesc.putBoolean( stringIDToTypeID( "artboard" ), true ); 

//or everything
//layerInfoDesc.putBoolean( stringIDToTypeID( "allInfo" ), true ); 

//comp attributes
//include layer settings in comp reporting
compInfoDesc.putBoolean( stringIDToTypeID( "layerSettings" ), true ); 

//image attributes
//16.1 only (16.0 and earlier will ignore these except for placed which forces the value of expandSmartObjects,
//and allInfo which forces all image attributes)

//whichInfoDesc.putBoolean( stringIDToTypeID( "resolution" ), true );
//whichInfoDesc.putBoolean( stringIDToTypeID( "globalLight" ), true );
whichInfoDesc.putBoolean( stringIDToTypeID( "file" ), true );
whichInfoDesc.putBoolean( stringIDToTypeID( "placed" ), true ); //16.1 ignores, uses expandSmartObjects
//whichInfoDesc.putBoolean( stringIDToTypeID( "selection" ), true );
//whichInfoDesc.putBoolean( stringIDToTypeID( "generatorSettings" ), true );
whichInfoDesc.putBoolean( stringIDToTypeID( "bounds" ), true );

//whichInfoDesc.putBoolean( stringIDToTypeID( "allInfo" ), true );  //everything

//16.0 and earlier requires both layers/comps to be present
//In 16.1 and later both are optional (missing implies no comp/layer info)

whichInfoDesc.putObject( stringIDToTypeID( "layers" ), stringIDToTypeID( "layers" ), layerInfoDesc );
whichInfoDesc.putObject( stringIDToTypeID( "comps" ), stringIDToTypeID( "comps" ), compInfoDesc );
desc.putObject( stringIDToTypeID( "whichInfo" ), stringIDToTypeID( "whichInfo" ), whichInfoDesc );

executeAction( idNS, desc, DialogModes.NO );

Returns JSON for requested image/layer attributes. See JSONFormat.txt for details Sample reply:

{
    "version": "1.3.0",
    "timeStamp": 1445661660.797,
    "count": 4,
    "id": 1484,
    "layers": [{
        "id": 12,
        "index": 8,
        "type": "textLayer",
        "name": "bla"
    }, {
        "id": 13,
        "index": 7,
        "type": "layer",
        "name": "Ellipse 6"
    }, {
        "id": 14,
        "index": 6,
        "type": "layer",
        "name": "Ellipse 5"
    }, {
        "id": 7,
        "index": 5,
        "type": "shapeLayer",
        "name": "Ellipse 4"
    }, {
        "id": 5,
        "index": 4,
        "type": "textLayer",
        "name": "blabla"
    }, {
        "id": 4,
        "index": 3,
        "type": "shapeLayer",
        "name": "Ellipse 3"
    }, {
        "id": 3,
        "index": 2,
        "type": "shapeLayer",
        "name": "Ellipse 2"
    }, {
        "id": 2,
        "index": 1,
        "type": "shapeLayer",
        "name": "Ellipse 1"
    }, {
        "id": 1,
        "index": 0,
        "type": "backgroundLayer",
        "name": "Background"
    }],
    "comps": [{
        "id": 306740676,
        "name": "Layer Comp 1",
        "hasWarning": true,
        "position": true,
        "visibility": true,
        "appearance": true,
        "layerSettings": [{
            "enabled": true,
            "layerID": 1
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": -211,
                    "vertical": -114
                }
            },
            "layerID": 2
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 63,
                    "vertical": -267
                }
            },
            "layerID": 3
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 49,
                    "vertical": 84
                }
            },
            "layerID": 4
        }, {
            "enabled": true,
            "layerSpecific": {
                "textLayerSettings": {
                    "warpStyle": "warpNone",
                    "warpValue": 0,
                    "warpPerspective": 0,
                    "warpPerspectiveOther": 0,
                    "warpRotate": "horizontal",
                    "textLayerSettingsWarpRect": [0, 0, 0, 0]
                }
            },
            "layerID": 5
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 37,
                    "vertical": -29
                }
            },
            "layerID": 7
        }, {
            "enabled": true,
            "layerSpecific": {
                "textLayerSettings": {
                    "warpStyle": "warpNone",
                    "warpValue": 0,
                    "warpPerspective": 0,
                    "warpPerspectiveOther": 0,
                    "warpRotate": "horizontal",
                    "textLayerSettingsWarpRect": [0, 0, 0, 0]
                }
            },
            "layerID": 12
        }]
    }, {
        "id": 312169337,
        "name": "Layer Comp 2",
        "hasWarning": true,
        "position": false,
        "visibility": true,
        "appearance": true,
        "layerSettings": [{
            "enabled": true,
            "layerID": 1
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": -211,
                    "vertical": -114
                }
            },
            "layerID": 2
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 63,
                    "vertical": -267
                }
            },
            "layerID": 3
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 49,
                    "vertical": 84
                }
            },
            "layerID": 4
        }, {
            "enabled": true,
            "layerSpecific": {
                "textLayerSettings": {
                    "warpStyle": "warpNone",
                    "warpValue": 0,
                    "warpPerspective": 0,
                    "warpPerspectiveOther": 0,
                    "warpRotate": "horizontal",
                    "textLayerSettingsWarpRect": [0, 0, 0, 0]
                }
            },
            "layerID": 5
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 37,
                    "vertical": -29
                }
            },
            "layerID": 7
        }, {
            "enabled": true,
            "layerSpecific": {
                "textLayerSettings": {
                    "warpStyle": "warpNone",
                    "warpValue": 0,
                    "warpPerspective": 0,
                    "warpPerspectiveOther": 0,
                    "warpRotate": "horizontal",
                    "textLayerSettingsWarpRect": [0, 0, 0, 0]
                }
            },
            "layerID": 12
        }]
    }, {
        "id": 316287052,
        "name": "Layer Comp 3",
        "comment": "comp commnet",
        "hasWarning": true,
        "position": false,
        "visibility": true,
        "appearance": true,
        "layerSettings": [{
            "enabled": true,
            "layerID": 1
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": -211,
                    "vertical": -114
                }
            },
            "layerID": 2
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 63,
                    "vertical": -267
                }
            },
            "layerID": 3
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 49,
                    "vertical": 84
                }
            },
            "layerID": 4
        }, {
            "enabled": true,
            "layerSpecific": {
                "textLayerSettings": {
                    "warpStyle": "warpNone",
                    "warpValue": 0,
                    "warpPerspective": 0,
                    "warpPerspectiveOther": 0,
                    "warpRotate": "horizontal",
                    "textLayerSettingsWarpRect": [0, 0, 0, 0]
                }
            },
            "layerID": 5
        }, {
            "enabled": true,
            "vectorMask": {
                "offset": {
                    "horizontal": 37,
                    "vertical": -29
                }
            },
            "layerID": 7
        }, {
            "enabled": true,
            "layerSpecific": {
                "textLayerSettings": {
                    "warpStyle": "warpNone",
                    "warpValue": 0,
                    "warpPerspective": 0,
                    "warpPerspectiveOther": 0,
                    "warpRotate": "horizontal",
                    "textLayerSettingsWarpRect": [0, 0, 0, 0]
                }
            },
            "layerID": 12
        }]
    }],
    "placed": [{
        "placedID": "a4b08876-ba20-1178-860a-9aaf4074c344",
        "name": "Ellipse 5.psb",
        "fileType": 943870018,
        "fileCreator": 943868237,
        "size": 1048576,
        "id": 1505,
        "layers": [{	
            "id": 14,
            "index": 0,
            "type": "shapeLayer",
            "name": "Ellipse 5"
        }]
    }, {
        "placedID": "a4b08877-ba20-1178-860a-9aaf4074c344",
        "name": "Ellipse 6.psb",
        "fileType": 943870018,
        "fileCreator": 943868237,
        "size": 1048576,
        "id": 1501,
        "layers": [{
            "id": 13,
            "index": 0,
            "type": "shapeLayer",
            "name": "Ellipse 6"
        }]
    }]
}


(note "count" is only present in Photoshop versions 14.2 and later, version will be 1.0.0 in Photoshop 14.1, and 1.1.0 in 14.2)

sendDocumentStreamToNetworkClient

Get the file info and file stream for a smart object

var idNS = stringIDToTypeID( "sendDocumentStreamToNetworkClient" );
var desc1 = new ActionDescriptor();
desc1.putInteger( stringIDToTypeID( "documentID" ), docID ); //optional document id, uses active doc if not specified

// "placedID" : Photoshop 16.1 and later, optional. reference smart object(s) within the document
//series of "ID" from layer:smartObject:{} or "placedID" from "image:placed:[{}]"

//var placedList = new ActionList();
//placedList.putString( "37b45136-b6b4-1178-944f-cc2a4c1f14fc", ); 
//placedList.putString( "354d49de-b6b4-1178-944f-cc2a4c1f14fc" ); //if nested. within the previous smart object
//placedList.putString( "354d49dd-b6b4-1178-944f-cc2a4c1f14fc" ); //etc, up to 5 ids
//desc1.putList( stringIDToTypeID( "placedID" ), placedList );

desc1.putBoolean( stringIDToTypeID( "selectedLayers" ), selectedLayers ); //return placed smart object stream the selected layers
desc1. putInteger( stringIDToTypeID( "layerID" ), layerID ); //return file for smart object with this layer id
desc1. putInteger( stringIDToTypeID( "ID" ), placedID ); //return file for smart object with this placed id ("ID" from layer:smartObject:{} or "placedID" from "image:placed:[{}]")


desc1.putLargeInteger( stringIDToTypeID( "position" ), pos ); //optional, offset into file (defaults to 0)
desc1. putLargeInteger( stringIDToTypeID( "size" ), six ); //optional, number of bytes to return (defaults to all bytes)

desc1.putBoolean( stringIDToTypeID( "path" ), true ); //optional, instead of returning the file stream back over the wire, write it to
							 //a file local to the server, and return the path as a string argument in the JSON
							//part of the FileStream Reply
executeAction( idNS, desc1, DialogModes.NO );

The maximum size returned by PS is 2 GB, if you have a smart object bigger than 2 GB, you need to use the position/size format. To return chunks, or the path format to write it to a temp file. Document stream/attributes are returned as a FileStream Reply (see below)

sendJSONToNetworkClient

Return JSON representation of an arbitrary action descriptor.

var idNS = stringIDToTypeID( "sendJSONToNetworkClient" );
executeAction( idNS, anyDescriptor, DialogModes.NO );

nodeMenuInitialize

Add generator menu items

var list1 = new ActionList();

var menu1 = new ActionDescriptor();
menu1.putString( stringIDToTypeID( "name" ), symbolicName1 ); //"name" used in nodeMenu, generatorMenuChanged. 
menu1.putString( stringIDToTypeID( "displayName" ), userVisibleName1 ); //human-readable name
menu1.putBoolean( stringIDToTypeID( "enabled" ), enabled ); //true: enable menu, false: disable menu
menu1.putBoolean( stringIDToTypeID( "checked" ), checked ); //true: check menu, false: uncheck menu
list1.putObject( stringIDToTypeID( "nodeMenu" ), menu1 );

//another menu (must all be in the same list/call, menus are cleared on each call to nodeMenuInitialize)s
var menu2 = new ActionDescriptor();
menu2.putString( stringIDToTypeID( "name" ), symbolicName2 );
menu2.putString( stringIDToTypeID( "displayName" ), userVisibleName2 );
menu2.putBoolean( stringIDToTypeID( "enabled" ), enabled );
menu2.putBoolean( stringIDToTypeID( "checked" ), checked );
list1.putObject( stringIDToTypeID( "nodeMenu" ), menu2 );

var nodeMenuInitializeID = stringIDToTypeID( "nodeMenuInitialize" );
var desc1 = new ActionDescriptor();
desc1.putList(nodeMenuInitializeID, list1);
executeAction( nodeMenuInitializeID, desc1, DialogModes.NO );

nodeMenu

Set menu states for generator items

var idNS = stringIDToTypeID( "nodeMenu" );
var desc1 = new ActionDescriptor();

desc1.putString( stringIDToTypeID( "name" ), menuName ); //menu name, same as "name" in nodeMenuInitialize
desc1.putBoolean( stringIDToTypeID( "enabled" ), enabled ); //true: enable menu, false: disable menu
desc1.putBoolean( stringIDToTypeID( "checked" ), checked ); //true: check menu, false: uncheck menu

executeAction( idNS, desc1, DialogModes.NO );

Persistent meta data

There is a special property, "generatorSettings" on the layer Extendscript object (accessible by a layer/property reference) that is used to store an arbitrary descriptor for generator (plugin) settings. There is a per-document "generatorSettings" descriptor, and a per layer "generatorSettings" descriptor that is saved/restored with the document. This descriptor is also reported by imageChanged and sendDocumentInfoToClient as "generatorSettings":{…}

If you specify a "property" key in the executable action descriptor (the one you give to executeAction, not the descriptor for the metadata settings) , it should just get/set generatorSettings->property. So you can specify the plugin name as property to scope the access to a particular plugin's settings. It's a good idea to use your plugin name as an object container for your settings so you don't stomp on other plugin's settings.

"generatorSettings" can be both read and written via a property reference.

The "json" property is a way to access the JSON format used by sendDocumentStreamToNetworkClient as an Extendscript object (so you can operate on the data without sending it to/from generator. "json" is read-only

Setting the generator settings on a layer

var classProperty = charIDToTypeID('Prpr');
var propNull = charIDToTypeID( 'null' );
var classNull = charIDToTypeID( 'null' );
var typeOrdinal = charIDToTypeID('Ordn');
var enumTarget = charIDToTypeID('Trgt');
var classDocument = charIDToTypeID('Dcmn');
var classLayer = charIDToTypeID('Lyr ');
var propProperty = stringIDToTypeID("property");
var propGeneratorSettings = stringIDToTypeID("generatorSettings");
var strMySettings = "mySettings"; //unique name for your settings/plugin
var propMyBoolProperty = stringIDToTypeID("myBoolProperty"); //unique name for the setting 
var propMyStringProperty = stringIDToTypeID("myStringProperty"); //unique name for the setting 

var keyTo = charIDToTypeID( 'T   ' );
var actionSet = charIDToTypeID( "setd" );

	//Make a property reference to generator settings for active layer.
	//(use classDocument for the active document)
	//NOTE: putProperty needs to come before putEnumerated

var theRef = new ActionReference();
theRef.putProperty(classProperty, propGeneratorSettings );
theRef.putEnumerated(classLayer, typeOrdinal, enumTarget);

	//Build descriptor for your plugin settings, with 2 example settings, a boolean and a string
	
var mySettingsDesc = new ActionDescriptor();
mySettingsDesc.putBoolean(propMyBoolProperty,true);
mySettingsDesc.putString(propMyStringProperty,"aStringProperty");

	//Execute the set action, setting the descriptor into the property reference,
	//setting just the plugin's settings (propProperty == strMySettings)

var setDescriptor = new ActionDescriptor();
setDescriptor.putReference(propNull,theRef);
setDescriptor.putObject(keyTo,classNull,mySettingsDesc);
setDescriptor.putString(propProperty, strMySettings);
executeAction( actionSet, setDescriptor, DialogModes.NO );

Getting the generator settings on a layer

var classProperty = charIDToTypeID('Prpr');
var propNull = charIDToTypeID( 'null' );
var classNull = charIDToTypeID( 'null' );
var typeOrdinal = charIDToTypeID('Ordn');
var enumTarget = charIDToTypeID('Trgt');
var classDocument = charIDToTypeID('Dcmn');
var classLayer = charIDToTypeID('Lyr ');
var propProperty = stringIDToTypeID("property");
var propGeneratorSettings = stringIDToTypeID("generatorSettings");
var propBla = stringIDToTypeID("bla");
var strMySettings = "mySettings"; //unique name for your settings/plugin
var propMyBoolProperty = stringIDToTypeID("myBoolProperty"); //unique name for the setting 
var propMyStringProperty = stringIDToTypeID("myStringProperty"); //unique name for the setting 

var actionGet = charIDToTypeID( "getd" );

	//Make a property reference to generator settings for active layer.
	//(use classDocument for the active document)
	//NOTE: putProperty needs to come before putEnumerated 

var theRef = new ActionReference();
theRef.putProperty(classProperty, propGeneratorSettings );
theRef.putEnumerated(classLayer, typeOrdinal, enumTarget);

	//Execute the get action, getting the descriptor for the property reference,
	//getting just the plugin's settings (propProperty == strMySettings)

var getDescriptor = new ActionDescriptor();
getDescriptor.putReference(propNull,theRef);
getDescriptor.putString(propProperty, strMySettings);
var actionResult = executeAction( actionGet, getDescriptor, DialogModes.NO );

	//Extract the settings

var mySettingsDesc = actionResult.getObjectValue(propGeneratorSettings);

"propMyBoolProperty: " + mySettingsDesc.getBoolean(propMyBoolProperty) +
		", propMyStringProperty: " + mySettingsDesc.getString(propMyStringProperty);

Message formats

Replies to the above APIs are returned on the same socket as the JavaScript request in the following format. This is the unencrypted version, numbers are in network byte order

  • Protocol version (uint32) This should be 1

  • Transaction id (uint32)

  • Type (uint32)

    Possible values of type are:

  • Illegal = 0

  • Error = 1

    Error string (only for response)

  • JavaScript = 2

    JavaScript to execute, a result from JavaScript execution, a JSON formatted event, or a KeepAlive request.

  • Image = 3

    • Type (byte) either pixmap (2) or jpeg (1)

      If pixmap

      • Width (uint32)
      • Height (uint32)
      • Row bytes (uint32)
      • Mode (byte) (only 1, rgb, supported at present)
      • Number of channels (byte)
      • Bits per channel (byte)
      • (followed by ARGB pixels)

      If JPEG

      • (JPEG stream)

    When an Image message is sent from a network client to Photoshop, Photoshop creates a document with the image Contents. Image message is used as a response format for the thumbnail apis above

  • Profile = 4

    Not yet supported.

  • DataBlob = 5

    Arbitrary bytes. When from a network client to Photoshop, Photoshop creates a temp file, and sends back the full path as a JavaScript message

  • KeepAlive = 6

    (no data)

    For sending by the client to test the connection. Photoshop should respond with a JavaScript (type 2) message containing "Yep, still alive"

  • FileStream = 7

    • JSON length (uint32)
    • JSON describing format
    {
    "mimeFormat" : (mime string)
    "position" : (position of file data returned)
    "size" : (number of file bytes returned)
    "fullSize" : (total number of bytes in file)
    "path" : (string, server-local path to file if path was set to true in the request)
    }
    
    • (followed by file data, if "path" is present, this is absent)
  • CancelCommand = 8 (Photoshop 14.2 and later)

    Cancels any pending JavaScript or Image request on this transaction/connection

  • EventStatus = 9 (Photoshop 14.2 and later)

    Sends information about the current command/event being handled in Photoshop, as JSON message (Javascript type 2) with following info eventID: numerical id for current event, 0 if none eventName: english string for event, "" if none eventTime: how long (seconds) the handler for the event has been executing, 0 if none

    Sample: no event executing (idle)

    {"eventID":0,"eventName":"","eventTime":0}
    

    Sample: handling a mouse down event:

    {"eventID":1,"eventName":"toolboxEventMouseDown","eventTime":0.166312}