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

recolor with closest pantone match

Contributor ,
Apr 10, 2023 Apr 10, 2023

Copy link to clipboard

Copied

Hi community.

 

I am trying to make somethign wild, trying to somehow "recolor artwork" via code, the main idea si to have a design with non-pantone colors and then the script with just assig the closest match possible to the fill color. I randomly wrote ths:

 

var mySelection = app.activeDocument.selection;
var pantoneBook = app.colorBooks.itemByName("PANTONE+ Solid Coated");
for (var i = 0; i < mySelection.length; i++) {
var item = mySelection[i];
var fillColor = item.fillColor;
var pantoneColor = pantoneBook.getPantoneSolidCoated(fillColor.red, fillColor.green, fillColor.blue);
item.fillColor = pantoneColor.colorValue;
}

 

But I get the error in the pantoneBook variable " Undefined is not an object". May I ask for some help? thanks

TOPICS
Bug , Feature request , Scripting

Views

493

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
Adobe
Contributor ,
Apr 10, 2023 Apr 10, 2023

Copy link to clipboard

Copied

Votes

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
Contributor ,
Apr 11, 2023 Apr 11, 2023

Copy link to clipboard

Copied

Wrong link, I probably copy another thread, my bad

Votes

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
Enthusiast ,
Apr 10, 2023 Apr 10, 2023

Copy link to clipboard

Copied

1) Are you writing code with ChatGPT? Unfortunately, AI creates methods and color attributes that you don't have in ExtendScript. This is useless code.
2) How does the jpg export in the link relate to your task?
3) See related topics on opening swatch libraries and adding swatches to a document to get started. Once the swatches are added, you can recolor objects.
https://community.adobe.com/t5/illustrator-discussions/how-to-apply-swatches-into-document-via-scrip...
https://community.adobe.com/t5/illustrator-discussions/illustrator-script-apply-swatch-from-library/...

Votes

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
Contributor ,
Apr 11, 2023 Apr 11, 2023

Copy link to clipboard

Copied

I'll check it in a minute, byy the way, Wrong link, I probably copy another thread, my bad there.

 

1) yes I was using it

2) nope, I got confused and paste the wrong link.

3) thank you!

Votes

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
LEGEND ,
Apr 11, 2023 Apr 11, 2023

Copy link to clipboard

Copied

ChatGPT is great for writing text that matches existing popular questions. But it understands nothing about the actual code, and your question is - as you say - something wild, not seen before. So it's impossible to expect AI to do the job for you. Wild jobs need a traditional approach... Read the documentation, study the libraries, write the code, debug it.

Votes

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 ,
Apr 26, 2023 Apr 26, 2023

Copy link to clipboard

Copied

LATEST

Hi @AntonioPacheco, I've written a script that attempts to match any basic colors of the selected items with any colors from a source document (eg. a PANTONE library document, but it can be any document with color swatches). If the source color document is another document to the selected artwork, the document doesn't update until it has been saved and re-opened, but this doesn't cause any other problems.

 

Most of the script is very new and hasn't been well tested, so feel free to give it a try and let me know how it breaks. The text handling in Illustrator is particular strange, but I think I made it work. Let me know how it goes.

- Mark

 

/**
 * Converts selected item's *basic* appearance
 * colors to nearest matching spot/global colors
 * from the source color document.
 * For example, can convert CMYK process colors
 * to PANTONE colors, if those are available as
 * a source colors document.
 *
 * Usage:
 * 1. Select the item(s) to convert to swatches.
 * 2. Run script (assume UI is turned on)
 * 3. Specify a Source Color Document (this is the
 *    document containing the source swatches - it
 *    can be the same document).
 * 4. Specify some options.
 * 5. Click Convert (if button is disabled, it probably means
 *    the Source Color Document is invalid).
 *
 * Notes:
 * - IMPORTANT: can only convert colors applied to an item's
 *   *basic* appearance, meaning its first fillColor and strokeColor.
 * - When a swatch from *a different document* is applied to an item
 *   Illustrator doesn't show the new swatch properly until the document
 *   has been saved, closed and re-opened. (The settings option
 *   `saveAsCopy` is designed for a quick way of seeing those swatches
 *   in the converted document.
 *
 * @author m1b
 * @discussion https://community.adobe.com/t5/illustrator-discussions/recolor-with-closest-pantone-match/td-p/13716401
 */
