Skip to main content
Participant
August 18, 2021
Answered

Can you automatically give every subsequent letter a different color for a batch of text designs?

  • August 18, 2021
  • 1 reply
  • 3612 views

Hi everyone, 

 

I would like to request some help with the following; I want to create a batch of text images where every single letter has a different color like in the image attached. I know how to use variables to generate multiple text designs, and I know how to manually change text color, but I was wondering if there is any way I can automatically make sure every subsequent letter (in every text image) gets a different color?

 

Many thanks!

 

 

This topic has been closed for replies.
Correct answer Kukurykus

If you mean first script, put on top of it:

 

arr = [], clrs = ['004fab', '00cfb3', 'ff7000', '14a41c', 'ffd802',
'f64397', '4be715', 'ffbbb1', '8243d0', 'ff0834', 'ffd802'];

 

Then replace:

 

with(c.hsb) {
	saturation = 100, brightness = 95; do{hue = Math.random() * 360}
	while(Math.abs(hueDifference - hue) < 60); hueDifference = hue
}

 

to:

 

!arr.length &&
arr = [].slice.call(clrs)
c.rgb.hexValue = arr.shift()

 

1 reply

Legend
August 18, 2021

For text layers try this script:

 

#target photoshop

var s2t = stringIDToTypeID;

(r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
var lrs = executeActionGet(r).getList(p);

for (var i = 0; i < lrs.count; i++) {
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('textKey'));
    r.putIdentifier(s2t('layer'), lrs.getReference(i).getIdentifier(s2t('layerID')));

    if (executeActionGet(r).hasKey(p)) {
        var textKey = executeActionGet(r).getObjectValue(p),
            style = textKey.getList(s2t('textStyleRange')).getObjectValue(0),
            text = textKey.getString(p),
            l = new ActionList(),
            hueDifference = 0;

        for (var x = 0; x < text.length; x++) {
            var k = copyDesc(style, new ActionDescriptor()),
                s = k.getObjectValue(s2t('textStyle'));

            k.putInteger(s2t('from'), x)
            k.putInteger(s2t('to'), x + 1)

            var c = new SolidColor;
            with (c.hsb) {
                saturation = 100
                brightness = 95

                do { hue = Math.random() * 360 } while (Math.abs(hueDifference - hue) < 60)
                hueDifference = hue
            }

            var d = new ActionDescriptor();
            d.putDouble(s2t('red'), c.rgb.red)
            d.putDouble(s2t('grain'), c.rgb.green)
            d.putDouble(s2t('blue'), c.rgb.blue)
            s.putObject(s2t('color'), s2t('RGBColor'), d)
            k.putObject(s2t('textStyle'), s2t('textStyle'), s)
            l.putObject(s2t('textStyleRange'), k)
        }
        if (l.count) {
            textKey.putList(s2t('textStyleRange'), l)
            var d = new ActionDescriptor();
            (r = new ActionReference()).putIdentifier(s2t('layer'), lrs.getReference(i).getIdentifier(s2t('layerID')));
            d.putReference(s2t('null'), r);
            d.putObject(s2t('to'), s2t('textLayer'), textKey);
            executeAction(s2t('set'), d, DialogModes.NO);
        }
    }

}

function copyDesc(from, to) {
    for (var i = 0; i < from.count; i++) {
        var k = from.getKey(i);
        if (to.hasKey(k)) continue;
        switch (from.getType(k)) {
            case DescValueType.ALIASTYPE: to.putPath(k, from.getPath(k)); break;
            case DescValueType.BOOLEANTYPE: to.putBoolean(k, from.getBoolean(k)); break;
            case DescValueType.CLASSTYPE: to.putClass(k, from.getClass(k)); break;
            case DescValueType.DOUBLETYPE: to.putDouble(k, from.getDouble(k)); break;
            case DescValueType.INTEGERTYPE: to.putInteger(k, from.getInteger(k)); break;
            case DescValueType.LISTTYPE: to.putList(k, from.getList(k)); break;
            case DescValueType.RAWTYPE: to.putData(k, from.getData(k)); break;
            case DescValueType.STRINGTYPE: to.putString(k, from.getString(k)); break;
            case DescValueType.LARGEINTEGERTYPE: to.putLargeInteger(k, from.getLargeInteger(k)); break;
            case DescValueType.REFERENCETYPE: to.putReference(k, from.getReference(k)); break;
            case DescValueType.OBJECTTYPE: to.putObject(k, from.getObjectType(k), from.getObjectValue(k)); break;
            case DescValueType.ENUMERATEDTYPE: to.putEnumerated(k, from.getEnumerationType(k), from.getEnumerationValue(k)); break;
            case DescValueType.UNITDOUBLE: to.putUnitDouble(k, from.getUnitDoubleType(k), from.getUnitDoubleValue(k)); break;
        }
    }
    return to
}

 

