Search code examples
javascriptcolorshexacrobatadobe-indesign

Changing the colour of all shapes and text in a PDF to the hex code entered in a text box


I'm trying to create a JavaScript function that can be added to a button in a PDF (that has been created in Adobe inDesign) that changes the colour of all shapes to that of a hex colour code entered into a text box. For example, if the user entered 'FFFFFF' into the text box then clicked this button, it would change all the shapes to white.

The next requirement is for any text placed on top of any shapes that have had their colour changed, to have their colour changed to contrast the new colour and still be legible (white text on dark colour shapes, black text on light colour shapes).

The final addition is for any text that includes the marker '[color]' to have it's fill colour changed to that of the hex code entered. When designing this document in InDesign, I would use a GREP style to make any instance of the '[color]' marker have a text size of 0.1pt and have no fill colour, so the user wouldn't have to see the markers on the final PDF. Although, if there are any methods of achieving the same results within this function, it would be gratefully received.

This is the code I have so far:

function changeColor() {
  // Get the user-entered hexadecimal color value
  var hexValue = getField("colorField").value;

  // Convert the hexadecimal value to RGB values
  var redValue = parseInt(hexValue.substring(0, 2), 16);
  var greenValue = parseInt(hexValue.substring(2, 4), 16);
  var blueValue = parseInt(hexValue.substring(4, 6), 16);

  // Loop through all page items in the document
  for (var i = 0; i < this.numPages; i++) {
    var currentPage = this.getPageNumWords(i);

    for (var j = 0; j < currentPage.length; j++) {
      var currentItem = currentPage[j];

      // Check if the current item is a shape object
      if (currentItem.typename === "PathItem") {
        // Change the fill color of the shape to the user-entered color
        currentItem.fillColor = [redValue / 255, greenValue / 255, blueValue / 255];

        // Check the brightness of the new color
        var brightness = (redValue * 299 + greenValue * 587 + blueValue * 114) / 1000;

        // Loop through all text items on the current page
        for (var k = 0; k < currentPage.length; k++) {
          var textItem = currentPage[k];

          // Check if the text item is above the current shape
          if (textItem.typename === "TextFrame" && textItem.geometricBounds[1] < currentItem.geometricBounds[1]) {
            // Change the color of the text to black or white depending on the brightness of the shape color
            if (brightness > 128) {
              textItem.fillColor = color.black;
            } else {
              textItem.fillColor = color.white;
            }
          }
        }
      } else if (currentItem.typename === "TextFrame") {
        // Check if the current text item has the [color] marker
        var contents = currentItem.contents;
        if (contents.indexOf("[color]") !== -1) {
          // Remove the marker and set the fill color to the user-entered color
          contents = contents.replace("[color]", "");
          currentItem.contents = contents;
          currentItem.fillColor = [redValue / 255, greenValue / 255, blueValue / 255];
        }
      }
    }
  }
}

I added this code as a 'mouse up' trigger on the exported PDF, but sadly nothing happens at all upon button click.

Any help with this would be very much appreciated.


Solution

  • In order to achieve this, text fields need to be the target of the colour change, instead of shapes, and the code has been simplified. Firstly, this document-level code needs to be added to remove the standard blue 'highlight' for text fields so the colour change is visible:

    //Remove standard light blue field colour
    app.runtimeHighlight = false;

    Then the following code reads and converts the hex colour code entered into the 'myHexColorField' text field and changes the fill colour of all text fields named 'myTextField'.

    Additionally, all text fields named 'textColorToChange' will have their text colour changed to white or black, depending on the lightness of the new fill colour.

    // Get the hex value from the hex text field
    var hexValue = getField("myHexColorField").valueAsString;
    
    // Convert the hexadecimal value to RGB values
    var redValue = parseInt(hexValue.substring(0, 2), 16);
    var greenValue = parseInt(hexValue.substring(2, 4), 16);
    var blueValue = parseInt(hexValue.substring(4, 6), 16);
    var redRgb = redValue / 255;
    var greenRgb = greenValue / 255;
    var blueRgb = blueValue / 255;
    
    // Apply the colour change 
    this.getField("myTextField").fillColor = ["RGB", redRgb, greenRgb, blueRgb];
    
    // Get the text fields that need text color change
    var textField = getField("textColorToChange");
    
    // Calculate the lightness value of the new colour fill
    var lightness = redRgb + greenRgb + blueRgb;
    
    // Set the text colour of the text field based on the lightness value
    if (lightness > 1.5) {
      // If the lightness is greater than 1.5, set the text colour to black
      textField.textColor = color.black;
    } else {
      // If the lightness is less than or equal to 1.5, set the text colour to white
      textField.textColor = color.white;
    }

    This code can be applied either to a button as a 'mouse up' action, or to the hex code text field itself as an 'on blur' action.

    Thanks to K J for the help in producing this code.