(function () {

    var settings = {
        showUI: true,
        // sourceColorsDocPath: 'feel/free/to/hardcode/your/path/here',
        swatchNameFilter: /^PANTONE/i,
        keepTints: true,
        showResults: true,
        saveAsCopy: false,
    };

    var doc = app.activeDocument,
        items = itemsInsideGroupItems(doc.selection);

    if (items.length == 0) {
        alert('Please select one or more page items and try again.');
        return;
    }

    // handle UI
    var result;
    while (settings.showUI) {

        result = showUI(settings);

        if (result == 1)
            // convert colors
            break;

        else if (result == 2)
            // user cancelled
            return;

        else if (result == 3)
            // count swatches in source colors document
            countSwatches(settings.sourceColorsDocPath || doc.fullName.fsName, settings.swatchNameFilter);

    }

    // open the color library file
    settings.sourceColorsDocPath = settings.sourceColorsDocPath || chooseFile('.ai');
    if (settings.sourceColorsDocPath == undefined)
        return;
    else if (settings.sourceColorsDocPath.constructor.name == 'File')
        settings.sourceColorsDocPath = settings.sourceColorsDocPath.fsName;

    var sourceColorsDoc = getDocument(settings.sourceColorsDocPath);

    if (sourceColorsDoc == undefined) {
        alert('Couldn\'t open color library file.');
        return;
    }

    var results = convertColors(items, doc, sourceColorsDoc, settings.swatchNameFilter, settings.keepTints, true);

    if (!results)
        return;

    if (
        results.conversionCount > 0
        && doc.saved
        && settings.saveAsCopy
        && sourceColorsDoc.fullName.fsName !== doc.fullName.fsName
    ) {
        var f1 = doc.fullName,
            f2 = File(getFilePathWithOverwriteProtectionSuffix(doc.fullName.fsName));
        doc.saveAs(f2);
        doc.close();
        app.open(f1);
        app.open(f2);
    }

    app.redraw();

    if (settings.showResults)
        alert('Convert Colors\nConverted ' + results.colorableCount + ' colorables\ninto ' + results.conversionCount + ' colors.');


})();


/**
 * Converts any basic fill and stroke colors
 * into the nearest swatch from `sourceColorsDoc`,
 * based on RGB values.
 * Note on `keepTints` param:
 * When given a SpotColor with 50% tint,
 * we have two options:
 * 1. convert to 100% of a color that matches
 *    the 50% tinted breakdown (keepTints == false).
 * 2. convert to 50% of a color that matches
 *    the untinted breakdown (keepTints == true).
 * @author m1b
 * @version 2023-04-21
 * @param {Array<PageItem>} items - Illustrator page items.
 * @param {Document} doc - the Illustrator Document to convert.
 * @param {Document} sourceColorsDoc - an Illustrator Document containing swatches (default: active document).
 * @param {Boolean} [keepTints] - whether to keep tints of the converted colors - see note above (default: true).
 * @param {RegExp} filter - a RegExp to filter swatch names in sourceColorsDoc.
 */
