Skip to main content
matias.kiviniemi
Legend
June 11, 2015
Question

Photoshop 2015 artboards in scripting

  • June 11, 2015
  • 5 replies
  • 9086 views

Anyone seen info / had a chance to test how artboards will workout in scripting? I guess data model could be pretty similar, i.e. an artboard is just new kind of group. The primary effect is in rendering / display, but probably most scripts will at least need an adjustment in logic (i.e. do you run through all art boards as one/separate or just the "active one".

Sneak Peek: Artboards in Photoshop CC - YouTube

This topic has been closed for replies.

5 replies

robertpaige
Participating Frequently
June 18, 2015

I have been trying to create a script all night that will turn my existing PSDs into Artboards for one document. Has anyone had any luck on this?

matias.kiviniemi
Legend
June 16, 2015

That happened quicker than I thought

One potentially big thing thing if you handle whole documents is that with Artboards the canvas size becomes virtual/fluid. I.e. it's still just one doc with one canvas and the size of the canvas being about the bounding box of all artboards. Each Artboard has it's bounds (just like it was a group in a big empty canvas) that also acts as mask. Creating/moving Artboards will automatically extend the canvas size. So if you have two 1024x768 Artboards horizontally with 200px in between, you will have about 3500x1000px canvas (there is some extra).

Chuck Uebele
Community Expert
Community Expert
June 16, 2015

Yes, that could be an issue. I think a whole new way of dealing with artboards is going to be required, plus a check to see if a document has artboards so you don't assume that the doc dimensions are static.

Participating Frequently
June 18, 2015

As a general tip, Install the Script Listener plugin (optional down-loadable plugin) to discover ExtendScript for any recordable action.

I'm including a sample script to do a bunch of things with Artboards. This shows how to create Artboards via a script in a few ways, and also how read existing artboard attributes.   This should help with the doc-wide "artboards" property (list of all artboard indeces, auto-expand enabled) as well as the layer-specific "artboards" property that holds the rectangle for the layer's artboard.

Caveat emptor, etc. I've only briefly tested this, so it's up to you to shake out any bugs in your own coding situations.

// =======================================================

// Copyright 2015.  Adobe Systems, Incorporated.  All rights reserved.

// Demonstrates basic scripting of artboards

// =======================================================

var classProperty = charIDToTypeID('Prpr');

var typeOrdinal = charIDToTypeID('Ordn');

var enumTarget = charIDToTypeID('Trgt');

var classDocument = charIDToTypeID('Dcmn');

var classLayer = charIDToTypeID('Lyr ');

var idnull = stringIDToTypeID( "null" );

// =======================================================

function DoAction(inActionName, inDescriptor) {

  return executeAction( stringIDToTypeID(inActionName), inDescriptor, DialogModes.NO );

  }

// =======================================================

function MakeDocTargetRef() {

  var ref12 = new ActionReference();

  ref12.putEnumerated( classDocument, typeOrdinal, enumTarget );

  return ref12;

  }

// =======================================================

function TargetLayers() {

  var ref12 = new ActionReference();

  ref12.putEnumerated( classLayer, typeOrdinal, enumTarget );

  return ref12;

  }

// =======================================================

function IndexedLayer(inIndex) {

  var ref12 = new ActionReference();

  ref12.putIndex( classLayer, inIndex );

  return ref12;

  }

// =======================================================

var idprevious= stringIDToTypeID( "previous" );

function PreviousLayer() {

  var ref12 = new ActionReference();

  ref12.putEnumerated( classLayer, idnull, idprevious );

  return ref12;

  }

// =======================================================

function Layer() {

  var ref12 = new ActionReference();

  ref12.putClass( classLayer );

  return ref12;

  }

// =======================================================

function IndexedLayers(inIndeces) {

  var ref12 = new ActionReference();

  for (var ll = 0; ll < inIndeces.length; ll++)

  {

  ref12.putIndex( classLayer, inIndeces[ll] );

  }

  return ref12;

  }

// =======================================================

function NamedLayer(inName) {

  var ref16 = new ActionReference();

  ref16.putName( classLayer,inName );

  return ref16;

  }

// =======================================================

function TargetLayerRef(inProp) {

  var theRef = new ActionReference();

  theRef.putProperty(classProperty, inProp);

  theRef.putEnumerated(classLayer, typeOrdinal, enumTarget);

  return theRef;

  }

// =======================================================

function IndexedLayerRef(inIndex,inProp) {

  var theRef = new ActionReference();

  theRef.putProperty(classProperty, inProp);

  theRef.putIndex(classLayer, inIndex+1); //putIndex uses 1-based index

  return theRef;

  }

// =======================================================

var idartboards = stringIDToTypeID( "artboards" );

var idorigin = stringIDToTypeID( "origin" );

var idlist = stringIDToTypeID( "list" );

var idtop = stringIDToTypeID( "top" );

var idbottom = stringIDToTypeID( "bottom" );

var idcanvasColor = stringIDToTypeID( "canvasColor" );

var idcanvasColorMode = stringIDToTypeID( "canvasColorMode" );

var idautoNestEnabled = stringIDToTypeID( "autoNestEnabled" );

var idautoExpandEnabled = stringIDToTypeID( "autoExpandEnabled" );

var idred = charIDToTypeID( 'Rd  ' );

var idgreen = charIDToTypeID( 'Grn ' );

var idblue = charIDToTypeID( 'Bl  ' );

var propArtboards = stringIDToTypeID("artboards");

var actionGet = charIDToTypeID( "getd" );

function TargetArtboardInfo() {

  var theRef = new ActionReference();

  theRef.putProperty(classProperty, propArtboards);

  theRef.putEnumerated(classDocument, typeOrdinal, enumTarget);

  var getDescriptor = new ActionDescriptor();

  getDescriptor.putReference(idnull,theRef);

  var abDesc = executeAction( actionGet, getDescriptor, DialogModes.NO ).getObjectValue(idartboards);

  var abOrigin = abDesc.getObjectValue(idorigin);

  var abCanvasColor = abDesc.getObjectValue(idcanvasColor);

  var abList = [];

  var abDescList = abDesc.getList( stringIDToTypeID( 'list' ));

  var abCount = abDescList.count;

  for(var cc=0;cc<abCount;++cc) {

  var abObj = abDescList.getObjectValue( cc );

  var abTopIndex = abObj.getInteger(idtop);

  var abBottomIndex = abObj.getInteger(idbottom);

  abList.push( {top:abTopIndex, bottom:abBottomIndex, rect:IndexedArtboardRect(abTopIndex), name:IndexedArtboardName(abTopIndex)});

  }

  return {origin:{x:abOrigin.getInteger(idhorizontal), y:abOrigin.getInteger(idvertical)},

  list:abList,

  autoExpandEnabled:abDesc.getBoolean(idautoExpandEnabled),

  autoNestEnabled:abDesc.getBoolean(idautoNestEnabled),

  canvasColorMode:typeIDToStringID(abDesc.getEnumerationValue(idcanvasColorMode)),

  canvasCustomColor:{red:abCanvasColor.getInteger(idred), green:abCanvasColor.getInteger(idgreen), blue:abCanvasColor.getInteger(idblue)}

  };

  }

// =======================================================

var idartboard = stringIDToTypeID( "artboard" );

var idartboardRect = stringIDToTypeID( "artboardRect" );

function RefArtboardRect(theRef) {

  var getDescriptor = new ActionDescriptor();

  getDescriptor.putReference(idnull,theRef);

  var artboardRect = executeAction( actionGet, getDescriptor, DialogModes.NO )

  .getObjectValue(idartboard).getObjectValue(idartboardRect);

  return {top: artboardRect.getInteger(idtop),

  left: artboardRect.getInteger(idleft),

  bottom: artboardRect.getInteger(idbottom),

  right: artboardRect.getInteger(idright)};

  }

// =======================================================

var propArtboardEnabled = stringIDToTypeID( "artboardEnabled" );

function TargetIsArtboard() {

  var getDescriptor = new ActionDescriptor();

  getDescriptor.putReference(idnull,TargetLayerRef(propArtboardEnabled));

  return executeAction( actionGet, getDescriptor, DialogModes.NO ).getBoolean(propArtboardEnabled);

}

// =======================================================

var propArtboard = stringIDToTypeID("artboard");

function TargetArtboardRect() {

  return RefArtboardRect(TargetLayerRef(propArtboard));

  }

// =======================================================

function IndexedArtboardRect(inIndex) {

  return RefArtboardRect(IndexedLayerRef(inIndex,propArtboard));

  }

// =======================================================

var propName = stringIDToTypeID( "name" );

function IndexedArtboardName(inIndex) {

  var getDescriptor = new ActionDescriptor();

  getDescriptor.putReference(idnull,IndexedLayerRef(inIndex,propName));

  return executeAction( actionGet, getDescriptor, DialogModes.NO ).getString(propName);

  }

// =======================================================

var propRulerOriginH = stringIDToTypeID( "rulerOriginH" );

var propRulerOriginV = stringIDToTypeID( "rulerOriginV" );

function TargetRulerOrigin() {

  var theRef = new ActionReference();

  theRef.putProperty(classProperty, propRulerOriginH);

  theRef.putProperty(classProperty, propRulerOriginV);

  theRef.putEnumerated(classDocument, typeOrdinal, enumTarget);

  var getDescriptor = new ActionDescriptor();

  getDescriptor.putReference(idnull,theRef);

  var rulerOrigin = executeAction( actionGet, getDescriptor, DialogModes.NO );

  return {x:rulerOrigin.getInteger(propRulerOriginH) / 65536,

  y:rulerOrigin.getInteger(propRulerOriginH) / 65536};

  }

// =======================================================

var idhorizontal = stringIDToTypeID( "horizontal" );

var idvertical = stringIDToTypeID( "vertical" );

var iddistanceUnit = stringIDToTypeID( "distanceUnit" );

function MakePoint(inX, inY) {

    var point = new ActionDescriptor();

    point.putUnitDouble( idhorizontal, idpixelsUnit, inX );

    point.putUnitDouble( idvertical, idpixelsUnit, inY );

    return point;

  }

// =======================================================

var idred = stringIDToTypeID( "red" );

var idgreen = stringIDToTypeID( "green" );

var idblue = stringIDToTypeID( "blue" );

function MakeRGBColor(inR, inG, inB) {

  var color = new ActionDescriptor();

  color.putDouble( idred, inR );

  color.putDouble( idgreen, inG );

  color.putDouble( idblue, inB );

  return color;

  }

// =======================================================

var idfill = stringIDToTypeID( "fill" );

var idtransparency = stringIDToTypeID( "transparency" );

var idname = stringIDToTypeID( "name" );

var idwidth = stringIDToTypeID( "width" );

var idheight = stringIDToTypeID( "height" );

var idRGBColorMode = stringIDToTypeID( "RGBColorMode" );

var idmode = stringIDToTypeID( "mode" );

var idresolution = stringIDToTypeID( "resolution" );

var iddepth = stringIDToTypeID( "depth" );

var idnew = stringIDToTypeID( "new" );

var iddocument = stringIDToTypeID( "document" );

function MakeDocument(inName, inWidth, inHeight) {

  var desc3 = new ActionDescriptor();

  var desc4 = new ActionDescriptor();

  desc4.putString( idname, inName );

  desc4.putEnumerated( idfill, idnull, idtransparency );

    desc4.putUnitDouble( idwidth, idpixelsUnit, inWidth );

    desc4.putUnitDouble( idheight, idpixelsUnit, inHeight );

    desc4.putUnitDouble( idresolution, idpixelsUnit, 72.0 );

    desc4.putInteger( iddepth, 8 );

    desc4.putClass( idmode, idRGBColorMode );

  desc3.putObject( idnew, iddocument, desc4 );

  DoAction( "make", desc3 );

  }

// =======================================================

var idcontentLayer = stringIDToTypeID( "contentLayer" );

var idRGBColor = stringIDToTypeID( "RGBColor" );

var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );

