( ′∀`)σ≡σ☆))Д′)レ(゚∀゚;)ヘ=З=З=Зε≡(ノ´_ゝ`)ノ HEX
HEX
Server: Apache/2.4.58 (Ubuntu)
System: Linux mail.thebrand.ai 6.8.0-107-generic #107-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 13 19:51:50 UTC 2026 x86_64
User: www-data (33)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: /var/www/html/tmpr/../tmpr/../tmpr/..//TheBrandPhotoshopExporterX.js
#target photoshop
app.bringToFront();

// This script exports Adobe Photoshop layers as individual PNGs. It also
// writes a JSON file which can be imported into Brand where the images
// will be displayed in the same positions and draw order.

// Copyright (c) 2019-2020, The Brand

var appVersion = 1.9; // This is incremented every time the script is modified, so you know if you have the latest.

var cs2 = parseInt(app.version) < 10;

var originalDoc;
try {
	originalDoc = app.activeDocument;
} catch (ignored) {}

var defaultSettings = {
	ignoreHiddenLayers: false,
	ignoreBackground: true,
	writeTemplate: false,
	writeJson: true,
	trimWhitespace: true,
	scale: 1,
	padding: 1,
	imagesDir: "./brandexport/assets/",
	jsonPath: "./brandexport/json/",
};
var settings = loadSettings();
showSettingsDialog();

var progress, cancel, errors;

