Take the 2-minute tour ×
Graphic Design Stack Exchange is a question and answer site for Graphic Design professionals, students, and enthusiasts. It's 100% free, no registration required.

Thanks to the help of various people here, I've just about nailed this script for InDesign that I'm working on. There's only one other bit that, while not 100% necessary, I would love to be able to see if ExtendScript can do it.

The documents that the script will be running on have a frame which contains a linked EPS file. This EPS file is a vector file (99% of the time) saved from Illustrator CS6. (The other 1% of the time, it's a bitmap that has been assigned a spot color.) I need to be able to see if any of the colors in that artwork are spot colors that are NOT 100%—in other words, they are halftones.

This is probably going to be a tough one, since I don't know if InDesign can check the artwork directly. It would likely need to open the original file in Illustrator, then check not only solid fills and solid strokes, but also if there are any gradient fills, gradient strokes, or mesh objects. (I'm under the assumption that all gradients and meshes contain, by their very nature, halftones.) In addition, it would need to identify (return) which spot colors are halftoned in the art.

Does anyone happen to have any ideas on how this can be accomplished?

share|improve this question

migrated from stackoverflow.com Jun 6 '13 at 0:04

This question came from our site for professional and enthusiast programmers.

1 Answer 1

up vote 2 down vote accepted

BridgeTalk to the rescue!

After asking this question, I've spent days doing research and trial & error to figure out how to get this to work. It seems that the only way to see which colors in a linked EPS file in InDesign is to open that EPS file into Illustrator and check it out there. Thankfully, Adobe has incorporated BridgeTalk into ExtendScript. Thus, I have come up with the following two functions. First, the bridgeToIllustrator function, which takes an EPS file as input and returns an Array to the global variable halftoneInks:

/**
 * The BridgeTalk function that will call Illustrator and run its script,
 * returning an array of halftone colors to the variable 'halftoneInks'.
 *
 * @param {File} oFile The EPS file in which to check for halftone colors.
 */
function bridgeToIllustrator(oFile) {
    var resArr = new Array;
    var epsFile = oFile.fullName;
    // create a new BridgeTalk message object
    var bt = new BridgeTalk();
    // send this msg to the Adobe Illustrator CS6 application
    bt.target = "illustrator-16";
    // the script passed to the target application
    bt.body = "var sentFile = File(\"" + epsFile + "\");";
    bt.body += "var SnpSentMessage = {}; SnpSentMessage.create = " + checkForHalftones.toString();
    bt.body += "SnpSentMessage.create(sentFile)";
    bt.onResult = function (resObj) {
        // use eval to reconstruct the array
        resArr = eval(resObj.body);
        // and now we can access the returned array
        halftoneInks = resArr;
    }
    bt.onError = function(errObj)
    {
        $.writeln(errObj.body);
        $.writeln(bt.body);
    }

    // send the message
    bt.send(30);
}

The second function is the one that will be passed on to Illustrator, checking every object in the EPS file and adding its fill color or stroke color to an Array if it is a halftone. There might be a better way to write this function, but for now, this works:

/**
 * The main part of the script that will run in Illustrator, checking the file for halftones.
 *
 * @param {File} theFile The file object that will be opened in Illustrator and checked.
 */
