• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers

Here's a script that makes blended squares between two selected swatches.

Explorer ,
Oct 08, 2022 Oct 08, 2022

Copy link to clipboard

Copied

We are often tasked to create printed squares to closely match a PMS color.  While there are many good starting points, in the end we have to produce a range of 5-6 variations.  While Illustrator does offer some tricks to employ, you still have to go through and label each square with the CMYK call outs.  Tedious and prone to error.  Let me introduce "Swatch-nado".  Make and select two new swatches or select two from your existing library.  Then run the script.  It will create all the squares, blending between the swatches and labeling them underneath each square.  Try it out.  I do have a request.  It fails on Global Swatches.  And I can't seem to make the exact number of squares at input.  It always adds 1.  Anyway here it is with attribution in the script.

 

// modified to create blended swatches between 2 input swatches//

// create a set of swatches that blend the start color to the end color ( selected swatches )

//modified by roy solorio

var document = app.activeDocument
document.defaultStroked = false;

function createBlendSwatches( steps ){
var doc = activeDocument,
swatches = doc.swatches,
swatchGroups = doc.swatchGroups,
startSwatch = swatches.getSelected()[0],
endSwatch = swatches.getSelected()[1],
steps = Math.floor( steps );
 
 
if( steps < 1 ){
alert( "steps must be 1 or greater" )
return;
}
 
if( swatches.getSelected().length != 2 ){
alert( "expected two swatches to be selected found:" + swatches.getSelected().length );
return;
 
} else {
var sGrp = swatchGroups.add();
with( sGrp ){
name="colorAverageSwatchs";
}
if( startSwatch.color == "[CMYKColor]" && endSwatch.color == "[CMYKColor]" ){
//alert ( "CMYK swatches selected" );
var colorIncrement = [ (endSwatch.color.cyan - startSwatch.color.cyan)/steps , (endSwatch.color.magenta- startSwatch.color.magenta)/steps, (endSwatch.color.yellow - startSwatch.color.yellow)/steps, (endSwatch.color.black - startSwatch.color.black)/steps ];
 
sGrp.addSwatch( DupSwatch( startSwatch ));
for( i=1; i<steps; i++){
var myColor = new CMYKColor(),
myNewSwatch = swatches.add();
with( myColor ){
cyan = Math.round( startSwatch.color.cyan + colorIncrement[0] * i );
magenta = Math.round(startSwatch.color.magenta + colorIncrement[1] * i );
yellow = Math.round( startSwatch.color.yellow + colorIncrement[2] * i );
black = Math.round( startSwatch.color.black + colorIncrement[3] * i );
}
with( myNewSwatch ){
name = ("C="+myColor.cyan+" "+"M="+myColor.magenta+" "+"Y="+myColor.yellow+" "+"K="+myColor.black );
color = myColor;
}
sGrp.addSwatch( myNewSwatch );
}
sGrp.addSwatch( DupSwatch( endSwatch ));
//alert( "created Swatch Group:"+sGrp.name );
return( sGrp );
 
} else if(startSwatch.color == "[RGBColor]" && endSwatch.color == "[RGBColor]" ){
//alert ( "RGB swatches selected" );
var colorIncrement = [ (endSwatch.color.red- startSwatch.color.red)/steps , (endSwatch.color.green- startSwatch.color.green)/steps, (endSwatch.color.blue - startSwatch.color.blue)/steps ];
 
sGrp.addSwatch( DupSwatch( startSwatch ));
for( i=1; i<steps; i++){
var myColor = new RGBColor(),
myNewSwatch = swatches.add();
 
with( myColor ){
red = Math.round( startSwatch.color.red + colorIncrement[0] * i );
green = Math.round( startSwatch.color.green + colorIncrement[1] * i );
blue = Math.round( startSwatch.color.blue + colorIncrement[2] * i );
}
with( myNewSwatch ){
name = ("r"+myColor.red+","+"g"+myColor.green+","+"b"+myColor.blue );
color = myColor;
}
 
sGrp.addSwatch( myNewSwatch );
}
sGrp.addSwatch( DupSwatch( endSwatch ));
alert( "created swatch:"+myNewSwatch.name );
return( sGrp );
 
} else {
alert( "requires 2 swatches of the same type, either RGB or CMYK" );
return;
 
}
}
}