* save this code to a text file, change its extension to .jsx, place it in the presets folder (Adobe Photoshop\Presets\Scripts\). Restart Photoshop, the script will appear in the File -> Scripts menu, after that manual launch, hotkey launch, recording to the action will be available.

This script works with styles of text layers. Randomly generated colors are used (the result is not always perfect, but each run of the script will produce a new set of color). It can work both with text typed in one layer, and with separate letters in different selected layers. 

 

For other layers (where each letter on separate layer) it will be more convenient to work with color fill using effects with this script (set random fill FX to every selected layer). Also here is example of use HSL intead HSB in script above:

 

#target photoshop

var s2t = stringIDToTypeID;

(r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
var lrs = executeActionGet(r).getList(p),
    hueDifference = 0;

for (var i = 0; i < lrs.count; i++) {
    (d = new ActionDescriptor()).putReference(s2t('null'), lrs.getReference(i));
    executeAction(s2t('select'), d, DialogModes.NO);

    (r = new ActionReference()).putProperty(s2t("property"), p = s2t("layerEffects"));
    r.putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));

    var fx = executeActionGet(r).hasKey(p) ? executeActionGet(r).getObjectValue(p) : new ActionDescriptor(),
        currentFill = fx.hasKey(p = s2t("solidFill")) ? fx.getObjectValue(p) : new ActionDescriptor();
    if (fx.hasKey(p = s2t("solidFillMulti"))) fx.erase(p);

    var saturation = 100,
        lightness = 50,
        hue = 0;

    do { hue = Math.random() * 360 } while (Math.abs(hueDifference - hue) < 60);
    hueDifference = hue

    var RGB = hslToRgb(hue, saturation, lightness)

    var d = new ActionDescriptor();
    d.putDouble(s2t('red'), RGB[0])
    d.putDouble(s2t('grain'), RGB[1])
    d.putDouble(s2t('blue'), RGB[2])
    currentFill.putObject(s2t("color"), s2t("RGBColor"), d);
    fx.putObject(s2t("solidFill"), s2t("solidFill"), currentFill);

    (d = new ActionDescriptor()).putReference(s2t("null"), r);
    d.putObject(s2t("to"), s2t("layerEffects"), fx);
    executeAction(s2t("set"), d, DialogModes.NO);
}

var r = new ActionReference();
for (var i = 0; i < lrs.count; i++) { r.putIdentifier(s2t('layer'), lrs.getReference(i).getIdentifier(s2t('layerID'))) }
(d = new ActionDescriptor()).putReference(s2t('null'), r);
executeAction(s2t('select'), d, DialogModes.NO);

function hslToRgb(h, s, l) {
    s /= 100;
    l /= 100;

    var c = (1 - Math.abs(2 * l - 1)) * s,
        x = c * (1 - Math.abs((h / 60) % 2 - 1)),
        m = l - c / 2,
        r = 0,
        g = 0,
        b = 0;

    if (0 <= h && h < 60) {
        r = c; g = x; b = 0;
    } else if (60 <= h && h < 120) {
        r = x; g = c; b = 0;
    } else if (120 <= h && h < 180) {
        r = 0; g = c; b = x;
    } else if (180 <= h && h < 240) {
        r = 0; g = x; b = c;
    } else if (240 <= h && h < 300) {
        r = x; g = 0; b = c;
    } else if (300 <= h && h < 360) {
        r = c; g = 0; b = x;
    }

    return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255)]
}

 

If you can create a set of predefined colors or rules by which to determine the color difference, then the color palette can be more accurate.

Participant
August 21, 2021

Hi Jazz-y, 

 

First of all, thank you so much for your reply, I was afraid I was going to have to do it all manually! To follow up, suppose I have a list of colors that I would like to use in a certain order, how would I have to change the script? For example; 

 

004fab

00cfb3

ff7000

14a41c

ffd802

f64397

4be715

ffbbb1

8243d0

ff0834

ffd802

 

And then after the last one start over again with the first color?

 

Thanks again!

 

Kind regards,

Kukurykus
KukurykusCorrect answer
Legend
August 21, 2021

If you mean first script, put on top of it:

 

arr = [], clrs = ['004fab', '00cfb3', 'ff7000', '14a41c', 'ffd802',
'f64397', '4be715', 'ffbbb1', '8243d0', 'ff0834', 'ffd802'];

 

Then replace:

 

with(c.hsb) {
	saturation = 100, brightness = 95; do{hue = Math.random() * 360}
	while(Math.abs(hueDifference - hue) < 60); hueDifference = hue
}

 

to:

 

!arr.length &&
arr = [].slice.call(clrs)
c.rgb.hexValue = arr.shift()