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

Indesign Script to alter page on data merge

Community Beginner ,
Jun 02, 2024 Jun 02, 2024

Copy link to clipboard

Copied

Hello,

 

I'm looking for ways to increase the utility of data merge on indesign, and the project I've come up with is I'd like to set a different background color on each page of a merged document (lets say around 200 pages, all unique colors, kind of like a swatch booklet).

 

I have a spreadsheet and each row has a color column (hex or rgb, whatever works best).

 

I've been having chatgpt help me write some code, which it seems to have given a decent starting point, but of course comes up with errors. Those don't scare me, but I am having the hardest time finding any documentation to give insight on how to come up with a solution.

 

Couple of questions

  1. Is what I'm doing possible? (editing page of document as it's being merged, so at the end of the day each page has a different color, end of story).
  2.  Where are the best resources/documentation for indesign scripts on data merges? 

 

I'll post the chatgpt code for reference, but it doesn't work (error 55: object does not support the property or method 'dataMergeRecords'

 

// ChangeBackgroundColor.jsx

// Main function
function changeBackgroundColors() {
    var doc = app.activeDocument;
    var dataMerge = doc.dataMergeProperties;
    var dataMergeRecords = dataMerge.dataMergeRecords;
    
    // Ensure the data merge is enabled
    if (!dataMerge.dataMergePreferences.dataSource) {
        alert("No data merge file found. Please import a data merge file first.");
        return;
    }

    // Loop through each data merge record
    for (var i = 0; i < dataMergeRecords.length; i++) {
        var record = dataMergeRecords[i];
        
        // Get the value of the background color field from the data merge
        var colorValue = record.getField("BackgroundColor");
        
        // Convert color value to RGB/CMYK
        var color = convertToColor(colorValue);

        // Create a new rectangle for the background
        var page = doc.pages[i];
        var backgroundRect = page.rectangles.add({
            geometricBounds: [0, 0, doc.documentPreferences.pageHeight, doc.documentPreferences.pageWidth],
            fillColor: color
        });
        
        // Send the rectangle to the back
        backgroundRect.sendToBack();
    }
}

// Function to convert color value to RGB/CMYK Color
function convertToColor(value) {
    // Assuming value is in hex format for this example
    var color = app.activeDocument.colors.itemByName(value);
    if (!color.isValid) {
        // Create new color if it doesn't exist
        color = app.activeDocument.colors.add();
        color.name = value;
        color.space = ColorSpace.RGB;
        color.colorValue = hexToRgb(value);
    }
    return color;
}

// Function to convert hex color to RGB array
function hexToRgb(hex) {
    var bigint = parseInt(hex.replace('#', ''), 16);
    var r = (bigint >> 16) & 255;
    var g = (bigint >> 8) & 255;
    var b = bigint & 255;
    return [r, g, b];
}

// Run the main function
changeBackgroundColors();

  

TOPICS
Experiment , How to , Scripting

Views

279

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 1 Correct answer

Community Expert , Jun 02, 2024 Jun 02, 2024

Hi @dougw50331988, I do this all the time... like this example:

 

Goal: I want to do a data merge, but I want to assign a different master page depending on the "BRAND" field in the data csv file.

 

1) I make a field in the data file csv that corresponds to the master page name, if it doesn't already exist.

 

2) I make a text frame in the Indesign template document. I usually put it in the slug area, off the page, but slightly overlapping—the text frame must overlap the page or I think datamerge

...

Votes

Translate

Translate
Community Expert ,
Jun 02, 2024 Jun 02, 2024

Copy link to clipboard

Copied

No you cannot run a script while a file is being merged. For what you're trying to accomplish, you'd want to do it after the merge is complete. You'll need to store the color elements, then iterate thru each page and apply. 

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 02, 2024 Jun 02, 2024

Copy link to clipboard

Copied

@dougw50331988

 

You have this error - because DataMerge doesn't give access to the linked DataSource.

 

https://www.indesignjs.de/extendscriptAPI/indesign-latest/#DataMerge.html

 

You can select DataSource as a file - but that's it. 

 

If you want to have access to the contents of each record and field - you need to "open" it yourself.

 

