# Scripting Illustrator Part 2 – How to Meld a Gradient into a Flat Process Color

In Part 1 of this two part tutorial series, we learned how to code a script which converts a flat process color into its matching gradient. In this tutorial, we will learn to code a script that converts a gradient fill into a flat process color. We will melt the available gradient color into a flat process color, which will be a mixture of all the colors available in that gradient.

This entire task will be performed via JavaScript script for Illustrator. The tutorial assumes that you’re familiar with the basics of scripting. For those who’ve directly landed on this tutorial, we have a little know-how covered about Illustrator’s Javascripts in Part 1 of this series. So without further delays, let’s get started!

### Vector Plus

Want access to the full Vector Source files and downloadable copies of every tutorial, including this one? Join Vector Plus for just 9\$ a month.

### Tutorial Details

• Program: Adobe Illustrator and ExtendedScript Toolkit
• Version: CS3
• Difficulty: Intermediate
• Estimated Completion Time: 3 to 4 Hrs

### Purpose of the Script

We want this script to perform a very simple task. In Adobe Illustrator, when a user selects some objects filled with a CMYK Gradient Color, and executes this Script; the objects shall get converted into a Flat CMYK fill. This flat fill will be the mixture of all the colors available in the former gradient. See the image below for clarification.

Hence, the aim of our script is to convert a Gradient CMYK Fill into a Flat CMYK Fill.

### Logic and Algorithm

The logic for melting the colors of a gradient into a single color is simple and straightforward. We’ll pick all the colors from the gradient, find their average and assign it to the object as a new color. We can understand this in five steps, as shown below:

• Step 1: Pick the color of the current object. i.e. currentColor = color of currently selected object.
• Step 2: Count the number of gradient stops in the current color.
• Step 3: At each gradient stop, pick the associated color and its CMYK values.
• Step 4: Calculate the average CMYK value for all colors available at different stops.
• Step 5:
Assign this average CMYK value as a new color to the object.

The above algorithm can be easily understood from the pictorial representation below.

We have seen a brief overview of the logic. Let’s get started with the coding.

### Step 1 – Starting with the Code Structure

Open ExtendedScript Toolkit and create a new Javascript file (Command + N). Next, select Adobe Illustrator for the target application.

In the code editing area, add the following code structure for certain validations and pre-requisite checks.

```if ( app.documents.length > 0 && app.activeDocument.pathItems.length > 0)
{
if(app.activeDocument.documentColorSpace == DocumentColorSpace.CMYK)
{
convertToFlat();
}
else
{
alert("Convert the Objects into CMYK First", "CMYK Conversion required");
}
}//end main if
else
{
alert("Either no document is available or the document is empty");
}
```

We are checking if at least one document with at least one object exists, so that we can work upon it. Next, we are checking whether the document color mode is CMYK or not. This is an essential step because all the logic for color conversion in this script is based upon CMYK colors. `convertToFlat()` is the main function which will contain all the logic. Next, save this file as test.jsx.

### Step 2

Let’s now start with the main function – `convertToFlat()`. We’ll check if any item is selected or not, because this script will work on the selected objects only. Hence, add the following lines of code to “test.jsx.”

```function convertToFlat()
{
var items = selection;
var totalSelected = items.length;
if(totalSelected > 0)
{
// proceed with the main logic
}
else
{
}
```

### Step 3

Next, we will start a loop inside the “`if(totalSelected > 0)`” block. This loop will contain the color conversion logic, which is repeated for each selected item. But just before the color conversion logic, let’s add some more validations and checks inside that loop.

