Copy link to clipboard
Copied
Hello all.
I have an issue where I have strings of hex codes that I have to change into a square that will be in the actual hex code itself. For the moment I'm changing them to the letter X (but will change the X later to a square using a font such as wingdings)
I've been experimenting with ChatGPT to write code recently, and it's very much a hit and miss affair. It has generated a script that is close, but when I run my script, here is what I get:
In short, it looks like it is skipping lines and concatenating two lines together. I've had a look over the code and it has me stumped. Can anyone else have a look over this code and see what I'm missing? It is driving me spare!
// Adobe InDesign ExtendScript
// Function to convert hexadecimal color code to RGB
function hexToRgb(hex) {
// Remove the hash if it exists
hex = hex.replace(/^#/, '');
// Parse the hexadecimal code
var bigint = parseInt(hex, 16);
// Extract RGB values
var r = (bigint >> 16) & 255;
var g = (bigint >> 8) & 255;
var b = bigint & 255;
// Return the RGB values
return [r, g, b];
}
// Main function to find and replace hexadecimal color codes
function findReplaceHexColors() {
// Reference to the active document
var doc = app.activeDocument;
// Loop through all stories in the document
for (var i = 0; i < doc.stories.length; i++) {
var story = doc.stories[i];
// Loop through all paragraphs in the story
for (var j = 0; j < story.paragraphs.length; j++) {
var paragraph = story.paragraphs[j];
// Regular expression to find hexadecimal color codes
var hexRegex = /#(?:[0-9a-fA-F]{3}){1,2}\b/g;
// Array to store matches
var matches = paragraph.contents.match(hexRegex);
// Check if matches were found
if (matches) {
// Loop through matches
for (var k = 0; k < matches.length; k++) {
// Get the current match
var hexColor = matches[k];
// Convert hexadecimal color code to RGB
var rgbColor = hexToRgb(hexColor);
// Create a character range for the current match
var charRange = paragraph.characters.itemByRange(
paragraph.contents.indexOf(hexColor),
paragraph.contents.indexOf(hexColor) + hexColor.length
);
// Create a text range for the character range
var textRange = charRange.texts[0];
// Change the content to 'X'
textRange.contents = 'X';
// Apply the color to the character range
charRange.fillColor = doc.colors.add({
model: ColorModel.process,
space: ColorSpace.rgb,
colorValue: rgbColor
});
}
}
}
}
}
// Call the main function
findReplaceHexColors();
Hi Colin,
It's very reassuring to see how far chatGPT is from an acceptable answer. Even if you don't see them, the errors in its code are quite numerous (not to mention optimization problems). It doesn't understand the importance of looping backwards through volatile text specifiers, it doesn't check if a document color has already been created, it throws an <myHugeString>.indexOf(…) on substrings which have no guarantee of occuring once (which promises some internal reference bugs), and so on.
...Hi Colin,
Well it's super easy to edit the script so it directly applies the colors to the hex codes (the operation is even simpler). Here are the two options combined into a single function — depending on whether you let the ADD_ON argument empty:
function findReplaceHexColors(/*?str*/ADD_ON, doc,K,pp,a,q,sto,s,m,i,t,x,k,p,z,rgb,color)
//----------------------------------
// Detect #RRGGBB or #RGB patterns and add a suffix (ADD_ON arg) with that
// fill color applied.
// [CHG240113] Leave ADD_
...
Copy link to clipboard
Copied
Hi Colin,
It's very reassuring to see how far chatGPT is from an acceptable answer. Even if you don't see them, the errors in its code are quite numerous (not to mention optimization problems). It doesn't understand the importance of looping backwards through volatile text specifiers, it doesn't check if a document color has already been created, it throws an <myHugeString>.indexOf(…) on substrings which have no guarantee of occuring once (which promises some internal reference bugs), and so on.
Below is a code that is undoubtedly very imperfect (to be corrected and improved), but at least the two or three basic concepts that every script developer knows are taken into consideration.
//====================================================================
// DISCLAIMER: This InDesign script has just been quickly sketched by
// a human being so may be a bit more efficient and significantly less
// dysfunctional than a ChatGPT 'solution'.
//====================================================================
function findReplaceHexColors( doc,K,pp,a,q,sto,s,m,i,t,x,k,p,rgb,color)
//----------------------------------
// Detect #RRGGBB or #RGB patterns and add a suffix (cf ADD_ON const)
// with that fill color applied.
// [REM] This function does not explore tables, notes, etc.
{
// Declare once and for all the regex (`#RGB` or `#RRGGBB` form).
const HEX_REG = /#(?:[0-9a-f]{3}){1,2}\b/gi;
// What string do you want to add and colorize?
const ADD_ON = "\tX";
// Check ref to active doc.
if( !(doc=app.properties.activeDocument) ) return;
// Store `doc.colors` collection and presets rgb prop.
K = doc.colors;
pp =
{
model: +ColorModel.process,
space: +ColorSpace.rgb,
colorValue: void 0, // pending
name: void 0, // pending
};
// Array of Story instances.
a = doc.stories.everyItem().getElements();
// Loop through all text units.
for( q={} ; sto=a.pop() ; )
{
s = sto.texts[0].contents; // s :: str ; tx contents
m = s.match(HEX_REG); // m :: str[]|null ; hex matches
if( !m ) continue; // No match found
// Loop through matches and indices *from the end*.
for( x=1/0, i=m.length ; i-- && 0 <= (x=s.lastIndexOf(t=m[i],x)) ; --x )
{
// Create a normalized key (k :: `#RRGGBB`)
k = t.toUpperCase();
4===k.length && (k=t.slice(0,2)+t[1]+t[2]+t[2]+t[3]+t[3]); // #RGB -> #RRGGBB
// Get or create the corresponding Color (cached!)
if( q.hasOwnProperty(k) )
{
color = resolve(q[k]);
}
else
{
(color=K.itemByName(k)).isValid
||
(
rgb = parseInt(k.slice(1),16),
pp.colorValue = [ 0xFF&(rgb>>>16), 0xFF&(rgb>>>8), 0xFF&(rgb>>>0) ],
pp.name = k,
q[k]=(color=K.add(pp)).toSpecifier()
);
}
// Now the hard part!
p = x+t.length;
sto.insertionPoints[p].contents = ADD_ON;
sto.characters.itemByRange(p,p+ADD_ON.length-1).fillColor = color;
}
}
}
// Call the main function
findReplaceHexColors();
Best,
Marc
Copy link to clipboard
Copied
Hello there Marc.
You didn't have to rewrite this but I thank you from the bottom of my heart. I'd tried writing my own but then realised InDesign didn't have Hex a DOM colorspace (https://www.indesignjs.de/extendscriptAPI/indesign-latest/#ColorSpace.html) so the Hex value had to be converted to an RGB value first. I tried using an adaptation of a find/change script but again was having no joy. I've heard so many people rave about ChatGPT being the way to go, and when it produces the code, from a novice scripter (like me!) perspective, the code looks clean and has all variables in full. That said, this is far from my first ChatGPT script fail (or tenth) but thought I'd get more opinions on it.
The script you made adds a tab and an X that is coloured, but I think my demonstration was misunderstood - I actually want the colored X to replace the hex number of the color. I'll try and jerry-rig the script you have prepared, though because many of the variables used in the script are single letters, it'll take me a little while to get there.
Copy link to clipboard
Copied
Hi Colin,
Well it's super easy to edit the script so it directly applies the colors to the hex codes (the operation is even simpler). Here are the two options combined into a single function — depending on whether you let the ADD_ON argument empty:
function findReplaceHexColors(/*?str*/ADD_ON, doc,K,pp,a,q,sto,s,m,i,t,x,k,p,z,rgb,color)
//----------------------------------
// Detect #RRGGBB or #RGB patterns and add a suffix (ADD_ON arg) with that
// fill color applied.
// [CHG240113] Leave ADD_ON arg empty (or falsy) to get the colors
// applied to the hex codes themselves.
// [REM] This function does not explore tables, notes, etc.
{
// Declare once and for all the regex (`#RGB` or `#RRGGBB` form).
const HEX_REG = /#(?:[0-9a-f]{3}){1,2}\b/gi;
// [CHG240113] Normalize ADD_ON (1st arg).
'string' == typeof ADD_ON || (ADD_ON=false);
// Check ref to active doc.
if( !(doc=app.properties.activeDocument) ) return;
// Store `doc.colors` collection and presets rgb prop.
K = doc.colors;
pp =
{
model: +ColorModel.process,
space: +ColorSpace.rgb,
colorValue: void 0, // pending
name: void 0, // pending
};
// Array of Story instances.
a = doc.stories.everyItem().getElements();
// Loop through all text units.
for( q={} ; sto=a.pop() ; )
{
s = sto.texts[0].contents; // s :: str ; tx contents
m = s.match(HEX_REG); // m :: str[]|null ; hex matches
if( !m ) continue; // No match found
// Loop through matches and indices *from the end*.
for( x=1/0, i=m.length ; i-- && 0 <= (x=s.lastIndexOf(t=m[i],x)) ; --x )
{
// Create a normalized key (k :: `#RRGGBB`)
k = t.toUpperCase();
4===k.length && (k=t.slice(0,2)+t[1]+t[2]+t[2]+t[3]+t[3]); // #RGB -> #RRGGBB
// Get or create the corresponding Color (cached!)
if( q.hasOwnProperty(k) )
{
color = resolve(q[k]);
}
else
{
(color=K.itemByName(k)).isValid
||
(
rgb = parseInt(k.slice(1),16),
pp.colorValue = [ 0xFF&(rgb>>>16), 0xFF&(rgb>>>8), 0xFF&(rgb>>>0) ],
pp.name = k,
q[k]=(color=K.add(pp)).toSpecifier()
);
}
// [CHG240113] Supports empty ADD_ON.
if( !ADD_ON )
{
// Colorize the hex code.
p = x;
z = t.length;
}
else
{
// Insert ADD_ON and colorize it.
p = x + t.length;
sto.insertionPoints[p].contents = ADD_ON;
z = ADD_ON.length;
}
sto.characters.itemByRange(p,p+z-1).fillColor = color;
}
}
}
findReplaceHexColors( ); // You can pass in an 'add-on' string, e.g "\t\u2022"
Here is what it looks like:
Best,
Marc