Search code examples
photoshop-script

How to keep margin(Positions) same while resizing objects


What is issue?

I don't want to confuse the community with my question so I'll tell that my question is Javascript based (Photoshop's DOM particularly). So if someone can help me on function/logic which requires basic javascript than they can take effort on reading further, Thanks.

Now; The situation is that I'm making a freebie of Photoshop Plugin (HTML Panel) named "PS Blender" which will simulate the same functionality of Illustrator's Blend Tool although Illustrator have very complex and powerful Blending options while I'm only planning to make basic blends with Positions, Rotations, Scales and Transparency. First prototype is ready and I've tested where everything worked fine except scale blendings. Before we continue, Please watch below GIFs so that you can understand the case.

  • First try with positions and transparency, which seems working perfectly First try with positions and transparency, which seems working perfectly

  • Second try with scaling included, which doesn't works well (The result should be like I brushed in the end of GIF) Second try with scaling included, which doesn't works well (The result should be like I brushed in the end of GIF)

My code regarding issue

So whole function of generating Blend is....

function generateBlend(data) {
    //Get user's input from panel
    var newLayerPositionX = data.split("&&&&")[0];
    var newLayerPositionY = data.split("&&&&")[1];
    var newLayerScaleX = data.split("&&&&")[2];
    var newLayerScaleY = data.split("&&&&")[3];
    var newLayerRotation = data.split("&&&&")[4];
    var newLayerTransparency = data.split("&&&&")[5];
    var steps = parseInt(data.split("&&&&")[6]);
    //calculates the difference between values where start values are the real data and new values are user input
    var xTransform = parseFloat(newLayerPositionX) - parseFloat(startLayerPositionX);
    var yTransform = parseFloat(newLayerPositionY) - parseFloat(startLayerPositionY);
    var xScale = parseFloat(newLayerScaleX) - parseFloat(startScaleX); //if positive then increase size and on negative decrease
    var yScale = parseFloat(newLayerScaleY) - parseFloat(startScaleY);
    var rot = parseFloat(newLayerRotation) - parseFloat(startRotation);
    var trans = parseFloat(newLayerTransparency) - parseFloat(startTransparency);
    //dummy variables to call after every increment in for loop
    var masterScaleX = parseFloat(startScaleX);
    var masterScaleY = parseFloat(startScaleY);
    var masterRotation = parseFloat(startRotation);
    var masterTransparency = parseFloat(startTransparency);
    //create a new smart object to start copying and cloning layers (steps)
    editSmartObject();
    duplicateLayer();
    moveLayerBelow();
    convertToSmart();
    renameLayer("SmartObject");
    //define masterPositionX and Y because startPositionX is the value of layers bound which lies in original document while our current layer lies in the smart object of original document so bounds need to be updated
    var docRef = app.activeDocument;
    var curLayer = docRef.activeLayer;
    var curLayerBounds = curLayer.bounds;
    var curLayerPositionX = curLayerBounds[0].value + ((curLayerBounds[2].value - curLayerBounds[0].value) / 2);
    var curLayerPositionY = curLayerBounds[1].value + ((curLayerBounds[3].value - curLayerBounds[1].value) / 2);
    var masterPositionX = parseFloat(curLayerPositionX);
    var masterPositionY = parseFloat(curLayerPositionY);
    //generates incremental values i.e. 50px move in 5 steps gives 10px per step.
    var splitPositionX = parseFloat(xTransform) / steps;
    var splitPositionY = parseFloat(yTransform) / steps;
    var splitScaleX = parseFloat(xScale) / steps;
    var splitScaleY = parseFloat(yScale) / steps;
    var splitRotation = parseFloat(rot) / steps;
    var splitTransparency = parseFloat(trans) / steps;
    //the main code for generating blends starts here
    for (var i = 0; i < steps; i++) {
        //updates masterPositing by adding splits
        masterPositionX = masterPositionX + parseFloat(splitPositionX);
        masterPositionY = masterPositionY + parseFloat(splitPositionY);
        //Photoshop DOM Scale method is relative rather than absolute so if we will change scale to 50 then it won't resize object by 50% but it will resize objects half by it's current size so we need to tweak resize method
        var masterScaleX = parseFloat(((masterScaleX + splitScaleX) * 100) / masterScaleX);
        var masterScaleY = parseFloat(((masterScaleY + splitScaleY) * 100) / masterScaleY);
        var masterRotation = masterRotation + parseFloat(splitRotation);
        var masterTransparency = masterTransparency + parseFloat(splitTransparency);
        //starts looping in where order will be duplicate SO-clear mask-move downside-apply transformation-select above layer-select bound-below layer mask (This all steps are what makes blend layers)
        try {
            duplicateLayer();
            moveLayerBelow();
            if (hasMask() == true) {
                selectLayerMask();
                deleteLayerMask();
            }
            transformLayer(parseFloat(splitPositionX), parseFloat(splitPositionY))
            resizeLayer(masterScaleX, masterScaleY);
            rotateLayer(masterRotation);
            changeTransparency(masterTransparency);
            revealAll();
            selectAboveLayer();
            selectBoundOfLayer()
            selectBelowLayer();
            createMask();
            invert();
            trim();
        } catch (e) {
            alert(e);
        }
    }
}

As you can see above in try segment I do all stuffs by calling separate methods; Now all you might be interested are in Resize method which code is....

function resizeLayer(xScale, yScale) {
    app.activeDocument.activeLayer.resize(xScale, yScale, AnchorPosition.MIDDLECENTER);
}

See this is very basic function directly forked from Official JS reference.

What I've tried?

Well I've tried some various method like changing the AnchorPosition and etc but since the blending direction can be any I can't really find a way to make it work. Well the function is doing it's work. Let's take a simple example: Think that layer should move 10px on every step and should resize by 5%, Now if there wouldn't any resize then it'll move clones by every 10 px but if we will now resize it then we need to move clones 10px+the area reduced due to resize and that area seems impossible to figure out since I'm not a developer at all and know very basic on JS.

What I need?

All I need is some guidance on how should I code the logic of resize to solve this problem. All of yours contribution will be very helpful since this is freebie which I'm making for community, I can share source code if you needed too. Thanks for taking your time on my question.

Best Regard!


Solution

  • The process was pretty simple and the question itself had answer but I never thought it from that perspective. the issue was how to maintain the margin even when object gets scaled down and all I had to do was add scaled down pixels to the xDisplacement and that worked perfectly.

    And here is even a good thing, I've decided to don't make the plugin on my own since I'm fear that I might get hundreds of questions since I'm newbie in development thing, The updated code and the first prototype is available on PS Blender GitHub page. (I released it as open source maybe I can post the link)