📜 ⬆️ ⬇️

GUI Automation (Photoshop + Starling)

The task was to automate the GUI build for one project X.

1 Current implementation


The artist does all his business in photoshop and gives them to programmers. The programmers, in turn, somehow pull the textures or atlases themselves and use the wipes to position each individual element on the stage flash drives, then add all text fields and effects to the pens, prescribe coordinates to all these elements, which are obtained thanks to the utility. The result is a very long and painful work, and when you consider that the programmer does it, it is AD.

1.1 Current Issues


The programmer has to:

I'm not talking about the case when something changes.

2 Solution



')

2.1 Restrictions




2.2 What we need




3 psd preparation


* it is taken into account that each separate layer is 1 element on the scene.
This is what the psd itself looks like:
image

3.1 Writing the jsx script


Open the Adobe ExtendScript Toolkit and change the target:

image

If you do not have such a tab, then I advise you to update photoshop. I struggled with this until I found a build with the Adobe Application Manager included.

3.1.1 Script


The basis of the basics:

#target photoshop //        app.bringToFront(); //       


Next we need to connect lib to work with JSON, since standard js does not want to work.
Liba itself rather big, so put it separately. All that is inside you just need to copy the script into the document, since we will do one document to easily transfer it.
jam_lib
Constants necessary to identify the type with which we work
 var TYPE_SPRITE = "sprite"; var TYPE_TEXT = "text"; var TYPE_COLLECTION = "collection"; 


Main variables in the script

 var arts = app.activeDocument.artLayers//     var sets = app.activeDocument.layerSets;//   var respont = new Object();//.       var arr = new Array();//.     var u = 0;//  .  var width_document = app.activeDocument.width.value; var heigth_document = app.activeDocument.height.value; 


Then we say Start, and we ask you to choose a place to save the result in JSON format (textures will also be added there).

 alert("!"); var defaultInFolder = new Folder ("C:\\"); var jsonFilter ="JSON Text Files:*.json,All Files:*.*"; var inFile = defaultInFolder.saveDlg ("Open JSON text file:", jsonFilter); 


Check on the validity of the selected path and run the script.

 if(inFile) main(); 


The main function is our execution entry point.

 function main() { for(var j=0; j<arts.length; j++) {//    respont[u] = setLayers(arts[j]); //  .    u+=1; } for(var i = 0;i<sets.length;i++)//    { respont[u] = setSets(sets[i]); //  .    u+=1; } for(var i = 0;i<arr.length;i++)//      { visible(false);//  visibleElement(arr[i],true);//     saveLayer (arr[i]);//  } visible(true);//    jamUtils.writeJsonFile (inFile, respont, 4);//    . alert ("!"); } 


Sheet group pars function

 function setSets(set) { var res = new Object(); res["type"] = TYPE_COLLECTION; res["name"] = set.name; for(var j=0; j<set.artLayers.length ; j++) { res[j] = setLayers(set.artLayers[j]); //      } return res; } 


Parsing the sheet itself.

 function setLayers(el) { var res= new Object(); var x; var y; x = el.bounds[0].value; y = el.bounds[1].value; res["x"] = x; res["y"] = y; res["alpha"] = Math.round(el.opacity)/100;//   0-1 res["name"] = el.name.replace(/\s+/g, '');//     try{//      var textItem = el.textItem res["type"] = TYPE_TEXT;//     , ,   res["color"] = textItem.color.rgb.hexValue; res["font"] = textItem.font; res["size"] = Math.round(textItem.size.value); res["contents"] = textItem.contents; res["width"] = Math.round(textItem.width.value); res["height"] = Math.round(textItem.height.value); }catch(e) { res["type"] = TYPE_SPRITE; } arr.push(el); return res; } 


The parsing of the texture preservation itself looks like this:

 function saveLayer(layer) { try{ var textItem = layer.textItem // ,       return; }catch(e){ } activeDocument.activeLayer = layer; var o = layer.opacity; //     var xx = (layer.bounds[0].value); var yy = (layer.bounds[1].value); var ww = (layer.bounds[2].value); var hh = (layer.bounds[3].value); var shape = [ [xx, yy], [ww,yy], [ww,hh], [xx,hh] ]; app.activeDocument.selection.select(shape);//   app.activeDocument.selection.translate(new UnitValue(-xx,"px"),new UnitValue(-yy,"px"));//   0 0 app.activeDocument.selection.deselect();//   app.activeDocument.resizeCanvas(new UnitValue(ww-xx, "px"), new UnitValue(hh-yy, "px"), AnchorPosition.TOPLEFT);//      activeDocument.activeLayer.opacity = 100;//  100 var saveFile= File(inFile.path+"/"+layer.name.replace(/\s+/g, '')+".png"); SavePNG(saveFile);//  activeDocument.activeLayer.opacity = o;//   app.activeDocument.resizeCanvas(new UnitValue(width_document, "px"), new UnitValue(heigth_document, "px"), AnchorPosition.TOPLEFT);//   app.activeDocument. activeLayer.translate(new UnitValue(xx,"px"),new UnitValue(yy,"px"));//   } function SavePNG(saveFile){ var pngOpts = new ExportOptionsSaveForWeb; pngOpts.format = SaveDocumentType.PNG pngOpts.PNG8 = false; pngOpts.transparency = true; pngOpts.interlaced = false; pngOpts.quality = 100; activeDocument.exportDocument(new File(saveFile),ExportType.SAVEFORWEB,pngOpts); } 


And 2 pounds. to display layers.

 function visibleElement(sprite,flag) { sprite.visible = flag; } function visible(flag) { for(var i = 0;i<arr.length;i++) { arr[i].visible = flag; } } 


3.2 Result


After pressing F5 in the editor, specify the path and wait for the words "Done", you can also see how the script does something on the screen (everything changes all the time).

The result can be seen in the directory that was specified at the start:

image

JSON file itself:

 { "0": { "x": 205, "y": 53, "alpha": 1, "name": "magic", "type": "text", "color": "0006FC", "font": "Verdana", "size": 30, "contents": "    ", "width": 417, "height": 180 }, "1": { "x": 458, "y": 281, "alpha": 1, "name": "el5", "type": "sprite" }, ... "6": { "type": "collection", "name": "btn", "0": { "x": 300, "y": 537, "alpha": 1, "name": "btn_art", "type": "sprite" } } } 


Next, we collect the usual texture atlas, I do it using TexturePackerGUI (do not forget to specify the format Sparrow / Starling)
And we throw in the engine assembled in a hurry. The result itself is visible after N seconds of compilation:

image

The article turned out to be rather big, so I decided to bring the full script code to the source (starling mini engine, asses, photoshop script). Available at the link: https://www.dropbox.com/s/8jurdz2ze4qzz18/pr.zip

Source: https://habr.com/ru/post/229103/


All Articles