var idshape = stringIDToTypeID( "shape" );

var idtop = stringIDToTypeID( "top" );

var idleft = stringIDToTypeID( "left" );

var idright = stringIDToTypeID( "right" );

var idbottom = stringIDToTypeID( "bottom" );

var idrectangle = stringIDToTypeID( "rectangle" );

var idunitValueQuadVersion = stringIDToTypeID( "unitValueQuadVersion" );

var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );

var idcolor = stringIDToTypeID( "color" );

var idtype = stringIDToTypeID( "type" );

var idusing = stringIDToTypeID( "using" );

function MakeRectangleShape(inTop,inLeft,inBottom,inRight) {

    var rect = new ActionDescriptor();

    rect.putInteger(idunitValueQuadVersion, 1)

    rect.putUnitDouble( idtop, idpixelsUnit, inTop );

    rect.putUnitDouble( idleft, idpixelsUnit, inLeft );

    rect.putUnitDouble( idbottom, idpixelsUnit, inBottom );

    rect.putUnitDouble( idright, idpixelsUnit, inRight );

    return rect;

  }

// =======================================================

function MakeRectangleLayerAt(inTop, inLeft, inBottom, inRight, inRGBColor) {

  var desc6 = new ActionDescriptor();

  var ref2 = new ActionReference();

  ref2.putClass( idcontentLayer );

  desc6.putReference( idnull, ref2 );

  var desc7 = new ActionDescriptor();

     var desc8 = new ActionDescriptor();

     desc8.putObject( idcolor, idRGBColor, inRGBColor  );

  desc7.putObject( idtype, idsolidColorLayer, desc8 );

  desc7.putObject( idshape, idrectangle, MakeRectangleShape(inTop,inLeft,inBottom,inRight) );

  desc6.putObject( idusing, idcontentLayer, desc7 );

  DoAction( "make", desc6 );

  }