function checkTextValues () {
	var layers2 = [];
	collectLayers(activeDocument, layers2);
	var layersCount2 = layers2.length;

 
	for (var i = 0; i < layersCount2; i++) {
	 
		var layer2 = layers2[i];
         
        var textornot = determinelayerkind(layer2);
        } 
}
function run () {
    
    
    
    	// user settings
	var prefs = new Object();
	prefs.countFrom     = 1;    // number to start counting from (default: 1)
	prefs.zeroPadding   = 3;    // number of digits to use for the layer number (defaul: 3)
	prefs.nameSeparator = ' ';  // character to insert between the layer name and number (default: ' ')
	prefs.topToBottom   = false; // rename layers top to bottom (true) or bottom to top (false)


	// rename layers

		renameLayers(activeDocument, prefs);
      
    
	errors = [];
	showProgressDialog();

	// Output dirs.
	var jsonFile = new File(jsonPath(settings.jsonPath));
	jsonFile.parent.create();
	var imagesDir = absolutePath(settings.imagesDir);
	var imagesFolder = new Folder(imagesDir);
	imagesFolder.create();

	var origin = rulerOrigin(), xOffSet = origin[0], yOffSet = origin[1];

	activeDocument.duplicate();
	deselectLayers();

	try {
		convertToRGB();
	} catch (ignored) {}
	if (app.activeDocument.mode != DocumentMode.RGB) {
		alert("update PSD image mode to RGB color.");
		return;
	}

	// Output template image.
	if (settings.writeTemplate) {
		if (settings.scale != 1) {
			storeHistory();
			scaleImage();
		}


var rand = Math.floor(Math.random() * 1000);
 
 
		var file = new File(imagesDir + "template"+rand+".jpg");
        var poster = file;
		if (file.exists) file.remove();

		saveJPG(file);

		if (settings.scale != 1) restoreHistory();
	}

	if (!settings.jsonPath && !settings.imagesDir) return;

	rasterizeAll();

	// Add a history item to prevent layer visibility from changing by the active layer being reset to the top.
	activeDocument.artLayers.add();


 

      //json  += '"brandType": [{ "type": "' + imagesDir + '" } ,\n';    

	// Collect and hide layers.
	var layers = [];
	collectLayers(activeDocument, layers);
	var layersCount = layers.length;

	// Add a history item to prevent layer visibility from changing by restoreHistory.
	activeDocument.artLayers.add();

	// Store the bones, slot names, and layers for each skin.
	var bones = { _root: { name: "brandStart", x: 0, y: 0, children: [] } };
	var slots = {}, slotsCount = 0;
	var skins = { _default: [] }, skinsCount = 0;
	var totalLayerCount = 0;
	outer:
	for (var i = 0; i < layersCount; i++) {
		if (cancel) return;
		var layer = layers[i];
        
            

		if (layer.kind != LayerKind.NORMAL && !isGroup(layer)) continue;

 
 

		var name = stripTags(layer.name).replace(/.png$/, "");
		name = name.replace(/[\\\/:"*?<>|]/g, "").replace(/^\.+$/, "").replace(/^__drag$/, ""); // Illegal.
		name = name.replace(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i, ""); // Windows.
		if (!name || name.length > 255) {
			error("Layer name is not a valid attachment name:\n\n" + layer.name);
			continue;
		}
		var folderPath = folders(layer, "");
		layer.attachmentName = folderPath + name;
		layer.attachmentPath = folderPath + (findTagValue(layer, "path:") || name);

		var bone = null;
		var boneLayer = findTagLayer(layer, "category");
		if (boneLayer) {
			var parent = getParentBone(boneLayer, bones);
			var boneName = findTagValue(boneLayer, "category");
			bone = get(bones, boneName);
			if (bone) {
				if (parent != bone.parent) {
					error("Multiple layers for the \"" + boneName + "\" bone have different parent bones:\n\n"
						+ bone.parent.name + "\n"
						+ parent.name);
					continue;
				}
			} else {
				set(bones, boneName, bone = { name: boneName, parent: parent, children: [] });
				parent.children.push(bone);
			}
			bone.x = layer.bounds[0].as("px") * settings.scale - settings.padding;
			bone.x += (layer.bounds[2].as("px") - layer.bounds[0].as("px")) * settings.scale / 2 + settings.padding;
			bone.y = (activeDocument.height.as("px") - layer.bounds[1].as("px")) * settings.scale + settings.padding;
			bone.y -= (layer.bounds[3].as("px") - layer.bounds[1].as("px")) * settings.scale / 2 + settings.padding;
			// Make relative to the Photoshop document ruler origin.
			bone.x -= xOffSet * settings.scale;
			bone.y -= (activeDocument.height.as("px") - yOffSet) * settings.scale;
		}

		layer.slotName = findTagValue(layer, "brandLayer") || layer.attachmentName;
		if (!get(slots, layer.slotName)) slotsCount++;
		var slot;
		set(slots, layer.slotName, slot = { bone: bone, attachment: layer.wasVisible ? layer.attachmentName : null });
		if (layer.blendMode == BlendMode.LINEARDODGE)
			slot.blend = "additive";
		else if (layer.blendMode == BlendMode.MULTIPLY)
			slot.blend = "multiply";
		else if (layer.blendMode == BlendMode.SCREEN)
			slot.blend = "screen";

		var skinName = findTagValue(layer, "brandLayerOrder") || "default";
		var skinSlots = get(skins, skinName);
		if (!skinSlots) {
			set(skins, skinName, skinSlots = {});
			skinsCount++;
		}

		var skinLayers = get(skinSlots, layer.slotName);
		if (!skinLayers) set(skinSlots, layer.slotName, skinLayers = []);
		for (var ii = 0, nn = skinLayers.length; ii < nn; ii++) {
			if (skinLayers[ii].attachmentName == layer.attachmentName) {
				error("Multiple layers for the \"" + skinName + "\" skin have the same name:\n\n"
					+ layer.attachmentName
					+ "\n\nRename or use the [path:name] or [ignore] tag for these layers.");
				continue outer;
			}
		}
		skinLayers[skinLayers.length] = layer;
		totalLayerCount++;
	}

	var n = errors.length;
	if (n) {
		var first = errors[0];
		var file;
		if (n > 1) {
			try {
				var all = "";
				for (var i = 0; i < n; i++) {
					if (i > 0) all += "---\n";
					all += errors[i].replace(/\n\n/g, "\n") + "\n";
				}
				file = new File(jsonFile.parent + "/errors.txt");
				file.parent.create();
				file.encoding = "UTF-8";
				file.remove();
				file.open("w", "TEXT");
				file.lineFeed = "\n";
				file.write(all);
				file.close();
				if (n == 2)
					first += "\n\nSee errors.txt for 1 additional error.";
				else
					first += "\n\nSee errors.txt for " + (n - 1) + " additional errors.";
			} catch (e) {
				if (n == 2)
					first += "\n\nUnable to write 1 additional error to errors.text.\n"+e;
				else
					first += "\n\nUnable to write " + (n - 1) + " additional errors to errors.txt.\n"+e;
			}
		}
		alert(first);
		if (file) file.execute();
		return;
	}
//checkTextValues ()
	// Output skeleton.
    
    
    
         


 var   json  = '{ \n "brandEngine": {  \n';
     
     
      
  json  += '"brandLocation": \n {  \n "images": "' + imagesDir + '"  \n },\n';   
       
       json  += ' "categorys":  \n  \n';
 
	// Output bones.
	function outputBone (bone) {
		var json = bone.parent ? ",\n" : "";
		json += '\t{ "name": ' + quote(bone.name);
		var x = bone.x, y = bone.y;
		if (bone.parent) {
			x -= bone.parent.x;
			y -= bone.parent.y;
			json += ', "parent": ' + quote(bone.parent.name);
		}
		if (x) json += ', "x": ' + x;
		if (y) json += ', "y": ' + y;
		json += ' }';
		for (var i = 0, n = bone.children.length; i < n; i++)
			json += outputBone(bone.children[i]);
		return json;
	}
	for (var boneName in bones) {
		if (cancel) return;
		if (!bones.hasOwnProperty(boneName)) continue;
		var bone = bones[boneName];
		if (!bone.parent) json += outputBone(bone);
	}
	json += ' \n  \n ,\n"brandLayers": \n [  \n';

	// Output slots. here
	var slotIndex = 0;
	for (var slotName in slots) {
		if (cancel) return;
		if (!slots.hasOwnProperty(slotName)) continue;
		var slot = slots[slotName];
		slotName = stripName(slotName);
		if (layer.kind == LayerKind.TEXT)
		{
			var stylo = "yes";
		}
		else
		{
			var stylo = "no";
		}
	 
	 
		
		json += '\t{  \n "name": ' + quote(slotName) + ',   \n "style": ' + quote(stylo) + ',   \n "category": ' + quote(slot.bone ? slot.bone.name : "brandStart");
		if (slot.attachment) json += ',  \n "attachment": ' + quote(slot.attachment);
		if (slot.blend) json += ', "blend": ' + quote(slot.blend);
		json += ' \n } \n ';
		slotIndex++;
		json += slotIndex < slotsCount ? ",\n" : "\n";
	}
	json += ' ] ,\n \n "brandLayerOrders":  \n {\n';

	// Output skins.
	var skinIndex = 0, layerCount = 0;
    
 
	for (var skinName in skins) {
		if (!skins.hasOwnProperty(skinName)) continue;
		var skinSlots = skins[skinName];
		skinName = stripName(skinName);
		json += '\t"' + skinName + '": {\n';

		var skinSlotIndex = 0, skinSlotsCount = countAssocArray(skinSlots);
		for (var slotName in skinSlots) {
			if (!skinSlots.hasOwnProperty(slotName)) continue;
			var bone = slots[slotName].bone;
			var skinLayers = skinSlots[slotName];
			slotName = stripName(slotName);

			json += '\t\t' + quote(slotName) + ': {\n';

			var skinLayerIndex = 0, skinLayersCount = skinLayers.length;
			for (var i = skinLayersCount - 1; i >= 0; i--) {
				var layer = skinLayers[i];
				layer.visible = true;

				if (cancel) return;
				setProgress(++layerCount / totalLayerCount, trim(layer.name));

				var placeholderName = layer.attachmentName, attachmentName = placeholderName, attachmentPath = layer.attachmentPath;
				if (skinName != "default") {
					attachmentName = skinName + "/" + attachmentName;
					attachmentPath = skinName + "/" + attachmentPath;
				}

				if (isGroup(layer)) {
					activeDocument.activeLayer = layer;
					layer = layer.merge();
				}

				rasterizeStyles(layer);

				storeHistory();

				var x = 0, y = 0;
				if (settings.trimWhitespace) {
					x = activeDocument.width.as("px") * settings.scale;
					y = activeDocument.height.as("px") * settings.scale;
					if (!layer.isBackgroundLayer) activeDocument.trim(TrimType.TRANSPARENT, false, true, true, false);
					x -= activeDocument.width.as("px") * settings.scale;
					y -= activeDocument.height.as("px") * settings.scale;
					if (!layer.isBackgroundLayer) activeDocument.trim(TrimType.TRANSPARENT, true, false, false, true);
				}
				var width = activeDocument.width.as("px") * settings.scale + settings.padding * 2;
				var height = activeDocument.height.as("px") * settings.scale + settings.padding * 2;

				// Save image.
				if (settings.imagesDir) {
					if (settings.scale != 1) scaleImage();
					if (settings.padding > 0) activeDocument.resizeCanvas(width, height, AnchorPosition.MIDDLECENTER);

					var file = new File(imagesDir + attachmentPath + ".png");
					file.parent.create();
					savePNG(file);
				}

				restoreHistory();
				if (layerCount < totalLayerCount) deleteLayer(layer);

				x += Math.round(width) / 2 - settings.padding;
				y += Math.round(height) / 2 - settings.padding;

				// Make relative to the Photoshop document ruler origin.
				x -= xOffSet;
				y -= (activeDocument.height.as("px") - yOffSet);

				if (bone) { // Make relative to parent bone.
					x -= bone.x;
					y -= bone.y;
				}


				json += "\t\t\t" + quote(placeholderName) + ': { ';
				if (attachmentName != placeholderName) json += '"name": ' + quote(attachmentName) + ', ';
				if (attachmentName != attachmentPath) json += '"path": ' + quote(attachmentPath) + ', ';
				json += '"x": ' + x + ', "y": ' + y + ', "width": ' + Math.round(width) + ', "height": ' + Math.round(height);

				json += " }" + (++skinLayerIndex < skinLayersCount ? ",\n" : "\n");
			}

			json += "\t\t\}" + (++skinSlotIndex < skinSlotsCount ? ",\n" : "\n");
		}

		json += "\t}" + (++skinIndex <= skinsCount ? ",\n" : "\n");
	}
	json += '}\n   ';

       activeDocument.close(SaveOptions.DONOTSAVECHANGES); 

	// Output JSON file.
	if (settings.writeJson && settings.jsonPath) {
		if (cancel) return;
		jsonFile.encoding = "UTF-8";
		jsonFile.remove();
		jsonFile.open("w", "TEXT");
		jsonFile.lineFeed = "\n";
	
        
        
        
        
        
        
       var layers2 = [];
	collectLayers(activeDocument, layers2);
	var layersCount2 = layers2.length;
 
  json  += ', \n "brandType": \n [ ';   
  
  for (var v = 0; v < layersCount2; v++) {
	 
		var layer2 = layers2[v];
      
        var textornot = determinelayerkind(layer2);  
          
          if(textornot == "Text Layer")
        {
    
       var fontSize =  layer2.textItem.size ;
       var fontFace = layer2.textItem.font;
       var fontColor = layer2.textItem.color.rgb.hexValue;
 
        }
        else
        {
             var fontSize =  "";
       var fontFace = "";
       var fontColor ="";
          
          }
        
    json  += '  \n{  \n "color": "'+fontColor+'" ,\n "face": "'+fontFace+'" ,\n "size": "'+fontSize+'" ,\n "id": "'+v+'" ,  \n "type": "'+textornot+'"  \n} ,\n';  
        } 
 
    json  += '  \n{  \n "color": "'+poster+'" ,\n "face": "'+poster+'" ,\n "size": "'+poster+'",  \n "id": "-'+poster+'" ,  \n "type":   "poster"  \n } \n  ] \n }\n';  
  
               
        json += '\n  } ';

	
    
        	jsonFile.write(json);
		jsonFile.close();
   	
	}










}






// Settings dialog:

function showSettingsDialog () {
	if (parseInt(app.version) < 9) {
		alert("Photoshop CS2 or later is required.");
		return;
	}
	if (!originalDoc) {
		alert("Please open a document before running the The Brand Tool.");
		return;
	}
	try {
		decodeURI(activeDocument.path);
	} catch (e) {
		alert("Please save the document before running the The Brand Tool.");
		return;
	}

	// Layout.
	var dialog = new Window("dialog", "The Brand v" + appVersion), group;
	
	
	g = dialog.graphics;
var myBrush = g.newBrush(g.BrushType.SOLID_COLOR, [0.99, 0.99, 0.99, 1]);
g.backgroundColor = myBrush;
dialog.title = dialog.add('statictext',undefined, 'The Brand Exporter');
var g = dialog.title.graphics;
g.font = ScriptUI.newFont("Georgia","BOLDITALIC",22);
dialog.p1  = dialog.add("panel", undefined, undefined, {borderStyle:"black"});


dialog.alignChildren = "fill";

	try {
		dialog.add("image", undefined, new File(scriptDir() + "logo.png"));
	} catch (ignored) {}

	var settingsGroup = dialog.add("panel", undefined, "Settings");
		settingsGroup.margins = [10,15,10,10];
		settingsGroup.alignChildren = "fill";
		var checkboxGroup = settingsGroup.add("group");
			checkboxGroup.alignChildren = ["left", ""];
			checkboxGroup.orientation = "row";
			group = checkboxGroup.add("group");
				group.orientation = "column";
				group.alignChildren = ["left", ""];
				var ignoreHiddenLayersCheckbox = group.add("checkbox", undefined, " Ignore hidden layers");
				ignoreHiddenLayersCheckbox.value = settings.ignoreHiddenLayers;
				var ignoreBackgroundCheckbox = group.add("checkbox", undefined, " Ignore background layer");
				ignoreBackgroundCheckbox.value = settings.ignoreBackground;
				var trimWhitespaceCheckbox = group.add("checkbox", undefined, " Trim whitespace");
				trimWhitespaceCheckbox.value = settings.trimWhitespace;
			group = checkboxGroup.add("group");
				group.orientation = "column";
				group.alignChildren = ["left", ""];
				group.alignment = ["", "top"];
				var writeJsonCheckbox = group.add("checkbox", undefined, " Write Brand JSON");
				writeJsonCheckbox.value = settings.writeJson;
				var writeTemplateCheckbox = group.add("checkbox", undefined, " Write template image");
				writeTemplateCheckbox.value = settings.writeTemplate;
		var scaleText, paddingText, scaleSlider, paddingSlider;
		if (!cs2) {
			var slidersGroup = settingsGroup.add("group");
				group = slidersGroup.add("group");
					group.orientation = "column";
					group.alignChildren = ["right", ""];
					group.add("statictext", undefined, "Scale:");
					group.add("statictext", undefined, "Padding:");
				group = slidersGroup.add("group");
					group.orientation = "column";
					scaleText = group.add("edittext", undefined, settings.scale * 100);
					scaleText.characters = 4;
					paddingText = group.add("edittext", undefined, settings.padding);
					paddingText.characters = 4;
				group = slidersGroup.add("group");
					group.orientation = "column";
					group.add("statictext", undefined, "%");
					group.add("statictext", undefined, "px");
				group = slidersGroup.add("group");
					group.orientation = "column";
					group.alignChildren = ["fill", ""];
					group.alignment = ["fill", ""];
					scaleSlider = group.add("slider", undefined, settings.scale * 100, 1, 100);
					paddingSlider = group.add("slider", undefined, settings.padding, 0, 4);
		} else {
			group = settingsGroup.add("group");
				group.add("statictext", undefined, "Scale:");
				scaleText = group.add("edittext", undefined, settings.scale * 100);
				scaleText.preferredSize.width = 50;
			scaleSlider = settingsGroup.add("slider", undefined, settings.scale * 100, 1, 100);
			group = settingsGroup.add("group");
				group.add("statictext", undefined, "Padding:");
				paddingText = group.add("edittext", undefined, settings.padding);
				paddingText.preferredSize.width = 50;
			paddingSlider = settingsGroup.add("slider", undefined, settings.padding, 0, 4);
		}

	var outputPathGroup = dialog.add("panel", undefined, "Output Paths");
		outputPathGroup.alignChildren = ["fill", ""];
		outputPathGroup.margins = [10,15,10,10];
		var imagesDirText, imagesDirPreview, jsonPathText, jsonPathPreview;
		if (!cs2) {
			var textGroup = outputPathGroup.add("group");
			textGroup.orientation = "column";
			textGroup.alignChildren = ["fill", ""];
			group = textGroup.add("group");
				group.add("statictext", undefined, "Images:");
				imagesDirText = group.add("edittext", undefined, settings.imagesDir);
				imagesDirText.alignment = ["fill", ""];
			imagesDirPreview = textGroup.add("statictext", undefined, "");
			imagesDirPreview.maximumSize.width = 260;
			group = textGroup.add("group");
				var jsonLabel = group.add("statictext", undefined, "JSON:");
				jsonLabel.justify = "right";
				jsonLabel.minimumSize.width = 41;
				jsonPathText = group.add("edittext", undefined, settings.jsonPath);
				jsonPathText.alignment = ["fill", ""];
			jsonPathPreview = textGroup.add("statictext", undefined, "");
			jsonPathPreview.maximumSize.width = 260;
		} else {
			outputPathGroup.add("statictext", undefined, "Images:");
			imagesDirText = outputPathGroup.add("edittext", undefined, settings.imagesDir);
			imagesDirText.alignment = "fill";
			outputPathGroup.add("statictext", undefined, "JSON:");
			jsonPathText = outputPathGroup.add("edittext", undefined, settings.jsonPath);
			jsonPathText.alignment = "fill";
		}
	var buttonGroup = dialog.add("group");
		var helpButton;
		if (!cs2) helpButton = buttonGroup.add("button", undefined, "Help");
		group = buttonGroup.add("group");
			group.alignment = ["fill", ""];
			group.alignChildren = ["right", ""];
			var runButton = group.add("button", undefined, "OK");
			var cancelButton = group.add("button", undefined, "Cancel");

	// Tooltips.
	writeTemplateCheckbox.helpTip = "When checked, a PNG is written for the currently visible layers.";
	writeJsonCheckbox.helpTip = "When checked, a Brand JSON file is written.";
	trimWhitespaceCheckbox.helpTip = "When checked, blank pixels aroind the edges of each image are removed.";
	scaleSlider.helpTip = "Scales the PNG files. Useful when using higher resolution art in Photoshop than in Brand.";
	paddingSlider.helpTip = "Blank pixels around the edge of each image. Can avoid aliasing artifacts for opaque pixels along the image edge.";
	imagesDirText.helpTip = "The folder to write PNGs. Begin with \"./\" to be relative to the PSD file. Blank to disable writing PNGs.";
	jsonPathText.helpTip = "Output JSON file if ending with \".json\", else the folder to write the JSON file. Begin with \"./\" to be relative to the PSD file. Blank to disable writing a JSON file.";

	// Events.
	scaleText.onChanging = function () { scaleSlider.value = scaleText.text; };
	scaleSlider.onChanging = function () { scaleText.text = Math.round(scaleSlider.value); };
	paddingText.onChanging = function () { paddingSlider.value = paddingText.text; };
	paddingSlider.onChanging = function () { paddingText.text = Math.round(paddingSlider.value); };
	cancelButton.onClick = function () {
		cancel = true;
		dialog.close();
		return;
	};
	if (!cs2) helpButton.onClick = showHelpDialog;
	jsonPathText.onChanging = function () {
		var text = jsonPathText.text ? jsonPath(jsonPathText.text) : "<no JSON output>";
		if (!cs2) {
			jsonPathPreview.text = text;
			jsonPathPreview.helpTip = text;
		} else
			jsonPathText.helpTip = text;
	};
	imagesDirText.onChanging = function () {
		var text = imagesDirText.text ? absolutePath(imagesDirText.text) : "<no image output>";
		if (!cs2) {
			imagesDirPreview.text = text;
			imagesDirPreview.helpTip = text;
		} else
			imagesDirText.helpTip = text;
	};

	// Run now.
	jsonPathText.onChanging();
	imagesDirText.onChanging();

	function updateSettings () {
		settings.ignoreHiddenLayers = ignoreHiddenLayersCheckbox.value;
		settings.ignoreBackground = ignoreBackgroundCheckbox.value;
		settings.writeTemplate = writeTemplateCheckbox.value;
		settings.writeJson = writeJsonCheckbox.value;
		settings.trimWhitespace = trimWhitespaceCheckbox.value;

		var scaleValue = parseFloat(scaleText.text);
		if (scaleValue > 0 && scaleValue <= 100) settings.scale = scaleValue / 100;

		settings.imagesDir = imagesDirText.text;
		settings.jsonPath = jsonPathText.text;

		var paddingValue = parseInt(paddingText.text);
		if (paddingValue >= 0) settings.padding = paddingValue;
	}

	runButton.onClick = function () {
		if (scaleText.text <= 0 || scaleText.text > 100) {
			alert("Scale must be between > 0 and <= 100.");
			return;
		}
		if (paddingText.text < 0) {
			alert("Padding must be >= 0.");
			return;
		}

		updateSettings();
		saveSettings();

		ignoreHiddenLayersCheckbox.enabled = false;
		ignoreBackgroundCheckbox.enabled = false;
		writeTemplateCheckbox.enabled = false;
		writeJsonCheckbox.enabled = false;
		trimWhitespaceCheckbox.enabled = false;
		scaleText.enabled = false;
		scaleSlider.enabled = false;
		paddingText.enabled = false;
		paddingSlider.enabled = false;
		imagesDirText.enabled = false;
		jsonPathText.enabled = false;
		if (!cs2) helpButton.enabled = false;
		runButton.enabled = false;
		cancelButton.enabled = false;

		var rulerUnits = app.preferences.rulerUnits;
		app.preferences.rulerUnits = Units.PIXELS;
		try {
			// var start = new Date().getTime();
			run();
			// alert(new Date().getTime() - start);
		} catch (e) {
			alert("An unexpected error has occurred.\n\nTo debug, run the The Brand Tool using Adobe ExtendScript "
				+ "with \"Debug > Do not break on guarded exceptions\" unchecked.");
			debugger;
		} finally {
			if (activeDocument != originalDoc) activeDocument.close(SaveOptions.DONOTSAVECHANGES);
			app.preferences.rulerUnits = rulerUnits;
			dialog.close();
		}
	};

	dialog.center();
	dialog.show();
}

function loadSettings () {
	var options = null;
	try {
		options = app.getCustomOptions(sID("settings"));
	} catch (e) {
	}

	var settings = {};
	for (var key in defaultSettings) {
		if (!defaultSettings.hasOwnProperty(key)) continue;
		var typeID = sID(key);
		if (options && options.hasKey(typeID))
			settings[key] = options["get" + getOptionType(defaultSettings[key])](typeID);
		else
			settings[key] = defaultSettings[key];
	}
	return settings;
}

function saveSettings () {
	if (cs2) return; // No putCustomOptions.
	var action = new ActionDescriptor();
	for (var key in defaultSettings) {
		if (!defaultSettings.hasOwnProperty(key)) continue;
		action["put" + getOptionType(defaultSettings[key])](sID(key), settings[key]);
	}
	app.putCustomOptions(sID("settings"), action, true);
}

function getOptionType (value) {
	switch (typeof(value)) {
	case "boolean": return "Boolean";
	case "string": return "String";
	case "number": return "Double";
	};
	throw new Error("Invalid default setting: " + value);
}

// Help dialog.

function showHelpDialog () {
	var dialog = new Window("dialog", "The Brand - Help");
	dialog.alignChildren = ["fill", ""];
	dialog.orientation = "column";
	dialog.alignment = ["", "top"];

	var helpText = dialog.add("statictext", undefined, ""
		+ "This script writes layers as images and creates a JSON file to bring the images into Brand with the same positions and draw order they had in Photoshop.\n"
		+ "\n"
		+ "The Photoshop ruler origin corresponds to 0,0 in Brand.\n"
		+ "\n"
		+ "Tags in square brackets can be used anywhere in layer and group names to customize the output. If \":name\" is omitted, the layer or group name is used.\n"
		+ "\n"
		+ "Group and layer names:\n"
		+ "•  [bone] or [bone:name]  Layers, slots, and bones are placed under a bone. The bone is created at the center of a visible layer. Bone groups can be nested.\n"
		+ "•  [slot] or [slot:name]  Layers are placed in a slot.\n"
		+ "•  [skin] or [skin:name]  Layers are placed in a skin. Skin layer images are output in a subfolder for the skin.\n"
		+ "•  [folder] or [folder:name]  Layers images are output in a subfolder. Folder groups can be nested.\n"
		+ "•  [ignore]  Layers, groups, and any child groups will not be output.\n"
		+ "\n"
		+ "Group names:\n"
		+ "•  [merge]  Layers in the group are merged and a single image is output.\n"
		+ "\n"
		+ "Layer names:\n"
		+ "•  [path:name]  Specifies the image file name, which can be different from the attachment name. Whitespace trimming is required. Can be used on a group with [merge]."
	, {multiline: true});
	helpText.preferredSize.width = 325;

	var closeButton = dialog.add("button", undefined, "Close");
	closeButton.alignment = ["center", ""];

	closeButton.onClick = function () {
		dialog.close();
	};

	dialog.center();
	dialog.show();
}

// Progress dialog:

function showProgressDialog () {
	var dialog = new Window("palette", "The Brand - Processing...");
	dialog.alignChildren = "fill";
	dialog.orientation = "column";

	var message = dialog.add("statictext", undefined, "Initializing...");

	var group = dialog.add("group");
		var bar = group.add("progressbar");
		bar.preferredSize = [300, 16];
		bar.maxvalue = 10000;
		var cancelButton = group.add("button", undefined, "Cancel");

	cancelButton.onClick = function () {
		cancel = true;
		cancelButton.enabled = false;
		return;
	};

	dialog.center();
	dialog.show();
	dialog.active = true;

	progress = {
		dialog: dialog,
		bar: bar,
		message: message
	};
}

function setProgress (percent, layerName) {
	progress.bar.value = 10000 * percent;
	progress.message.text = "Layer: " + layerName;
	if (!progress.dialog.active) progress.dialog.active = true;
}

// The Brand utility:

function unlock (layer) {
	if (layer.allLocked) layer.allLocked = false;
	if (!layer.layers) return;
	for (var i = layer.layers.length - 1; i >= 0; i--)
		unlock(layer.layers[i]);
}

function deleteLayer (layer) {
	unlock(layer);
	activeDocument.activeLayer = activeDocument.artLayers[0];
	layer.remove();
}

function collectLayers (parent, collect) {
	outer:
	for (var i = parent.layers.length - 1; i >= 0; i--) {
		if (cancel) return;
		var layer = parent.layers[i];
		if (settings.ignoreHiddenLayers && !layer.visible) continue;
		if (settings.ignoreBackground && layer.isBackgroundLayer) {
			deleteLayer(layer);
			continue;
		}
		if (findTagLayer(layer, "ignore")) {
			deleteLayer(layer);
			continue;
		}
		var group = isGroup(layer);
		if (!group && layer.bounds[2] == 0 && layer.bounds[3] == 0) {
			deleteLayer(layer);
			continue;
		}

		// Ensure tags are valid.
		var re = /\[([^\]]+)\]/g;
		while (true) {
			var matches = re.exec(layer.name);
			if (!matches) break;
			var tag = matches[1].toLowerCase();
			if (group) {
				if (!isValidGroupTag(tag)) {
					var message = "Invalid group name:\n\n" + layer.name;
					if (isValidLayerTag(tag))
						message += "\n\nThe [" + tag + "] tag is only valid for layers, not for groups.";
					else
						message += "\n\nThe [" + tag + "] tag is not a valid tag.";
					error(message);
					continue outer;
				}
			} else if (!isValidLayerTag(tag)) {
				var message = "Invalid layer name:\n\n" + layer.name;
				if (isValidGroupTag(tag))
					message += "\n\nThe [" + tag + "] tag is only valid for groups, not for layers.";
				else
					message += "\n\nThe [" + tag + "] tag is not a valid tag.";
				error(message);
				continue outer;
			}
		}

		// Path is only valid if trimming whitespace.
		if (!settings.trimWhitespace && layer.name.search(/\[path:[^\]]+\]/i, "") != -1) {
			error("The [path:name] tag requires whitespace trimming to be enabled:\n" + layer.name);
			continue outer;
		}


		var changeVisibility = layer.kind == LayerKind.NORMAL || group;
		if (changeVisibility) {
			layer.wasVisible = layer.visible;
			layer.visible = true;
			if (layer.allLocked) layer.allLocked = false;
		}

		if (group && findTagLayer(layer, "merge")) {
			collectGroupMerge(layer);
			if (!layer.layers || layer.layers.length == 0) continue;
		} else if (layer.layers && layer.layers.length > 0) {
			collectLayers(layer, collect);
			continue;
		} else if (group)
			continue;

		if (changeVisibility) layer.visible = false;
		collect.push(layer);
	}
}