function DupSwatch( swatch ){
var copy = activeDocument.swatches.add();
with( copy ){
name = swatch.name;
color = swatch.color;
}
return( copy );
}
//=========
//
// MODIFIED
//
/////////////////////////////////////////////////////////////////
// Render Swatch Legend v1.1 -- CS, CS2, CS3, CS4, CS5
//>=--------------------------------------
//
// This script will generate a legend of rectangles for every swatch in the main swatches palette.
// You can configure spacing and value display by configuring the variables at the top
// of the script.
// update: v1.1 now tests color brightness and renders a white label if the color is dark.
//>=--------------------------------------
// JS code (c) copyright: John Wundes ( john@wundes.com ) www.wundes.com
// copyright full text here: http://www.wundes.com/js4ai/copyright.txt
//
//////////////////////////////////////////////////////////////////
function RenderSwatchLegend( swatchGrp )
{
var doc = activeDocument,
swatches = swatchGrp.getAllSwatches(),
displayAs = "CMYKColor", //or "RGBColor"
rectRef=null,
textRectRef=null,
textRef=null,
rgbColor=null,
w=100;
h=100,
h_pad = 36,
v_pad = 100,
y_pad = 18,
x_pad = 94,
t_h_pad = 0,
t_v_pad = -104,
x=null,
y=null,
black = new GrayColor(),
white = new GrayColor()
sc=0
wedgeCount = 25;
 
cols = Math.floor(( doc.width - h_pad ) / ( w + y_pad ));

black.gray = 100;
white.gray = 0;
 
var wedgeLayer = doc.layers.add();
with(wedgeLayer){
name = "Swatch-nado";
locked= false;
}
{var text1 = doc.textFrames.add();
text1.translate(h_pad,-x_pad);
text1.textRange.characterAttributes.size = 18;
text1.textRange.characterAttributes.textFont = app.textFonts["Gotham-Book"];
text1.contents = "PMS xxxx";
}
var newGroup = doc.groupItems.add();
with( newGroup ){
name = "Color";
parent = wedgeLayer;
}

newGroup.move( doc, ElementPlacement.PLACEATBEGINNING );

for(var c=0,len=swatches.length;c<len;c++)
{

var swatchGroup = doc.groupItems.add();
swatchGroup.name = swatches[c].name;
if(swatchGroup.name != "[None]" && swatchGroup.name != "[Registration]")
{
x= (w+y_pad)*(sc% cols) + h_pad;
y=((h+v_pad)*(Math.floor((sc+.01)/cols))*-1) - v_pad;
rectRef = doc.pathItems.rectangle(y,x, w,h);
rgbColor = swatches[c].color;
rectRef.fillColor = rgbColor;
textRectRef = doc.pathItems.rectangle(y+t_v_pad,x+ t_h_pad,w,h+(.8*t_v_pad));
textRef = doc.textFrames.areaText(textRectRef);
textRef.contents = swatches[c].name;
textRef.textRange.characterAttributes.size = 8;
textRef.textRange.characterAttributes.textFont = app.textFonts["Gotham-Book"];
textRef.textRange.fillColor = black;
rectRef.move( swatchGroup, ElementPlacement.PLACEATBEGINNING );
textRef.move( swatchGroup, ElementPlacement.PLACEATBEGINNING );
swatchGroup.move( newGroup, ElementPlacement.PLACEATEND );
sc ++;
}
}
}


function rgb2cmyk (r,g,b) {
var computedC = 0;
var computedM = 0;
var computedY = 0;
var computedK = 0;

//remove spaces from input RGB values, convert to int
var r = parseInt( (''+r).replace(/\s/g,''),10 );
var g = parseInt( (''+g).replace(/\s/g,''),10 );
var b = parseInt( (''+b).replace(/\s/g,''),10 );

if ( r==null || g==null || b==null ||
isNaN(r) || isNaN(g)|| isNaN(b) )
{
alert ('Please enter numeric RGB values!');
return;
}
if (r<0 || g<0 || b<0 || r>255 || g>255 || b>255) {
alert ('RGB values must be in the range 0 to 255.');
return;
}

// BLACK
if (r==0 && g==0 && b==0) {
computedK = 1;
return [0,0,0,1];
}

computedC = 1 - (r/255);
computedM = 1 - (g/255);
computedY = 1 - (b/255);

var minCMY = Math.min(computedC,
Math.min(computedM,computedY));
computedC = (computedC - minCMY) / (1 - minCMY) ;
computedM = (computedM - minCMY) / (1 - minCMY) ;
computedY = (computedY - minCMY) / (1 - minCMY) ;
computedK = minCMY;

return [Math.floor(computedC*100),Math.floor(computedM*100),Math.floor(computedY*100),Math.floor(computedK*100)];
}

function is_dark(color){
if(color.typename)
{
switch(color.typename)
{
case "CMYKColor":
return (color.black>50 || (color.cyan>50 && color.magenta>50)) ? true : false;
case "RGBColor":
return (color.red<100 && color.green<100 ) ? true : false;
case "GrayColor":
return color.gray > 50 ? true : false;
case "SpotColor":
return is_dark(color.spot.color);
 
return false;
}
}
}

