• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Need Help: Programmatically Applying Free Transform Based on JSON Data in Photoshop Script

Community Beginner ,
Apr 07, 2024 Apr 07, 2024

Copy link to clipboard

Copied

Hello Adobe Community,

I am working on a Photoshop script that aims to automate the process of creating layers and adjusting their shapes based on coordinates defined in a JSON file. My script is currently able to generate new layers and draw rectangle shapes according to source coordinates (srcquad) provided in the JSON. The next step, where I'm seeking assistance, involves transforming these newly created layers to align with destination coordinates (dstquad), also specified in the JSON file. This transformation might require moving and distorting the layer to fit the new coordinates.

The specific function I'm working with is createLayerAndRectangle(sourceLayer, layerName, srcquad, dstquad). It successfully creates a layer and shapes based on the srcquad. My objective is to apply a free transform to the new layer to match the dstquad coordinates.

Here's an excerpt from my script:

 

 

#target photoshop
#include "JsonPlugins/json2.js"

app.bringToFront();

// 创建窗口对象
var win = new Window("dialog", "JSON File Selector");
win.orientation = "column";
win.alignChildren = "fill";

win.add("statictext", undefined, "Select JSON File:");
var inputGroup = win.add("group");
inputGroup.orientation = "row";
inputGroup.alignChildren = "center";

var jsonInput = inputGroup.add("edittext", undefined, "");
jsonInput.characters = 35;

var browseButton = inputGroup.add("button", undefined, "Browse...");
browseButton.onClick = function() {
    var file = File.openDialog("Select a JSON file", "*.json", false);
    if (file) jsonInput.text = file.fsName;
};

var buttonGroup = win.add("group");
buttonGroup.orientation = "row";
buttonGroup.alignChildren = "center";

var progressPanel = win.add("panel", undefined, "Progress");
progressPanel.alignChildren = "fill";
var progressBar = progressPanel.add("progressbar", undefined, 0, 100);
progressBar.preferredSize.width = 300;

var cancelRequested = false;
var cancelButton = progressPanel.add("button", undefined, "Cancel");
cancelButton.onClick = function() {
    cancelRequested = true;
};

var okButton = buttonGroup.add("button", undefined, "OK");
okButton.onClick = function() {
    var jsonFile = File(jsonInput.text);
    if (jsonFile.exists) {
        jsonFile.open('r');
        var jsonData = JSON.parse(jsonFile.read());
        jsonFile.close();

        progressBar.maxvalue = jsonData.length;
        progressBar.value = 0;
        var doc = app.activeDocument;
        var sourcelayer = doc.layers[0];

        var testForMax =  10; // 我们测试20张图片防止过过
        for (var i = 2; i < jsonData.length; i++) {
            var obj = jsonData[i];
            try {
                if(i >= testForMax) 
                break;

                createLayerAndRectangle(sourcelayer,"Layer " + (obj.hashId || i + 1), obj.srcquad,obj.desquad);
            } catch (error) {
                alert("Error processing object at index " + i + ": " + error.message);
                break; // Exit the loop if an error occurs
            }
            progressBar.value = i + 1;
        }

        alert("Process completed with " + i + " objects processed successfully.");
    } else {
        alert("JSON file does not exist.");
    }
};

var closeButton = buttonGroup.add("button", undefined, "Close");
closeButton.onClick = function() {
    win.close();
};

function createLayerAndRectangle(sourceLayer, layerName, srcquad, dstquad) {
    var doc = app.activeDocument;
    doc.activeLayer = sourceLayer;

    // source quad points
    var topLeft = [srcquad[0].x, srcquad[0].y];
    var topRight = [srcquad[3].x, srcquad[3].y];
    var bottomRight = [srcquad[2].x, srcquad[2].y];
    var bottomLeft = [srcquad[1].x, srcquad[1].y];
    var shapeRef = [topLeft, topRight, bottomRight, bottomLeft, topLeft];  

    // dest quad points
    var dstTopLeft = [dstquad[0].x, dstquad[0].y];
    var dstTopRight = [dstquad[3].x, dstquad[3].y];
    var dstBottomRight = [dstquad[2].x, dstquad[2].y];
    var dstBottomLeft = [dstquad[1].x, dstquad[1].y];

    if (topLeft == topRight && topRight == bottomLeft && bottomLeft == bottomRight) {
        return;  
    }

    doc.selection.select(shapeRef);
    // copy to new layer
    var idCpTL = charIDToTypeID("CpTL");
    executeAction(idCpTL, undefined, DialogModes.NO);

    // rename new layer
    var newLayer = doc.activeLayer;
    newLayer.name = layerName;
 
    //todo : how to free transform to dest quad ?
 
}


win.center();
win.show();

 

When doing this process manually, I would use Ctrl + T to initiate a free transform, then, while holding Ctrl, drag the corners to the desired coordinates specified by dstquad. My question to the community is: How can I replicate this manual process of free transforming a layer to an arbitrary quadrilateral shape programmatically through scripting?

Is there a known method, or could anyone suggest a series of commands within the Photoshop scripting framework that could mimic holding Ctrl and dragging points to new positions as done in the manual process?

Any guidance, advice, or suggestions would be greatly appreciated as I navigate through scripting this solution. Thank you for your time and help!

TOPICS
Actions and scripting , Windows

Views

132

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

People's Champ , Apr 07, 2024 Apr 07, 2024

Use the function. Where P0 is the initial rectangle, P1 is the final quadrilateral.

 

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.putUn
...

Votes

Translate

Translate
Adobe
People's Champ ,
Apr 07, 2024 Apr 07, 2024

Copy link to clipboard

Copied

Use the function. Where P0 is the initial rectangle, P1 is the final quadrilateral.

 

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; }        
    }

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Apr 08, 2024 Apr 08, 2024

Copy link to clipboard

Copied

Hello,

Firstly, I want to express my gratitude for the code and assistance you've provided earlier. I have attempted to implement the function based on your suggestions, but it seems my requirements might slightly differ from the solution provided. In my project, I'm working with a source quadrilateral (srcquad), which is a standard rectangle, and I need to transform it to match a target quadrilateral (dstquad). The target quadrilateral is an irregular shape that has undergone various transformations such as translation, rotation, and scaling.

My goal is to ensure that each point of the srcquad precisely matches the corresponding point on the dstquad. More specifically, I'm looking to align the top-left corner (index 0) of the srcquad with the top-left corner (index 0) of the dstquad and so on, ensuring a point-to-point alignment.

The challenge I'm facing is how to achieve this precise point-to-point transformation within Photoshop scripting. I understand this might involve non-affine transformations, but I'm unsure if Photoshop scripting supports such operations, or if there's another way to achieve this.

If possible, I would appreciate any advice on adjusting the method you've previously provided or if there are any other features or techniques within Photoshop scripting that could assist in accomplishing a precise transformation from a regular rectangle to an irregular quadrilateral that has been subject to matrix transformations.

Thank you again for your time and help. I look forward to your response.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Apr 08, 2024 Apr 08, 2024

Copy link to clipboard

Copied

Apologies... After running your code with a set of test data again, I believe it actually meets my needs. It seems there may have been an error in my dataset that led to my misunderstanding. I will double-check my data once more.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 16, 2024 May 16, 2024

Copy link to clipboard

Copied

Should p0 have x,y, coordinates in the same way p1 has?

I'm not sure how to set the values for p0 in the example given

 

(any help would be greatly appreciated) 🙂

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 16, 2024 May 16, 2024

Copy link to clipboard

Copied

LATEST

@r-bin stated »Where P0 is the initial rectangle«, so it’s an Array of four values. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines