Having fun with your idea although I still get a huge number of unassigned swatches in the 'Others' category (last group).
My script allows to play with the thresholds you've provided, you'll probably want to restore the original values.
////////////////////////////////////////////////////////////
//
// SWATCH SORTER for InDesign - v.1.001b - indiscripts.com
//
////////////////////////////////////////////////////////////
#targetengine 'SwatchSorter1001b'
$.global.hasOwnProperty('ProgressBar')||(function(H/*OST*/,S/*ELF*/,I/*NNER*/)
{
H = function ProgressBar(/*str*/title, /*uint*/width, /*uint*/height)
{
(60<=(width||0))||(width=340);
(40<=(height||0))||(height=60);
var H = 22,
Y = (3*height-2*H)>>2,
W = new Window('palette', ' '+title, [0,0,width,height]),
P = W.add('progressbar', { x:20, y:height>>2, width:width-40, height:12 }, 0,100),
T = W.add('statictext' , { x:0, y:Y, width:width, height:H }),
__ = function(a,b){ return localize.apply(null,a.concat(b)) };
this.pattern = ['%1'];
W.center();
// ---
// API
// ---
this.msg = function(/*str*/s, v)
// ---------------------------------
{
s && (T.location = [(width-T.graphics.measureString(s)[0])>>1, Y]);
T.text = s;
W.update();
};
this.show = this.reset = function(/*str*/s, /*uint*/v)
// ---------------------------------
{
if( s && s != localize(s,1,2,3,4,5,6,7,8,9) )
{
this.pattern[0] = s;
s = __(this.pattern, [].slice.call(arguments,2));
}
else
{
this.pattern[0] = '%1';
}
P.value = 0;
P.maxvalue = v||0;
P.visible = !!v;
this.msg(s);
W.show();
W.update();
};
this.hit = function(x)
// ---------------------------------
{
++P.value;
('undefined' != typeof x) && this.msg(__(this.pattern, [].slice.call(arguments,0)));
W.update();
};
this.hide = function()
// ---------------------------------
{
W.hide();
};
this.close = function()
// ---------------------------------
{
W.close();
};
};
})($.global,{toString:function(){return 'ProgressBar'}},{});
$.global.hasOwnProperty('SwatchSorter')||(function(H/*OST*/,S/*SELF*/,I/*NNER*/)
{
H = S;
//======================================================
// DATA AND SHORTCUTS
//======================================================
I.O_ROOT = app;
I.O_LOCKED = { 'None':1, 'Black':1,'Paper':1, 'Registration':1 };
I.CM_MIX = +ColorModel.MIXEDINKMODEL;
I.CM_PROCESS = +ColorModel.PROCESS;
I.CM_REG = +ColorModel.REGISTRATION;
I.CM_SPOT = +ColorModel.SPOT;
I.CS_CMYK = +ColorSpace.CMYK;
I.CS_LAB = +ColorSpace.LAB;
I.CS_MIX = +ColorSpace.MIXEDINK;
I.CS_RGB = +ColorSpace.RGB;
// Keep colors and tints together.
I.O_ORDER = { 'Color':1, 'Tint':1, 'Gradient':3, 'MixedInk':4 };
I.BUILD_CLUSTERS = 1;
I.CLUSTER_MASK = 0xF000;
I.O_CLUSTERS = {
'_0' : 'Magentas', // 0x0000
'_4096' : 'Reds', // 0x1000
'_8192' : 'Oranges', // 0x2000
// ---
'_16384' : 'Yellows', // 0x4000
'_20480' : 'Warm Greens', // 0x5000
'_24576' : 'Cool Greens', // 0x6000
// ---
'_32768' : 'Cyans', // 0x8000
'_36864' : 'Blues', // 0x9000
'_40960' : 'Purples', // 0xA000
// ===
'_49152' : 'Grays', // 0xC000
'_53248' : 'Darks', // 0xD000
'_57344' : 'Pastels', // 0xE000
'_61440' : 'Others', // 0xF000
};
//======================================================
// CMYK ROUTINES
//======================================================
I.F_APPLY_CMYK_TINT = function(/*0..100[4]&*/CMYK, /*]0,1]*/t)
//----------------------------------
{
CMYK[0] *= t;
CMYK[1] *= t;
CMYK[2] *= t;
CMYK[3] *= t;
};
I.F_TO_CMYK_KEY = function F(/*0..100[4]*/CMYK, d,a,v,i,t)
//----------------------------------
{
const mABS = Math.abs,
mMIN = Math.min,
mMAX = Math.max;
const INK_MIN = 50,
INK_MAX = 35,
GRAY_VAR = 5,
DARK_MIN = 70,
PASTEL_MAX = 25;
F.DENSITY || (F.DENSITY=[49,60,7,91]);
F.BUFFER || (F.BUFFER=[0,0,0,0]);
for( d=0, a=F.BUFFER, v=F.DENSITY, i=-1 ; ++i < 4 ; (d+=v*(t=CMYK)), a=-(INK_MAX>t)||+(INK_MIN<t) );
d >>>= 3; // <= 0xA1B
for( t=(0<=a[3]), i=-1 ; (!t) && (++i < 3) ; t = 0 > a && 0 < a[(1+i)%3] && a[(2+i)%3] );
if( 3 > (i&=3) )
{
// CMY CLASSES (0x0000 -> 0xAA1B).
// ---------------------------------------------
// DOM SUB DENSITY(12b)
//
// ---------------------------------------------
// Magentas: 00 00 xxxx xxxx xxxx
// Reds: 00 01 xxxx xxxx xxxx
// Oranges: 00 10 xxxx xxxx xxxx
// ---------------------------------------------
// Yellows: 01 00 xxxx xxxx xxxx
// Warm Greens: 01 01 xxxx xxxx xxxx
// Cool Greens: 01 10 xxxx xxxx xxxx
// ---------------------------------------------
// Cyans: 10 00 xxxx xxxx xxxx
// Blues: 10 01 xxxx xxxx xxxx
// Purples: 10 10 xxxx xxxx xxxx
// ---------------------------------------------
++t && (t -= CMYK[(2+i)%3] <= CMYK[(1+i)%3] );
t |= (i<<2);
return d | (t<<12);
}
// ---
// Darks, pastels, grays, others
// ---
d >>>= 2;
i = 0;
t = 3;
while( v = CMYK[0] + CMYK[1] + CMYK[2] )
{
// Other classes (0xC000 -> 0xFFFF)
// ---------------------------------------------
// MK CTG DOM DENSITY(10b)
//
// ---------------------------------------------
// Grays (M) 11 00 00 xx xxxx xxxx
// Grays (Y) 11 00 01 xx xxxx xxxx
// Grays (C) 11 00 10 xx xxxx xxxx
// Grays (K) 11 00 11 xx xxxx xxxx
// ---------------------------------------------
// Darks (M) 11 01 00 xx xxxx xxxx
// Darks (Y) 11 01 01 xx xxxx xxxx
// Darks (C) 11 01 10 xx xxxx xxxx
// ---------------------------------------------
// Pastels (M) 11 10 00 xx xxxx xxxx
// Pastels (Y) 11 10 01 xx xxxx xxxx
// Pastels (C) 11 10 10 xx xxxx xxxx
// ---------------------------------------------
// Others (M) 11 11 00 xx xxxx xxxx
// Others (Y) 11 11 01 xx xxxx xxxx
// Others (C) 11 11 10 xx xxxx xxxx
// ---------------------------------------------
v /= 3;
t = ( CMYK[1] < CMYK[2] || CMYK[1] < CMYK[0] ) << ( CMYK[2] < CMYK[0] );
// Grays
// ---
if( GRAY_VAR >= mMAX(mABS(CMYK[0]-v),mABS(CMYK[1]-v),mABS(CMYK[2]-v)) ) break;
// Darks
// ---
if( ++i && DARK_MIN < mMIN.apply(null,CMYK) ) break;
// Pastels
// ---
if( ++i && PASTEL_MAX > mMAX.apply(null,CMYK) ) break;
// Others
// ---
++i; break;
}
t |= 0x30 | (i<<2);
return d | (t<<10);
};
I.F_CONVERT_TO_CMYK = function(/*Color*/o,/*ColorSpace*/cs,/*ColorValue*/cv, r)
//----------------------------------
{
try {
// Convert to cmyk space if possible.
// This might fail due to imported swatches.
// ---
o.space = I.CS_CMYK;
r = o.colorValue;
// Revert to initial color props.
// ---
o.properties = { space:cs, colorValue:cv };
}
catch(_)
{
// Not implemented
// if( I.CS_RGB==cs && 3==cv.length ) r = I.FN_RGB_TO_CMYK_APPROX(cv);
}
return r || false;
};
I.F_COLOR_TO_CMYK = function(/*Color*/o, r,cv,cs)
//----------------------------------
{
r = false;
if( I.CM_MIX == +o.model ) return r;
cv = o.colorValue;
cs = +o.space;
r = I.CS_CMYK == cs ? cv : I.F_CONVERT_TO_CMYK(o,cs,cv);
return r;
};
//======================================================
// PARSING
//======================================================
I.F_TO_FULL_KEY = function(/*uint*/order,/*[c,m,y,k]*/CMYK,/*str*/name,/*uint*/id)
//----------------------------------
{
return String.fromCharCode(0x40+order,I.F_TO_CMYK_KEY(CMYK)) +
name + '\x01' + id;
};
I.F_PARSE_Color = function(/*Color*/o,/*str*/name,/*uint*/id, a,k)
//----------------------------------
{
if( I.O_LOCKED.hasOwnProperty(name) ) return '';
if( !(a=I.F_COLOR_TO_CMYK(o)) ) return '';
return I.F_TO_FULL_KEY(I.O_ORDER['Color'],a,name,id);
};
I.F_PARSE_Tint = function(/*Tint*/o,/*str*/name,/*uint*/id, bc,a,k)
//----------------------------------
{
bc = o.baseColor;
if( I.O_LOCKED.hasOwnProperty(bc.name) ) return '';
if( !(a=I.F_COLOR_TO_CMYK(bc)) ) return '';
I.F_APPLY_CMYK_TINT(a,o.tintValue/100);
return I.F_TO_FULL_KEY(I.O_ORDER['Tint'],a,name,id);
};
I.F_PARSE_Gradient = function(/*Color*/o,/*str*/name,/*uint*/id)
//----------------------------------
// Not implemented
{
return '';
};
I.F_PARSE_MixedInk = function(/*Color*/o,/*str*/name,/*uint*/id)
//----------------------------------
// Not implemented
{
return '';
};
//==========================================================================
// ORDERING
//==========================================================================
I.F_APPLY_ORDER_CLUSTERS = function(/*ProgressBar*/PB,/*str{}*/data,/*Swatches*/coll, n,o,i,k,s,t)
//----------------------------------
{
const CM = I.CLUSTER_MASK,
OC = I.O_CLUSTERS;
n = data.length;
PB.reset("Assigning groups... (%1 / %2)",n);
o = {};
for( i = 0 ; i < n ; ++i )
{
PB.hit(1+i,n);
if( !(k=data) ) continue;
s = '_' + (CM & k.charCodeAt(1));
if( !OC.hasOwnProperty(s) ) continue;
s = OC;
k = k.substr(2).split('\x01');
if( !(t=coll.itemByID(parseInt(k[1],10))).isValid ) continue;
(o||(o=[])).push(t);
}
n = o.__count__;
i = 0;
t = I.O_ROOT.colorGroups;
PB.reset("Creating group %1... (%2 / %3)",n);
for( k in o )
{
if( !o.hasOwnProperty(k) ) continue;
PB.hit(k,++i,n);
t.add(k,o);
o.length = 0;
}
};
I.F_APPLY_ORDER_FLAT = function(/*ProgressBar*/PB,/*str{}*/data,/*Swatches*/coll, n,i,k,t,o,d)
//----------------------------------
{
n = data.length;
PB.reset("Reordering swatches... (%1 / %2)",n);
for( i = 0 ; i < n ; ++i )
{
PB.hit(1+i,n);
if( !(k=data) ) continue;
k = k.substr(2).split('\x01');
if( !(t=coll.itemByID(parseInt(k[1],10))).isValid ) continue;
t = t.getElements()[0]; // !important!
switch( t.constructor.name )
{
case 'Color':
o = t.duplicate();
t.remove(o);
o.name = k[0];
break;
case 'Tint':
o = t.properties;
d = o.tintValue > 50 ? -.001 : +.001;
o.tintValue += d;
o = I.O_ROOT.tints.add(o);
t.remove(o);
o.tintValue -= d;
break;
default:
// not implemented
}
}
};
I.F_PROCESS_ALL_SWATCHES = function(/*ProgressBar*/PB,/*Swatches*/coll, ei,a,names,ids,i,n,t,k)
//----------------------------------
{
ei = coll.everyItem();
a = ei.getElements();
names = ei.name;
ids = ei.id;
i = n = a.length;
// Parsing swatches
// ---
PB.reset("Parsing swatches... (%1 / %2)",n);
while( i-- )
{
PB.hit(n-i,n);
t = a;
k = 'F_PARSE_' + t.constructor.name;
a = I.hasOwnProperty(k) ? I(t,names,ids) : '';
}
// Sorting
// ---
PB.reset("Sorting colors...");
a.sort();
// Reordering swatches
// ---
I['F_APPLY_ORDER_' + ((I.BUILD_CLUSTERS && 'colorGroups' in app) ? 'CLUSTERS' : 'FLAT')](PB,a,coll);
a.length = 0;
};
//==========================================================================
// IDLE MANAGER
//==========================================================================
(I.F_IDLE_TASK = ('idleTasks' in app) ?
function F(/*?fct*/callback, t)
//----------------------------------
{
t = app.idleTasks.length;
// Cleanup
// ---
if( t && (t=app.idleTasks.itemByName(F.Q.name)).isValid )
{
t.eventListeners.everyItem().remove();
t.remove();
}
// Set callback (if any)
// ---
if( 'function' == typeof callback )
{
app.idleTasks.add({ name:F.Q.name, sleep: F.Q.rate }).
addEventListener(IdleEvent.ON_IDLE, callback, false);
}
}:
function F(/*fct*/callback)
//----------------------------------
{
if( 'function' == typeof callback ) callback();
}
).Q = {name:'Task'+S, rate:25};
(I.F_EXIT_PROCESS = function F()
//----------------------------------
{
// Stop the task
// ---
I.F_IDLE_TASK();
// Close the PB
// ---
F.Q && (F.Q.close());
}).Q = 0;
//==========================================================================
// API
//==========================================================================
S.run = function(/*?Document*/doc,/*bool=0*/NO_CLUSTERS, PB,t)
//----------------------------------
{
I.BUILD_CLUSTERS = +!NO_CLUSTERS;
PB = new ProgressBar(S + ' \xA9indiscripts.com',400,100);
if( ('panels' in app) && (t=app.panels.itemByName('$ID/Swatches')).visible ) t.visible = false;
doc || (doc=app.properties.activeDocument);
if( doc instanceof Document )
{
doc.preflightOptions.properties = { preflightOff: true };
t = doc;
}
else
{
t = app;
}
if( ('colorGroups' in app) && 1 < t.colorGroups.length )
{
t.colorGroups.itemByRange(1,-1).ungroup();
}
I.O_ROOT = t;
app.doScript('I.F_PROCESS_ALL_SWATCHES(PB,t.swatches);',
ScriptLanguage.javascript,
undefined,
UndoModes.entireScript,
''+S
);
PB.reset("Refreshing the GUI. Please, wait...");
if( 'panels' in app )
{
app.panels.itemByName('$ID/Swatches').visible = true;
}
I.F_EXIT_PROCESS.Q = PB;
I.F_IDLE_TASK(I.F_EXIT_PROCESS);
};
})($.global,{toString:function(){return 'SwatchSorter'}}, {});
SwatchSorter.run();