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

A script that transitions the text fill colour of a section from one colour to other with each line

Community Beginner ,
Jun 25, 2023 Jun 25, 2023

Copy link to clipboard

Copied

Hi ! I am making a small zine, where I have a long text without paragraphs and I am looking for a script transitions the text fill colour of a section from one colour to the other with each line.  I am not good with code and still learning, so its a bit too complicated for me. Does someone have a solution?

TOPICS
EPUB , Experiment , Feature request , How to , Scripting , SDK , Type , UXP Scripting

Views

458

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 ,
Jun 25, 2023 Jun 25, 2023

Copy link to clipboard

Copied

a long text without paragraphs

 

Do you perhaps mean 'a long text in a single paragraph'?

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 Beginner ,
Jun 25, 2023 Jun 25, 2023

Copy link to clipboard

Copied

yes

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 ,
Jun 25, 2023 Jun 25, 2023

Copy link to clipboard

Copied

You don't need any script. Use nested lines styles.

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 ,
Jun 25, 2023 Jun 25, 2023

Copy link to clipboard

Copied

Hi @default1zn7l8u4ete5, I love playing with these things, and I had some functions already written for other projects, so I've put together a script that (hopefully) will do what you want. To use it, just color the first line and last line of text in the colors/tints that you want to blend between, then select that text (or text frame) and run script. Paragraphs don't count, just Lines, so it doesn't matter whether there are multiple paragraphs or just one paragraph. I haven't tested much at all, so please give it a try, then post back here if you find any bugs and I'll update with a fix.

- Mark

demo.gif

P.S. There is no reason you can't run the script more than once and blend between several colors.

/**
 * Applies a color blend to lines of text,
 * by interpolating colors of first character
 * of first line of selected text with first
 * character of last line of selected text.
 * @file Blend Text Line Colors.js
 * @author m1b
 * @discussion https://community.adobe.com/t5/indesign-discussions/a-script-that-transitions-the-text-fill-colour-of-a-section-from-one-colour-to-other-with-each-line/m-p/13890952
 */
function main() {

    var doc = app.activeDocument;
    blendTextLineColors(doc, doc.selection[0]);

}

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Do Script');


/**
 * Apply a fill color to each line of `text`
 * such that each line has a color derived
 * by interpolation between the colors of
 * the first character of the first and
 * last lines of text.
 * @author m1b
 * @version 2023-06-26
 * @param {Document} doc - an Indesign Document.
 * @param {Text|Textframe} text - the text to color.
 */
function blendTextLineColors(doc, text) {

    if (text == undefined)
        return;

    if (text.constructor.name == 'TextFrame')
        text = text.texts[0];

    if (!text.hasOwnProperty('lines'))
        return;

    var lineCount = text.lines.length,
        startColor = text.lines[0].characters[0].fillColor,
        startTint = text.lines[0].characters[0].fillTint,
        endColor = text.lines[-1].characters[0].fillColor,
        endTint = text.lines[-1].characters[0].fillTint,
        hasTints = startTint !== endTint,
        breakdowns = interpolateArrays(startColor.colorValue, endColor.colorValue, lineCount),
        tints;

    if (hasTints) {
        if (startTint == -1)
            startTint = 100;
        if (endTint == -1)
            endTint = 100;
        tints = interpolateArrays([startTint], [endTint], lineCount);
    }

    for (var i = 0; i < lineCount; i++) {

        var c = makeColor(doc, breakdowns[i]);

        if (!c || !c.isValid)
            continue;

        text.lines[i].fillColor = makeColor(doc, breakdowns[i]);

        if (hasTints)
            text.lines[i].fillTint = tints[i][0];

    }

};


/**
 * 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, ..., arr2] where length == n.
 */
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;

};


/**
 * Returns a new, unnamed color.
 * @param {Document} doc - an Indesign Document.
 * @param {Array<Number>} breakdown - the color values.
 * @returns {Color}
 */
function makeColor(doc, breakdown) {

    var color,
        colorSpace;

    if (breakdown.length === 4)
        colorSpace = ColorSpace.CMYK;
    else if (breakdown.length == 3)
        colorSpace = ColorSpace.RGB;
    else
        return;

    if (!doc.colors[-1].isValid)
        return;

    // this will make an unnamed color, ie. it won't show up in document
    // thanks to https://community.adobe.com/t5/indesign-discussions/coloring-a-font-with-a-rgb-etc-without-adding-the-color-to-the-document-swatches/m-p/3655060
    color = doc.colors[-1].duplicate();
    color.properties = {
        space: colorSpace,
        colorValue: breakdown,
    };

    return color;

};

 

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