function checkForHalftones(theFile) {
    var document = app.open(theFile);

    var colorsArray = [];
    colorsInUse(document.layers[0]);

    function colorsInUse(currPageItem) {
        for (var i = 0; i < currPageItem.pageItems.length; i++) {
            // Stepping through each item on the layer.
            var currentItem = currPageItem.pageItems[i];
            if (currentItem.typename === "GroupItem" && !currentItem.guides) {
                // If it's a group, dig into the group and start the function over.
                colorsInUse(currentItem);
            } else if (currentItem.typename === "RasterItem") {
                if (currentItem.imageColorSpace === ImageColorSpace.CMYK) {
                    $.writeln("Four-color process image in artwork.");
                } else if (currentItem.channels > 1) {
                    if (currentItem.colorants[0] === "Gray") {
                        if (colorsArray.toString().indexOf("Black") === -1) {
                            colorsArray.push("Black");
                        }
                    } else {
                        if (colorsArray.toString().indexOf(currentItem.colorants[0]) === -1) {
                            colorsArray.push(currentItem.colorants[0]);
                        }
                    }
                } else {
                    $.writeln("The raster image in the art file must be a 1-channel bitmap and, thus, does not need to be listed as a halftone.");
                }
            } else if ((currentItem.fillColor || currentItem.strokeColor) && !currentItem.guides) {
                // If the current object has either a fill or a stroke, continue.
                var fillColorType = currentItem.fillColor.typename;
                var strokeColorType = currentItem.strokeColor.typename;
                switch (fillColorType) {
                    case "CMYKColor":
                        if (currentItem.fillColor.cyan === 0 && currentItem.fillColor.magenta === 0 && currentItem.fillColor.yellow === 0) {
                            if (currentItem.fillColor.black === 0) {
                                break;
                            } else if (currentItem.fillColor.black === 100) {
                                break;
                            } else {
                                if (colorsArray.toString().indexOf("Black") === -1) {
                                    colorsArray.push("Black");
                                }
                            }
                        } else {
                            $.writeln("Four color process!");
                        }
                        break;
                    case "GrayColor":
                        if (currentItem.fillColor.gray > 0 && currentItem.fillColor.gray < 100) {
                            if (colorsArray.toString().indexOf("Black") === -1) {
                                colorsArray.push("Black");
                            }
                        }
                        break;
                    case "SpotColor":
                        if (currentItem.fillColor.tint < 100) {
                            if (colorsArray.toString().indexOf(currentItem.fillColor.spot.name) === -1) {
                                colorsArray.push(currentItem.fillColor.spot.name);
                            }
                        }
                        break;
                    case "GradientColor":
                        for (var j = 0; j < currentItem.fillColor.gradient.gradientStops.length; j++) {
                            var gStop = currentItem.fillColor.gradient.gradientStops[j].color;
                            switch (gStop.typename) {
                                case "GrayColor":
                                    if (colorsArray.toString().indexOf("Black") === -1) {
                                        colorsArray.push("Black");
                                    }
                                    break;
                                case "SpotColor":
                                    if (colorsArray.toString().indexOf(gStop.spot.name) === -1) {
                                        colorsArray.push(gStop.spot.name);
                                    }
                                    break;
                                case "CMYKColor":
                                    if (gStop.cyan === 0 && gStop.magenta === 0 && gStop.yellow === 0 && gStop.black != 0) {
                                        if (colorsArray.toString().indexOf("Black") === -1) {
                                            colorsArray.push("Black");
                                        }
                                    } else if (gStop.cyan === 0 && gStop.magenta === 0 && gStop.yellow === 0 && gStop.black === 0) {
                                        break;
                                    } else {
                                        $.writeln("Four color process.");
                                    }
                                    break;
                                default:
                                    $.writeln("Four color process?");
                            }
                        }
                        break;
                    case "NoColor":
                        break;
                    default:
                        $.writeln("The fill color on object number " + i + " is of type " + fillColorType);
                }

                switch (strokeColorType) {
                    case "CMYKColor":
                        if (currentItem.strokeColor.cyan === 0 && currentItem.strokeColor.magenta === 0 && currentItem.strokeColor.yellow === 0) {
                            if (currentItem.strokeColor.black === 0) {
                                break;
                            } else if (currentItem.strokeColor.black === 100) {
                                break;
                            } else {
                                if (colorsArray.toString().indexOf("Black") === -1) {
                                    colorsArray.push("Black");
                                }
                            }
                        } else {
                            $.writeln("Four color process!");
                        }
                        break;
                    case "GrayColor":
                        if (currentItem.strokeColor.gray > 0 && currentItem.strokeColor.gray < 100) {
                            if (colorsArray.toString().indexOf("Black") === -1) {
                                colorsArray.push("Black");
                            }
                        }
                        break;
                    case "SpotColor":
                        if (currentItem.strokeColor.tint < 100) {
                            if (colorsArray.toString().indexOf(currentItem.strokeColor.spot.name) === -1) {
                                colorsArray.push(currentItem.strokeColor.spot.name);
                            }
                        }
                        break;
                    case "GradientColor":
                        for (var j = 0; j < currentItem.strokeColor.gradient.gradientStops.length; j++) {
                            var gStop = currentItem.strokeColor.gradient.gradientStops[j].color;
                            switch (gStop.typename) {
                                case "GrayColor":
                                    if (colorsArray.toString().indexOf("Black") === -1) {
                                        colorsArray.push("Black");
                                    }
                                    break;
                                case "SpotColor":
                                    if (colorsArray.toString().indexOf(gStop.spot.name) === -1) {
                                        colorsArray.push(gStop.spot.name);
                                    }
                                    break;
                                case "CMYKColor":
                                    if (gStop.cyan === 0 && gStop.magenta === 0 && gStop.yellow === 0 && gStop.black != 0) {
                                        if (colorsArray.toString().indexOf("Black") === -1) {
                                            colorsArray.push("Black");
                                        }
                                    } else if (gStop.cyan === 0 && gStop.magenta === 0 && gStop.yellow === 0 && gStop.black === 0) {
                                        break;
                                    } else {
                                        $.writeln("Four color process.");
                                    }
                                    break;
                                default:
                                    $.writeln("Four color process?");
                            }
                        }
                        break;

                    case "NoColor":
                        break;
                    default:
                        $.writeln("The stroke color on object number " + i + " is of type " + strokeColorType);
                }
            }
        }
        return;
    }

    document.close(SaveOptions.DONOTSAVECHANGES);

    return colorsArray.toSource();
};

A few key things to note about this set of functions:

  1. The semicolon at the end is necessary, since the entire function will be turned into a string and sent to Illustrator by way of BridgeTalk. I discovered this the hard way.
  2. Since any information returned to InDesign from Illustrator is likewise sent as a string, an Array has to be handled carefully. In order to send an Array from Illustrator back to InDesign via BridgeTalk, it will need to be sent with a .toSource() method. Then, when BridgeTalk executes the .onResult callback, you need to use eval() in order for it to reconstruct the array into something useable for InDesign. Yes, it sucks. Yes, it's necessary. That's just how BridgeTalk functions.
  3. I had a bear of a time getting the proper syntax for the file to be sent to Illustrator via BridgeTalk. In the end, I discovered that as long as I get the file's .fullName, then place that within quotes within the File() constructor within the bt.body area, it would work. And, of course, to have quotes be interpreted as quotes within quotes, each one must be prepended with a backslash. Whew! Talk about confusing!

Anyway, I hope this has been of help to anyone else out there who needs to learn how to use BridgeTalk between InDesign and Illustrator. Cheers!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.