```    if(totalSelected > 0)
{
for(var j=0; j < totalSelected; j++)
{
var currentObject = app.activeDocument.selection[j];
if(currentObject.typename != "CompoundPathItem" &&
currentObject.typename != "GroupItem")
{
if(currentObject.filled==true &&
currentObject.fillColor.typename != "CMYKColor" &&
currentObject.fillColor.typename != "PatternColor" &&
currentObject.fillColor.typename != "SpotColor")
{
// Color conversion Block
} //endif
else
{
alert("Fill an object with CMYK or Grayscale Gradient. Flat Colors, Patterns, Spot Colors and Empty Fills are not allowed."," Only Gradients Allowed");
}
} //endif
else
{
alert("This script only works with Non-Compound Objects or Isolated Group items.\nAny items with Groups or Compound Objects will be omitted.", "Ungroup or Isolate the Group Items");
}
}//endfor
}// endif
```

For each selected item, we are checking whether it is a Compound Path or a Group Item. If so, the script shall not execute anymore and return an alert message. Further, we are checking if the fill-type of the selected item is something other than Gradient Fill. i.e. If it is a spot color, flat CMYK color or a pattern; the script shall return an alert. These checks are performed because our script will only work for gradient filled non-compound path items.
Next, we will modify the Color conversion Block.

### Step 4

At this stage, we need to extract individual C, M, Y and K values for the colors residing at different gradient stops. For that, we will create some variables which will hold individual CMYK values. So, add the following variable declarations just inside the Color conversion block:

```        var currentColor = currentObject.fillColor;
var colorBox=[];
var cyanBox=[];
var magentaBox=[];
var yellowBox=[];
var blackBox=[];
var grayBox =[];
var cyanTotal = 0;
var magentaTotal = 0;
var yellowTotal = 0;
var blackTotal = 0;
var grayTotal = 0;
```

We will see the role of each variable one-by-one:

• `currentColor` will store the fill color (gradient) of the currently selected object.
• `numOfStops` contains the total number of gradient stops available in currently selected object. This will be used to find the average of color values in later stages.
• `colorBox` is an array which will hold the fill-color value for all the gradient stops. i.e. if `numOfStops` is four.
• `colorBox` array will contain four colors.
• `cyanBox` is an array which holds cyan values for each color on different gradient stops.
• Similarly, `magentaBox`, `yellowBox` and
`blackBox` hold their respective color values for each color on different gradient stops.
• `grayBox` is an array which holds gray values for the color on any gradient stop. This is essential because the gray color is a different specification than CMYK color specification. In case, an object contains a gray gradient, we will handle the situation separately by making use of this variable.
• Finally, we have `cyanTotal`, `magentaTotal`, `yellowTotal`, `blackTotal` and `grayTotal`. These variables contain the summation of all the cyan, magenta, yellow, black or gray values respectively.

### Step 5

We have performed the validations and checks. We have also created necessary containers to hold color values. Next, we will run a loop which reads each gradient stop one-by-one. For that, create a loop, as shown below:

```    for(var k=0; k < numOfStops; k++)
{
if(colorBox[k].typename == "GrayColor")
{
// Extract Gray Color values
}
else
{
// Extract CMYK Color values
}
}//end for k
```

`currentColor.gradient.gradientStops[k].color` returns the color of a particular gradient stop for each iteration of k.

For each gradient stop, we are checking if the available color is a `GrayColor` specification or a `CMYKColor` specification. Depending upon that, we will implement our logic.

### Step 6 - Summation of GrayColor Values

Inside the "`if block`" for `GrayColor` specification, add the following lines of code:

```    grayBox[k] = Math.round(colorBox[k].gray);
grayTotal = grayTotal + grayBox[k];
```

Hence, `grayBox[k]` will hold all the gray values for each color at their respective gradient stops.
Next, `grayTotal` will be the summation of these gray color values, which will be used later.

### Step 7 - Summation of CMYK Color values

Inside the "`else block`" for `CMYKColor` specification, add the following lines of code:

```    cyanBox[k] = Math.round(colorBox[k].cyan);
magentaBox[k] = Math.round(colorBox[k].magenta);
yellowBox[k] = Math.round(colorBox[k].yellow);
blackBox[k] = Math.round(colorBox[k].black);
cyanTotal = cyanTotal + cyanBox[k];
magentaTotal = magentaTotal + magentaBox[k];
yellowTotal = yellowTotal + yellowBox[k];
blackTotal = blackTotal + blackBox[k];
```