function collectGroupMerge (parent) {
	if (!parent.layers) return;
	for (var i = parent.layers.length - 1; i >= 0; i--) {
		var layer = parent.layers[i];
		if (settings.ignoreHiddenLayers && !layer.visible) continue;
		if (findTagLayer(layer, "ignore")) {
			deleteLayer(layer);
			continue;
		}

		collectGroupMerge(layer);
	}
}

function isValidGroupTag (tag) {
	return isValidLayerTag(tag) || tag == "merge";
}

function isValidLayerTag (tag) {
	switch (tag) {
	case "category":
	case "brandLayer":
	case "brandLayerOrder":
	case "folder":
	case "ignore":
		return true;
	}
	if (startsWith(tag, "category:")) return true;
	if (startsWith(tag, "brandLayer:")) return true;
	if (startsWith(tag, "brandLayerOrder:")) return true;
	if (startsWith(tag, "folder:")) return true;
	if (startsWith(tag, "path:")) return true;
	return false;
}

function isGroup (layer) {
	return layer.typename == "LayerSet";
}

function stripTags (name) {
	return trim(name.replace(/\[[^\]]+\]/g, ""));
}

function findTagLayer (layer, tag) {
	var groupTag = isValidGroupTag(tag), layerTag = isValidLayerTag(tag);
	if (endsWith(tag, ":")) tag = tag.slice(0, -1);
	var re = new RegExp("\\[" + tag + "(:[^\\]]+)?\\]", "i");
	while (layer) {
		var group = isGroup(layer);
		if (((group && groupTag) || (!group && layerTag)) && re.exec(layer.name)) return layer;
		layer = layer.parent;
	}
	return null;
}

