Copy link to clipboard
Copied
Is there a way to [script] transform/warp/arch? The TextItem object has it for text, but I want to warp an arbitrary rectangle in an ArtLayer. Thanks
Use the scriptlistner plugin to record the type of transform you need. Below is a cleaned up output of the arch warp
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putEnumerated( charIDToTypeID( "FTcs" ), charIDToTypeID( "QCSt" ), charIDToTypeID( "Qcsa" ) );
var desc1 = new ActionDescriptor()
Copy link to clipboard
Copied
Use the scriptlistner plugin to record the type of transform you need. Below is a cleaned up output of the arch warp
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putEnumerated( charIDToTypeID( "FTcs" ), charIDToTypeID( "QCSt" ), charIDToTypeID( "Qcsa" ) );
var desc1 = new ActionDescriptor();
desc1.putUnitDouble( charIDToTypeID( "Hrzn" ), charIDToTypeID( "#Rlt" ), 0.000000 );
desc1.putUnitDouble( charIDToTypeID( "Vrtc" ), charIDToTypeID( "#Rlt" ), -0.000000 );
desc.putObject( charIDToTypeID( "Ofst" ), charIDToTypeID( "Ofst" ), desc1 );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( stringIDToTypeID( "warpStyle" ), stringIDToTypeID( "warpStyle" ), stringIDToTypeID( "warpArch" ) );
desc2.putDouble( stringIDToTypeID( "warpValue" ), 50.000000 );
desc2.putDouble( stringIDToTypeID( "warpPerspective" ), 0.000000 );
desc2.putDouble( stringIDToTypeID( "warpPerspectiveOther" ), 0.000000 );
desc2.putEnumerated( stringIDToTypeID( "warpRotate" ), charIDToTypeID( "Ornt" ), charIDToTypeID( "Hrzn" ) );
desc2.putInteger( stringIDToTypeID( "uOrder" ), 4 );
desc2.putInteger( stringIDToTypeID( "vOrder" ), 2 );
desc.putObject( stringIDToTypeID( "warp" ), stringIDToTypeID( "warp" ), desc2 );
executeAction( charIDToTypeID( "Trnf" ), desc, DialogModes.NO );
Copy link to clipboard
Copied
Thanks - This is such an arcane way to do it! Kind of like borrowing assembly code... But it works. I use the technique in the following code to split an image into multiple tiles that look like photographs tossed on a table (be sure to define the drop1 style in PS):
// tile.jsx: tile image into 4x3 (actually CELLSMAX x CELLSMIN)
// Author: Eric Onasick (with help from Michael Hale), April 2009
// This script splits an image into 12 (or 16 if square) tiles, adds an external stroke of FOREGROUND color,
// and creates a new document that looks like a bunch of photos tossed on a table (color = BACKGROUND color)
// Make sure the colors are set using a Normal blend mode (e.g. set while on the Background layer)
// Works on any aspect ratio, and indep of whatever layers are present because it merges all into a new doc.
// Assumes you have defined a Style in the style palette called "drop1" with an 8/8/8 drop shadow at 135 degrees (not global light) and 64% opacity
#target photoshop
// debug level: 0-2 (0:disable, 1:break on error, 2:break at beginning)
$.level = 0;
// debugger; // launch debugger on next line
var CELLSMAX = 4 ; // number of tiles in larger dimension (or square)
var CELLSMIN = 3 ; // number of tiles in smaller dimension
var DROPSHADOWSTYLE = "drop1" ; // must be predefined in Adobe Photoshop
var SQUARETOLERANCE = 100 ; // number of pixels difference between width and height to call it square
/////////////////////////////////////////////////////////////////////////////
function Select( x, y, cx, cy, type) // select a region
{
var selRegion = Array(
Array( x, y ),
Array( x + cx, y ),
Array( x + cx, y + cy ),
Array( x, y + cy ),
Array( x, y )
) ;
doc.selection.select( selRegion, type ) ;
}
function ModifyTile() // add style, warp, roation and jitter to a tile
{
var tile = doc.activeLayer ; // current layer
tile.applyStyle( DROPSHADOWSTYLE ) ;
// add arch (courtesy Michael L Hale) to look like a curled photo
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putEnumerated( charIDToTypeID( "FTcs" ), charIDToTypeID( "QCSt" ), charIDToTypeID( "Qcsa" ) );
var desc1 = new ActionDescriptor();
desc1.putUnitDouble( charIDToTypeID( "Hrzn" ), charIDToTypeID( "#Rlt" ), 0.000000 );
desc1.putUnitDouble( charIDToTypeID( "Vrtc" ), charIDToTypeID( "#Rlt" ), 0.000000 );
desc.putObject( charIDToTypeID( "Ofst" ), charIDToTypeID( "Ofst" ), desc1 );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( stringIDToTypeID( "warpStyle" ), stringIDToTypeID( "warpStyle" ), stringIDToTypeID( "warpArch" ) );
var archLimit = 8 ;
var arch = Math.random() * archLimit - archLimit/2 ;
desc2.putDouble( stringIDToTypeID( "warpValue" ), arch ); // amount of arch
desc2.putDouble( stringIDToTypeID( "warpPerspective" ), 0.000000 );
desc2.putDouble( stringIDToTypeID( "warpPerspectiveOther" ), 0.000000 );
desc2.putEnumerated( stringIDToTypeID( "warpRotate" ), charIDToTypeID( "Ornt" ), charIDToTypeID( "Hrzn" ) );
desc2.putInteger( stringIDToTypeID( "uOrder" ), 4 );
desc2.putInteger( stringIDToTypeID( "vOrder" ), 2 );
desc.putObject( stringIDToTypeID( "warp" ), stringIDToTypeID( "warp" ), desc2 );
executeAction( charIDToTypeID( "Trnf" ), desc, DialogModes.NO );
// rotate a small random amount
var df = 2 ; // degrees of freedom, literally 🙂
var degrees = Math.random() * df - df/2 ; // range -df to df
tile.rotate( degrees ) ;
// translate a bit too
var xJitter = 100 ; // pixels
var yJitter = 100 ; // pixels
var dx = Math.random() * xJitter - xJitter/2 ;
var dy = Math.random() * yJitter - yJitter/2 ;
tile.translate( dx, dy ) ;
}
/// main code ///////////////////////////////////////////////////////////////////////////
app.bringToFront(); // in case we double clicked the file
app.displayDialogs = DialogModes.NO;
var strtRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// merge into new doc
var doc = app.activeDocument.duplicate( app.activeDocument.name + "_tiled" , true) ;
var cx = 1 ; // width of tile
var cy = 1 ; // height of tile
if (Math.abs( doc.width - doc.height ) < SQUARETOLERANCE ) // square-ish (in pixels)
{
cy = cx = doc.width / CELLSMAX ;
}
else if (doc.height < doc.width ) // LS
{
cx = doc.width / CELLSMAX;
cy = doc.height / CELLSMIN ;
}
else // PT
{
cx = doc.width / CELLSMIN ;
cy = doc.height / CELLSMAX ;
}
// divide up "source" layer:
var artLayerCurrent = doc.activeLayer ;
var strokefillcolor = app.foregroundColor ;
var dx = Math.round( cx / 16 ); // stroke width
var dy = dx ; // isometric (can change if you like)
doc.resizeCanvas( doc.width + 2 * dx, doc.height + 2 * dy ) ; // accomodate tile strokes at edges
for( var x = dx; x < doc.width - dx; x += cx )
{
for( var y = dy; y < doc.height - dy; y += cy )
{
Select( x, y, cx, cy ) ;
doc.selection.copy() ; // to clipboard
doc.paste( false ) ; // create a new tile layer
// add stroke
Select( x-dx, y-dy, cx + 2 * dx, cy + 2 * dy ) ; // select an area bigger than pasted part
Select( x, y, cx, cy, SelectionType.DIMINISH ) ; // deselect pasted part leaving stroke boundary
doc.selection.fill( strokefillcolor );
Select( x-dx, y-dy, cx + 2 * dx, cy + 2 * dy ) ; // select the whole thing now
ModifyTile() ; // add style, arch, rotation and jitter to each tile to simulate photographs
doc.activeLayer = artLayerCurrent ; // back to where we were for another bite
}
}
// fill bkgd layer (currently active layer)
doc.selection.selectAll() ;
doc.selection.fill( app.backgroundColor ) ;
doc.selection.deselect() ;
doc.resizeCanvas( doc.width * 1.1, doc.height * 1.1 ) ; // make bigger
// restore old state
app.preferences.rulerUnits = strtRulerUnits;
// caveat: I'm still learning so this code is an early attempt
Find more inspiration, events, and resources on the new Adobe Community
Explore Now