Highlighted

I need a script that groups filled paths by color for paintings by numbers.

New Here ,
Aug 25, 2020

Copy link to clipboard

Copied

Hello folks,

In a recent post (https://community.adobe.com/t5/illustrator/script-insert-text-number-in-the-middle-of-visible-bounds...) I was reading on the following matter: the author uploaded a script that groups filled paths by color for paintings by numbers. However, when I tried to apply it to my Illustrator, it didn't work. Instead of showing different numbers in each field, I only get one and the same number.

 

I would appreciate it if someone could help me with a new, working script. I am also willing to pay for one.

 

Cheers.

Adobe Community Professional
Correct answer by Charu Rajput | Adobe Community Professional

Hi,

Another version of the script. This is handling just pathItems and CMYK colors.  You can test it for simple sneario. This is not final and clean version. Code reference from the same link that you have shared

 

 

 

#target illustrator
    
var doc = app.activeDocument;
function main() {
    var _pageItems = doc.pageItems;
    var _layersCollection = [];
    for (var p = 0; p < _pageItems.length; p++) {
        collectItemsBasedOnColors(_pageItems[p], _layersCollection);
    }
    lays = doc.layers;
    WORK_LAY = lays.add();
    NUM_LAY = lays.add();

    for (var l = 0; l < _layersCollection.length; l++) {
        process(_layersCollection[l].pathItems, false, (l + 1));
    }
}

function process(items, isCompound, _num) {
    var j = 0,
        b, xy, s, p, op;

    for (; j < items.length; j++) {
        // process each pathItem
        op = items[j];
        // add stroke
        if (isCompound) {
            strokeComPath(op);
        } else {
            !op.closed && op.closed = true;
            op.filled = false;
            op.stroked = true;
        };
        b = getCenterBounds(op);
        xy = [b[0] + (b[2] - b[0]) / 2, b[1] + (b[3] - b[1]) / 2];
        s = (
            Math.min(op.height, op.width) < 20 ||
            (op.area && Math.abs(op.area) < 150)
        ) ? 4 : 6; // adjust font size for small area paths.
        add_nums(_num, xy, s);
    }
}

function collectItemsBasedOnColors(myCurrentObject, _layersCollection) {
    var myLayerName = "Unknown";
    if (myCurrentObject.typename == "PathItem") {
        if (myCurrentObject.filled == true) {
            if (myCurrentObject.fillColor == "[CMYKColor]") {
                myLayerName = "CMYK: " + Math.round(myCurrentObject.fillColor.cyan) + "," + Math.round(myCurrentObject.fillColor.magenta) + "," + Math.round(myCurrentObject.fillColor.yellow) + "," + Math.round(myCurrentObject.fillColor.black);
            }
        }
        try {
            var _layer = doc.layers.getByName(myLayerName);
            myCurrentObject.move(_layer, ElementPlacement.PLACEATBEGINNING);
        }

        catch (e) {
            var _layer = doc.layers.add()
            _layer.name = myLayerName
            myCurrentObject.move(_layer, ElementPlacement.PLACEATBEGINNING);
            _layersCollection.push(_layer);
        }
    }
}

function getCenterBounds(op) {
    var originalMinSize = getMinVisibleSize(op.visibleBounds);

    var p = applyOffset(op, false);

    if (getMinVisibleSize(p.visibleBounds) > originalMinSize) {
        // in some cases, path p becomes larger for some unknown reason
        p.remove();
        p = applyOffset(op, true);
    }

    var b = p.visibleBounds;

    if (getMinVisibleSize(b) > 10) {
        activeDocument.selection = [p];
        executeMenuCommand("expandStyle");
        p = activeDocument.selection[0];
        if (p.typename == "CompoundPathItem") {
            b = findBestBounds(op, p);
        }
    }

    p.remove();
    return b;
}

function getMinVisibleSize(b) {
    var s = Math.min(b[2] - b[0], b[1] - b[3]);
    return Math.abs(s);
}

function add_nums(n, xy, s) {
    var txt = NUM_LAY.textFrames.add();

    txt.contents = n;
    txt.textRange.justification = Justification.CENTER;
    txt.textRange.characterAttributes.size = s;
    txt.position = [xy[0] - txt.width / 2, xy[1] + txt.height / 2];
}


function applyOffset(op, checkBounds) {
    var p = op.duplicate(WORK_LAY, ElementPlacement.PLACEATBEGINNING),
        // offset value the small the better, but meantime more slow. 
        offset = function () {
            var minsize = Math.min(p.width, p.height);
            if (minsize >= 50) {
                return '-1'
            } else if (20 < minsize && minsize < 50) {
                return '-0.5'
            } else {
                return '-0.2' // 0.2 * 2 (both side ) * 50 (Times) = 20
            }
        },
        xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="I jntp 2 R mlim 4 R ofst #offset"/></LiveEffect>'
            .replace('#offset', offset()),
        TIMES = 100; // if shapes are too large, should increase the value.

    if (checkBounds) {
        // check its size only if it needs, because it's too slow
        while (TIMES-- && getMinVisibleSize(p.visibleBounds) > 3) p.applyEffect(xmlstring);
    } else {
        while (TIMES--) p.applyEffect(xmlstring);
    }
    return p;
}

function getGeometricCenter(p) {
    var b = p.geometricBounds;
    return [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2];
}

// returns square of distance between p1 and p2
function getDist2(p1, p2) {
    return Math.pow(p1[0] + p2[0], 2) + Math.pow(p1[1] + p2[1], 2);
}

// returns visibleBounds of a path in a compoundPath p
// which is closest to center of the original path op
function findBestBounds(op, p) {
    var opc = getGeometricCenter(op);
    var idx = 0,
        d;
    var minD = getDist2(opc, getGeometricCenter(p.pathItems[0]));
    for (var i = 0, iEnd = p.pathItems.length; i < iEnd; i++) {
        d = getDist2(opc, getGeometricCenter(p.pathItems[i]));
        if (d < minD) {
            minD = d;
            idx = i;
        }
    }
    return p.pathItems[idx].visibleBounds;
}

main();

 

 

 

Running with attached sample file. Ofcourse more can be done to handle other scenarios.

Sample File 

TOPICS
Draw and design, Feature request, Scripting, Tools

Views

239

Likes

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

I need a script that groups filled paths by color for paintings by numbers.

New Here ,
Aug 25, 2020

Copy link to clipboard

Copied

Hello folks,

In a recent post (https://community.adobe.com/t5/illustrator/script-insert-text-number-in-the-middle-of-visible-bounds...) I was reading on the following matter: the author uploaded a script that groups filled paths by color for paintings by numbers. However, when I tried to apply it to my Illustrator, it didn't work. Instead of showing different numbers in each field, I only get one and the same number.

 

I would appreciate it if someone could help me with a new, working script. I am also willing to pay for one.

 

Cheers.

Adobe Community Professional
Correct answer by Charu Rajput | Adobe Community Professional

Hi,

Another version of the script. This is handling just pathItems and CMYK colors.  You can test it for simple sneario. This is not final and clean version. Code reference from the same link that you have shared

 

 

 

#target illustrator
    
var doc = app.activeDocument;
function main() {
    var _pageItems = doc.pageItems;
    var _layersCollection = [];
    for (var p = 0; p < _pageItems.length; p++) {
        collectItemsBasedOnColors(_pageItems[p], _layersCollection);
    }
    lays = doc.layers;
    WORK_LAY = lays.add();
    NUM_LAY = lays.add();

    for (var l = 0; l < _layersCollection.length; l++) {
        process(_layersCollection[l].pathItems, false, (l + 1));
    }
}

function process(items, isCompound, _num) {
    var j = 0,
        b, xy, s, p, op;

    for (; j < items.length; j++) {
        // process each pathItem
        op = items[j];
        // add stroke
        if (isCompound) {
            strokeComPath(op);
        } else {
            !op.closed && op.closed = true;
            op.filled = false;
            op.stroked = true;
        };
        b = getCenterBounds(op);
        xy = [b[0] + (b[2] - b[0]) / 2, b[1] + (b[3] - b[1]) / 2];
        s = (
            Math.min(op.height, op.width) < 20 ||
            (op.area && Math.abs(op.area) < 150)
        ) ? 4 : 6; // adjust font size for small area paths.
        add_nums(_num, xy, s);
    }
}

function collectItemsBasedOnColors(myCurrentObject, _layersCollection) {
    var myLayerName = "Unknown";
    if (myCurrentObject.typename == "PathItem") {
        if (myCurrentObject.filled == true) {
            if (myCurrentObject.fillColor == "[CMYKColor]") {
                myLayerName = "CMYK: " + Math.round(myCurrentObject.fillColor.cyan) + "," + Math.round(myCurrentObject.fillColor.magenta) + "," + Math.round(myCurrentObject.fillColor.yellow) + "," + Math.round(myCurrentObject.fillColor.black);
            }
        }
        try {
            var _layer = doc.layers.getByName(myLayerName);
            myCurrentObject.move(_layer, ElementPlacement.PLACEATBEGINNING);
        }

        catch (e) {
            var _layer = doc.layers.add()
            _layer.name = myLayerName
            myCurrentObject.move(_layer, ElementPlacement.PLACEATBEGINNING);
            _layersCollection.push(_layer);
        }
    }
}

function getCenterBounds(op) {
    var originalMinSize = getMinVisibleSize(op.visibleBounds);

    var p = applyOffset(op, false);

    if (getMinVisibleSize(p.visibleBounds) > originalMinSize) {
        // in some cases, path p becomes larger for some unknown reason
        p.remove();
        p = applyOffset(op, true);
    }

    var b = p.visibleBounds;

    if (getMinVisibleSize(b) > 10) {
        activeDocument.selection = [p];
        executeMenuCommand("expandStyle");
        p = activeDocument.selection[0];
        if (p.typename == "CompoundPathItem") {
            b = findBestBounds(op, p);
        }
    }

    p.remove();
    return b;
}

function getMinVisibleSize(b) {
    var s = Math.min(b[2] - b[0], b[1] - b[3]);
    return Math.abs(s);
}

function add_nums(n, xy, s) {
    var txt = NUM_LAY.textFrames.add();

    txt.contents = n;
    txt.textRange.justification = Justification.CENTER;
    txt.textRange.characterAttributes.size = s;
    txt.position = [xy[0] - txt.width / 2, xy[1] + txt.height / 2];
}


function applyOffset(op, checkBounds) {
    var p = op.duplicate(WORK_LAY, ElementPlacement.PLACEATBEGINNING),
        // offset value the small the better, but meantime more slow. 
        offset = function () {
            var minsize = Math.min(p.width, p.height);
            if (minsize >= 50) {
                return '-1'
            } else if (20 < minsize && minsize < 50) {
                return '-0.5'
            } else {
                return '-0.2' // 0.2 * 2 (both side ) * 50 (Times) = 20
            }
        },
        xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="I jntp 2 R mlim 4 R ofst #offset"/></LiveEffect>'
            .replace('#offset', offset()),
        TIMES = 100; // if shapes are too large, should increase the value.

    if (checkBounds) {
        // check its size only if it needs, because it's too slow
        while (TIMES-- && getMinVisibleSize(p.visibleBounds) > 3) p.applyEffect(xmlstring);
    } else {
        while (TIMES--) p.applyEffect(xmlstring);
    }
    return p;
}

function getGeometricCenter(p) {
    var b = p.geometricBounds;
    return [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2];
}

// returns square of distance between p1 and p2
function getDist2(p1, p2) {
    return Math.pow(p1[0] + p2[0], 2) + Math.pow(p1[1] + p2[1], 2);
}

// returns visibleBounds of a path in a compoundPath p
// which is closest to center of the original path op
function findBestBounds(op, p) {
    var opc = getGeometricCenter(op);
    var idx = 0,
        d;
    var minD = getDist2(opc, getGeometricCenter(p.pathItems[0]));
    for (var i = 0, iEnd = p.pathItems.length; i < iEnd; i++) {
        d = getDist2(opc, getGeometricCenter(p.pathItems[i]));
        if (d < minD) {
            minD = d;
            idx = i;
        }
    }
    return p.pathItems[idx].visibleBounds;
}

main();

 

 

 

Running with attached sample file. Ofcourse more can be done to handle other scenarios.

Sample File 

TOPICS
Draw and design, Feature request, Scripting, Tools

Views

240

Likes

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
Aug 25, 2020 0
Adobe Community Professional ,
Aug 25, 2020

Copy link to clipboard

Copied

Hi,

Another version of the script. This is handling just pathItems and CMYK colors.  You can test it for simple sneario. This is not final and clean version. Code reference from the same link that you have shared

 

 

 

#target illustrator
    
var doc = app.activeDocument;
function main() {
    var _pageItems = doc.pageItems;
    var _layersCollection = [];
    for (var p = 0; p < _pageItems.length; p++) {
        collectItemsBasedOnColors(_pageItems[p], _layersCollection);
    }
    lays = doc.layers;
    WORK_LAY = lays.add();
    NUM_LAY = lays.add();

    for (var l = 0; l < _layersCollection.length; l++) {
        process(_layersCollection[l].pathItems, false, (l + 1));
    }
}

function process(items, isCompound, _num) {
    var j = 0,
        b, xy, s, p, op;

    for (; j < items.length; j++) {
        // process each pathItem
        op = items[j];
        // add stroke
        if (isCompound) {
            strokeComPath(op);
        } else {
            !op.closed && op.closed = true;
            op.filled = false;
            op.stroked = true;
        };
        b = getCenterBounds(op);
        xy = [b[0] + (b[2] - b[0]) / 2, b[1] + (b[3] - b[1]) / 2];
        s = (
            Math.min(op.height, op.width) < 20 ||
            (op.area && Math.abs(op.area) < 150)
        ) ? 4 : 6; // adjust font size for small area paths.
        add_nums(_num, xy, s);
    }
}

function collectItemsBasedOnColors(myCurrentObject, _layersCollection) {
    var myLayerName = "Unknown";
    if (myCurrentObject.typename == "PathItem") {
        if (myCurrentObject.filled == true) {
            if (myCurrentObject.fillColor == "[CMYKColor]") {
                myLayerName = "CMYK: " + Math.round(myCurrentObject.fillColor.cyan) + "," + Math.round(myCurrentObject.fillColor.magenta) + "," + Math.round(myCurrentObject.fillColor.yellow) + "," + Math.round(myCurrentObject.fillColor.black);
            }
        }
        try {
            var _layer = doc.layers.getByName(myLayerName);
            myCurrentObject.move(_layer, ElementPlacement.PLACEATBEGINNING);
        }

        catch (e) {
            var _layer = doc.layers.add()
            _layer.name = myLayerName
            myCurrentObject.move(_layer, ElementPlacement.PLACEATBEGINNING);
            _layersCollection.push(_layer);
        }
    }
}

function getCenterBounds(op) {
    var originalMinSize = getMinVisibleSize(op.visibleBounds);

    var p = applyOffset(op, false);

    if (getMinVisibleSize(p.visibleBounds) > originalMinSize) {
        // in some cases, path p becomes larger for some unknown reason
        p.remove();
        p = applyOffset(op, true);
    }

    var b = p.visibleBounds;

    if (getMinVisibleSize(b) > 10) {
        activeDocument.selection = [p];
        executeMenuCommand("expandStyle");
        p = activeDocument.selection[0];
        if (p.typename == "CompoundPathItem") {
            b = findBestBounds(op, p);
        }
    }

    p.remove();
    return b;
}

function getMinVisibleSize(b) {
    var s = Math.min(b[2] - b[0], b[1] - b[3]);
    return Math.abs(s);
}

function add_nums(n, xy, s) {
    var txt = NUM_LAY.textFrames.add();

    txt.contents = n;
    txt.textRange.justification = Justification.CENTER;
    txt.textRange.characterAttributes.size = s;
    txt.position = [xy[0] - txt.width / 2, xy[1] + txt.height / 2];
}


function applyOffset(op, checkBounds) {
    var p = op.duplicate(WORK_LAY, ElementPlacement.PLACEATBEGINNING),
        // offset value the small the better, but meantime more slow. 
        offset = function () {
            var minsize = Math.min(p.width, p.height);
            if (minsize >= 50) {
                return '-1'
            } else if (20 < minsize && minsize < 50) {
                return '-0.5'
            } else {
                return '-0.2' // 0.2 * 2 (both side ) * 50 (Times) = 20
            }
        },
        xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="I jntp 2 R mlim 4 R ofst #offset"/></LiveEffect>'
            .replace('#offset', offset()),
        TIMES = 100; // if shapes are too large, should increase the value.

    if (checkBounds) {
        // check its size only if it needs, because it's too slow
        while (TIMES-- && getMinVisibleSize(p.visibleBounds) > 3) p.applyEffect(xmlstring);
    } else {
        while (TIMES--) p.applyEffect(xmlstring);
    }
    return p;
}

function getGeometricCenter(p) {
    var b = p.geometricBounds;
    return [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2];
}

// returns square of distance between p1 and p2
function getDist2(p1, p2) {
    return Math.pow(p1[0] + p2[0], 2) + Math.pow(p1[1] + p2[1], 2);
}

// returns visibleBounds of a path in a compoundPath p
// which is closest to center of the original path op
function findBestBounds(op, p) {
    var opc = getGeometricCenter(op);
    var idx = 0,
        d;
    var minD = getDist2(opc, getGeometricCenter(p.pathItems[0]));
    for (var i = 0, iEnd = p.pathItems.length; i < iEnd; i++) {
        d = getDist2(opc, getGeometricCenter(p.pathItems[i]));
        if (d < minD) {
            minD = d;
            idx = i;
        }
    }
    return p.pathItems[idx].visibleBounds;
}

main();

 

 

 

Running with attached sample file. Ofcourse more can be done to handle other scenarios.

Sample File 

Best regards

Likes

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
Reply
Loading...
Aug 25, 2020 1
New Here ,
Aug 25, 2020

Copy link to clipboard

Copied

qqqqq.jpg

Likes

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
Reply
Loading...
Aug 25, 2020 0
Adobe Community Professional ,
Aug 25, 2020

Copy link to clipboard

Copied

Just updated the code, keep following line

var doc = app.activeDocument;

out the main() function.

Best regards

Likes

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
Reply
Loading...
Aug 25, 2020 0
New Here ,
Aug 25, 2020

Copy link to clipboard

Copied

When I try the updated code the same error pops-up as before. 

Likes

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
Reply
Loading...
Aug 25, 2020 0
Adobe Community Professional ,
Aug 25, 2020

Copy link to clipboard

Copied

How are you executing the code? Are you using extended toolkit?

Best regards

Likes

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
Reply
Loading...
Aug 25, 2020 0
New Here ,
Aug 25, 2020

Copy link to clipboard

Copied

I load the code directly from illustrator.01.jpg

Likes

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
Reply
Loading...
Aug 25, 2020 0
Adobe Community Professional ,
Aug 25, 2020

Copy link to clipboard

Copied

I tried in this way as well, and it is running successfully.

Did you save your code with .jsx extension?

Best regards

Likes

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
Reply
Loading...
Aug 25, 2020 1
Engaged ,
Aug 25, 2020

Copy link to clipboard

Copied

I tried the script on this thread in CS6 and it seems to be working fine for me.  (Thank you, Charu.)

Likes

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
Reply
Loading...
Aug 25, 2020 1
Adobe Community Professional ,
Aug 25, 2020

Copy link to clipboard

Copied

Thanks femkeblanco  for confirming 🙂

Best regards

Likes

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
Reply
Loading...
Aug 25, 2020 0
New Here ,
Aug 26, 2020

Copy link to clipboard

Copied

I would like the script to show the numbers from 1 to 9 and then to start to show letters: "A,B,C..." and so on. So, for example - 1,2,3,4,5,6,7,8,9,A,B,C,D...etc. 

Likes

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
Reply
Loading...
Aug 26, 2020 0
New Here ,
Aug 28, 2020

Copy link to clipboard

Copied

Hello folks,

Can someone of you please help me with a code I need for Illustrator? 

 

I'm working with paintings by numbers and would like the script to show the numbers from 1 to 9 and then to start to show letters: "A,B,C..." and so on. So, for example - 1,2,3,4,5,6,7,8,9,A,B,C,D...etc. 

 

Any help would greatly be appreciated.

Likes

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
Reply
Loading...
Aug 28, 2020 0
Engaged ,
Aug 28, 2020

Copy link to clipboard

Copied

Replace the line (which is line 100 in the above script)

txt.contents = n;

with these two lines

var x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
txt.contents = x[n];

 

The script will fail if you go beyond "Z".

 

Likes

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
Reply
Loading...
Aug 28, 2020 1
New Here ,
Aug 29, 2020

Copy link to clipboard

Copied

Thank you very nice.

Likes

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
Reply
Loading...
Aug 29, 2020 0
Resources