function findTagValue (layer, tag) {
	layer = findTagLayer(layer, tag);
	if (!layer) return null;
	if (endsWith(tag, ":")) tag = tag.slice(0, -1);
	var matches = new RegExp("\\[" + tag + ":([^\\]]+)\\]", "i").exec(layer.name);
	if (matches && matches.length) return trim(matches[1]);
	return stripTags(layer.name);
}

function getParentBone (boneLayer, bones) {
	var parentName = findTagValue(boneLayer.parent, "category") || "brandStart";
	var parent = get(bones, parentName);
	if (!parent) { // Parent bone group with no attachment layers.
		var parentParent = getParentBone(boneLayer.parent, bones);
		set(bones, parentName, parent = { name: parentName, parent: parentParent, children: [], x: 0, y: 0 });
		parentParent.children.push(parent);
	}
	return parent;
}

function jsonPath (jsonPath) {
	if (endsWith(jsonPath, ".json")) {
		var index = jsonPath.replace(/\\/g, "/").lastIndexOf("/");
		if (index != -1) return absolutePath(jsonPath.slice(0, index + 1)) + jsonPath.slice(index + 1);
		return absolutePath("./") + jsonPath;
	} 
	var name = decodeURI(originalDoc.name);
	return absolutePath(jsonPath) + name.substring(0, name.indexOf(".")) + ".json";
}

