196 lines
6.2 KiB
JavaScript
196 lines
6.2 KiB
JavaScript
|
|
// This script exports photoshop layers as individual images.
|
|
// It also write a JSON file that can be imported into Spine
|
|
// where the images will be displayed in the same positions.
|
|
|
|
// Settings.
|
|
var ignoreHiddenLayers = true;
|
|
var savePNGs = true;
|
|
var saveJSON = true;
|
|
var scaleFactor = 1;
|
|
showDialog();
|
|
|
|
function main () {
|
|
// Output dir.
|
|
var dir = app.activeDocument.path + "/images/";
|
|
|
|
new Folder(dir).create();
|
|
|
|
var name = decodeURI(app.activeDocument.name);
|
|
name = name.substring(0, name.indexOf("."));
|
|
|
|
app.activeDocument.duplicate();
|
|
|
|
// Collect original layer visibility and hide all layers.
|
|
var layers = [];
|
|
getLayers(app.activeDocument, layers);
|
|
|
|
var layerCount = layers.length;
|
|
var layerVisibility = {};
|
|
|
|
for (var i = layerCount - 1; i >= 0; i--) {
|
|
var layer = layers[i];
|
|
layerVisibility[layer] = layer.visible;
|
|
layer.visible = false;
|
|
}
|
|
|
|
// Save JSON.
|
|
if (saveJSON || savePNGs) {
|
|
var json = "{\"bones\":[{\"name\":\"root\"}],\"slots\":[\n";
|
|
for (var i = layerCount - 1; i >= 0; i--) {
|
|
var layer = layers[i];
|
|
|
|
if (ignoreHiddenLayers && !layerVisibility[layer]) continue;
|
|
|
|
json += "{\"name\":\"" + trim(layer.name) + "\",\"bone\":\"root\",\"attachment\":\"" + trim(layer.name) + "\"},\n";
|
|
}
|
|
json += "],\"skins\":{\"default\":{\n";
|
|
for (var i = layerCount - 1; i >= 0; i--) {
|
|
var layer = layers[i];
|
|
|
|
if (ignoreHiddenLayers && !layerVisibility[layer]) continue;
|
|
|
|
var x = app.activeDocument.width.as("px") * scaleFactor;
|
|
var y = app.activeDocument.height.as("px") * scaleFactor;
|
|
|
|
layer.visible = true;
|
|
if (!layer.isBackgroundLayer)
|
|
app.activeDocument.trim(TrimType.TRANSPARENT, false, true, true, false);
|
|
x -= app.activeDocument.width.as("px") * scaleFactor;
|
|
y -= app.activeDocument.height.as("px") * scaleFactor;
|
|
if (!layer.isBackgroundLayer)
|
|
app.activeDocument.trim(TrimType.TRANSPARENT, true, false, false, true);
|
|
var width = app.activeDocument.width.as("px") * scaleFactor;
|
|
var height = app.activeDocument.height.as("px") * scaleFactor;
|
|
|
|
// Save image.
|
|
if (savePNGs) {
|
|
if (scaleFactor != 1) scaleImage();
|
|
|
|
var file = File(dir + "/" + trim(layer.name));
|
|
if (file.exists) file.remove();
|
|
activeDocument.saveAs(file, new PNGSaveOptions(), true, Extension.LOWERCASE);
|
|
|
|
if (scaleFactor != 1) stepHistoryBack();
|
|
}
|
|
|
|
if (!layer.isBackgroundLayer) {
|
|
stepHistoryBack();
|
|
stepHistoryBack();
|
|
}
|
|
layer.visible = false;
|
|
|
|
x += Math.round(width) / 2;
|
|
y += Math.round(height) / 2;
|
|
json += "\"" + trim(layer.name) + "\":{\"" + trim(layer.name) + "\":{\"x\":" + x + ",\"y\":" + y+ ",\"width\":" + Math.round(width) + ",\"height\":" + Math.round(height) + "}},\n";
|
|
}
|
|
json += "}}, \"animations\": { \"animation\": {} }}";
|
|
|
|
if (saveJSON) {
|
|
// Write file.
|
|
var file = new File(dir + name + ".json");
|
|
file.remove();
|
|
file.open("a");
|
|
file.lineFeed = "\n";
|
|
file.write(json);
|
|
file.close();
|
|
}
|
|
}
|
|
|
|
activeDocument.close(SaveOptions.DONOTSAVECHANGES);
|
|
}
|
|
|
|
// Unfinished!
|
|
function hasLayerSets (layerset) {
|
|
layerset = layerset.layerSets;
|
|
for (var i = 0; i < layerset.length; i++)
|
|
if (layerset[i].layerSets.length > 0) hasLayerSets(layerset[i]);
|
|
}
|
|
|
|
function scaleImage() {
|
|
var imageSize = app.activeDocument.width.as("px");
|
|
app.activeDocument.resizeImage(UnitValue(imageSize * scaleFactor, "px"), undefined, 72, ResampleMethod.BICUBICSHARPER);
|
|
}
|
|
|
|
function stepHistoryBack () {
|
|
var desc = new ActionDescriptor();
|
|
var ref = new ActionReference();
|
|
ref.putEnumerated( charIDToTypeID( "HstS" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Prvs" ));
|
|
desc.putReference(charIDToTypeID( "null" ), ref);
|
|
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
|
|
}
|
|
|
|
function getLayers (layer, collect) {
|
|
if (!layer.layers || layer.layers.length == 0) return layer;
|
|
for (var i = 0, n = layer.layers.length; i < n; i++) {
|
|
// For checking if its an adjustment layer, but it also excludes
|
|
// LayerSets so we need to find the different types needed.
|
|
//if (layer.layers[i].kind == LayerKind.NORMAL) {
|
|
var child = getLayers(layer.layers[i], collect)
|
|
if (child) collect.push(child);
|
|
//}
|
|
}
|
|
}
|
|
|
|
function trim (value) {
|
|
return value.replace(/^\s+|\s+$/g, "");
|
|
}
|
|
|
|
function hasFilePath() {
|
|
var ref = new ActionReference();
|
|
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
|
|
return executeActionGet(ref).hasKey(stringIDToTypeID('fileReference'));
|
|
}
|
|
|
|
function showDialog () {
|
|
if (!hasFilePath()) {
|
|
alert("File path not found.\nYou need to save the document before continuing.");
|
|
return;
|
|
}
|
|
|
|
var dialog = new Window("dialog", "Export Layers");
|
|
|
|
dialog.savePNGs = dialog.add("checkbox", undefined, "Save PNGs");
|
|
dialog.savePNGs.value = savePNGs;
|
|
dialog.savePNGs.alignment = "left";
|
|
|
|
dialog.saveJSON = dialog.add("checkbox", undefined, "Save JSON");
|
|
dialog.saveJSON.alignment = "left";
|
|
dialog.saveJSON.value = saveJSON;
|
|
|
|
dialog.ignoreHiddenLayers = dialog.add("checkbox", undefined, "Ignore hidden layers");
|
|
dialog.ignoreHiddenLayers.alignment = "left";
|
|
dialog.ignoreHiddenLayers.value = ignoreHiddenLayers;
|
|
|
|
var scaleGroup = dialog.add("panel", [0, 0, 180, 50], "Image Scale");
|
|
var scaleText = scaleGroup.add("edittext", [10,10,40,30], scaleFactor * 100);
|
|
scaleGroup.add("statictext", [45, 12, 100, 20], "%");
|
|
var scaleSlider = scaleGroup.add("slider", [60, 10,165,20], scaleFactor * 100, 1, 100);
|
|
scaleText.onChanging = function() {
|
|
scaleSlider.value = scaleText.text;
|
|
if (scaleText.text < 1 || scaleText.text > 100) {
|
|
alert("Valid numbers are 1-100.");
|
|
scaleText.text = scaleFactor * 100;
|
|
scaleSlider.value = scaleFactor * 100;
|
|
}
|
|
};
|
|
scaleSlider.onChanging = function() { scaleText.text = Math.round(scaleSlider.value); };
|
|
|
|
var confirmGroup = dialog.add("group", [0, 0, 180, 50]);
|
|
var runButton = confirmGroup.add("button", [10, 10, 80, 35], "Ok");
|
|
var cancelButton = confirmGroup.add("button", [90, 10, 170, 35], "Cancel");
|
|
cancelButton.onClick = function() { this.parent.close(0); return; };
|
|
runButton.onClick = function() {
|
|
savePNGs = dialog.savePNGs.value;
|
|
saveJSON = dialog.saveJSON.value;
|
|
ignoreHiddenLayers = dialog.ignoreHiddenLayers.value;
|
|
scaleFactor = scaleSlider.value / 100;
|
|
main();
|
|
this.parent.close(0);
|
|
};
|
|
|
|
dialog.orientation = "column";
|
|
dialog.center();
|
|
dialog.show();
|
|
}
|