During the development of Doomsday I had to position the 96 cards on A3 sheets for printing, and while its easy to use the guides, I found it was not always accurate particularly when zoomed out or in, therefore I wrote this Photoshop script to layout layers in an array for easy printing of game cards on pages.
Copy the code and paste it into a new .jsx file on your computer remembering to change the variables on lines 30-36 to the values that suit your desired print output.
Read the “change this value” comments in the code.
- leftMargin
- topMargin
- cardWidth
- cardHeight
- cardsInARow
- cardsInAColumn
- groupPages
Then load all the images as layers using the “Load files into stack” script that comes with Photoshop. Next resize your canvas to the page size of your printer (A4, A3 etc..).
Lastly run my script using file->scripts->browse and locate the saved jsx file.
I could make it real simple and make a dialog for this but using a hard coded script you only need to change the code once and a dialog would require you enter the values every time you set up your cards.
Oh don’t forget to add your cut lines as the top most layer, you can do this before and then lock the layer and the code will ignore the locked layers.
#target photoshop; app.bringToFront(); var doc = app.activeDocument; function positionLayer( lyr, x, y ) { // layerObject, Number, Number // if can not move because its locked return false if(lyr.isBackgroundLayer||lyr.positionLocked) { return false; } // get the layer bounds var layerBounds = lyr.bounds; // get top left position var layerX = layerBounds[0].value; var layerY = layerBounds[1].value; // the difference between where layer needs to be and is now var deltaX = x-layerX; var deltaY = y-layerY; // move the layer into position lyr.translate (deltaX, deltaY); return true; } function moveLayers() { var leftMargin = 83; // change this value for the left margin var topMargin = 51; // change this value for the top margin var cardWidth = 746; // change this value for width of the card var cardHeight = 1038;// change this value for height of the card var cardsInARow = 5 // change this value for number of cards across page var cardsInAColumn = 5 // change this value for number of rows of cards down page var groupPages = true; // set to false if you dont want the cards in groups var pageX = leftMargin; var pageY = topMargin; var cardsXCount = 1; var cardsYCount = 1; if(groupPages==true) { var theGroup = app.activeDocument.layerSets.add() } var length = doc.artLayers.length-1; for (var layer = length; layer >= 0 ; layer--) { var thisLayer = doc.artLayers[layer]; if(positionLayer(thisLayer, pageX,pageY)==true) { if(groupPages==true) { thisLayer.move(theGroup, ElementPlacement.INSIDE); } pageX += cardWidth; // width in pixels of you cards cardsXCount ++; if(cardsXCount>cardsInARow) { cardsXCount = 1; pageX = leftMargin; // reset to the left margin pageY += cardHeight; cardsYCount ++; if(cardsYCount>cardsInAColumn) { pageY = topMargin; cardsYCount = 1; if(groupPages==true) { theGroup = app.activeDocument.layerSets.add(); } } } } } } moveLayers();
After developing the above code I added some more featurs to it, in this version it does more of the work for you. You just need to set the card width and height, and it reads the page size from photoshop and then it ads the cut marks and centers the cards on the page.
Hope this works better for you.
#target photoshop; app.bringToFront(); var doc = app.activeDocument; //var debug = new File("f:\script.txt"); app.preferences.rulerUnits = Units.PIXELS; // Set the ruler units to PIXELS var w = doc.width; var h = doc.height; var groupPages = true; // set to false if you dont want the cards in groups var cardWidth = 746; // change this value for width of the card var cardHeight = 1038; // change this value for height of the card var cardsInARow = Math.floor(w/cardWidth); // change this value for number of cards across page var cardsInAColumn = Math.floor(h/cardHeight); // change this value for number of rows of cards down page var leftMargin = (w-(cardsInARow*cardWidth))/2; // change this value for the left margin (83) var topMargin = (h-(cardsInAColumn*cardHeight))/2; // change this value for the top margin (51) function positionLayer( lyr, x, y ) { // layerObject, Number, Number // if can not move because its locked return false if(lyr.isBackgroundLayer||lyr.positionLocked) { return false; } // get the layer bounds var layerBounds = lyr.bounds; // get top left position var layerX = layerBounds[0].value; var layerY = layerBounds[1].value; // the difference between where layer needs to be and is now var deltaX = x-layerX; var deltaY = y-layerY; // debug.open('a'); // debug.writeln("x:"+x+" y:"+y+" layerX:"+layerX+" layerY:"+layerY+" deltaX:"+deltaX+" deltaY:"+deltaY); // debug.close(); // move the layer into position lyr.translate (deltaX, deltaY); return true; } function toDPI(valu) { var defaultDPI = 72; var docDPI = 300; var dpiRation = docDPI/defaultDPI; return Math.floor(valu/dpiRation); } // exported from photoshop listener function DrawShape() { var doc = app.activeDocument; var y = arguments.length; var i = 0; var rectArray = []; for (i = 0; i < y; i++) { rectArray[i] = new PathPointInfo; rectArray[i].kind = PointKind.CORNERPOINT; rectArray[i].anchor = arguments[i]; rectArray[i].leftDirection = rectArray[i].anchor; rectArray[i].rightDirection = rectArray[i].anchor; } var lineSubPathArray = new SubPathInfo(); lineSubPathArray.closed = true; lineSubPathArray.operation = ShapeOperation.SHAPEADD; lineSubPathArray.entireSubPath = rectArray; var myPathItem = doc.pathItems.add("myPath", [lineSubPathArray]); var actionDescript = new ActionDescriptor(); var contentLayer = new ActionReference(); contentLayer.putClass(stringIDToTypeID("contentLayer")); actionDescript.putReference(charIDToTypeID("null"), contentLayer); var actionType = new ActionDescriptor(); var actionColor = new ActionDescriptor(); var color = new ActionDescriptor(); color.putDouble(charIDToTypeID("Rd "), 0.0); // R color.putDouble(charIDToTypeID("Grn "), 0.0); // G color.putDouble(charIDToTypeID("Bl "), 0.0); // B var rgbCoverted = charIDToTypeID("RGBC"); actionColor.putObject(charIDToTypeID("Clr "), rgbCoverted, color); actionType.putObject(charIDToTypeID("Type"), stringIDToTypeID("solidColorLayer"), actionColor); actionDescript.putObject(charIDToTypeID("Usng"), stringIDToTypeID("contentLayer"), actionType); executeAction(charIDToTypeID("Mk "), actionDescript, DialogModes.NO); myPathItem.remove(); } // exported from photoshop listener function addShape() { var idAddT = charIDToTypeID( "AddT" ); var desc16 = new ActionDescriptor(); var idnull = charIDToTypeID( "null" ); var ref5 = new ActionReference(); var idPath = charIDToTypeID( "Path" ); var idOrdn = charIDToTypeID( "Ordn" ); var idTrgt = charIDToTypeID( "Trgt" ); ref5.putEnumerated( idPath, idOrdn, idTrgt ); desc16.putReference( idnull, ref5 ); var idT = charIDToTypeID( "T " ); var desc17 = new ActionDescriptor(); var idTop = charIDToTypeID( "Top " ); var idPxl = charIDToTypeID( "#Pxl" ); desc17.putUnitDouble( idTop, idPxl, arguments[0] ); var idLeft = charIDToTypeID( "Left" ); var idPxl = charIDToTypeID( "#Pxl" ); desc17.putUnitDouble( idLeft, idPxl, arguments[1] ); var idBtom = charIDToTypeID( "Btom" ); var idPxl = charIDToTypeID( "#Pxl" ); desc17.putUnitDouble( idBtom, idPxl,arguments[2] ); var idRght = charIDToTypeID( "Rght" ); var idPxl = charIDToTypeID( "#Pxl" ); desc17.putUnitDouble( idRght, idPxl, arguments[3] ); var idRctn = charIDToTypeID( "Rctn" ); desc16.putObject( idT, idRctn, desc17 ); executeAction( idAddT, desc16, DialogModes.NO ); } function addCutMarks() { var vCut = 0 var xT = Math.floor(toDPI(leftMargin)); var yT = Math.floor(toDPI(topMargin-50)); var yB = Math.floor(cardsInAColumn*cardHeight); var sw = toDPI(1); var sh = toDPI(yB+100); DrawShape([(xT),(yT)],[(xT+sw),(yT)],[(xT+sw),(yT+sh)],[(xT),(yT+sh)]); xT = Math.floor(leftMargin); yT = Math.floor(topMargin-50); yB = Math.floor(yT+(cardsInAColumn*cardHeight)+100); // verticle for(var vCut=0;vCut<cardsInARow;vCut++) { xT += cardWidth; addShape(yT,xT,yB,(xT+1)); } xT = Math.floor(leftMargin-50) yT = Math.floor(topMargin); xB = Math.floor(xT+(cardsInARow*cardWidth)+100); addShape(yT,xT,yT,xB); // horizontal for(var hCut=0;hCut<cardsInAColumn;hCut++) { yT += cardHeight; addShape(yT,xT,yT,xB); } } function moveLayers() { var pageX = leftMargin; var pageY = topMargin; var cardsXCount = 1; var cardsYCount = 1; if(groupPages==true) { var theGroup = app.activeDocument.layerSets.add() } var length = doc.artLayers.length-1; for (var layer = length; layer >= 0 ; layer--) { var thisLayer = doc.artLayers[layer]; if(positionLayer(thisLayer, pageX,pageY)==true) { if(groupPages==true) { thisLayer.move(theGroup, ElementPlacement.INSIDE); } pageX += cardWidth; // width in pixels of you cards cardsXCount ++; if(cardsXCount>cardsInARow) { cardsXCount = 1; pageX = leftMargin; // reset to the left margin pageY += cardHeight; cardsYCount ++; if(cardsYCount>cardsInAColumn) { pageY = topMargin; cardsYCount = 1; if(groupPages==true) { theGroup = app.activeDocument.layerSets.add(); } } } } } } moveLayers(); addCutMarks();