Copy link to clipboard

Copied

LATEST

Hi Mark, Thanks for posting your script. I have an old AppleScript that makes a group of blend swatches from two selected swatches, which I translated for the example below. In this case I’m converting the start and end colors to Lab, so it doesn’t matter what the mode of the two colors are—you could blend a CMYK and RGB color and maintain a color managed appearance:

 

if (app.activeDocument.selection > 0) {
	app.doScript(makeDialog, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Blend Text Color');
} 

var sc, ec;
function makeDialog(){
    var s = app.activeDocument.selection[0];
    if (s.constructor.name == "TextColumn" || s.constructor.name == "Text" || s.constructor.name == "Paragraph" ) {
        var d = app.dialogs.add({name:"Blend Colors", canCancel:true});
        with(d.dialogColumns.add()){
            staticTexts.add({staticLabel:"Start Color:"});
            staticTexts.add({staticLabel:"End Color:"});
        }
        with(d.dialogColumns.add()){
            sc = dropdowns.add({stringList:getSwatchNames(), selectedIndex:0, minWidth:80});
            ec = dropdowns.add({stringList:getSwatchNames(), selectedIndex:0, minWidth:80})
        }
        if(d.show() == true){
            sc = getSwatchNames()[sc.selectedIndex];
            ec = getSwatchNames()[ec.selectedIndex];
            blendTextColor(s)
            d.destroy();
	    }
    }else{
        alert("Please Select More Than One Line of Text")
        return
    }
}

function blendTextColor(sel){
    var doc = app.activeDocument;
    var ln = sel.lines;
   
    //duplicate the selected swatches and set them to process Lab
    //skips Gradients, Mixed Ink, Tint Colors
    try {
        var sColor = doc.colors.itemByName(sc).duplicate();
        var eColor = doc.colors.itemByName(ec).duplicate();  
    }catch(e) {
        alert("Illegal Swatch Choice");
        return
    }  
    
    sColor.space = ColorSpace.LAB;
    sColor.model = ColorModel.PROCESS;
    eColor.space = ColorSpace.LAB;
    eColor.model = ColorModel.PROCESS;
    var inc = getIncrement(sColor.colorValue, eColor.colorValue, ln.length);
    ln[0].fillColor =  makeColor(doc, ColorSpace.LAB, sColor.colorValue)
    var ncv;
    for (var i = 1; i < ln.length; i++){
        ncv = getBlendColor(sColor.colorValue, inc, i)
        ln[i].fillColor = makeColor(doc, ColorSpace.LAB, ncv)
    }; 
    sColor.remove();
    eColor.remove();
}


/**
* The amount to increment each color channel 
* @ param cv1 the starting Lab color 
* @ param cv2 the end Lab color 
* @ param n the number of increments 
* @ return an array of channel increments 
* 
*/
function getIncrement(cv1, cv2, n){
    var a = [0,0,0]
    for (var i = 0; i < a.length; i++){
        a[i] = (cv2[i] - cv1[i])/n
    };   
    return a
}

/**
* Get the incremented blend value 
* @ param c the starting value array
* @ param n the array of increment amounts
* @ param m the increment multiplier
* @ return new color value array
* 
*/
function getBlendColor(c,n,m){
    var a = []
    for (var i = 0; i < c.length; i++){
        a.push( parseFloat((c[i] + (n[i] * m))));
    }
    return a
}


/**
* Makes an unnamed color
* @ param the document to add the color to 
* @ param color space 
* @ param color value 
* @ return the color 
*/

function makeColor(d, s, cv){
    var c;
    if (d.colors[-1].isValid) {
        c = d.colors[-1].duplicate();
        c.space = s;
        c.colorValue = cv
    }
    return c;
}


function getSwatchNames(){
    var arr = app.activeDocument.swatches.everyItem().getElements();
    var da = ["None", "Registration", "Paper", "Black"];
    var a = new Array;
    for(var i = 0; i < arr.length; i++){
        if (!checkItem(da, arr[i].name)) {
            a.push(arr[i].name);
        } 
    }
    return a
}

function checkItem(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

 

 

Screen Shot 24.pngScreen Shot 25.png

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