function convertColors(items, doc, sourceColorsDoc, filter, keepTints) {

    var previousInteractionLevel = app.userInteractionLevel;
    app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;

    var colorData = getColorData(sourceColorsDoc.swatches, filter),
        convertedColors = {},
        newColors = {},
        colorables = [],
        colorablesCounter = 0,
        convertedColorCounter = 0;

    // check colorData
    if (colorData.length == 0) {
        alert('There are no swatches found in "' + sourceColorsDoc.name + '"' + (filter == undefined ? '.' : ' after filtering.'));
        return;
    }

    keepTints = keepTints !== false;

    itemsLoop:
    for (var i = 0; i < items.length; i++)
        colorables = colorables.concat(getBasicColorablesFromItem(doc, items[i]));

    colorablesCounter += colorables.length;

    colorablesLoop:
    for (var i = 0; i < colorables.length; i++) {

        keysLoop:
        for (var key in colorables[i]) {

            if (key == 'color')
                continue keysLoop;

            var item = colorables[i][key],
                col = colorables[i].color,
                tintFactor = 1, // 100%
                tint = 100;

            // if spot color (or global color)
            // handle tinting
            if (col.constructor.name == 'SpotColor') {
                if (keepTints)
                    tint = col.tint;
                else
                    tintFactor = col.tint / 100;
                col = col.spot.color;
            }

            var breakdown;

            if (col.constructor.name === 'CMYKColor')
                breakdown = [col.cyan * tintFactor, col.magenta * tintFactor, col.yellow * tintFactor, col.black * tintFactor];

            else if (col.constructor.name === 'RGBColor')
                breakdown = [col.red * tintFactor, col.green * tintFactor, col.blue * tintFactor];

            if (breakdown == undefined)
                continue keysLoop;

            var colorID = colorString(col, tintFactor),
                closestColor = convertedColors[colorID];

            if (closestColor == undefined)
                closestColor = getClosestColorRGB(colorData, breakdown);

            if (closestColor != undefined) {

                // set the new color
                var sw = sourceColorsDoc.swatches.getByName(closestColor.name);

                if (newColors[sw.name] == undefined) {
                    newColors[sw.name] = true;
                    convertedColorCounter++;
                }

                if (
                    keepTints
                    && sw.color.hasOwnProperty('tint')
                ) {
                    sw.color.tint = tint;
                }

                if (convertedColors[colorID] == undefined) {
                    // mark and count this color
                    convertedColors[colorID] = closestColor;
                }

                if (key === 'colorize') {
                    // only way to set the raster item's color to SpotColor
                    var originalSelection = doc.selection;
                    doc.selection = [item];
                    doc.defaultFillColor = sw.color;
                    doc.selection = originalSelection;
                }

                else
                    item[key] = sw.color;

            }

        }

    }

    // clean up
    app.userInteractionLevel = previousInteractionLevel;

    return {
        colorableCount: colorablesCounter,
        conversionCount: convertedColorCounter,
    };

};



/**
 * Returns array of swatches or colors
 * found in fill or stroke of page item.
 * @author m1b
 * @version 2022-10-11
 * @param {PageItem} item - an Illustrator page item.
 * @returns {Object} -  {fillColors: Array<Color>, strokeColors: Array<Color>}
 */
function getBasicColorablesFromItem(doc, item) {

    if (item == undefined)
        throw Error('getBasicColorablesFromItem: No `item` supplied.');

    var colorables = [];

    // collect all the colorables
    if (item.constructor.name == 'PathItem') {
        colorables = colorables.concat(getBasicColorables(item));
    }

    else if (
        item.constructor.name == 'CompoundPathItem'
        && item.pathItems
    ) {
        colorables = colorables.concat(getBasicColorables(item.pathItems[0]));
    }

    else if (
        item.constructor.name == 'RasterItem'
    ) {
        // only way to get the raster item's color
        var originalSelection = doc.selection;
        doc.selection = [item];
        colorables.push({
            color: doc.defaultFillColor,
            colorize: item,
        });
        doc.selection = originalSelection;
    }

    else if (
        item.constructor.name == 'TextFrame'
        && item.textRanges
    ) {
        var ranges = getTextStyleRanges(item.textRange, ['fillColor', 'strokeColor']);
        for (var i = ranges.length - 1; i >= 0; i--)
            colorables = colorables.concat(getBasicColorables(ranges[i]));
    }

    else if (item.constructor.name == 'GroupItem') {
        for (var i = 0; i < item.pageItems.length; i++)
            colorables = colorables.concat(getBasicColorables(item.pageItems[i]));

    }

    return colorables;

};



/**
 * Returns array of colorable things.
 * @date 2023-04-20
 * @param {PageItem} item - an Illustrator page item.
 * @returns {Array<Object>}
 */
function getBasicColorables(item) {

    var colorables = [],
        noColor = "[NoColor]";

    if (
        item.hasOwnProperty('fillColor')
        && item.fillColor != noColor
        && (
            !item.hasOwnProperty('filled')
            || item.filled == true
        )
        && item.fillColor != undefined
    )
        colorables.push({
            color: item.fillColor,
            fillColor: item
        });

    if (
        item.hasOwnProperty('strokeColor')
        && item.strokeColor != noColor
        && (
            !item.hasOwnProperty('stroked')
            || item.stroked == true
        )
        && item.strokeColor != undefined
    )
        colorables.push({
            color: item.strokeColor,
            strokeColor: item
        });

    return colorables;

};


/**
 * Returns a document, given a path.
 * Will look in open documents first.
 * @author m1b
 * @version 2023-04-21
 * @param {String} path - a path to a Document's file.
 * @returns {Document}
 */