// =======================================================

var idto = stringIDToTypeID( "to" );

var idoffset = stringIDToTypeID( "offset" );

function DuplicateLayerTo(inLayerRef, inOffset) {

  var desc63 = new ActionDescriptor();

  desc63.putReference( idnull, inLayerRef );

  desc63.putObject( idto, idoffset, inOffset );

  DoAction( "copyEvent", desc63 );

  }

// =======================================================

var idselectionModifier = stringIDToTypeID( "selectionModifier" );

var idselectionModifierType = stringIDToTypeID( "selectionModifierType" );

var idaddToSelectionContinuous = stringIDToTypeID( "addToSelectionContinuous" );

function AddToSelection(inLayerRef) {

  var desc74 = new ActionDescriptor();

  desc74.putReference( idnull, inLayerRef );

  desc74.putEnumerated( idselectionModifier, idselectionModifierType, idaddToSelectionContinuous );

  DoAction( "select", desc74 );

  }

// =======================================================

var classArtboardSection = stringIDToTypeID( "artboardSection" );

var idfrom = stringIDToTypeID( "from" );

function MakeArtboardFromSelection(inLayerRef) {

  var desc = new ActionDescriptor();

  var ref = new ActionReference();

  ref.putClass( classArtboardSection );

  desc.putReference( idnull, ref );

  desc.putReference( idfrom, inLayerRef );

  //desc.putString( idname, inName );

  DoAction( "make", desc  );

  }

// =======================================================

var classLayerSection = stringIDToTypeID( "layerSection" );

function MakeLayerGroup() {

    var desc = new ActionDescriptor();

    var ref = new ActionReference();

    ref.putClass( classLayerSection );

    desc.putReference( idnull, ref );

  DoAction( "make", desc  );

  }

// =======================================================

function RectToDesc(inRect) {

  var rect = new ActionDescriptor();

  rect.putDouble( idtop, inRect.top );

  rect.putDouble( idleft, inRect.left );

  rect.putDouble( idright, inRect.right );

  rect.putDouble( idbottom, inRect.bottom );

  return rect;

}

// =======================================================

var classFloatRect = stringIDToTypeID( "classFloatRect" );

function MakeArtboardFromLayerGroup(inLayerRef, inRect) {

  var desc = new ActionDescriptor();

  desc.putReference( idnull, inLayerRef );

  var abDesc = new ActionDescriptor();

  abDesc.putObject( idartboardRect, classFloatRect, RectToDesc(inRect) );

  desc.putObject( idartboard, idartboard, abDesc );

  DoAction( "artboardFromLayerGroupEvent", desc  );

  }

// =======================================================

function MakeArtboard(inLayerRef, inRect) {

  var ref = new ActionReference();

  ref.putClass( classArtboardSection );

    var desc = new ActionDescriptor();

    desc.putReference( idnull, ref );

    desc.putObject( idartboardRect, classFloatRect, RectToDesc(inRect) );

  DoAction( "make", desc  );

}

// =======================================================

function EditArtboard(inLayerRef, inRect) {

  var desc = new ActionDescriptor();

  desc.putReference( idnull, inLayerRef );

  var abDesc = new ActionDescriptor();

  abDesc.putObject( idartboardRect, classFloatRect, RectToDesc(inRect) );

  desc.putObject( idartboard, idartboard, abDesc );

  DoAction( "editArtboardEvent", desc  );

}

// =======================================================

function RectToString(inRect) {

  return "" + inRect.top + ","  + inRect.left + ","  + inRect.bottom + "," + inRect.right;

  }

// =======================================================

function PointToString(inPt) {

  return "" + inPt.x + ","  + inPt.y;

  }

// =======================================================

function RGBToString(inRGB) {

  return "" + inRGB.red + ","  + inRGB.green + ","  + inRGB.blue;

  }

// =======================================================

function ABListToString(inList) {

  var str = "";

  for (var aa = 0; aa < inList.length; ++aa) {

  str += "   top:" + inList[aa].top +

  ", bottom:" + inList[aa].bottom +

  ", rect:" + RectToString(inList[aa].rect) +

  ", name:" + inList[aa].name + "\n";

  }

  return str;

  }

// =======================================================

// Display artboard rectangle of selected artboard.

function DisplayTargetArtboard() {

  if (TargetIsArtboard()) {

  var artboardRect = TargetArtboardRect();

  alert("Artboard: " + RectToString(artboardRect) );

  }

}

// =======================================================

// Display info about all artboard/artboard properties of active document.

function DisplayTargetArtboards() {

  var abInfo = TargetArtboardInfo();

  var rulerOrigin = TargetRulerOrigin();

  alert("Artboards\n" +

   "Artboards:\n" + ABListToString(abInfo.list)  + "\n" +

   "Artboard Origin: " + PointToString(abInfo.origin) + "\n" +

   "Auto Expand Enabled: " + abInfo.autoExpandEnabled + "\n" +

   "Auto Nest Enabled: " + abInfo.autoNestEnabled + "\n" +

   "Canvas Mode: " + abInfo.canvasColorMode + "\n" +

   (abInfo.canvasColorMode == 'custom' ? ("Canvas Custom Color: " + RGBToString(abInfo.canvasCustomColor) + "\n") : "") +

   "Ruler Origin: " + PointToString(rulerOrigin)

  );

}

// =======================================================

var abSpaceX = 1000;

