1

I'm trying to convert something that looks like this into a bunch of slices, where each slice might overlap with another, but should contain each island of non-transparent pixels. The long continuous strokes don't have to be converted, but most of the "spots" should be.

enter image description here

So effectively, I'm trying to automatically slice it to look some thing like this (excuse the rough manual slicing):

enter image description here

I'm still somewhat new to Photoshop scripting, and I am also not sure if this is something that has existing scripting or other Photoshop functionality already available? Or, how would you do it?

(Full story, a step I can easily do once I have structured data of the image slices... This will then be exported to Unity in a game! I suppose slices aren't the only way - just something that can easily demarcate xy location and size of each island on the global image.)

4
  • well it seems you trying to extract those little stuffs but sadly it is possible only if it follows specific pattern but since your image is random and your slicing pattern is random it seems scripting can't help much but still there might be workaround like transparency to detect it but im not sure :)
    – Mr.Online
    Commented May 23, 2019 at 6:13
  • Well, it's basically based on transparency + contiguous "islands" ... so it's not exactly random?
    – ina
    Commented May 23, 2019 at 8:40
  • well if we had contiguous pattern like "circle + 50px space + circle +50px + circle.." then we can code to create slices but since it's not fixed positioned it's quite hard to create slice with different dimesions via scripts and well now only transparency is left so it might possible since i somewhere saw people extracting image like yours from single transparent file :) so let's just wait for someone else
    – Mr.Online
    Commented May 23, 2019 at 8:53
  • 1
    photoshopscripts.wordpress.com/2012/12/09/split-to-layers if you want images extracted then use above script
    – Mr.Online
    Commented May 23, 2019 at 9:00

1 Answer 1

2

Input image is difficult to work with because there're...

  • strokes that should be ignored but it may be difficult to set specific conditions for that
  • spots with different transparency
  • spots almost fused with strokes (between slices 9 and 12 in your example)

here's how I'd approach this. Let's say those are my spots image. Arrows indicate problematic sections.

enter image description here

Then I'd create a helper-layer: a copy of this layer, where I'd manually remove the parts I don't need and make half-transparent spots more obvious. It doesn't need to be perfect, just a quick strong indication to help the script recognize the regions:

![enter image description here

Then the script would do the following:

  1. use Magic Wand in the top-left corner with Contiguous option turned on and Tolerance set to 0 and invert selection, like this I'll get selections of all the regions I need:

![enter image description here

  1. I'll Expand selection a bit (2px for instance) and since Selection object in Photoshop doesn't have separate coordinates for each selection island, I'll convert selection to paths first

enter image description here

  1. Now I can loop through separate paths, recreate them and load each one as a selection, get selection.bounds and make a slice based on these bounds. Final result with original layer displayed:

enter image description here

P.S. not sure if you need specifically Slices or it was the first thing came to mind? If you simply need to generate a list of coordinated of bounding boxes, you can write them to a file or clipboard and read in Unity later.

Final code:

function main()
{

    var pathPoints = [];

    magicWand();

    invertSelection();

    expandSelection(2);

    selectionToPath(.7);

    var workPath = activeDocument.pathItems[0];

    for (i = 0; i < workPath.subPathItems.length; i++)
    {
        var tempAr = [];
        for (var k = 0; k < workPath.subPathItems[i].pathPoints.length; k++)
        {
            tempAr.push([
                workPath.subPathItems[i].pathPoints[k].anchor,
                workPath.subPathItems[i].pathPoints[k].leftDirection,
                workPath.subPathItems[i].pathPoints[k].rightDirection
            ]);
        };
        pathPoints.push(tempAr);
    };

    for (var i = 0; i < pathPoints.length; i++)
    {
        createPath(pathPoints[i]);
        loadSelectionFromPath();
        var bounds = activeDocument.selection.bounds;
        makeSlice(bounds);
        deselect();
    }

    activeDocument.pathItems[0].remove();

    /////////////////////////////////////////////////////////////////////////////////////
    // FUNCTIONS

    function cTID(s)
    {
        return app.charIDToTypeID(s);
    };

    function sTID(s)
    {
        return app.stringIDToTypeID(s);
    };

    function makeSlice(data)
    {
        var desc2 = new ActionDescriptor();
        var ref1 = new ActionReference();
        ref1.putClass(sTID('slice'));
        desc2.putReference(cTID('null'), ref1);
        var desc3 = new ActionDescriptor();
        desc3.putEnumerated(cTID('Type'), sTID('sliceType'), sTID('user'));
        var desc4 = new ActionDescriptor();
        desc4.putUnitDouble(cTID('Top '), cTID('#Pxl'), data[1]);
        desc4.putUnitDouble(cTID('Left'), cTID('#Pxl'), data[0]);
        desc4.putUnitDouble(cTID('Btom'), cTID('#Pxl'), data[3]);
        desc4.putUnitDouble(cTID('Rght'), cTID('#Pxl'), data[2]);
        desc3.putObject(cTID('At  '), cTID('Rctn'), desc4);
        desc2.putObject(cTID('Usng'), sTID('slice'), desc3);
        executeAction(cTID('Mk  '), desc2, DialogModes.NO);
    }; // end of makeSlice()

    function createPath(_path)
    {
        var desc1 = new ActionDescriptor();
        var ref1 = new ActionReference();
        ref1.putProperty(charIDToTypeID('Path'), charIDToTypeID('WrPt'));
        desc1.putReference(charIDToTypeID('null'), ref1);
        var list1 = new ActionList();
        var desc20 = new ActionDescriptor();
        desc20.putEnumerated(stringIDToTypeID("shapeOperation"), stringIDToTypeID("shapeOperation"), stringIDToTypeID('add'));
        var list4 = new ActionList();
        var desc21 = new ActionDescriptor();
        var list5 = new ActionList();
        desc21.putBoolean(charIDToTypeID('Clsp'), true);
        for (var p = 0; p < _path.length; p++)
        {
            var desc22 = new ActionDescriptor();
            var desc23 = new ActionDescriptor();
            desc23.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), _path[p][0][0]);
            desc23.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), _path[p][0][1]);
            desc22.putObject(charIDToTypeID('Anch'), charIDToTypeID('Pnt '), desc23);
            var desc24 = new ActionDescriptor();
            desc24.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), _path[p][1][0]);
            desc24.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), _path[p][1][1]);
            desc22.putObject(charIDToTypeID('Fwd '), charIDToTypeID('Pnt '), desc24);
            var desc25 = new ActionDescriptor();
            desc25.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), _path[p][2][0]);
            desc25.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), _path[p][2][1]);
            desc22.putObject(charIDToTypeID('Bwd '), charIDToTypeID('Pnt '), desc25);
            list5.putObject(charIDToTypeID('Pthp'), desc22);
        }
        desc21.putList(charIDToTypeID('Pts '), list5);
        list4.putObject(charIDToTypeID('Sbpl'), desc21);
        desc20.putList(charIDToTypeID('SbpL'), list4);
        list1.putObject(charIDToTypeID('PaCm'), desc20);
        desc1.putList(charIDToTypeID('T   '), list1);
        executeAction(charIDToTypeID('setd'), desc1, DialogModes.NO);
    }; // end of createPath()

    function magicWand()
    {
        var desc3904 = new ActionDescriptor();
        var ref621 = new ActionReference();
        ref621.putProperty(cTID('Chnl'), cTID('fsel'));
        desc3904.putReference(cTID('null'), ref621);
        var desc3905 = new ActionDescriptor();
        desc3905.putUnitDouble(cTID('Hrzn'), cTID('#Pxl'), 0);
        desc3905.putUnitDouble(cTID('Vrtc'), cTID('#Pxl'), 0);
        desc3904.putObject(cTID('T   '), cTID('Pnt '), desc3905);
        desc3904.putInteger(cTID('Tlrn'), 0);
        desc3904.putBoolean(cTID('Mrgd'), false);
        desc3904.putBoolean(cTID('AntA'), true);
        desc3904.putBoolean(cTID('Cntg'), true);
        executeAction(cTID('setd'), desc3904, DialogModes.NO);
    }; // end of magicWand()

    function invertSelection()
    {
        executeAction(cTID('Invs'), undefined, DialogModes.NO);
    }; // end of invertSelection()


    function expandSelection(value)
    {
        var desc62 = new ActionDescriptor();
        desc62.putUnitDouble(cTID('By  '), cTID('#Pxl'), value);
        desc62.putBoolean(sTID('selectionModifyEffectAtCanvasBounds'), true);
        executeAction(cTID('Expn'), desc62, DialogModes.NO);
    }; // end of expandSelection()

    function selectionToPath(value)
    {
        var desc12 = new ActionDescriptor();
        var ref7 = new ActionReference();
        ref7.putClass(cTID('Path'));
        desc12.putReference(cTID('null'), ref7);
        var ref8 = new ActionReference();
        ref8.putProperty(cTID('csel'), cTID('fsel'));
        desc12.putReference(cTID('From'), ref8);
        desc12.putUnitDouble(cTID('Tlrn'), cTID('#Pxl'), value);
        executeAction(cTID('Mk  '), desc12, DialogModes.NO);
    }; // end of selectionToPath()

    function loadSelectionFromPath()
    {
        var desc92 = new ActionDescriptor();
        var ref20 = new ActionReference();
        ref20.putProperty(cTID('Chnl'), cTID('fsel'));
        desc92.putReference(cTID('null'), ref20);
        var ref21 = new ActionReference();
        ref21.putProperty(cTID('Path'), cTID('WrPt'));
        desc92.putReference(cTID('T   '), ref21);
        desc92.putInteger(cTID('Vrsn'), 1);
        desc92.putBoolean(sTID('vectorMaskParams'), true);
        executeAction(cTID('setd'), desc92, DialogModes.NO);
    }; // end of loadSelectionFromPath()

    function deselect()
    {
        var desc5 = new ActionDescriptor();
        var ref1 = new ActionReference();
        ref1.putProperty(cTID('Chnl'), cTID('fsel'));
        desc5.putReference(cTID('null'), ref1);
        desc5.putEnumerated(cTID('T   '), cTID('Ordn'), cTID('None'));
        executeAction(cTID('setd'), desc5, DialogModes.NO);
    }; // end of deselect()

}
app.activeDocument.suspendHistory("create slices based on transparency", "main()");

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.