function main(){
var userSteps = Number( prompt( "After the FIRST SWATCH, how many more do you need?", 5 ));
var swatchGrp = createBlendSwatches( userSteps );
RenderSwatchLegend( swatchGrp );
}
main();
TOPICS
Scripting , Tools

Views

110

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
community guidelines
Community Expert ,
Oct 08, 2022 Oct 08, 2022

Copy link to clipboard

Copied

Hi @RoyBoySolorio, fantastic work getting this script together and working. I had a look through the code and, to be honest, it is a bit complicated for me to easily fix the remaining problems. I have a little script object called SwatchCollection that I wrote for laying out swatches in a similar way and I could fairly easily extend it to do the interpolation that you need. Is that something you'd be interested in? If so, I can post when I get a chance. Meanwhile someone else might have a quicker answer.

- Mark

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
community guidelines
Explorer ,
Oct 09, 2022 Oct 09, 2022

Copy link to clipboard

Copied

Thanks M1b 

 

I looked at your script while gathering info, so thank again.

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
community guidelines
Community Expert ,
Oct 10, 2022 Oct 10, 2022

Copy link to clipboard

Copied

Hi @RoyBoySolorio, I have adapted a bit with some functions that you discuss but I haven't tested it much. Have a read through the code and you can get some ideas for your script, or try it out for your situation. You can configure it by setting the ColorChip properties at line 40.  Let me know how you go.

- Mark

 

P.S. one thing it doesn't do it multi-row chips.

 

/**
 * @file Sample usage of ColorChips.js
 * @author m1b
 * @discussion https://community.adobe.com/t5/illustrator-discussions/here-s-a-script-that-makes-blended-squares-between-two-selected-swatches/m-p/13253249
 */



(function () {
    // normally ColorChips is a separate library
    // file but, for the forum post, I'll include
    // it at the end of this script
    var ColorChips = loadColorChips();


    // 1. get two selected colors

    var doc = app.activeDocument,
        selectedSwatches = doc.swatches.getSelected();
    // selectedSwatches = [doc.swatches[5], doc.swatches[7]];

    if (selectedSwatches.length != 2) {
        alert('Please select two swatches and try again.');
        return;
    }


    // 2. make interpolated breakdowns of the two swatches

    var numberOfChips = Number(prompt('Create how many color chips?', 7) || 7),
        breakdowns = interpolateArrays(ColorChips.breakdownFromColor(selectedSwatches[0].color), ColorChips.breakdownFromColor(selectedSwatches[1].color), numberOfChips);


    // 3. make the ColorChips

    var chips = new ColorChips(

        // edit any of the following settings:

        {
            doc: doc,
            position: [100, 100],

            showName: false,
            showBreakdown: true,

            nameFilter: function (c, i) { return c.name.replace(/^PANTONE\s/, '') },

            labelFont: 'Gotham-Book',
            labelFontSize: 6,
            labelColor: undefined,
            labelGap: 5,

            chipWidth: 30,
            chipHeight: 30,
            chipStrokeWidth: 0.5,
            chipStrokeColor: undefined,
            chipGap: 5,

            makeSwatches: true,
            makeGlobalSwatches: true,
            makeColorGroup: true,
            colorGroupName: 'My Colors',

            showBorder: true,
            borderColor: undefined,
            margin: 10,

            breakdowns: breakdowns,

        }

    );

    // draw the ColorChips:

    // horizontal layout
    chips.drawHorizontally();

    // vertical layout
    // chips.drawVertically();


    /**
 * Returns `n` interpolations of the
 * two supplied Arrays, inclusive.
 * @author m1b
 * @version 2022-10-03
 * @param {Array<Number>} arr1
 * @param {Array<Number>} arr2
 * @param {Number} n - the number of interpolated arrays returns, inclusive of arr1 and arr2.
 * @returns {Array<Array>} - an array of arrays [arr1, inter1, inter2, inter3, ..., interN, arr2]
 */
    function interpolateArrays(arr1, arr2, n) {

        if (
            arr1 == undefined
            || arr2 == undefined
        )
            throw Error('interpolateArrays: missing argument(s).');

        if (arr1.length !== arr2.length)
            throw Error('interpolateArrays: array lengths don\'t match.');

        if (
            n.constructor.name != 'Number'
            || n < 0
            || n !== n
        )
            throw Error('interpolateArrays: bad argument for "n".');

        // calculate the interpolations
        var results = [];
        for (var j = 0; j < n; j++)
            results[j] = [];

        for (var i = 0; i < arr1.length; i++) {

            var s = arr1[i],
                e = arr2[i];

            for (var j = 0; j < n; j++)
                results[j].push(s + ((s - e) / (n - 1)) * -j);

        }

        return results;

    }

})();