var abSpaceY = 1000;

var abRows = 1;

var abCols = 3;

var rectX = 500;

var rectY = 500;

var rectWidth = 500;

var rectHeight = 500;

var abWidth = 512;

var abHeight = 512;

var placedX = 750; //center pos

var placedY = 750; //center pos

var dupOffsetX = 50;

var dupOffsetY = 50;

var abOriginX = 0;

var abOriginY = 0;

var createArtboardDoc = true;

if (createArtboardDoc) {

  // new document.

  MakeDocument("Artboard Sample", 2048, 2048);

  // create some artboards

  for (var rr = 0; rr < abRows; rr++) {

  for (var cc = 0; cc < abCols; cc++) {

  var posX = cc*abSpaceX;

  var posY = rr*abSpaceY;

  var rectPosX =  rectX + posX;

  var rectPosY = rectY + posY;

  var centerX =   (activeDocument.width/2);

  var centerY = (activeDocument.height/2);

  var placedPosX =   (placedX + posX) - activeDocument.width/2;

  var placedPosY = (placedY + posY) - activeDocument.height/2;

  var rectColor = MakeRGBColor((rr*cc*255)/(abRows*abCols),(rr*255)/abRows,(cc*255)/abCols);

  //create two rectangle shape layers, and put them into a new artboard.

  MakeRectangleLayerAt(rectPosY, rectPosX, rectPosY + rectHeight, rectPosX + rectWidth, rectColor);

  DuplicateLayerTo(TargetLayers(), MakePoint(dupOffsetX, dupOffsetY));

  AddToSelection( PreviousLayer() );

  MakeArtboardFromSelection(TargetLayers());

  DisplayTargetArtboard();

  }

  }

  //create a normal layer group, then convert it into an artboard with specified rectangle

  MakeLayerGroup();

  MakeArtboardFromLayerGroup(TargetLayers(), {top:2048,left:2048,bottom:2148,right:2148});

  DisplayTargetArtboard();

  //create new artboard with specified rectangle

  MakeArtboard(TargetLayers(), {top:2048,left:2248,bottom:2148,right:2348});

  DisplayTargetArtboard();

  //change artboard rect of selection

  EditArtboard(TargetLayers(), {top:2048,left:2348,bottom:2148,right:2448});

  DisplayTargetArtboard();

}

//show doc-wide artboard info

DisplayTargetArtboards();


Thanks Tim. That's very helpful!

matias.kiviniemi
Legend
June 12, 2015

@Chuck: Trying to figure out if I should be excited of the possibilities or worried about how it'll break every script I have

Artboards seems pretty much an app designer thing, probably not so useful in web scale as it's hard to have multiple boards visible at reasonable zoom..

Chuck Uebele
Community Expert
Community Expert
June 12, 2015

Matias, I would imagine they script like groups, as they seem to be just another type of container for layers, but that's just a guess. So I would imagine they will not break old scripts, other than I'm not sure how scripts that go through all the layers now will work. I guess it could be a problem if either you can't tell the difference between a group and an art board, or the old scripts need to be updated, because it doesn't know what to do with them. Looks like we will find out soon. Yes, they do seem to be just for designers, but maybe others can find uses for them. With the explosion of mobile devices, designers do need a way to be able to layout multiple designs easily. Having to work with multiple documents and attempting to tile all the windows could be a real pain.

JJMack
Community Expert
Community Expert
June 12, 2015

I think on the 16th Adobe is going to officially announce CC 2015.

The Artboards demo was not very impressive to me.  I would not need such a feature. I do not develop web pages or touch type apps.  The Artboard demo just look like a new type of Layer group that are call Artboards instead of Layer Group.  These seem to be spread out over a canvas that seem to automatically expand as you create new Artboards.  Artboards can be resized using preset sizes.

JJMack
Chuck Uebele
Community Expert
Community Expert
June 12, 2015

Very broad questions for a feature that isn't even released yet.