function folders (layer, path) {
	var folderLayer = findTagLayer(layer, "folder");
	return folderLayer ? folders(folderLayer.parent, findTagValue(folderLayer, "folder") + "/" + path) : path;
}

function error (message) {
	errors.push(message);
}

// Photoshop utility:

function get (object, name) {
	return object["_" + name];
}
function set (object, name, value) {
	object["_" + name] = value;
}
function stripName (name) {
	return name.substring(1);
}

function rulerOrigin () {
	var action = new ActionReference();
	action.putEnumerated(cID("Dcmn"), cID("Ordn"), cID("Trgt"));
	var result = executeActionGet(action);
	return [result.getInteger(sID("rulerOriginH")) >> 16, result.getInteger(sID("rulerOriginV")) >> 16];
}

function rasterizeAll () {
	try {
		executeAction(sID("rasterizeAll"), undefined, DialogModes.NO);
	} catch (ignored) {}
}

function rasterizeStyles (layer) {
	try {
		activeDocument.activeLayer = layer;
		var desc = new ActionDescriptor();
		var ref = new ActionReference();
		ref.putEnumerated(cID("Lyr "), cID("Ordn"), cID("Trgt"));
		desc.putReference(cID("null"), ref);
		desc.putEnumerated(cID("What"), sID("rasterizeItem"), sID("layerStyle"));
		executeAction(sID("rasterizeLayer"), desc, DialogModes.NO);
	} catch (ignored) {}
}

