Thanks for looking
Inspired by,
Frank Thomas,
Ollie Johnston,
Glen Keane,
Milt Kahl
Alan Becker’s online YouTube tutorial on ‘12 principles of animation’
And Hopkins
this tool allows placing an image in a grid layout in a new photoshop document. it has some examples for creating a simple ui in photoshop using javascript. it also has some examples of writing methods/creating variables in photoshop javascript. it also is an example of storing a photoshop ui file in separate file than the core of the tool. there may be bugs or better ways to implement so please modify/use at your own risk.
here is a video of the tool in action:
//a simple tool to create story panels from an input image. example from a blank panel
//tested in Photoshop 10.0.1
//please modify/use at your own risk
#include "core.jsx"
/*check if input path is a valid image path
Args:
path (str): path to check ex: Users/Nathaniel/Desktop/photoshopTools/storyPanels/test_scene.jpg
Returns:
(bool): true if path is a valid image.
*/
function isPathValidImage(path)
{
var fileObj = new File(path);
var validExtensions = ["jpg", "jpeg", "png", "tif"];
if(!fileObj.exists)
{
return false;
}
var pathExt = path.split('.').pop().toLowerCase();
//check if path's extension is in valid extensions
for(var i=0; i<validExtensions.length; i++)
{
if(pathExt == validExtensions[i])
{
//path is valid extension. dont need to check any more extensions
return true;
}
}
return false;
}
/*
Returns:
(bool): true if there is a document open false otherwise
*/
function isDocumentOpen()
{
return app.documents.length > 0
}
function showUI(){
if(!isDocumentOpen())
{
alert("requires a document open to use tool.")
return
}
var dlg = new Window("dialog", "Panel Importer UI");
dlg.orientation = "column";
dlg.preferredSize = [600, 200];
dlg.alignChildren = "left"; //align all widgets in window to the left
//stores options for generating panels
var parameterGroupLabel = dlg.add("statictext", undefined, "1. choose parameters for final panel layout")
var parameterGroup = dlg.add("group");
parameterGroup.orientation = "row";
var numRowsLabel = parameterGroup.add("statictext", undefined, "rows:");
var numRowsIntField = parameterGroup.add("edittext", undefined, "2");
numRowsIntField.characters = 4; //set width
var numColsLabel = parameterGroup.add("statictext", undefined, "cols:");
var numColsIntField = parameterGroup.add("edittext", undefined, "2");
numColsIntField.characters = 4; //set width
var borderWidthPixelsLabel = parameterGroup.add("statictext", undefined, "border width (pixels):");
var borderWidthPixelsIntField = parameterGroup.add("edittext", undefined, "20");
borderWidthPixelsIntField.characters = 4; //set width
//
//limit int fields to numbers only
var intFields = [numRowsIntField, numColsIntField, borderWidthPixelsIntField];
//limit int fields to numbers
var sharedOnChange = function()
{
//alert("field changed:" + this.text);
//remove non numeric character
this.text = this.text.replace(/[^\d]/g, '');
}
//assign shared onChange function
for(var j=0; j<intFields.length; j++)
{
intFields[j].onChanging = sharedOnChange;
}
//
//button
var addPathBtn = dlg.add("button", undefined, "2. add image path to use for panel")
//stores image path
var imagePathText = dlg.add("statictext", undefined, "No Image Selected");
imagePathText.preferredSize = [600, 50];
var createPanelBtn = dlg.add("button", undefined, "3. create panels from image");
var closeBtn = dlg.add("button", undefined, "close");
//add function to button click
addPathBtn.onClick = function()
{
var fileObj = File.openDialog("Select Image");
if(fileObj)
{
selectedPath = fileObj.fsName;
if(!isPathValidImage(selectedPath))
{
alert("selected path not a valid image. exiting");
return;
}
imagePathText.text = selectedPath;
}
}
createPanelBtn.onClick = function()
{
var imagePath = imagePathText.text;
//get parameters from ui
var numRows = parseInt(numRowsIntField.text);
var numCols = parseInt(numColsIntField.text);
var numPanels = numRows*numCols;
var borderWidth = parseInt(borderWidthPixelsIntField.text);
var panelImporter = new PanelImporter(imagePath=imagePath,
numPanels=numPanels,
numRows=numRows,
numCols=numCols,
borderWidth=borderWidth);
panelImporter.doIt();
alert("yaay creating storyboard panels done!");
dlg.close(); //close ui when done so active document refreshed with story panels
}
closeBtn.onClick = function()
{
dlg.close();
}
dlg.show();
}
showUI();
//core.jsx
//old style class with ability to import an image multiple times to form a panel layout
/*
Args:
imagePath(str): path to image to use for each panel
numPanels(int): number of panels to create
numRows(int): number of rows for storyboard
numCols(int): number of cols for storyboard
borderWidth(int): how many pixels to separate panels
*/
function PanelImporter(imagePath, numPanels, numRows, numCols, borderWidth)//(imagePath, numPanels, numRows, numCols, borderWidth)
{
this.doc = app.activeDocument; //assumes in a created document. todo make a document if there is none
this._imagePath = imagePath;
this._numPanels = numPanels;
this._numRows = numRows;
this._numCols = numCols;
this._borderWidth = borderWidth;
/*do any additional initializations for this class
apparently cant run a method of this class in its init. when using old style function for class
*/
this._init = function()
{
this._images = this._getImages(this._imagePath, this._numPanels);//will hold image paths to use for each panel
}
/*
Args:
imagePath(str): path to image to use for each panel ex: /Users/Nathaniel/Desktop/photoshopTools/storyPanels/test_scene.jpg
*/
this.doIt = function()
{
this._init();
this._createPanels();
}
/*
Args:
imagePath(str): path to image to use for each panel ex: /Users/Nathaniel/Desktop/photoshopTools/storyPanels/test_scene.jpg
numPanels(int): number of times to repeat imagePath
Returns:
list(str): the imagePath repeated numPanels many times
*/
this._getImages = function(imagePath, numPanels)
{
var images = [];
//var imagePath = "/Users/Nathaniel/Desktop/photoshopTools/storyPanels/test_scene.jpg";
for(var i=0; i<numPanels; i++)
{
images.push(imagePath);
}
return images;
}
/*creates storyboard panels using a single image for each panel
*/
this._createPanels = function()
{
//var doc = app.activeDocument;
var targetDoc = this.doc;//app.activeDocument;
var images = this._images;
var numRows = this._numRows;
var numCols = this._numCols;
var borderWidth = this._borderWidth;
var imageIndex = 0; //will be used to query images
var numImages = images.length;
if(numImages > numRows*numCols)
{
alert("too many images. make sure number of images is smaller than number of rows multiplied by number of columns");
return;
}
for(var i=0; i<numRows; i++)
{
for(var j=0; j<numCols; j++)
{
if(imageIndex >= numImages)
{
break;
}
var pathToImage = images[imageIndex];
var fileObj = new File(pathToImage);
if(!fileObj.exists){
alert("image file doesnt exist");
return;
}
//open image file
var imgDoc = app.open(fileObj);
//select all and copy
imgDoc.selection.selectAll();
imgDoc.selection.copy();
//close the opened image file
imgDoc.close(SaveOptions.DONOTSAVECHANGES);
//paste image into active document
var newLayer = targetDoc.paste();
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
//set goal x y pixels
//width = right - left
//bounds [left, top, right, bottom]
var widthImage = newLayer.bounds[2].value - newLayer.bounds[0].value;
var heightImage = newLayer.bounds[3].value - newLayer.bounds[1].value;
var goalX = j*widthImage + (j+1)*borderWidth; //the columns are used for x coordinate
var goalY = i*heightImage + (i+1)*borderWidth;//the rows are used for the y coordinate
var curX = newLayer.bounds[0].value;
var curY = newLayer.bounds[1].value;
var dx = goalX - curX;
var dy = goalY - curY;
//move imported image to goal x, y pixels
newLayer.translate(dx, dy);
//increment image index
imageIndex += 1;
}
}
//restore original untis
app.preferences.rulerUnits = originalRulerUnits;
}
}
Thanks for looking