function getDocument(path) {

    var activeDoc = app.activeDocument,
        f = File(path);

    if (!f.exists)
        return;

    for (var i = 0; i < app.documents.length; i++)
        if (app.documents[i].fullName.fsName === f.fsName)
            return app.documents[i]

    var doc = app.open(f);
    app.activeDocument = activeDoc;
    return doc;

};


/**
  * Shows open file dialog and
  * filters for file extension.
  * @author m1b
  * @version 2023-04-22
  * @param {String} [fileExtension] - default 'txt'
  * @returns {File}
  */
function chooseFile(fileExtension) {

    var fsFilter;
    if (fileExtension != undefined) {
        fileExtension == fileExtension || 'txt';
        fileExtension = fileExtension.replace('.', '');
        if ($.os.match("Windows")) {
            fsFilter = "*." + fileExtension;
        } else {
            var regex = RegExp('\.' + fileExtension + '$', 'i');
            fsFilter = function (f) { return (regex.test(decodeURI(f.name)) || f.constructor.name == 'Folder') };
        };
    }

    var f = File.openDialog("Please select an '" + fileExtension + "' File", fsFilter, false);

    if (f != undefined && f.exists)
        return f;

};


/**
 * Returns the closest color from `colorData`
 * by calculating the Euclidean distance.
 * @param {Array<Array>} colorData - array of name/breakdown pairs eg. [ "PANTONE 714 CP", [ 0, 40.0000005960464, 58.9999973773956, 0 ]].
 * @param {Array<Number>} target - [C, M, Y, K].
 * @returns {Array<Array>} - a colorData name/breakdown element.
 */
function getClosestColorRGB(colorData, target) {

    if (target.length === 4)
        // convert to RGB
        target = app.convertSampleColor(ImageColorSpace.CMYK, target, ImageColorSpace.RGB, ColorConvertPurpose.defaultpurpose);

    if (target.length !== 3)
        return;

    // add distances from target to colorData
    for (var i = 0; i < colorData.length; i++) {

        var breakdown = colorData[i].breakdown;

        // add euclidean distance
        colorData[i].distance = Math.sqrt(
            Math.pow(breakdown[0] - target[0], 2) +
            Math.pow(breakdown[1] - target[1], 2) +
            Math.pow(breakdown[2] - target[2], 2)
        );

    };

    colorData.sort(function (a, b) { return a.distance - b.distance; });

    // return the closest match
    return colorData[0];

};


/**
 * Returns name and breakdown (in RGB)
 * of any spot colors in `swatches`
 * that passes the name filter.
 * @author m1b
 * @version 2023-04-26
 * @param {Swatches} swatches
 * @param {RegExp} [nameFilter] - a test to filter swatches by name (degault: ignore square bracket swatches).
 * @returns {Array<Object>} - example: { name:'PANTONE 131 CP', breakdown: [123,52,3] }
 */
function getColorData(swatches, nameFilter) {

    var colorData = [];

    nameFilter = nameFilter || /^[^\[]/;

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

        var sw = swatches[i];

        try {

            if (
                !sw.hasOwnProperty('name')
                || !nameFilter.test(sw.name)
                || sw.color.constructor.name != 'SpotColor'
            )
                continue;

            var colorDatum = {};
            colorDatum.name = sw.name;
            colorDatum.breakdown = sw.color.spot.getInternalColor();

            if (sw.color.spot.spotKind == SpotColorKind.SPOTLAB)
                colorDatum.breakdown = app.convertSampleColor(ImageColorSpace.LAB, colorDatum.breakdown, ImageColorSpace.RGB, ColorConvertPurpose.defaultpurpose);

            else if (sw.color.spot.spotKind == SpotColorKind.SPOTCMYK)
                colorDatum.breakdown = app.convertSampleColor(ImageColorSpace.CMYK, colorDatum.breakdown, ImageColorSpace.RGB, ColorConvertPurpose.defaultpurpose);

        } catch (error) {
            continue;
        }


        colorData.push(colorDatum);

    }

    return colorData;

};


/**
 * Returns an array of TextRanges,
 * determined by mapping changes
 * in supplied keys. For example,
 * supplying the 'fillColor' key
 * will return ranges divided when
 * the text's fillColor changes.
 * @author m1b
 * @version 2023-04-26
 * @param {TextRange} textRange - an Illustrator TextRange.
 * @param {Array<String>} keys - an array of keys to match, eg ['fillColor'].
 */