function scaleImage () {
	var imageSize = activeDocument.width.as("px") * settings.scale;
	activeDocument.resizeImage(UnitValue(imageSize, "px"), null, null, ResampleMethod.BICUBICSHARPER);
}

var history;
function storeHistory () {
	history = activeDocument.activeHistoryState;
}
function restoreHistory () {
	activeDocument.activeHistoryState = history;
}

function scriptDir () {
	var file;
	if (!cs2)
		file = $.fileName;
	else {
		try {
			var error = THROW_ERROR; // Force error which provides the script file name.
		} catch (ex) {
			file = ex.fileName;
		}
	}
	return new File(file).parent + "/";
}

function absolutePath (path) {
	path = trim(path);
	if (!startsWith(path, "./")) {
		var absolute = decodeURI(new File(path).absoluteURI);
		if (!startsWith(absolute, decodeURI(new File("child").parent.absoluteURI))) return absolute + "/";
		path = "./" + path;
	}
	if (path.length == 0)
		path = decodeURI(activeDocument.path);
	else if (startsWith(settings.imagesDir, "./"))
		path = decodeURI(activeDocument.path) + path.substring(1);
	path = (new File(path).fsName).toString();
	path = path.replace(/\\/g, "/");
	if (path.substring(path.length - 1) != "/") path += "/";
	return path;
}

