📜 ⬆️ ⬇️

Transfer files from designer to programmer. Scripts

image
Suppose we have a mobile application development team. In such a team, there is a designer and a programmer. At first, they are engaged in each of their work - the programmer develops a prototype, mechanics, the designer makes sketches of keys, backgrounds. But there comes a time when the designer must submit his work in order to see it already in the application. And here there can be difficulties.

Consider this on the example of a single menu screen. It can have 30-40 graphic elements. These are keys (static, pressed), an animated logo of 10 objects, a pop-up menu, background animation. Mostly the designer issues each file separately, and then the programmer adds it to the new one. Thus, a constructor comes out that folds and unfolds several times. Then the design can change and everything has to be done in a new way.

How to automate this process as much as possible

Here are a few steps that I use to get the most convenient set of files from the designer to the programmer without any loss of quality.

AI source file in maximum resolution (2048 * 1536px in my case) with a draft design.
- decompose and group all objects in layers
- call them correctly (buttons - Btn, icons - Icon, underlays - Underlay ...)
- make all elements a multiple of 2px in width and height
- arrange all elements in XY multiples of 2px
- export the XY-coordinates of each layer, its name and position on the sheet. Since Illustrator is not able to export a text file - the data will be placed in the topmost layer in the object * Text *
XY layer coordinates script
if (app.documents.length > 0) { var doc = app.activeDocument; var x, y, t; app.coordinateSystem = CoordinateSystem.ARTBOARDCOORDINATESYSTEM; var count = doc.layers.length; var out_txt=""; for ( var i = 0; i < count; ++i) { doc.activeLayer = doc.layers[i]; doc.layers[i].hasSelectedArtwork = true; } for ( var i = 0; i < count; ++i) { x = doc.selection[i].position[0]; y = doc.selection[i].position[1]*(-1); // Layer name, X, Y, layer number out_txt += doc.layers[i].name + ";;;;x=" + x.toFixed(0) + ";;;;y=" + y.toFixed(0) + ";;;;" + i +"\n"; } //Create text frame in first layer on position 0,0 t = doc.layers[0].textFrames.add(); t.contents = out_txt; } 


- export each layer to a separate PNG24 file in double size. Arcticmill
Export Layers as PNG files
 // *** Export Layers as PNG files (in multiple resolutions) *** // This script will export all layers that have a name starting with "#", or "%" into a subfolder of the current .ai document. // These options can be configured below: // *** Config options *** var subFolderName = "Export"; var saveInMultipleResolutions = true; // ... // Note: only use one character! var exportLayersStartingWith = "#"; var exportLayersWithArtboardClippingStartingWith = "%"; // ... var lowResolutionFileAppend = "@Low"; var normalResolutionFileAppend = "-ipad"; var highResolutionFileAppend = "-ipadhd"; // ... var lowResolutionScale = 50; var normalResolutionScale = 100; var highResolutionScale = 200; // *** Start of script *** var doc = app.activeDocument; // Make sure we have saved the document if (doc.path != "") { // Check if we need to create the export directory or we will get errors up ahead var exportDirectoryPath = doc.path + "/" + subFolderName; var exportDirectory = new Folder(exportDirectoryPath); if (!exportDirectory.exists) { // We must create the export directory it seems var newFolder = new Folder(exportDirectoryPath); newFolder.create(); } var layerData = new Array(); // Finds all layers that should be saved and saves these to the export layers array collectLayerData(doc, null); var layersToExportCount = 0; for (var i = 0; i < layerData.length; i++) { if ((layerData[i].tag == "include") || (layerData[i].tag == "include_and_clip")) { // Hide all layers first hideAllLayers(); var clipToArtboard = false; if (layerData[i].tag == "include_and_clip") { clipToArtboard = true; } // Now show all layers needed to actually display the current layer on screen layerData[i].showIncludingParentAndChildLayers(); //showIncludingParents(); // Now we can export the layer as one or multiple PNG files! var savePath = doc.path; // Save to same folder as document but in a sub directory if (saveInMultipleResolutions) { // iPhone 3GS (50%) savePath.changePath(subFolderName + "/" + layerData[i].layer.name.substring(1, layerData[i].layer.name.length) + fixFileAppend(lowResolutionFileAppend)); savePNG(savePath, lowResolutionScale, clipToArtboard); savePath = doc.path; // iPhone 4 (100%) savePath.changePath(subFolderName + "/" + layerData[i].layer.name.substring(1, layerData[i].layer.name.length) + fixFileAppend(normalResolutionFileAppend)); savePNG(savePath, normalResolutionScale, clipToArtboard); savePath = doc.path; // iPad Retina (200%) savePath.changePath(subFolderName + "/" + layerData[i].layer.name.substring(1, layerData[i].layer.name.length) + fixFileAppend(highResolutionFileAppend)); savePNG(savePath, highResolutionScale, clipToArtboard); } else { // Save normally (100%) savePath.changePath(subFolderName + "/" + layerData[i].layer.name.substring(1, layerData[i].layer.name.length)); savePNG(savePath, normalResolutionScale, clipToArtboard); } layersToExportCount++; } } // Restore everything like it was before! restoreAllLayers(); // Was there anything exported? If not make a warning! if (layersToExportCount == 0) { alert("Ooops, Found no layers to export!\n\nRemember that you must add a \"" + exportLayersStartingWith + "\" (when exporting the layer cropped to it's bound) or \"" + exportLayersWithArtboardClippingStartingWith + "\" (when layer should be clipped to artboard) to the beginning of the layer name. Also make sure that they layers you want to export are not locked or hidden."); } else { // Show a completed message alert(layersToExportCount + " layer(s) was successfully exported to: \n" + exportDirectoryPath); } } else { // Document not saved yet! alert("Sorry, but you must save your document before you can use the export layers script! This is because exported images are saved in a subfolder to your original file."); } function fixFileAppend(fileAppend) { if (fileAppend == "") { return ""; } else { return fileAppend + ".png"; } } function hideAllLayers() { for (var i = 0; i < layerData.length; i++) { layerData[i].hide(); } } function restoreAllLayers() { for (var i = 0; i < layerData.length; i++) { layerData[i].restoreVisibility(); } } // Collects information about the various layers function collectLayerData(rootLayer, extendedRootLayer) { for (var i = 0; i < rootLayer.layers.length; i++) { // We never even process locked or hidden layers if ((!rootLayer.layers[i].locked) && (rootLayer.layers[i].visible)) { var extendedLayer = new ExtendedLayer(rootLayer.layers[i]); // Set up parent extendedLayer.parentLayer = extendedRootLayer; // Also add this layer to the parents child collection if (extendedRootLayer != null) { extendedRootLayer.childLayers.push(extendedLayer); } layerData.push(extendedLayer); // Tag these layers so that we later can find out if we should export these layers or not if (rootLayer.layers[i].name.substring(0, 1) == exportLayersStartingWith) { extendedLayer.tag = "include"; } else if (rootLayer.layers[i].name.substring(0, 1) == exportLayersWithArtboardClippingStartingWith) { extendedLayer.tag = "include_and_clip"; } else { extendedLayer.tag = "skip"; } // We should not export this layer but we continue looking for sub layers that might need to be exported collectLayerData(rootLayer.layers[i], extendedLayer); } } } // Holds info and additional methods for layers function ExtendedLayer(layer) { this.originalVisibility = layer.visible; this.layer = layer; this.tag = ""; this.hide = hide; this.show = show; this.showIncludingParentAndChildLayers = showIncludingParentAndChildLayers; this.restoreVisibility = restoreVisibility; this.restoreVisibilityIncludingChildLayers = restoreVisibilityIncludingChildLayers; this.layerName = layer.name; // Set after creating this.childLayers = new Array(); this.parentLayer = null; function hide() { layer.visible = false; } function show() { layer.visible = true; } // Shows this layer including it's parent layers (up to the root) and it's child layers function showIncludingParentAndChildLayers() { var parentlayerName = ""; if (this.parentLayer != null) { parentlayerName = this.parentLayer.layerName; } // Show all parents first var aParentLayer = this.parentLayer; while (aParentLayer != null) { aParentLayer.restoreVisibility(); // Keep looking aParentLayer = aParentLayer.parentLayer; } // Show our own layer finally this.restoreVisibilityIncludingChildLayers(); } function restoreVisibility() { layer.visible = this.originalVisibility; } function restoreVisibilityIncludingChildLayers() { this.restoreVisibility(); // Call recursively for each child layer for (var i = 0; i < this.childLayers.length; i++) { this.childLayers[i].restoreVisibilityIncludingChildLayers(); } } } // Save PNG file function savePNG(file, scale, artBoardClipping) { var exp = new ExportOptionsPNG24(); exp.transparency = true; exp.horizontalScale = scale exp.verticalScale = scale; exp.artBoardClipping = artBoardClipping; doc.exportFile(file, ExportType.PNG24, exp); } 


- make an atlas of 4096 * 4096 (or smaller, but necessarily square) from these files using Zwoptex or Texture Packer. Make sure to indent between 8px pictures
- avoid problems with transparency, which happen if neglected by multiplicity of 2px in a vector file. Fortunately, there is an action for Photoshop AlphaUnity
image
- reduce the atlas by 2 times
- overtake file in PNG8
')
Thus, the programmer will receive from me a text file with the names of the pictures, their coordinates, position on the sheet, PLIST or XML with coordinates and rotations, an atlas of pictures in optimal quality and a thumbnail. It so happens that neither the designer nor the programmer want to do this routine, but very necessary procedure.

Such an algorithm of actions will be difficult and long only for the first time, but then it will greatly simplify the lives of all the project participants.

Link to scripts and action. Github

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


All Articles