And that's another example why ChatGPT is useless - most of the time. 

 

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 02, 2024 Jun 02, 2024

Copy link to clipboard

Copied

Hi @dougw50331988, I do this all the time... like this example:

 

Goal: I want to do a data merge, but I want to assign a different master page depending on the "BRAND" field in the data csv file.

 

1) I make a field in the data file csv that corresponds to the master page name, if it doesn't already exist.

 

2) I make a text frame in the Indesign template document. I usually put it in the slug area, off the page, but slightly overlapping—the text frame must overlap the page or I think datamerge won't populate it. There are other ways to do this step but this is a simple approach. I assign a script label to this text frame, eg. "BRAND" so the script can read it later.

 

3) I do the data merge and now have a multi-page document, say 1000 pages. At the top of each page is the BRAND text frame (with the brand name or ID in it from the data csv file).

 

4) I run a script that assigns whatever master page matches the name in the BRAND text frame.

 

See script example below. I use this to (a) set the master page to match the brand, and (b) swap certain paragraph styles to match the brand. This isn't specific to your needs, but should help you understand.

- Mark

 

/**
 * Set Paragraph Styles and Master Pages.js
 * @author m1b
 * @version 2024-03-15
 *
 * Script to run after a datamerge
 * to apply master pages and paragraph styles
 * based on a "BASE BRAND" variable on each page.
 *
 * - the BASE BRAND variable is found in a text frame on each page.
 * - for each page, apply a master page named for that page's BASE BRAND.
 * - every paragraph of each page is checked, and if a paragraph style
 *   name matches the `brandMatcher` RegExp, then change the paragraph
 *   style to the style matching the page's BASE BRAND.
 *
 * If a master page or a paragraph style named for the BASE BRAND doesn't
 * exist, then the change won't be made. This can be intentional.
 */
function main() {

    var settings = {
        brandFrameName: 'BASE BRAND',
        brandMatcher: /^[^-]+/, // matches the prefix before a hyphen, eg. "myBrand-Body"
    };

    var doc = app.activeDocument,
        counter = 0;

    for (var i = 0, page, paras, len = doc.pages.length; i < len; i++) {

        page = doc.pages[i];
        paras = page.textFrames.everyItem().paragraphs.everyItem().getElements();

        var brandFrame = page.textFrames.itemByName(settings.brandFrameName);
        if (!brandFrame.isValid)
            continue;

        var newMaster = getThing(doc.masterSpreads, 'baseName', brandFrame.contents);

        if (newMaster && page.appliedMaster !== newMaster)
            page.appliedMaster = getThing(doc.masterSpreads, 'baseName', brandFrame.contents);

        doSomethingToThings(paras,
            function changeParagraphStyle(paragraph) {

                if (!paragraph.isValid)
                    return;

                var style = paragraph.appliedParagraphStyle,
                    match = style.name && style.name.match(settings.brandMatcher);

                if (!match)
                    return;

                var newStyle = getThing(doc.allParagraphStyles, 'name', style.name.replace(settings.brandMatcher, brandFrame.contents));

                if (!newStyle || newStyle === style)
                    return;

                paragraph.appliedParagraphStyle = newStyle;

                counter++;

            }
        );

    }

    alert(counter);

};

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Set Paragraph Styles');

/**
 * Performs function `doThisTo` on each element of `things`.
 * @param {Array<*>} things - array of things.
 * @param {Function} doThisTo - the function to execute, given a thing.
 */
function doSomethingToThings(things, doThisTo) {

    for (var i = things.length - 1; i >= 0; i--)
        doThisTo(things[i]);

};

/**
 * Returns a thing with matching property.
 * @param {Array|collection} things - the things to look through, eg. PageItems.
 * @param {String} key - the property name, eg. 'name'.
 * @param {*} value - the value to match.
 * @returns {*} - the thing.
 */
function getThing(things, key, value) {

    for (var i = 0; i < things.length; i++)
        if (things[i][key] == value)
            return things[i];

};

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 07, 2024 Jun 07, 2024

Copy link to clipboard

Copied

LATEST