function loadColorChips() {

    /**
     * Makes a "Color Chips" group item
     * with can be drawn horizontally or
     * vertically, with one chip per
     * supplied breakdown or swatch.
     * @author m1b
     * @version 2022-10-03
     * All positioning measurements are in points.
     * @constructor
     * @param {Object} options
     * @param {Document} [options.doc] - an Illustrator Document (default: activeDocument).
     * @param {Array<Number>} [options.position] - [x, y] position of top left of swatch collection (default: center of view).
     * @param {Number} [options.chipWidth] - the color chip width (default: 30).
     * @param {Number} [options.chipHeight] - the color chip height (default: 30).
     * @param {Number} [options.chipStrokeWidth] - the color chip stroke width (default: 1).
     * @param {Number} [options.chipGap] - the space between color chips (default: 10).
     * @param {Number} [options.labelFont] - the label font (default: Illustrator's default).
     * @param {Number} [options.labelFontSize] - the label text size (default: 7).
     * @param {Number} [options.labelGap] - the space between the chip and the label (default: 5).
     * @param {Number} [options.margin] - the space between the border and the chips (default: 10).
     * @param {Boolean} [options.showBorder] - whether to show the outer border (default: true).
     * @param {Boolean} [options.showName] - whether to show labels (default: true).
     * @param {Boolean} [options.showBreakdown] - whether to show labels (default: true).
     * @param {Color} [options.borderColor] - the color of the border (default: non-global black).
     * @param {Color} [options.chipStrokeColor] - the color of the strokes (default: non-global black).
     * @param {Color} [options.labelColor] - the color of the labels (default: non-global black).
     * @param {Boolean} [options.makeSwatches] - whether to make swatches (default: false).
     * @param {Boolean} [options.makeGlobalSwatches] - whether swatches made are global (default: false).
     * @param {Boolean} [options.makeColorGroup] - whether to put swatches in a ColorGroup (default: false).
     * @param {String} [options.colorGroupName] - name for the ColorGroup (default: 'Chips').
     * @param {Array<Swatch>|Swatches|Array<Number>} [options.swatches] - an array of Swatches or a Swatches object (default: all swatches in document).
     * @param {Function} [options.swatchFilter] - a function that filters swatches (default: no filter).
     * @param {Function} [options.nameFilter] - a function that returns the color name (default: returns unmodified name).
     */
    function ColorChips(options) {

        var black = new GrayColor()
        black.gray = 100;

        var self = this,
            doc = self.doc = options.doc || app.activeDocument,
            position = self.position = options.position,
            chipWidth = self.chipWidth = options.chipWidth || 30,
            chipHeight = self.chipHeight = options.chipHeight || 30,
            chipStrokeWidth = self.chipStrokeWidth = options.chipStrokeWidth != undefined ? options.chipStrokeWidth : 1,
            chipGap = self.chipGap = options.chipGap != undefined ? options.chipGap : 0,
            labelFont = self.labelFont = options.labelFont,
            labelGap = self.labelGap = options.labelGap != undefined ? options.labelGap : 5,
            showBorder = self.showBorder = options.showBorder !== false,
            margin = self.margin = options.margin != undefined ? options.margin : 0,
            borderColor = self.borderColor = options.borderColor || black,
            chipStrokeColor = self.chipStrokeColor = options.chipStrokeColor || black,
            nameFilter = self.nameFilter = options.nameFilter || function (c) { return c.name },
            showName = self.showName = options.showName !== false,
            showBreakdown = self.showBreakdown = options.showBreakdown !== false,
            labelColor = self.labelColor = options.labelColor || black,
            labelFontSize = self.labelFontSize = options.labelFontSize || 7,
            unfilteredSwatches = options.swatches || doc.swatches,
            swatchFilter = options.swatchFilter || function (c, index) { return index > 1 },
            colors = self.colors = [],
            breakdowns = self.breakdowns = options.breakdowns || [],
            makeSwatches = options.makeSwatches !== false,
            makeGlobalSwatches = options.makeGlobalSwatches !== false,
            makeColorGroup = options.makeColorGroup !== false,
            colorGroupName = self.colorGroupName = options.colorGroupName || 'Untitled';

        self.colorChipsGroupItems = [];

        if (breakdowns != undefined) {

            // make colors from breakdowns
            for (var i = 0; i < breakdowns.length; i++) {
                var c = ColorChips.colorFromBreakdown(breakdowns[i]);
                if (c != undefined)
                    colors.push(c);
            }

        }

        else {

            // filter swatches
            for (var i = 0; i < unfilteredSwatches.length; i++)
                if (
                    options.swatchFilter == undefined
                    || options.swatchFilter(unfilteredSwatches[i], i)
                ) {
                    colors.push(unfilteredSwatches[i]);
                }

        }

        if (makeSwatches === true)
            self.colorGroup = self.makeSwatches(makeGlobalSwatches, makeColorGroup, colorGroupName)

        if (self.labelFont != undefined)
            self.labelFont = app.textFonts[self.labelFont];

    }


    /**
     * Draw the ColorChips to document.
     * @author m1b
     * @version 2022-10-03
     * @param {Bool} isHorizontal - whether to draw in horizontal or vertical format (default: true).
     * @param {Array<Number>} position - the coordinates of the top-left of the swatch panel item.
     * @returns {GroupItem} - the ColorChips page item.
     */
    ColorChips.prototype.draw = function (isHorizontal, position) {

        var self = this,
            group = self.doc.groupItems.add(),
            doc = self.doc,
            chipWidth = self.chipWidth,
            chipHeight = self.chipHeight,
            chipGap = self.chipGap,
            chipStrokeWidth = self.chipStrokeWidth,
            makeLabel = self.showName === true || self.showBreakdown === true,
            labelGap = makeLabel ? self.labelGap : 0,
            margin = self.margin,
            labelFunction = self.labelFunction || isHorizontal ? basicLabelHorizontal : basicLabelVertical;

        var x = 0,
            y = 0,
            textWidth = 0,
            textHeight = 0;

        for (var i = 0; i < self.colors.length; i++) {

            var c = self.colors[i];

            // make the label textFrame
            if (makeLabel) {

                var textFrame = labelFunction(doc, x, y, c, i, self);

                if (textFrame.width > textWidth)
                    textWidth = textFrame.width;

                if (textFrame.height > textHeight)
                    textHeight = textFrame.height;

                textFrame.moveToEnd(group);

            }

            // make the chip rectangle
            var rect = doc.pathItems.rectangle(y, x, chipWidth, chipHeight);

            rect.filled = true;
            rect.fillColor = c.hasOwnProperty('color') ? c.color : c;
            rect.stroked = self.chipStrokeWidth > 0;
            rect.strokeWidth = chipStrokeWidth;
            rect.strokeColor = self.chipStrokeColor;
            rect.moveToEnd(group);

            if (isHorizontal)
                x += self.chipWidth + self.chipGap;

            else
                y -= self.chipHeight + self.chipGap;

        }

        var totalWidth,
            totalHeight;

        if (isHorizontal) {
            totalWidth = margin + (chipWidth * self.colors.length) + (chipGap * (self.colors.length - 1)) + margin;
            totalHeight = margin + chipHeight + labelGap + textHeight + margin;
        }

        else {
            totalWidth = margin + chipWidth + labelGap + textWidth + margin;
            totalHeight = margin + chipHeight * self.colors.length + chipGap * (self.colors.length - 1) + margin;
        }


        // outer border
        if (self.showBorder) {

            rect = doc.pathItems.rectangle(margin, - margin, totalWidth, totalHeight);
            rect.strokeColor = self.borderColor;
            rect.strokeWidth = self.chipStrokeWidth;
            rect.filled = false;
            rect.moveToEnd(group);

        }

        if (position != undefined)
            position = doc.convertCoordinate([position[0] + margin, -position[1] - margin], CoordinateSystem.ARTBOARDCOORDINATESYSTEM, CoordinateSystem.DOCUMENTCOORDINATESYSTEM);

        else if (self.position != undefined)
            position = doc.convertCoordinate([self.position[0], -self.position[1]], CoordinateSystem.ARTBOARDCOORDINATESYSTEM, CoordinateSystem.DOCUMENTCOORDINATESYSTEM);

        else
            position = [doc.activeView.centerPoint[0] - totalWidth / 2, doc.activeView.centerPoint[1] + totalHeight / 2];

        // final positioning
        group.position = position;

        self.colorChipsGroupItems.push(group);

        return group;

    };


    /**
     * Draw the ColorChips to document, horizontally.
     * @author m1b
     * @version 2022-10-01
     * @param {Array<Number>} position - the coordinates of the top-left of the swatch panel item.
     * @returns {GroupItem} - the ColorChips page item.
     */
    ColorChips.prototype.drawHorizontally = function (position) {

        return this.draw(true, position);

    };


    /**
     * Draw the ColorChips to document, vertically.
     * @author m1b
     * @version 2022-10-01
     * @param {Array<Number>} position - the coordinates of the top-left of the swatch panel item.
     * @returns {GroupItem} - the ColorChips page item.
     */
    ColorChips.prototype.drawVertically = function (position) {

        return this.draw(false, position);

    };


    /**
     * Returns Color object when given an array of values.
     * @author m1b
     * @version 2022-10-08
     * eg. [50] = GrayColor
     *     [255,128,0] = RGBColor
     *     [10,20,30,0] = CMYKColor
     * @param {Array<Number>} breakdown - an array of color breakdown values.
     * @returns {Color}
     */
    ColorChips.colorFromBreakdown = function colorFromBreakdown(breakdown) {

        if (breakdown == undefined)
            return;

        // sanity check
        for (var i = 0; i < breakdown.length; i++)
            if (breakdown[i] < 0)
                breakdown[i] = 0;

        var colr;

        switch (breakdown.length) {

            case 1: // [K]
                colr = new GrayColor();
                colr.gray = breakdown[0];
                break;

            case 3: // [R,G,B]
                colr = new RGBColor();
                colr.red = breakdown[0];
                colr.green = breakdown[1];
                colr.blue = breakdown[2];
                break;

            case 4: // [C,M,Y,K]
                colr = new CMYKColor();
                colr.cyan = breakdown[0];
                colr.magenta = breakdown[1];
                colr.yellow = breakdown[2];
                colr.black = breakdown[3];
                break;

            default:
                throw Error('ColorChips.colorFromBreakdown: couldn\'t parse color (' + breakdown + ')');

        }

        return colr;

    };


    /**
     * Returns the color breakdown of a given Color.
     * eg. GrayColor = [50]
     *     RGBColor = [255,128,0]
     *     CMYKColor = [10,20,30,0]
     * @author m1b
     * @version 2022-10-08
     * @param {Color} colr - an Illustrator Color.
     * @returns {Array<Number>}
     */
    ColorChips.breakdownFromColor = function breakdownFromColor(colr) {

        if (colr == undefined)
            return;

        else if (colr.constructor.name == 'Swatch')
            colr = colr.color;

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

        else if (colr.constructor.name == 'GradientColor')
            colr = colr.gradient.gradientStops[0].color;

        var breakdown;

        switch (colr.constructor.name) {

            case 'GrayColor': // [K]
                breakdown = [colr.gray];
                break;

            case 'RGBColor': // [R,G,B]
                breakdown = [colr.red, colr.green, colr.blue];
                break;

            case 'CMYKColor': // [C,M,Y,K]
                breakdown = [colr.cyan, colr.magenta, colr.yellow, colr.black];
                break;

            default:
                throw Error('ColorChips.breakdownFromColor: couldn\'t parse breakdown from "' + colr + '".');

        }

        return breakdown;

    };


    /**
     * Returns array of Colors by interpolating
     * between the two supplied colors.
     * eg. 20K and 50K with n = 2 -> [20K, 30K, 40K, 50K]
     * @author m1b
     * @version 2022-10-08
     * @param {Color} c1 - an Illustrator Color.
     * @param {Color} c2 - an Illustrator Color.
     * @param {Number} n - the number of steps in between.
     * @returns {Array<Number>}
     */
    ColorChips.colorsByInterpolation = function colorsByInterpolation(c1, c2, n) {

        var colrs = [],
            breakdown1 = ColorChips.breakdownFromColor(c1),
            breakdown2 = ColorChips.breakdownFromColor(c2);

        var breakdowns = interpolateArrays(breakdown1, breakdown2, n);

        // make colors
        for (var i = 0; i < breakdowns.length; i++) {
            var c = ColorChips.colorFromBreakdown(breakdowns[i]);
            if (c != undefined)
                colrs.push(c);
        }

    };


    /**
     * Create a ColorGroup containing
     * the ColorChip's colors.
     * @author m1b
     * @version 2022-10-03
     * @param {Boolean} makeGlobal - whether the swatches created will be global (default: false).
     * @param {Boolean} makeColorGroup - whether the swatches created will be global (default: false).
     * @param {String} colorGroupName - the name of the colorGroup.
     * @returns {SwatchGroup}
     */
    ColorChips.prototype.makeSwatches = function makeSwatches(makeGlobal, makeColorGroup, colorGroupName) {

        var self = this,
            colorGroup;

        if (makeColorGroup === true) {

            for (var i = 0; i < self.doc.swatchGroups.length; i++)
                if (self.doc.swatchGroups[i].name == colorGroupName)
                    colorGroup = self.doc.swatchGroups[i];

            if (colorGroup == undefined) {
                colorGroup = self.doc.swatchGroups.add();
                colorGroup.name = colorGroupName;
            }

            if (colorGroup == undefined)
                makeColorGroup = false;

        }

        for (var i = 0; i < self.colors.length; i++) {

            var c = self.colors[i],
                colorName = basicLabelForColor(c, '=', ' '),
                existingColor = getSwatch(self.doc, colorName),
                sw;

            if (existingColor != undefined)
                existingColor.remove();

            if (makeGlobal === true) {
                sw = self.doc.spots.add();
                sw.colorType = ColorModel.PROCESS;
            }

            else {
                sw = self.doc.swatches.add();
            }

            sw.name = colorName;
            sw.color = c;

            // store the swatch of the color
            for (var j = 0; j < self.doc.swatches.length; j++)
                if (self.doc.swatches[j].name == colorName)
                    self.colors[i] = self.doc.swatches[j];

            if (makeColorGroup)
                colorGroup.addSwatch(self.colors[i]);


            // self.colors[i] = self.doc.swatches.itemByName(colorName);

        }

        return colorGroup;


        /**
         * Returns a document swatch by name.
         * @author m1b
         * @version 2022-10-10
         * @param {Document} doc - and Illustrator Document.
         * @param {String} name - the swatch name.
         * @returns {Swatch}
         */
        function getSwatch(doc, name) {

            for (var i = 0; i < doc.swatches.length; i++)
                if (doc.swatches[i].name == name)
                    return doc.swatches[i];

        };


    };


    /**
     * Creates and formats a text label
     * for horizontally drawn ColorChips.
     * @author m1b
     * @version 2022-10-09
     * @param {Document} doc - an Illustrator Document.
     * @param {Number} x - the label position x.
     * @param {Number} y - the label position y.
     * @param {Color} c - an Illustrator Color.
     * @param {any} self - a parent object, eg. a ColorChips.
     * @returns {TextFrame} - the label.
     */
    function basicLabelHorizontal(doc, x, y, c, i, self) {

        var textFrame = doc.textFrames.pointText([x, y]);

        if (self.labelFont != undefined)
            textFrame.textRange.characterAttributes.textFont = self.labelFont;

        var nameParts = [];
        if (self.showName)
            nameParts.push(self.nameFilter(c, i));
        if (self.showBreakdown)
            nameParts.push(basicLabelForColor(c, '\t', '\n'));

        textFrame.contents = nameParts.join('\n');

        textFrame.textRange.fillColor = self.labelColor;
        textFrame.textRange.size = self.labelFontSize;

        // JUSTIFIED LEFT
        textFrame.position = [x, y - self.chipHeight - self.labelGap];
        textFrame.textRange.justification = Justification.LEFT;

        // JUSTIFIED CENTRED
        // textFrame.position = [x + self.chipWidth / 2, y - self.chipHeight - self.labelGap];
        // textFrame.textRange.justification = Justification.CENTER;

        // set tab stop to align value
        var tstops = [new TabStopInfo()];
        tstops[0].position = self.labelFontSize * 1.2;
        textFrame.textRange.tabStops = tstops;

        return textFrame;

    };


    /**
     * Creates and formats a text label
     * for vertically drawn ColorChips.
     * @author m1b
     * @version 2022-10-09
     * @param {Document} doc - an Illustrator Document.
     * @param {Number} x - the label position x.
     * @param {Number} y - the label position y.
     * @param {Color} c - an Illustrator Color.
     * @param {any} self - a parent object, eg. a ColorChips.
     * @returns {TextFrame} - the label.
     */
    function basicLabelVertical(doc, x, y, c, i, self) {

        var textFrame = doc.textFrames.pointText([x, y]);

        if (self.labelFont != undefined)
            textFrame.textRange.characterAttributes.textFont = self.labelFont;

        var nameParts = [];
        if (self.showName)
            nameParts.push(self.nameFilter(c, i));
        if (self.showBreakdown)
            nameParts.push(basicLabelForColor(c, '\t', '\n'));

        textFrame.contents = nameParts.join('\n');

        textFrame.textRange.fillColor = self.labelColor;
        textFrame.textRange.size = self.labelFontSize;

        // JUSTIFIED LEFT
        textFrame.position = [x + self.chipWidth + self.labelGap, y];
        textFrame.textRange.justification = Justification.LEFT;

        // set tab stop to align value
        var tstops = [new TabStopInfo()];
        tstops[0].position = self.labelFontSize * 1.2;
        textFrame.textRange.tabStops = tstops;

        return textFrame;

    };


    /**
     * Returns a string suitable for
     * labelling a color.
     * @author m1b
     * @version 2022-10-09
     * Example output:
     * 'C=100 M=50 Y=0 K=10' (to match Color.toString)
     * 'C\t100\nM\t50\nY\t0\nK\t10' (align value with tabs, one per line)
     * @param {Color} cc - an Illustrator Color.
     * @param {String} delim1 - a string that delimits channel values (default: '=').
     * @param {String} delim2 - a string that divides the channel reference and the value (default: ' ').
     * @param {Number} [decimalPlaces] - how many decimal places to show in value (default: 0).
     * @returns {String}
     */
    function basicLabelForColor(c, delim1, delim2, decimalPlaces) {

        var label,
            cc = c.hasOwnProperty('color') ? c.color : c;

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

        if (
            cc.hasOwnProperty('red')
            || cc.length == 3
        ) {
            label = symbolValueString(cc, delim1, delim2, decimalPlaces, [
                { symbol: 'R', property: 'red' },
                { symbol: 'G', property: 'green' },
                { symbol: 'B', property: 'blue' }
            ]);
        }

        else if (
            cc.hasOwnProperty('cyan')
            || cc.length == 4
        ) {
            label = symbolValueString(cc, delim1, delim2, decimalPlaces, [
                { symbol: 'C', property: 'cyan' },
                { symbol: 'M', property: 'magenta' },
                { symbol: 'Y', property: 'yellow' },
                { symbol: 'K', property: 'black' }
            ]);

        }

        else if (
            cc.hasOwnProperty('gray')
            || cc.length == 1
        ) {
            label = symbolValueString(cc, delim1, delim2, decimalPlaces, [
                { symbol: 'K', property: 'gray' }
            ]);
        }

        else
            label = '#ERROR';

        return label;


    };


    /**
     * Returns a text label derived
     * from a color's breakdown.
     * @author m1b
     * @version 2022-10-09
     * The `obj` argument can be any
     * object having properties expressed
     * in `map`, eg. an Illustrator Color
     * with properties expressed in the map,
     * eg. 'red' which gets the value '210';
     * or it can be an array of values,
     * eg. [210, 255, 33] for RGB and the
     * map's properties can be '0', '1', '2'.
     * Example output:
     * "R=210 G=255 B=33"
     * @param {Object} obj - an object or an array of values.
     * @param {String} [delim1] - first delimiter (default: '=').
     * @param {String} [delim2] - second delimiter, between values (default: ' ').
     * @param {Number} [decimalPlaces] - how many decimal places to show in value (default: 0).
     * @param {Object} map - label info object {symbol: 'R', property: 'red'}
     */
    function symbolValueString(obj, delim1, delim2, decimalPlaces, map) {

        if (delim1 == undefined)
            delim1 = '=';

        if (delim2 == undefined)
            delim2 = ' ';

        if (decimalPlaces == undefined)
            decimalPlaces = 0;

        var label = [];

        for (var i = 0; i < map.length; i++)
            label.push(map[i].symbol + delim1 + (obj[map[i].property] != undefined ? round(obj[map[i].property], decimalPlaces) : round(obj[i])));

        return label.join(delim2);

    };


    /**
     * Rounds a number to n decimal places.
     * @author m1b
     * @version 2022-10-09
     * @param {Number} num - the number to round.
     * @param {Number} [places] - the number of decimal places (default: 0)
     */
    function round(num, places) {

        places = Math.pow(10, places || 0);
        return Math.round(num * places) / places;

    };


    return ColorChips;

}

 

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
community guidelines
Explorer ,
Oct 12, 2022 Oct 12, 2022

Copy link to clipboard

Copied

LATEST

This great, m1b!  Love the ways you can show or hide frames/labels and change size pretty easily. Very impressive code.

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
community guidelines
Advisor ,
Oct 08, 2022 Oct 08, 2022

Copy link to clipboard

Copied

I do have a request. It fails on Global Swatches. And I can't seem to make the exact number of squares at input. It always adds 1.

 

When I tick the "global" box in a swatch's options and run the script, I get the message "requires 2 swatches of the same type, either RGB or CMYK". I may be misunderstanding the question or the concept of a global color, but ticking the "global" box makes a script read a color as a spot color. So it should be a matter of adding a block to the script to work with a spot color (similar to the ones for CMYK and RGB).

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
community guidelines
Explorer ,
Oct 09, 2022 Oct 09, 2022

Copy link to clipboard

Copied

I did find a script that converts the selected swatches into global swatches, which is a starting point.  Your idea to build the next block with those spots in mind could be the solution. Thanks

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
community guidelines