function cID (id) {
	return charIDToTypeID(id);
}

function sID (id) {
	return stringIDToTypeID(id);
}

function bgColor (control, r, g, b) {
	control.graphics.backgroundColor = control.graphics.newBrush(control.graphics.BrushType.SOLID_COLOR, [r, g, b]);
}

function deselectLayers () {
	var desc = new ActionDescriptor();
	var ref = new ActionReference();
	ref.putEnumerated(cID("Lyr "), cID("Ordn"), cID("Trgt"));
	desc.putReference(cID("null"), ref);
	executeAction(sID("selectNoLayers"), desc, DialogModes.NO);
}

function convertToRGB () {
	var desc = new ActionDescriptor();
	desc.putClass(cID("T   "), cID("RGBM"));
	desc.putBoolean(cID("Mrge"), false);
	desc.putBoolean(cID("Rstr"), true);
	executeAction(cID("CnvM"), desc, DialogModes.NO);
}

function savePNG (file) {
	var options = new PNGSaveOptions();
	options.compression = 6;
	activeDocument.saveAs(file, options, true, Extension.LOWERCASE);
}

function saveJPG (file) {
	var options = new JPEGSaveOptions();
    
options.quality = 12;
options.embedColorProfile = true;
options.formatOptions = FormatOptions.PROGRESSIVE;
if(options.formatOptions == FormatOptions.PROGRESSIVE){
options.scans = 5};
options.matte = MatteType.NONE;

 
	activeDocument.saveAs(file, options, true, Extension.LOWERCASE);
}
// JavaScript utility:

