Skip to main content
Inspiring
February 9, 2024
Answered

Script that sorts items in selection

  • February 9, 2024
  • 3 replies
  • 1393 views

I'm trying to write a script that sorts/arranges the items in the selection (no strokes and all using spot colors) by "lightest to darkest". It's part of a larger goal to hopefully automate making separations for screenprinting but I'm stuck on this aspect. I've tried to accomplish this in several ways but the one I think has the most promise is converting each item's fill to grayscale, storing the original fill colors and the new gray values of each item in an array as objects, sorting the array based on gray values, and then making the items then match the new order of the array and returning the items to their original fill color. But I can't seem to make that work. Is there an easier way to accomplish this that I'm just not thinking of? also, is it possible to just assign a number to a zorder of an item rather than lengthy looping SENDBACKWARDS/SENDFORWARDS for the function? Thanks in advance.

Correct answer m1b

Hi @Isaac265865188lnf, I have some functions I have previously written on hand, so I have put together this script quickly to do what I think you want. At the least it will show you a different approach and I think that will be useful.

- Mark

 

/**
 * Sort the selected items by their darkness value
 * (we use convert to grayscale, but you may want
 * to try other methods, too) and re-order so that
 * the darker items are in front of lighter items.
 * @author m1b
 * @discussion https://community.adobe.com/t5/illustrator-discussions/script-that-sorts-items-in-selection/m-p/14413597
 */
(function () {

    var doc = app.activeDocument,
        items = doc.selection,
        ordered = Array(items.length);

    // calculate the darkness and add to a sortable array
    for (var i = 0; i < items.length; i++) {

        if (undefined != items[i].fillColor)

            ordered[i] = {
                uuid: items[i].uuid,
                value: getGrayScaleValueFor(items[i].fillColor),
            };

    }

    // sort by darkness, descending
    ordered.sort(function (a, b) { return b.value - a.value });

    // make an item to act as a layer reference
    var reference = doc.groupItems.add();
    reference.move(items[0], ElementPlacement.PLACEBEFORE);

    try {

        // move each item to above the reference, in new order
        for (var i = 0, item; i < ordered.length; i++) {
            item = doc.getPageItemFromUuid(ordered[i].uuid);
            item.move(reference, ElementPlacement.PLACEBEFORE);
        }

    }

    catch (error) {
        alert(error);
    }

    finally {
        // clean up
        reference.remove();
    }

})();


/**
 * Returns a grayscale value, given a color breakdown.
 * @author m1b
 * @version 2022-05-23
 * @param {Array<Number>|Color} breakdown - array of color values, eg. [c, m, y, k] or [r, g, b], or a Color, eg. CMYKColor.
 * @returns {Number}
 */
function getGrayScaleValueFor(breakdown) {

    if ('Array' !== breakdown.constructor.name)
        breakdown = getColorBreakdown(breakdown);

    var gray;

    if (breakdown.length === 4)
        gray = app.convertSampleColor(ImageColorSpace.CMYK, breakdown, ImageColorSpace.GrayScale, ColorConvertPurpose.defaultpurpose);

    else if (breakdown.length === 3)
        gray = app.convertSampleColor(ImageColorSpace.RGB, breakdown, ImageColorSpace.GrayScale, ColorConvertPurpose.defaultpurpose);

    return gray;

};


/**
 * Returns an array of color channel values.
 * @author m1b
 * @version 2022-05-23
 * @param {Swatch|Color} col - an Illustrator Swatch or Color.
 * @param {Number} [tintFactor] - a number in range 0..1 (default: 1).
 * @returns {Array<Number>}
 */
function getColorBreakdown(col, tintFactor) {

    tintFactor = tintFactor || 1;

    if (col.hasOwnProperty('color'))
        col = col.color;

    if (col.constructor.name == 'SpotColor')
        col = col.spot.color;

    if (col.constructor.name === 'CMYKColor')
        return [col.cyan * tintFactor, col.magenta * tintFactor, col.yellow * tintFactor, col.black * tintFactor];

    else if (col.constructor.name === 'RGBColor')
        return [col.red * tintFactor, col.green * tintFactor, col.blue * tintFactor];

    else if (col.constructor.name === 'GrayColor')
        return [col.gray * tintFactor];

};

3 replies

femkeblanco
Brainiac
February 9, 2024

Here's a simple snippet that sorts paths horizontally based on the black value of the fill. 

var doc  = app.activeDocument;
var paths = doc.pathItems;

var array1 = [];
for (var i = 0; i < paths.length; i++) {
    array1.push(paths[i]);
}

