Main Page
 The gatekeeper of reality is
 quantified imagination.

Stay notified when site changes by adding your email address:

Your Email:

Bookmark and Share
Email Notification
Project Adobe Photoshop JSX Map Maker
    Purpose
The purpose of this project is to demonstrate how you can use Adobe Photoshop CS2 to create 2D maps from an external file containing the X, Y coordinates of objects.


How I Approach This Project
This work was based on a larger project I had undertaken with an MMO-PVP game a while back. Given the sheer size of the 2D map ~10002equivalent miles and no mechanisms to identify all player positions relative to your own (perhaps part of "fog of war") it was clear that a method was needed in order to "map out" the entire area to get a top-down view of the entire battlespace in order to formulate effective strategy. Thus this map maker using Adobe Photoshop CS2 was created that accepts the 2D X, Y coordinates of objects so that they can be plotted onto a map.

Let's Begin
The things that you will need is Adobe Photoshop CS2 or later with the ExtendScript Toolkit (where you put the JSX) and 4 small images (one representing each type of object you want to map). Additionally, when this iteration of JSX was put together, due to the sheer volume of objects the script was geared to creating a map for a particular object at a time. With some tweeks you could adjust such behavior.

The plain-text file that holds the object coordinates is called "map-coordinates.txt" where each row in the text file represents a separate object. There are also a few other attributes that are handled but this, too, could be tweeked.

The entire JSX is included below. It is important to note that, aside from needing your own small images to place on a map, you'll also have to change the file paths that will be unique to your computer.

#target photoshop
app.bringToFront();