function countAssocArray (obj) {
	var count = 0;
	for (var key in obj)
		if (obj.hasOwnProperty(key)) count++;
	return count;
}

function trim (value) {
	return value.replace(/^\s+|\s+$/g, "");
}

function startsWith (str, prefix) {
	return str.indexOf(prefix) === 0;
}

function endsWith (str, suffix) {
	return str.indexOf(suffix, str.length - suffix.length) !== -1;
}

function quote (value) {
	return '"' + value.replace(/"/g, '\\"') + '"';
}


 
	
///////////////////////////////////////////////////////////////////////////////
// renameLayers - rename layers, top to bottom, or bottom to top
///////////////////////////////////////////////////////////////////////////////
function renameLayers(ref, prefs) {
	// declare local variables
	var len = ref.layers.length;

	// rename layers top to bottom
	if (prefs.topToBottom) {
		for (var i = 0; i < len; i++) {
			rename();
		}
	}
	// rename layers bottom to top
	else {
		for (var i = len - 1; i >= 0; i--) {
			rename();
		}
	}

	// rename - rename layer
	function rename() {
		var layer = ref.layers[i];
		var vis = layer.visible;
		var txt = ".png";
var txt = "thebrand"+Math.floor(Math.random() * 100);
		// check for groups
		if (layer.typename == 'LayerSet') {
			renameLayers(layer, prefs);
		}
		// rename layer
		else {
			layer.name = layer.name.concat(txt);
			layer.name = layer.name.replace(" ", "_");
		 layer.name = layer.name.replace("@", "_");
			layer.name = layer.name.replace("(", "");
			layer.name = layer.name.replace(")", "");
 

			if (!vis) {
				layer.visible = false;
			}
			prefs.countFrom++;
		}
	}
}
 

 
function determinelayerkind (layer) {
if(layer.kind == LayerKind.TEXT) {layerkind = "Text Layer";return layerkind;} // Text Layer
else if(layer.kind == LayerKind.SOLIDFILL) {layerkind = "Shape Layer";return layerkind; } /* Shape Layer */ 
else if(layer.kind == LayerKind.BLACKANDWHITE) {layerkind = "Black and White adjustment layer";return layerkind; } /* Black and White */ 
else if(layer.kind == LayerKind.BRIGHTNESSCONTRAST) {layerkind = "Brightness contrast adjustment layer";return layerkind; } /* Brightness contrast adjustment layer */ 
else if(layer.kind == LayerKind.CHANNELMIXER) {layerkind = "Channel mixer adjustment layer";return layerkind; } /* Channel mixer adjustment layer */ 
else if(layer.kind == LayerKind.COLORBALANCE) {layerkind = "Color balance adjustment layer";return layerkind; } /* Color balance adjustment layer */ 
else if(layer.kind == LayerKind.CURVES) {layerkind = "Curves adjustment layer";return layerkind; } /* Curves adjustment layer */
else if(layer.kind == LayerKind.EXPOSURE) {layerkind = "Exposure layer";return layerkind; } /* Exposure layer */ 
else if(layer.kind == LayerKind.GRADIENTFILL) {layerkind = "Gradient fill";return layerkind; } /* Gradient fill */ 
else if(layer.kind == LayerKind.GRADIENTMAP) {layerkind = "Gradient map adjustment layer";return layerkind; } /* Gradient map adjustment layer */ 
else if(layer.kind == LayerKind.HUESATURATION) {layerkind = "Hue saturation adjustment layer";return layerkind; } /* Hue saturation adjustment layer */ 
else if(layer.kind == LayerKind.INVERSION) {layerkind = "Invert adjustment layer";return layerkind; } /* Invert adjustment layer */ 
else if(layer.kind == LayerKind.LAYER3D) {layerkind = "3D layer";return layerkind; } /* 3D layer */
else if(layer.kind == LayerKind.LEVELS) {layerkind = "Levels adjustment layer";return layerkind; } /* Levels adjustment layer */ 
else if(layer.kind == LayerKind.NORMAL) {layerkind = "Normal layer";return layerkind; } /* Normal Layer */ 
else if(layer.kind == LayerKind.PATTERNFILL) {layerkind = "Pattern fill layer";return layerkind; } /* Pattern fill layer */ 
else if(layer.kind == LayerKind.PHOTOFILTER) {layerkind = "Photo filter layer";return layerkind; } /* Photo filter layer */ 
else if(layer.kind == LayerKind.POSTERIZE) {layerkind = "Posterize adjustment layer";return layerkind; } /* Posterize adjustment layer */ 
else if(layer.kind == LayerKind.SELECTIVECOLOR) {layerkind = "Selective color adjustment layer.";return layerkind; } /* Selective color adjustment layer */ 
else if(layer.kind == LayerKind.SMARTOBJECT) {layerkind = "Smart object layer";return layerkind; } /* Smart object layer */ 
else if(layer.kind == LayerKind.THRESHOLD) {layerkind = "Threshold adjustment layer";return layerkind; } /* Threshold adjustment layer */ 
else if(layer.kind == LayerKind.VIBRANCE) {layerkind = "Vibrance layer";return layerkind; } /* Vibrance layer */ 
else if(layer.kind == LayerKind.VIDEO) {layerkind = "Video layer";return layerkind; } /* Video layer */ 
}