array1.sort(function(a, b) {
    return b.fillColor.spot.color.black - a.fillColor.spot.color.black;
})

bubbleSort(array1);

function bubbleSort(a){
    for (var i = a.length-1; i > 0; i--){
        for (var j = 0; j < i; j++){
            if (a[j].top > a[j+1].top){
                var temp = a[j].top;
                a[j].top = a[j+1].top;
                a[j+1].top = temp;
            }
        }
    }
}

 

 

m1b
Brainiac
February 9, 2024

Nice! 🙂

m1b
m1bCorrect answer
Brainiac
February 9, 2024

Hi @Isaac265865188lnf, I have some functions I have previously written on hand, so I have put together this script quickly to do what I think you want. At the least it will show you a different approach and I think that will be useful.

- Mark

 

/**
 * Sort the selected items by their darkness value
 * (we use convert to grayscale, but you may want
 * to try other methods, too) and re-order so that
 * the darker items are in front of lighter items.
 * @author m1b
 * @discussion https://community.adobe.com/t5/illustrator-discussions/script-that-sorts-items-in-selection/m-p/14413597
 */
(function () {

    var doc = app.activeDocument,
        items = doc.selection,
        ordered = Array(items.length);

    // calculate the darkness and add to a sortable array
    for (var i = 0; i < items.length; i++) {

        if (undefined != items[i].fillColor)

            ordered[i] = {
                uuid: items[i].uuid,
                value: getGrayScaleValueFor(items[i].fillColor),
            };

    }

    // sort by darkness, descending
    ordered.sort(function (a, b) { return b.value - a.value });

    // make an item to act as a layer reference
    var reference = doc.groupItems.add();
    reference.move(items[0], ElementPlacement.PLACEBEFORE);

    try {

        // move each item to above the reference, in new order
        for (var i = 0, item; i < ordered.length; i++) {
            item = doc.getPageItemFromUuid(ordered[i].uuid);
            item.move(reference, ElementPlacement.PLACEBEFORE);
        }

    }

    catch (error) {
        alert(error);
    }

    finally {
        // clean up
        reference.remove();
    }

})();


/**
 * Returns a grayscale value, given a color breakdown.
 * @author m1b
 * @version 2022-05-23
 * @param {Array<Number>|Color} breakdown - array of color values, eg. [c, m, y, k] or [r, g, b], or a Color, eg. CMYKColor.
 * @returns {Number}
 */
function getGrayScaleValueFor(breakdown) {

    if ('Array' !== breakdown.constructor.name)
        breakdown = getColorBreakdown(breakdown);

    var gray;

    if (breakdown.length === 4)
        gray = app.convertSampleColor(ImageColorSpace.CMYK, breakdown, ImageColorSpace.GrayScale, ColorConvertPurpose.defaultpurpose);

    else if (breakdown.length === 3)
        gray = app.convertSampleColor(ImageColorSpace.RGB, breakdown, ImageColorSpace.GrayScale, ColorConvertPurpose.defaultpurpose);

    return gray;

};


/**
 * Returns an array of color channel values.
 * @author m1b
 * @version 2022-05-23
 * @param {Swatch|Color} col - an Illustrator Swatch or Color.
 * @param {Number} [tintFactor] - a number in range 0..1 (default: 1).
 * @returns {Array<Number>}
 */
function getColorBreakdown(col, tintFactor) {

    tintFactor = tintFactor || 1;

    if (col.hasOwnProperty('color'))
        col = col.color;

    if (col.constructor.name == 'SpotColor')
        col = col.spot.color;

    if (col.constructor.name === 'CMYKColor')
        return [col.cyan * tintFactor, col.magenta * tintFactor, col.yellow * tintFactor, col.black * tintFactor];

    else if (col.constructor.name === 'RGBColor')
        return [col.red * tintFactor, col.green * tintFactor, col.blue * tintFactor];

    else if (col.constructor.name === 'GrayColor')
        return [col.gray * tintFactor];

};
Inspiring
February 10, 2024

This. Works. PERFECTLY!!  Exactly what I was trying to do. I've been stuck trying to figure the logic required for a few days. I can't thank you enough!

m1b
Brainiac
February 10, 2024

Good to hear! 🙂

femkeblanco
Brainiac
February 9, 2024

Sorting shouldn't be a problem.  How are you converting a color to grayscale? 

Inspiring
February 9, 2024

I have one function that creates the objects pushed to the array with properties for original colors (item.fillColor.spot.name) and a gray property I leave blank. Then I use app.executeMenuCommand('Colors7') to convert to grayscale. And another function pushes each item's grey equivalent to the gray property of the object.