function main() {
app.displayDialogs = DialogModes.NO;
preferences.rulerUnits = Units.PIXELS;
preferences.typeUnits = TypeUnits.PIXELS;
/* Dimensions of the map that will be generated and size of the border */
var imageWidth = 3600;
var imageHeight = 3600;
var imageBoundsBorder = 2;
/* Maximum size of the largest plot image */
var importImgWidth = 22;
var importImgHeight = 24;
/* Maximum size of the text that goes under the plot image */
var textPointWidth = 124;
var textPointWidthNoType = 75;
var textPointHeight = 12;
/* Text specifications */
var fillColor = "FFFFFF";
var textColor = "000000";
var textFont = "Arial";
var textSize = 12;
/* Create the new document */
backgroundColor.rgb.hexValue = fillColor;
foregroundColor.rgb.hexValue = textColor;
var headerDoc = documents.add(imageWidth, imageHeight, 72, "Map", NewDocumentMode.RGB, DocumentFill.BACKGROUNDCOLOR, 1);
/* Read map coordinates of plain-text file "map-coordinates.txt" and dump into array */
/* Plain-text Row format of file: Aes 1039, 1200-(tower)-25-25 */
/* The plotted image title is "Aes 1039, 1200" */
/* The type of image to show is: (tower) */
/* The re-calculated coordinate plot points to accurately place image on map is: 25, 25 */
var loadFile = File("c:\\Users\\flapjacks\\Downloads\\map-coordinates.txt");
var saveNameOfFile = "";
var datarows = new Array();
if (loadFile.open( "r" )) {
	datarows = loadFile.read(loadFile.length).split("\n");
	loadFile.close();
}
/* Iterate through the rows of data we've got and create the map */
for (var r = 0; r < datarows.length; r++) {
	var row = datarows[r];
	var displayTxt = row.split("-")[0];
	var displayType = row.split("-")[1].split("-")[0];
	var displayX = parseInt(row.split("-")[2].split("-")[0]);
	var displayY = parseInt(row.split("-")[3]);
	if (displayX <= 0) { displayX = 0; }
	if (displayY <= 0) { displayY = 0; }
	//var msg = "Display Text: " + displayTxt + "\n";
	//msg = msg + "Display Type: " + displayType + "\n";
	//msg = msg + "X = " + displayX + "\n";
	//msg = msg + "Y = " + displayY + "\n";
	/* Offset positioning if it will cause plotted image or text to appear outside the bounds of document */
	// Assess X-Axis Left
	if (displayX <= imageBoundsBorder) {
		displayX = imageBoundsBorder + 2;
	}
	// Assess X-Axis Right - special handling depending on whether or not there is (...) present or not which changes the length of the string
	if (displayType.length > 2) {
		if ((displayX + textPointWidth + (imageBoundsBorder + 2)) >= imageWidth) {
			displayX = imageWidth - (textPointWidth + (imageBoundsBorder + 2));
		}
	}
	else {
		if ((displayX + textPointWidthNoType + (imageBoundsBorder + 2)) >= imageWidth) {
			displayX = imageWidth - (textPointWidthNoType + (imageBoundsBorder + 2));
		}
	}
	// Assess Y-Axis Top
	if (displayY <= imageBoundsBorder) {
		displayY = imageBoundsBorder + 2;
	}
	// Assess Y-Axis Bottom
	if ((displayY + importImgHeight + textPointHeight + (imageBoundsBorder + 2)) >= imageHeight) {
		displayY = imageHeight - (importImgHeight + textPointHeight + (imageBoundsBorder + 2));
	}

	/* Determine the type of image to plot */
	var imgFileLocation = "";
	if (displayType.toLowerCase() == "(tower)") {
		imgFileLocation = "c:\\Users\\flapjacks\\Downloads\\tower-tiny.png";
		saveNameOfFile = "towers";
	}
	else if (displayType.toLowerCase() == "(hive)") {
		imgFileLocation = "c:\\Users\\flapjacks\\Downloads\\hive-tiny.png";
		saveNameOfFile = "hives";
	}
	else if (displayType.toLowerCase() == "(outpost)") {
		imgFileLocation = "c:\\Users\\flapjacks\\Downloads\\outpost-tiny.png";
		saveNameOfFile = "outposts";
	}
	else {
		imgFileLocation = "c:\\Users\\flapjacks\\Downloads\\castle-tiny.png";
		saveNameOfFile = "castles";
	}
	/* Plot the image */
	// Open specific file and place on the main document "headerDoc" at the top of the list of layers
	var fileRef = new File(imgFileLocation);
	var doc = app.open(fileRef);
	doc.changeMode(ChangeMode.RGB);
	doc.bitsPerChannel = BitsPerChannelType.EIGHT;
	var layer = doc.activeLayer;
	// move image to the main document "headerDoc" as the top-most layer
	layer.duplicate(headerDoc, ElementPlacement.PLACEATBEGINNING);
	//close document to avoid error "The requested action requires that the target document is the frontmost document"
	doc.close(SaveOptions.DONOTSAVECHANGES);
	// re-position the new layer in the main document "headerDoc"
	var layerimgmv = headerDoc.activeLayer;
	var imgX = displayX;
	var imgY = displayY;
	layerimgmv.translate(imgX, imgY);
	/* Plot the text to accompany the duplicated image that is in the main document "headerDoc" */
	var imageText = displayTxt + " " + displayType;
	var textLayer = headerDoc.artLayers.add();
	textLayer.kind = LayerKind.TEXT;
	textLayer.textItem.contents = imageText;
	textLayer.textItem.font = textFont;
	textLayer.textItem.color = foregroundColor;
	textLayer.textItem.size = textSize;
	textLayer.textItem.antiAliasMethod = AntiAlias.SHARP;
	// re-position the new layer text to below the image
	var txtX = imgX;
	var txtY = (imgY + importImgHeight + (textSize / 1.2));
	textLayer.textItem.position = Array(txtX, txtY);
	/* Flatten new document to avoid adding too many layers and running out of memory */
	headerDoc.flatten();
	}
	/* END: for (var r = 0; r < datarows.length; r++) */
/* Apply border around the new map document */
var fillColor = new RGBColor;
fillColor.hexValue = foregroundColor.rgb.hexValue;
/* Apply boundary around the content */
// Top
var selectedRegion = Array(Array(0, 0), Array(0, imageBoundsBorder), Array(imageWidth, imageBoundsBorder), Array(imageWidth, 0));
headerDoc.selection.select(selectedRegion);
headerDoc.selection.fill(fillColor);
headerDoc.selection.deselect();
// Bottom
selectedRegion = Array(Array(0, (imageHeight - imageBoundsBorder)), Array(0, imageHeight), Array(imageWidth, imageHeight), Array(imageWidth, (imageHeight - imageBoundsBorder)));
headerDoc.selection.select(selectedRegion);
headerDoc.selection.fill(fillColor);
headerDoc.selection.deselect();
// Left
selectedRegion = Array(Array(0, 0), Array(0, imageHeight), Array(imageBoundsBorder, imageHeight), Array(imageBoundsBorder, 0));
headerDoc.selection.select(selectedRegion);
headerDoc.selection.fill(fillColor);
headerDoc.selection.deselect();
// Right
selectedRegion = Array(Array((imageWidth - imageBoundsBorder), 0), Array((imageWidth - imageBoundsBorder), imageHeight), Array(imageWidth, imageHeight), Array(imageWidth, 0));
headerDoc.selection.select(selectedRegion);
headerDoc.selection.fill(fillColor);
headerDoc.selection.deselect();
/* Save the new map document */
var saveFile = new File("c:\\Users\\flapjacks\\Downloads\\" + saveNameOfFile + ".png");
var headerDocSaveOptions = new PNGSaveOptions();
headerDoc.saveAs(saveFile, headerDocSaveOptions, true, Extension.LOWERCASE);
headerDoc.close(SaveOptions.DONOTSAVECHANGES);
}
/* Run the script function */
main();


About Joe