Copy link to clipboard
Copied
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.
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
...
Copy link to clipboard
Copied
Sorting shouldn't be a problem. How are you converting a color to grayscale?
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
var doc = app.activeDocument;
var selection = doc.selection;
var objectsInSelection = [];
var grayObjectsInSelection = [];
//=============================================================================
function findFills() {
// Iterate through selected objects
for (var i = 0; i < selection.length; i++) {
var item = selection[i];
var fillColor = item.fillColor ? item.fillColor.spot.name : "None";
// Create an object for each item in the selection
var obj = {
fillColor: fillColor,
grayAmount: "", // Placeholder for gray amount
order: i // Index of the item in the selection
}
objectsInSelection.push(obj);
}
}
//==============================================================================
function findGrayFills() {
// Iterate through selected objects
for (var i = 0; i < selection.length; i++) {
var item = selection[i];
var fillColorGray = item.fillColor ? item.fillColor.gray : "None";
// Create an object for each item in the selection
var obj = {
fillColor: objectsInSelection[i].fillColor,
grayAmount: fillColorGray,
order: i // Index of the item in the selection
}
grayObjectsInSelection.push(obj);
objectsInSelection[i].grayAmount = fillColorGray;
}
}
//=============================================================================
// Define the comparison function for sorting
function compare(a, b) {
if (a.grayAmount < b.grayAmount) {
return -1;
}
if (a.grayAmount > b.grayAmount) {
return 1;
}
return 0;
}
//===========================================
function sortSelection(){
sorting function i cant figure out
}
//========================================
findFills();
app.executeMenuCommand('Colors7');
findGrayFills();
objectsInSelection.sort(compare);
sortSelection();
Copy link to clipboard
Copied
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];
};
Copy link to clipboard
Copied
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!
Copy link to clipboard
Copied
Good to hear! 🙂
Copy link to clipboard
Copied
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;
}
}
}
}
Copy link to clipboard
Copied
Nice! 🙂
Copy link to clipboard
Copied
I was looking to reorganize the items in the selection by their zOrder as they would end up in the order each ink would be printed BUT what you've done here would/will also prove very handy for listing swatch/inks in their correct order visually on customer proofs and such. Thank you!
Copy link to clipboard
Copied
It can easily be modified to sort in zOrder.
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].zOrderPosition > a[j+1].zOrderPosition){
a[j].move(a[j+1], ElementPlacement.PLACEAFTER);
}
}
}
}