function getTextStyleRanges(textRange, keys) {

    if (
        textRange == undefined
        || textRange.constructor.name != 'TextRange'
    )
        throw Error('getTextStyleRanges: bad `textRange` supplied.');

    if (
        keys == undefined
        || keys.constructor.name != 'Array'
    )
        throw Error('getTextStyleRanges: bad `textRange` supplied.');

    // check keys are valid
    for (var j = 0; j < keys.length; j++)
        if (!textRange.characterAttributes.hasOwnProperty(keys[j]))
            throw Error('getTextStyleRanges: bad key supplied ("' + keys[j] + '")');

    var ranges = [],
        start = 0,
        currentValues = {};

    charactersLoop:
    for (var i = 0; i < textRange.length; i++) {

        var tr = textRange.textRanges[i],
            matches = true;

        // check each key
        keysLoop:
        for (var j = 0; j < keys.length; j++) {

            if (i == 0)
                currentValues[keys[j]] = tr.characterAttributes[keys[j]];

            else if (stringify(tr.characterAttributes[keys[j]]) !== stringify(currentValues[keys[j]])) {
                matches = false;
                break keysLoop;
            }
        }

        currentValues[keys[j]] = tr.characterAttributes[keys[j]];

        if (
            i == textRange.length - 1
            || !matches
        ) {
            // start a new range
            var newTextRange = textRange.textRanges[start];
            newTextRange.end = i == textRange.length - 1 ? i + 1 : i;
            ranges.push(newTextRange);
            start = i;
        }

    }

    return ranges;

};


/**
 * Stringify tailored for the purpose
 * of identifying identical Swatches.
 * @author m1b
 * @version 2023-04-26
 * @param {Object} obj - the object to stringify.
 * @returns {String}
 */
function stringify(obj) {

    var str = obj.toString();

    for (var key in obj) {

        if (!obj.hasOwnProperty(key))
            continue;

        if (
            key == 'spot'
            || key == 'color'
        )
            str += stringify(obj[key]);

        else
            str += (obj[key]);

    }

    return str;

};


/**
 * Returns array containing items, including
 * items found inside GroupItems.
 * Example usage:
 * var items = itemsInsideGroupItems(doc.selection, ['PathItem', 'CompoundPathItem']);
 * @author m1b
 * @version 2022-05-23
 * @param {Array<PageItem>} items - array or collection of Illustrator page items.
 * @param {String|Array<String>} [typenames] - item constructor names to target (default: target all typenames).
 * @param {Number} [level] - recursion level (private parameter).
 * @returns {Array<PathItem>} the path items found.
 */
function itemsInsideGroupItems(items, typenames, level) {

    try {

        if (level == undefined)
            level = 0;

        var found = [];

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

            var item = items[i];

            if (
                item.uuid == undefined
                || item.parent.typename == 'CompoundPathItem'
            )
                continue;

            if (item.typename == 'GroupItem') {
                found = found.concat(itemsInsideGroupItems(item.pageItems, typenames, level + 1));
            }

            else if (typenames === undefined || itemIsType(item, typenames)) {
                found.push(item);
            }

        }

        return found;

    } catch (err) {
        alert('itemsInsideGroupItems: ' + err)
    }

};


/**
 * Returns true if item.typename
 * matches any of the typenames supplied.
 * @param {PageItem} item - an Illustrator page item.
 * @param {String|Array<String>} typenames - the typenames to check against.
 * @returns {Boolean}
 */
function itemIsType(item, typenames) {

    if (!typenames.constructor.name == 'Array')
        typenames = [typenames];

    var matched = false;
    for (var i = 0; i < typenames.length; i++) {
        if (typenames[i] == item.typename) {
            matched = true;
            break;
        }
    }

    return matched;

};


/**
 * Returns a string derived from the Color,
 * or color breakdown. Used for the purpose
 * of matching Color objects.
 * @author m1b
 * @version 2023-04-22
 * @param {Color|Array<Number>} c - the Color or color breakdown.
 * @param {Number} [tint] - scale factor, a number in range 0..1 (default: 1);
 * @returns {String} - example "C100M0Y30K10"
 */
