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

InDesign Javascript to replace hex text with actual hex colored letter - ChatGPT letting me down

Community Expert ,
Jan 10, 2024 Jan 10, 2024

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)

 

Screen Shot 2024-01-10 at 11.48.54 pm.png

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:

Screen Shot 2024-01-10 at 11.50.53 pm.png

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();

 

If the answer wasn't in my post, perhaps it might be on my blog at colecandoo!
TOPICS
How to , Scripting

Views

321

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

correct answers 2 Correct answers

Guide , Jan 10, 2024 Jan 10, 2024

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.

...

Votes

Translate

Translate
Guide , Jan 13, 2024 Jan 13, 2024

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_
...

Votes

Translate

Translate
Guide ,
Jan 10, 2024 Jan 10, 2024

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

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 ,
Jan 13, 2024 Jan 13, 2024

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.

If the answer wasn't in my post, perhaps it might be on my blog at colecandoo!

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
Guide ,
Jan 13, 2024 Jan 13, 2024

Copy link to clipboard

Copied

LATEST

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:

 

HexColors.gif

 

Best,

Marc

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