For the sake of closing this thread up, this was my final code for my needs. This structure of looping through each page, grabbing the named text frame and altering it in some way based on the script is a powerful tool to have in the arsenal. Thanks again

 

function main() {

    var doc = app.activeDocument,
        counter = 0;

    for (var i = 0, page, paras, len = doc.pages.length; i < len; i++) {

        page = doc.pages[i];
        
        var valueFrame = page.textFrames.itemByName("value-title");

        if (doc.colors.item(valueFrame.contents) == null) {
            var colorFrame = page.textFrames.itemByName("background-color");
            var color = colorFrame.contents;
            var colorSum = 0;
            var colorArr;

            // Color formatted as "rgb(255, 255, 255)"
            if (color !== null) {
                colorArr = color.substring(4, color.length - 1).split(", ");
                for (var j = 0; j < colorArr.length; j++) {
                    colorArr[j] = parseInt(colorArr[j]);
                    colorSum += colorArr[j];
                }
                doc.colors.add({name:valueFrame.contents, space:ColorSpace.RGB, colorValue:colorArr});           
            }

            colorFrame.fillColor = doc.colors.item(valueFrame.contents);
            colorFrame.contents = "";
            
            if (colorSum <= 450 || colorArr[1] <= 180) {
                
                for (var k = 0; k < valueFrame.paragraphs.length; k++) {

                    if (k == 0) {
                        valueFrame.paragraphs[k].applyParagraphStyle(doc.paragraphStyles.itemByName("h1-reverse"));
                    } else {
                        valueFrame.paragraphs[k].applyParagraphStyle(doc.paragraphStyles.itemByName("p-reverse"));
                    }
                }                
            }
        }
     }
};

 

 

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 02, 2024 Jun 02, 2024

Copy link to clipboard

Copied

There are some major issues with this ChatGpt code.

1. The error that you get. Because that property does not exist. The property that does exist is dataMergeFields

2. The code here is based on the premise that the InDesign DOM does provide us with the data of each record in the CSV. Which sadly is not the case. The dataMergeFields property just gives information about the fields i.e. the header row. Apart from that you get things like no. of records etc. So this logic won't work.

You have two options either to read the CSV via your code and do whatever you like for each record. Or for your current use case the approach given by @m1b would work fine.

-Manan

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 03, 2024 Jun 03, 2024

Copy link to clipboard

Copied

I have several articles over at CreativePro.com about changing colours during a data merge that might assist you:

1) change QR colours during a data merge: https://creativepro.com/creating-colored-qr-codes-during-a-data-merge/

2) Basic change of colours during a data merge: https://creativepro.com/changing-colors-during-a-data-merge/

3) Apply any CMYK combination during a data merge: https://creativepro.com/applying-any-cmyk-color-during-a-data-merge/

4) Colorising greyscale images during a data merge: https://creativepro.com/colorizing-variable-grayscale-images-during-data-merge/

5) trying out all colour combinations in a logo design using data merge: https://creativepro.com/exploring-color-combinations-with-data-merge/

 

 

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
Community Beginner ,
Jun 03, 2024 Jun 03, 2024

Copy link to clipboard

Copied

Can I just say how impressively helpful this community is. Thank you for all the advice and solutions! It was helpful to know that there isn't currently a way to alter documents as they're merged as mentioned by @brianp311, so whatever I do needs to be done to the merged document.

 

I think @m1b's solution will work for my needs, and will read up on @colcol2's blog posts to see if they'll work as well. I wish they didn't feel so hacky (hiding a text box so the value gets passed is pretty janky, but whatever works).

 

It has been close to 10 years since I've used InDesign and datamerge in any really significant capacity. It's a little dissapointing to see that the feature has been hardly touched or expanded by Adobe in that time. It could be an absolute powerhouse if a little more attention was given to it.

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 03, 2024 Jun 03, 2024

Copy link to clipboard

Copied

quote

Can I just say how impressively helpful this community is. Thank you for all the advice and solutions! It was helpful to know that there isn't currently a way to alter documents as they're merged. [...] 


By @dougw50331988

 

Built-in DataMerge is quite simple / limited. 

 

There are solutions that can offer much greater functionality - including building document(s) from scratch any way you want - but they are not free. 

 

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