function colorString(c, tint) {

    tint = tint || 1;

    if (c.constructor.name == 'Array') {
        if (c.length === 4)
            return 'C' + (c[0] * tint) + 'M' + (c[1] * tint) + 'Y' + (c[2] * tint) + 'K' + (c[3] * tint);
        else if (c.length === 3)
            return 'R' + (c[0] * tint) + 'G' + (c[1] * tint) + 'B' + (c[2] * tint);
    }

    else if (c.constructor.name == 'CMYKColor')
        return 'C' + (c.cyan * tint) + 'M' + (c.magenta * tint) + 'Y' + (c.yellow * tint) + 'K' + (c.black * tint);

    else if (c.constructor.name == 'RGBColor')
        return 'R' + (c.red * tint) + 'G' + (c.green * tint) + 'B' + (c.blue * tint);

    else if (c.constructor.name == 'GrayColor')
        return 'K' + (c.gray * tint);

};



/**
 * Shows UI for the various divide functions.
 * @author m1b
 * @version 2023-04-07
 * @param {Object} settings - the settings associated with the UI.
 */
function showUI(settings) {

    if (settings == undefined)
        throw Error('showUI: bad `settings` parameter.');

    var suppressEvents = false,
        columnWidth = 480,

        // set up the window
        w = new Window("dialog { text:'Convert Colors by m1b', properties:{ resizeable:true } }"),

        // user input view
        sourceColorsDocGroup = w.add("Group { orientation: 'column', alignment: ['fill','fill'], margins: [0,0,0,-8]  }"),
        sourceColorsDocPathLabel = sourceColorsDocGroup.add("Statictext { text:'', justify:'left', alignment:['fill','fill'], properties:{ multiline: false } }"),
        sourceColorsDocPathGroup = w.add("Group { orientation: 'row', alignment: ['fill','top'], margins: [10,0,0,0] }"),
        sourceColorsDocPathField = sourceColorsDocPathGroup.add("EditText { text:'', alignment:['fill','center'] }"),
        sourceColorsDocChooseButton = sourceColorsDocPathGroup.add("Button { text:'/', bounds:[0,0,0,0], size:[34,34] }"),

        filterGroup = w.add("Group {orientation:'column', alignment:['fill','fill'], margins:[5,0,5,0] }"),
        swatchNameFilterLabel = filterGroup.add("Statictext { text:'Source Swatch Name Filter:', justify:'left', alignment:['fill','top'], properties:{ multiline: false } }"),
        swatchNameFilterField = filterGroup.add("EditText { text:'', alignment:['fill','top'] }"),

        extrasGroup = w.add("Group {orientation:'row', alignment:['fill','fill'], margins:[5,0,5,0] }"),
        keepTintsCheckbox = extrasGroup.add("Checkbox { text:'Keep Tints', alignment:'left', value:false }"),
        saveAsCopyCheckbox = extrasGroup.add("Checkbox { text:'Save As Copy', alignment:'left', value:false }"),
        showResultsCheckbox = extrasGroup.add("Checkbox { text:'Show Results', alignment:'left', value:false }"),

        tipGroup = w.add("Group {orientation:'row', alignment:['fill','fill'], margins:[5,0,5,0] }"),
        helpMessage = tipGroup.add("Statictext { text:'', justify:'left', preferredSize:[-1,50], alignment:['fill','top'], properties:{ multiline: true } }"),

        bottomUI = w.add("group {orientation:'row', alignment:['fill','fill'], margins:[0,1,0,0] }"),
        aux = bottomUI.add("group {orientation:'row', alignment:['fill','bottom'], alignChildren:'left', margins:[5,0,5,0] }"),
        countSwatchesButton = aux.add("Button { text: 'Count Swatches'}"),
        buttons = bottomUI.add("group {orientation:'row', alignment:['right','center'], alignChildren:'right' }"),
        cancelButton = buttons.add("Button { text: 'Cancel', properties: {name:'cancel'} }"),
        okayButton = buttons.add("Button { text:'Convert', enabled: true, properties: {name:'ok'} }");

    sourceColorsDocPathField.preferredSize.width = columnWidth;
    sourceColorsDocPathField.minimumSize.width = columnWidth;

    // update from settings
    swatchNameFilterField.text = String(settings.swatchNameFilter || '');
    sourceColorsDocPathField.text = settings.sourceColorsDocPath || 'Click right button to load color document.';
    keepTintsCheckbox.value = settings.keepTints !== false;
    saveAsCopyCheckbox.value = settings.saveAsCopy === true;
    showResultsCheckbox.value = settings.showResults === true;

    // event handling
    sourceColorsDocPathField.addEventListener('change', updateUI);
    swatchNameFilterField.addEventListener('change', updateUI);
    sourceColorsDocChooseButton.onClick = chooseAIDocument;
    keepTintsCheckbox.onClick = updateUI;
    saveAsCopyCheckbox.onClick = updateUI;
    showResultsCheckbox.onClick = updateUI;
    okayButton.onClick = function () { w.close(1) };
    cancelButton.onClick = function () { w.close(2) };
    countSwatchesButton.onClick = function () { w.close(3) };

    updateUI();

    // show dialog
    w.center();
    return w.show();

    /**
     * Updates the UI when controls have changed.
     */
    function updateUI() {

        if (suppressEvents)
            return;

        suppressEvents = true;

        if (sourceColorsDocPathField.text == '')
            sourceColorsDocPathField.text = app.activeDocument.fullName.fsName;

        // update settings;
        settings.sourceColorsDocPath = sourceColorsDocPathField.text;
        settings.keepTints = keepTintsCheckbox.value;
        settings.saveAsCopy = saveAsCopyCheckbox.value;
        settings.showResults = showResultsCheckbox.value;
        settings.swatchNameFilter = makeRegExp(swatchNameFilterField.text);

        // update help message
        helpMessage.text = 'Handling of Tints: ' + (settings.keepTints
            ? 'Converted items will keep their tint value.'
            : 'Tints will be discarded, but will match the tinted color visually.'
        );

        helpMessage.text += (settings.saveAsCopy
            ? '\nConverted document will be saved with a new name. Both documents will be opened.' : ''
        );

        // update enabled
        var sourceColorsFile = File(settings.sourceColorsDocPath);
        okayButton.enabled = sourceColorsFile.exists;
        countSwatchesButton.enabled = sourceColorsFile.exists;
        saveAsCopyCheckbox.enabled = sourceColorsFile.exists;
        showResultsCheckbox.enabled = sourceColorsFile.exists;
        sourceColorsDocPathLabel.text = 'Source Colors Document: '
            + (sourceColorsFile.exists
                ? decodeURI(sourceColorsFile.name)
                : 'ERROR: no .ai document found.'
            );

        suppressEvents = false;

    };

    /**
     * Shows UI to choose an .ai file
     * and sets sourceColorsDocPathField.
     */
    function chooseAIDocument() {
        var aiFile = chooseFile('.ai');
        if (aiFile)
            sourceColorsDocPathField.text = aiFile.fsName;
        updateUI();
    };

};