To understand what is being performed here, we will take an example of Cyan color. `cyanBox[k]` is storing the cyan values for all the colors residing at different gradient stops. Next, `cyanTotal` is the summation of all these cyan values that are stored in `cyanBox[k]`.

A similar operation is performed for magenta, yellow and black too. Once the summation is done, we can come out of the loop and proceed ahead for average.

### Step 8 - Averaging the Color Values

We have gathered the individual summation of `grayColor` and `CMYKColor` for all the gradient stops. Now we need to average them. For that, close the "`for k loop`" and enter the following lines of code just after the closing bracelet of "`for k loop`", as shown below:

```    } // end for k loop
var finalBlack = blackTotal + grayTotal;
var newCyan = Math.round(cyanTotal / numOfStops);
var newMagenta = Math.round(magentaTotal / numOfStops);
var newYellow = Math.round(yellowTotal / numOfStops);
var newBlack = Math.round(finalBlack / numOfStops);
```

In the above lines of code, we are dividing individual summations of C, M, Y and K by `numOfStops`. i.e. If there were five gradient stops, we will divide the summation of individual C, M, Y and K values with five. Thereby, returning an average of five values. These averaged values are stored as `newCyan`, `newMagenta`, `newYellow` and `newBlack` respectively.

Note the tricky case of gray and black here. The summation of K is not just `blackTotal`. Rather, it's a sum of `grayTotal` and `blackTotal`.

Why we have done that? There are cases when a gradient fill may contain both GrayColor stops and CMYK stops. In that case, the gray Color values are added to the K value of the CMYK color. Gray can not be added to cyan, magenta or yellow. It will fall in the category of K only.

Now we have all the new averaged values for C, M, Y and K in hand. In the next step, we will implement these values as a new CMYK color on the current object.

### Step 9 - Implementing the New Color

To implement the new color, we will create a new `CMYKColor` object and modify its C, M, Y and K values to the ones that we just calculated in Step 7. To do that, add the following lines of code:

```    var newColor = new CMYKColor();
newColor.cyan = newCyan;
newColor.magenta = newMagenta;
newColor.yellow = newYellow;
newColor.black = newBlack;
currentObject.fillColor = newColor;
```

We have created a `newColor` object and assigned the values of `newCyan`, `newMagenta`, `newYellow` and `newBlack` as its C, M, Y and K values respectively.

Next, we have assigned the `newColor` as a `fillColor` to the current object. Hence, our final code will now look like the one below:

```if ( app.documents.length > 0 && app.activeDocument.pathItems.length > 0)
{
if(app.activeDocument.documentColorSpace == DocumentColorSpace.CMYK)
{
convertToFlat();
}
else
{
alert("Convert the Objects into CMYK First", "CMYK Conversion required");
}
}//end main if
else
{
alert("Either no document is available or the document is empty");
}
function convertToFlat() {
var items = selection;
var totalSelected = items.length;
if(totalSelected > 0)
{
for(var j=0; j < totalSelected; j++)
{
var currentObject = app.activeDocument.selection[j];
if(currentObject.typename != "CompoundPathItem" &&
currentObject.typename != "GroupItem")
{
if(currentObject.filled == true &&
currentObject.fillColor.typename != "CMYKColor" &&
currentObject.fillColor.typename != "PatternColor" &&
currentObject.fillColor.typename != "SpotColor")
{
var currentColor = currentObject.fillColor;
var colorBox=[];
var cyanBox=[];
var magentaBox=[];
var yellowBox=[];
var blackBox=[];
var grayBox =[];
var cyanTotal = 0;
var magentaTotal = 0;
var yellowTotal = 0;
var blackTotal = 0;
var grayTotal = 0;
for(var k=0; k < numOfStops; k++)
{
if(colorBox[k].typename == "GrayColor")
{
grayBox[k] = Math.round(colorBox[k].gray);
grayTotal = grayTotal + grayBox[k];
}
else
{
cyanBox[k] = Math.round(colorBox[k].cyan);
magentaBox[k] = Math.round(colorBox[k].magenta);
yellowBox[k] = Math.round(colorBox[k].yellow);
blackBox[k] = Math.round(colorBox[k].black);
cyanTotal = cyanTotal + cyanBox[k];
magentaTotal = magentaTotal + magentaBox[k];
yellowTotal = yellowTotal + yellowBox[k];
blackTotal = blackTotal + blackBox[k];
}
}//end for k
var finalBlack = blackTotal + grayTotal;
var newCyan = Math.round(cyanTotal / numOfStops);
var newMagenta = Math.round(magentaTotal / numOfStops);
var newYellow = Math.round(yellowTotal / numOfStops);
var newBlack = Math.round(finalBlack / numOfStops);
var newColor = new CMYKColor();
newColor.cyan = newCyan;
newColor.magenta = newMagenta;
newColor.yellow = newYellow;
newColor.black = newBlack;
currentObject.fillColor = newColor;
} //endif
else
{
alert("Fill an object with CMYK or Grayscale Gradient. Flat Colors, Patterns, Spot Colors and Empty Fills are not allowed."," Only Gradients Allowed");
}
}// endif
else
{
alert("This script only works with Non-Compound Objects or Isolated Group items.\nAny items with Groups or Compound Objects will be omitted.", "Ungroup or Isolate the Group Items");
}
}//end for j
}// endif
else
{
}
}//endFunction
```

### Step 10 - Executing the Script

Save this script as "test.jsx" and open Adobe Illustrator. Next, create some objects with colorful gradient fills. Now to test this script, select some objects and go to File > Scripts > Other Script (Command + F12) and locate this script.

After successful execution of the script, you should see a melt of the gradients; something similar to this:

### Conclusion and Scope

In this tutorial, we have seen how to melt a gradient into a flat color fill with the help of scripts. This script may be found useful in cases when you need to find the average of two or more colors. But the fruit of this tutorial is to understand the basics of scripting and their implementation with Illustrator.

There is a wide scope of vector creativity and innovation through scripting. Hope this two-part tutorial series will inspire readers and authors in bringing forward the essence of scripting. Thanks for your valuable time in reading this tutorial.

Subscribe to the Vectortuts+ RSS Feed to stay up to date with the latest vector tutorials and articles.

Saurabh Sharma is SaurabhSharma on Themeforest
• Eliecer

thank you

• http://www.tastybytes.net Brian

never even knew illustrator had script capabilities, thanks!

• MattS

Very interesting and original tutorial.
Thanks.

• Justin St. Germain

i really dont see the point of doing all that when i can just select the color i want instead.

• Christian Wisniewski

If you need to get the exact average value of a gradient…
Though I don’t see much use for that aswell, but the Tutorial is there to show you how to get used to scripting, i.e. how to use Array and document objects like Gradients.
Sometimes you need Scripts for automatisation (let’s say you need to make add a copyright to 100 pages…Why do it manually if you can use a script that will open the page, place the watermark/logo, save it).

• http://margaretnicholdesign.deviantart.com/ margaret

you could get that exact colour by using the blend tool in an object between two objects that contain the two colours of the gradient. Although this might be helpful if there are more than two colours in the gradient?

• http://www.edsign.com.au Peter Breis

It would be wonderful to tackle some the more mundane but useful tasks.

Such as taking all your .eps files and resaving them as cmyk compressed .ai files with embedded .pdf so you could simply preview, catalog & use them with and without color management profiles.

Or taking multiple artboard files and dividing them up into sub-numbered individual files.

Or examining a file shrinking it to its bounding box, determining if it contains gradients and saving that as an .ai file, otherwise as a .pdf.

or Stripping off all unused swatches, patterns, colors, styles, brushes and symbols. The principle reason the CS .ai files are grossly fat.

• http://www.psdbase.com Imon