Copy link to clipboard
Copied
This one would transform a placed image according to a four-point path.
// works only if the path for the tv-screens is comprised of only four corner points without handles;
// transforms the selected layer according to the selected or topmost path in the paths panel;
// use it at your own risk;
// 2008, pfaffenbichler;
#target photoshop
var myDocument = app.activeDocument;
var aPath = selectedPath2015 ();
var originalUnits = app.preferences.rulerUnits;
myDocument.pathItems[0].select();
myDocu
...
Copy link to clipboard
Copied
I have a code but it has too many steps, what I need is for it to fill the TV
(function () {
// Script variables
var abort;
var bounds;
var docMaster;
var mask;
var maskC;
var maskH;
var maskW;
var title = "Adobe Script Tutorial 8";
// Reusable UI variables
var g; // group
var p; // panel
var w; // window
// SETUP
if (!app.documents.length) {
alert("Open the master document", title, false);
return;
}
app.displayDialogs = DialogModes.NO;
app.preferences.rulerUnits = Units.PIXELS;
docMaster = app.activeDocument;
mask = docMaster.channels.getByName("mask");
docMaster.selection.load(mask);
bounds = docMaster.selection.bounds;
maskW = bounds[2] - bounds[0];
maskH = bounds[3] - bounds[1];
maskC = [bounds[0] + (maskW / 2), bounds[1] + (maskH / 2)];
function maskLayer() {
// Mask active layer using document selection.
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
desc1.putClass(charIDToTypeID("Nw "), charIDToTypeID("Chnl"));
ref1.putEnumerated(charIDToTypeID("Chnl"), charIDToTypeID("Chnl"), charIDToTypeID("Msk "));
desc1.putReference(charIDToTypeID("At "), ref1);
desc1.putEnumerated(charIDToTypeID("Usng"), charIDToTypeID("UsrM"), charIDToTypeID("RvlS"));
executeAction(charIDToTypeID("Mk "), desc1, DialogModes.NO);
}
function processFile(file) {
var doc;
var docWork;
var fileJpg;
var layer;
var layerC;
var layerH;
var layerW;
var saveOptions;
var scale;
var scaleH;
var scaleW;
docWork = docMaster.duplicate();
doc = app.open(file);
try {
progress.message(File.decode(doc.name));
// Do something with image here
app.activeDocument = doc;
doc.flatten();
// Resize image
scaleH = maskH / doc.height;
scaleW = maskW / doc.width;
scale = Math.max(scaleH, scaleW);
doc.resizeImage(doc.width * scale, doc.height * scale, null, ResampleMethod.BICUBICSHARPER);
// Copy image to work document.
layer = doc.layers[0].duplicate(docWork);
app.activeDocument = docWork;
docWork.activeLayer = layer;
// Resize image to fit in master mask.
bounds = layer.bounds;
layerW = bounds[2] - bounds[0];
layerH = bounds[3] - bounds[1];
layerC = [bounds[0] + (layerW / 2), bounds[1] + (layerH / 2)];
layer.translate(maskC[0] - layerC[0], maskC[1] - layerC[1]);
docWork.selection.load(mask);
maskLayer();
// Save JPG
fileJpg = new File(txtFolderOutput.text + "/" + doc.name.replace(/\.[^\.]*$/, "") + "-framed.jpg");
saveOptions = new JPEGSaveOptions();
saveOptions.embedColorProfile = true;
saveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
saveOptions.quality = 12;
docWork.saveAs(fileJpg, saveOptions);
progress.increment();
} finally {
doc.close(SaveOptions.DONOTSAVECHANGES);
docWork.close(SaveOptions.DONOTSAVECHANGES);
}
}
function progress(message) {
var b;
var t;
var w;
w = new Window("palette", "Progress", undefined, {
closeButton: false
});
t = w.add("statictext", undefined, message);
t.preferredSize = [450, -1];
b = w.add("progressbar");
b.preferredSize = [450, -1];
progress.close = function () {
w.close();
};
progress.increment = function () {
b.value++;
};
progress.message = function (message) {
t.text = message;
app.refresh();
};
progress.set = function (steps) {
b.value = 0;
b.minvalue = 0;
b.maxvalue = steps;
};
w.show();
app.refresh();
}
})();
Copy link to clipboard
Copied
Please explain the actual task.
Do you have to insert many screens into one (or several pictures), the same screen in multiple images, …?
Copy link to clipboard
Copied
only 1 image per screen. The important thing is that it can be stretched to fit the selection you create.
Copy link to clipboard
Copied
The transformation could be automated if you create a four-point-path instead of a Selection.
Copy link to clipboard
Copied
can you help me create a script to do that job. i thank you very much for that. it helps me a lot in my work
Copy link to clipboard
Copied
This one would transform a placed image according to a four-point path.
// works only if the path for the tv-screens is comprised of only four corner points without handles;
// transforms the selected layer according to the selected or topmost path in the paths panel;
// use it at your own risk;
// 2008, pfaffenbichler;
#target photoshop
var myDocument = app.activeDocument;
var aPath = selectedPath2015 ();
var originalUnits = app.preferences.rulerUnits;
myDocument.pathItems[0].select();
myDocument.pathItems[0].deselect();
myDocument.selection.deselect();
// switch units to pixels;
app.preferences.rulerUnits = Units.PIXELS;
// check path;
if (aPath == undefined) {var aPath = myDocument.pathItems[0]};
if (aPath != undefined) {
// confirm the path has 4 points;
if (aPath.subPathItems.length == 1 && myDocument.pathItems[0].subPathItems[0].pathPoints.length == 4) {
// get the horicontal and vertical coordinates in pixels;
var hor1 = Number(aPath.subPathItems[0].pathPoints[0].anchor[0]);
var hor2 = Number(aPath.subPathItems[0].pathPoints[1].anchor[0]);
var hor3 = Number(aPath.subPathItems[0].pathPoints[2].anchor[0]);
var hor4 = Number(aPath.subPathItems[0].pathPoints[3].anchor[0]);
var ver1 = Number(aPath.subPathItems[0].pathPoints[0].anchor[1]);
var ver2 = Number(aPath.subPathItems[0].pathPoints[1].anchor[1]);
var ver3 = Number(aPath.subPathItems[0].pathPoints[2].anchor[1]);
var ver4 = Number(aPath.subPathItems[0].pathPoints[3].anchor[1]);
// order the horicontal and vertical coordinates;
var horList = [hor1, hor2, hor3, hor4];
var verList = [ver1, ver2, ver3, ver4];
horList.sort(sortNumber);
verList.sort(sortNumber);
// check the horicontal value;
var leftPoints = new Array;
var rightPoints = new Array;
for (var k=0; k<aPath.subPathItems[0].pathPoints.length; k++) {
if (aPath.subPathItems[0].pathPoints[k].anchor[0] == horList[0]
|| aPath.subPathItems[0].pathPoints[k].anchor[0] == horList[1]) {
leftPoints = leftPoints.concat(aPath.subPathItems[0].pathPoints[k].anchor)
}
else {
rightPoints = rightPoints.concat(aPath.subPathItems[0].pathPoints[k].anchor)
}
};
// define the four cornerpoints;
if (leftPoints[1] <= leftPoints[3]) {
var aTopLeft = [leftPoints[0], leftPoints[1]]
var aBottomLeft = [leftPoints[2], leftPoints[3]];
}
else {
var aTopLeft = [leftPoints[2], leftPoints[3]]
var aBottomLeft = [leftPoints[0], leftPoints[1]];
};
if (rightPoints[1] <= rightPoints[3]) {
var aTopRight = [rightPoints[0], rightPoints[1]]
var aBottomRight = [rightPoints[2], rightPoints[3]];
}
else {
var aTopRight = [rightPoints[2], rightPoints[3]]
var aBottomRight = [rightPoints[0], rightPoints[1]];
};
// sort numbers, found at www.w3schools.com;
function sortNumber(a,b) {
return a - b;
};
//////////// transformation ////////////
// from adobe’s terminology.jsx;
const classChannel = app.charIDToTypeID('Chnl');
const classRectangle = app.charIDToTypeID('Rctn');
const enumNone = app.charIDToTypeID('None');
const eventSet = app.charIDToTypeID('setd');
const eventTransform = app.charIDToTypeID('Trnf');
const keySelection = app.charIDToTypeID('fsel');
const krectangleStr = app.stringIDToTypeID("rectangle");
const kquadrilateralStr = app.stringIDToTypeID("quadrilateral");
const keyBottom = app.charIDToTypeID('Btom');
const keyLeft = app.charIDToTypeID('Left');
const keyNull = app.charIDToTypeID('null');
const keyRight = app.charIDToTypeID('Rght');
const keyTo = app.charIDToTypeID('T ');
const keyTop = app.charIDToTypeID('Top ');
const typeOrdinal = app.charIDToTypeID('Ordn');
const unitPixels = app.charIDToTypeID('#Pxl');
// from adobe’s geometry.jsx;
//
// =================================== TPoint ===================================
//
function TPoint( x, y )
{
this.fX = x;
this.fY = y;
}
// TPoint Constants
const kTPointOrigion = new TPoint( 0, 0 );
TPoint.kOrigin = kTPointOrigion;
const kTPointInfinite = new TPoint( Infinity, Infinity );
TPoint.kInfinite = kTPointInfinite;
const kTPointClassname = "TPoint";
TPoint.prototype.className = kTPointClassname;
// Overloaded math operators
TPoint.prototype["=="] = function( Src )
{
return (this.fX == Src.fX) && (this.fY == Src.fY);
}
TPoint.prototype["+"] = function( b )
{
return new TPoint( this.fX + b.fX, this.fY + b.fY );
}
TPoint.prototype["-"] = function( b, reversed )
{
if (typeof(b) == "undefined") // unary minus
return new TPoint( -this.fX, -this.fY )
else
{
if (reversed)
return new TPoint( b.fX - this.fX, by.fY - this.fY );
else
return new TPoint( this.fX - b.fX, this.fY - b.fY);
}
}
//
// Multiply and divide work with scalars as well as points
//
TPoint.prototype["*"] = function( b )
{
if (typeof(b) == 'number')
return new TPoint( this.fX * b, this.fY * b );
else
return new TPoint( this.fX * b.fX, this.fY * b.fY );
}
TPoint.prototype["/"] = function( b, reversed )
{
if (reversed)
{
if (typeof(b) == "number")
debugger;
// Can't divide a number by a point
else
return new TPoint( b.fX / this.fX, b.fY / this.fY );
}
else
{
if (typeof(b) == 'number')
return new TPoint( this.fX / b, this.fY / b );
else
return new TPoint( this.fX / b.fX, this.fY / b.fY );
}
}
TPoint.prototype.toString = function()
{
return "[" + this.fX.toString() + "," + this.fY.toString() + "]";
}
TPoint.prototype.vectorLength = function()
{
return Math.sqrt( this.fX * this.fX + this.fY * this.fY );
}
//////////// the new corners ////////////
transformActiveLayer( [new TPoint(aTopLeft[0], aTopLeft[1]), new TPoint(aTopRight[0], aTopRight[1]), new TPoint(aBottomRight[0], aBottomRight[1]), new TPoint(aBottomLeft[0], aBottomLeft[1])]);
// from adobe’s stacksupport.jsx;
// Apply a perspective transform to the current layer, with the
// corner TPoints given in newCorners (starts at top left, in clockwise order)
// Potential DOM fix
function transformActiveLayer( newCorners )
{
function pxToNumber( px )
{
return px.as("px");
}
var saveUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var i;
var setArgs = new ActionDescriptor();
var chanArg = new ActionReference();
chanArg.putProperty( classChannel, keySelection );
// setArgs.putReference( keyNull, chanArg );
var boundsDesc = new ActionDescriptor();
var layerBounds = app.activeDocument.activeLayer.bounds;
boundsDesc.putUnitDouble( keyTop, unitPixels, pxToNumber( layerBounds[1] ) );
boundsDesc.putUnitDouble( keyLeft, unitPixels, pxToNumber( layerBounds[0] ) );
boundsDesc.putUnitDouble( keyRight, unitPixels, pxToNumber( layerBounds[2] ) );
boundsDesc.putUnitDouble( keyBottom, unitPixels, pxToNumber( layerBounds[3] ) );
// setArgs.putObject( keyTo, classRectangle, boundsDesc );
// executeAction( eventSet, setArgs );
var result = new ActionDescriptor();
var args = new ActionDescriptor();
var quadRect = new ActionList();
quadRect.putUnitDouble( unitPixels, pxToNumber( layerBounds[0] ) );
// ActionList put is different from ActionDescriptor put
quadRect.putUnitDouble( unitPixels, pxToNumber( layerBounds[1] ) );
quadRect.putUnitDouble( unitPixels, pxToNumber( layerBounds[2] ) );
quadRect.putUnitDouble( unitPixels, pxToNumber( layerBounds[3] ) );
var quadCorners = new ActionList();
for (i = 0; i < 4; ++i)
{
quadCorners.putUnitDouble( unitPixels, newCorners[i].fX );
quadCorners.putUnitDouble( unitPixels, newCorners[i].fY );
}
args.putList( krectangleStr, quadRect );
args.putList( kquadrilateralStr, quadCorners );
executeAction( eventTransform, args );
// Deselect
deselArgs = new ActionDescriptor();
deselRef = new ActionReference();
deselRef.putProperty( classChannel, keySelection );
deselArgs.putReference( keyNull, deselRef );
deselArgs.putEnumerated( keyTo, typeOrdinal, enumNone );
executeAction( eventSet, deselArgs );
app.preferences.rulerUnits = saveUnits;
}
// resets the preferences units;
app.preferences.rulerUnits = originalUnits
}
else {
alert ("the topmost path does not conform to the requirements, it either comprises of more than one path or does not have exactly four points")};
};
////// determine selected path, updated 09.2015 //////
function selectedPath2015 () {
try {
var ref = new ActionReference();
ref.putProperty (stringIDToTypeID("property"), stringIDToTypeID("targetPathIndex"));
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var docDesc = executeActionGet(ref);
return app.activeDocument.pathItems[docDesc.getInteger(stringIDToTypeID("targetPathIndex"))]
}
catch (e) {return undefined}
};
Copy link to clipboard
Copied
you are so good. it is amazing. it works very well. thank you very much. i think a lot of people will need it. have a nice day, i don't know how to thank you
Copy link to clipboard
Copied
You’re welcome.
You may be able to amend the Script to more closely meet your needs, for example by providing a file-selection-dialog (for placing an external image) instead of it working on an existing Smart Object.
Copy link to clipboard
Copied
i am adding some steps to fit my work i am doing. but the hardest part you have already helped me complete them. awesome, you are so good, i will try to be a part of you
Copy link to clipboard
Copied
Copy link to clipboard
Copied
No, the Path has to have exactly four points to make the intended transformation unequivocally clear.
How did you create the Path? Can you provide the file with the path?
Copy link to clipboard
Copied
This is the photo I saved the path. There will be many cases where the path number is greater than 4. I know it is very difficult but I still ask you if there is any other way. If not, then I still thank you very much for helping me all this time, I wish you good health. Thank you very much
Copy link to clipboard
Copied
Those paths are »no good«.
I suppose it would be possible to »filter out« the offending parts and calculate the proper fourth point, but it would be easier to use two separate paths.
Copy link to clipboard
Copied
Great script! Though I’m sorry it doesn’t work with smart objects 😓. That would significantly increase its value!
Copy link to clipboard
Copied
It should work on Smart Objects.
Could you please post screenshots with the pertinent Panels (Toolbar, Layers, Options Bar, …) visible to clarify?
Copy link to clipboard
Copied
đúng vậy sẽ thật tuyệt nếu nó có thể hoạt động một cách thông minh. vì không phải lúc nào màn hình cũng là hình chữ nhật, nó có thể là màn hình cong hoặc có đồ vật khác che lấp. kịch bản trên đã hoạt đống rất tốt với những trường hợp màn hình là hình chữ nhật có 4 góc, nhưng đôi khi vùng chọn bị lệch vài pixel thì chúng sẽ không hoạt động, chúng cần 1 vùng chọn chính xác tuyệt đối
Copy link to clipboard
Copied
Copy link to clipboard
Copied
@Andrew Bold , could you please provide the file? (feel free to black out or blur or mosaic the images.)
Might be related to ruler units, but I thought I had addressed that issue.
Copy link to clipboard
Copied
Surprisingly, when I changed the image size a bit, the script started working fine with smart objects too.
But it's not because of the small original file resolution. Because then I reduced the image size again to smaller numbers than the original one. And the script still continued to work 🙃
It doesn't want to work with the original file for some reason, but if you resize the image by +1 pixel, everything starts working 🙂
And this is the situation with all files, not just this one.
In fact, it is enough for me to write two steps in the action ‘Reduce image by 1 pixel’, ‘increase image by 1 pixel’ before the script. And then everything will work in my case 😃
Copy link to clipboard
Copied
Changing both images to 300ppi (without resampling) also seems to work …
I am not sure yet what the actual problem is.
Copy link to clipboard
Copied
Please try this:
// works only if the path for the tv-screens is comprised of only four corner points without handles;
// transforms the selected layer according to the selected or topmost path in the paths panel;
// transformation function by r-bin;
// 2025, use it at your own risk;
var myDocument = app.activeDocument;
var aPath = selectedPath2015 ();
var originalUnits = app.preferences.rulerUnits;
myDocument.pathItems[0].select();
myDocument.pathItems[0].deselect();
myDocument.selection.deselect();
// switch units to pixels;
app.preferences.rulerUnits = Units.PIXELS;
// check path;
if (aPath == undefined) {var aPath = myDocument.pathItems[0]};
if (aPath != undefined) {
// confirm the path has 4 points;
if (aPath.subPathItems.length == 1 && myDocument.pathItems[0].subPathItems[0].pathPoints.length == 4) {
// get the horicontal and vertical coordinates in pixels;
var hor1 = Number(aPath.subPathItems[0].pathPoints[0].anchor[0]);
var hor2 = Number(aPath.subPathItems[0].pathPoints[1].anchor[0]);
var hor3 = Number(aPath.subPathItems[0].pathPoints[2].anchor[0]);
var hor4 = Number(aPath.subPathItems[0].pathPoints[3].anchor[0]);
var ver1 = Number(aPath.subPathItems[0].pathPoints[0].anchor[1]);
var ver2 = Number(aPath.subPathItems[0].pathPoints[1].anchor[1]);
var ver3 = Number(aPath.subPathItems[0].pathPoints[2].anchor[1]);
var ver4 = Number(aPath.subPathItems[0].pathPoints[3].anchor[1]);
// order the horicontal and vertical coordinates;
var horList = [hor1, hor2, hor3, hor4];
var verList = [ver1, ver2, ver3, ver4];
horList.sort(sortNumber);
verList.sort(sortNumber);
// check the horicontal value;
var leftPoints = new Array;
var rightPoints = new Array;
for (var k=0; k<aPath.subPathItems[0].pathPoints.length; k++) {
if (aPath.subPathItems[0].pathPoints[k].anchor[0] == horList[0]
|| aPath.subPathItems[0].pathPoints[k].anchor[0] == horList[1]) {
leftPoints = leftPoints.concat(aPath.subPathItems[0].pathPoints[k].anchor)
}
else {
rightPoints = rightPoints.concat(aPath.subPathItems[0].pathPoints[k].anchor)
}
};
// define the four cornerpoints;
if (leftPoints[1] <= leftPoints[3]) {
var aTopLeft = [leftPoints[0], leftPoints[1]]
var aBottomLeft = [leftPoints[2], leftPoints[3]];
}
else {
var aTopLeft = [leftPoints[2], leftPoints[3]]
var aBottomLeft = [leftPoints[0], leftPoints[1]];
};
if (rightPoints[1] <= rightPoints[3]) {
var aTopRight = [rightPoints[0], rightPoints[1]]
var aBottomRight = [rightPoints[2], rightPoints[3]];
}
else {
var aTopRight = [rightPoints[2], rightPoints[3]]
var aBottomRight = [rightPoints[0], rightPoints[1]];
};
// sort numbers, found at www.w3schools.com;
function sortNumber(a,b) {
return a - b;
};
//////////// the new corners ////////////
var p2 = [[aTopLeft[0], aTopLeft[1]], [aTopRight[0], aTopRight[1]], [aBottomRight[0], aBottomRight[1]], [aBottomLeft[0], aBottomLeft[1]]];
try {executeAction( stringIDToTypeID( "placedLayerResetTransforms" ), undefined, DialogModes.NO )} catch (e) {};
non_affine_transform(myDocument.activeLayer.bounds, p2);
// resets the preferences units;
app.preferences.rulerUnits = originalUnits
}
else {
alert ("the topmost path does not conform to the requirements, it either comprises of more than one path or does not have exactly four points")};
};
////// determine selected path, updated 09.2015 //////
function selectedPath2015 () {
try {
var ref = new ActionReference();
ref.putProperty (stringIDToTypeID("property"), stringIDToTypeID("targetPathIndex"));
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var docDesc = executeActionGet(ref);
return app.activeDocument.pathItems[docDesc.getInteger(stringIDToTypeID("targetPathIndex"))]
}
catch (e) {return undefined}
};
////// by r-bin //////
function non_affine_transform(p0, p1)
{
try {
var d = new ActionDescriptor();
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
d.putReference(stringIDToTypeID("null"), r);
var l = new ActionList();
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p0[0]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p0[1]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p0[2]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p0[3]);
d.putList(stringIDToTypeID("rectangle"), l );
var l = new ActionList();
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p1[0][0]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p1[0][1]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p1[1][0]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p1[1][1]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p1[2][0]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p1[2][1]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p1[3][0]);
l.putUnitDouble(stringIDToTypeID("pixelsUnit"), p1[3][1]);
d.putList(stringIDToTypeID("quadrilateral"), l);
d.putEnumerated(stringIDToTypeID("interpolation"), stringIDToTypeID("interpolationType"), stringIDToTypeID("bicubic"));
executeAction(stringIDToTypeID("transform"), d, DialogModes.NO);
return true;
}
catch (e) { alert(e); return false; }
};
Copy link to clipboard
Copied
Oh, yeah! Now it's working perfectly.
This script will come in very handy for creating mockups, as well as visualisations of banners and ad planes.
Thank you very much for your hard work! 🙏