/**
 * Test the ColorData gathering.
 * @param {String} path - path to document.
 * @param {RegExp} nameFilter
 */
function countSwatches(path, nameFilter) {

    var doc = getDocument(path),
        colorData = getColorData(doc.swatches, nameFilter);

    alert('Source Color Document:\n' + doc.name + '\nFound ' + colorData.length + ' swatches.');

}


/**
 * Returns a RegExp made from
 * a RegExp literal string.
 * @param {String} str - a RegExp literal string, eg. /^test/ig.
 * @returns {RegExp}
 */
function makeRegExp(str) {

    if (str == '')
        return;

    var parts = str.match(/^\/?([^\/]*)\/([ig]*)?/);

    if (parts == null)
        return RegExp(str);
    else {
        parts[2] = parts[2] || '';
        return RegExp(parts[1], parts[2]);
    }

};


/**
 * Returns a path that will not overwrite a file.
 * Adds an incremental suffix to avoid overwrites.
 * @author m1b
 * @version 2022-07-20
 * For example, if `myFile.txt` already exists it
 * will return `myFile(1).txt` and if that already
 * exists, it will return `myFile(2).txt` etc.
 * @param {String} path - the path to test.
 * @returns {String} a path that will not overwrite a file.
 */
function getFilePathWithOverwriteProtectionSuffix(path) {

    var index = 1,
        parts = path.split(/(\.[^\.]+)$/);

    while (File(path).exists)
        path = parts[0] + '(' + (++index) + ')' + parts[1];

    return path;

};

 

Votes

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