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

Add new page based on CSV content

New Here ,
Jul 03, 2017 Jul 03, 2017

Copy link to clipboard

Copied

For an advertisement newspaper, I've constructed a script that reads a CSV file with information about the ads, their size and desired location.

The ads are imported and placed correctly, until a new page is created. The placed files keep on being added on the first page.

Is there a way to activated the newly added page, or am I doing something fundamentally wrong?

Disclaimer: I'm no developer, so the code might not be ideal. I hope the solution is near!

Thanks for taking time.

CSV

Page;AdName;Width(mm);Height(mm);X-value;Y-value

1;G26-3548-2x1.pdf;83.666;27;86.666;0

1;G26-0006-A.pdf;83.666;27;86.333;30

1;F40-0004.pdf;83.666;57;173.333;0

2;G03-1459.pdf;40.333;57;0;0

3;G25-3264.pdf;127;57;40.333;0

JS

function main() {

    // Create a filter for CSV files

    var csvFilter = function(f){return/\.csv$/i.test ( f.name ); },

    // Open a dialog to import the CSV file

    f = File.openDialog ("Please select the CSV File…", csvFilter, false),

    docsData = [], csvSep = ";", csvContent, csvHeaders;

    // If we have a CSV file

    if ( !f ) return;

    // Open it

    f.open('r');

  

    // And start reading

    csvHeaders = f.readln().split(";");

    // if there is no doc create one

    if(app.documents.length < 1){

        doc = app.documents.add();

    // if there is one - use it

    } else {

        doc = app.activeDocument;  

    }

    // Loop through the data

    while (!f.eof){

        // Read the line and split it

        s = f.readln().split(";");

        // Loop through the six columns

        if ( s.length>=6 )  {

            // What's in the CSV

            var pageNumber = s[0];

            var fileName = s[1];

            var width = s[2];

            var height = s[3];

            var topLeftX = s[4];

            var topLeftY = s[5];

            // If the desired pagenumber is not the same as the documentpagenumber

            if(app.activeWindow.activePage.name != pageNumber){

              

                // Add a new page

                np = doc.pages.add(LocationOptions.AT_END);

                //np.activate();

            }

            // Draw rectangle in the right place

            var rect = doc.pages.item(0).rectangles.add();

            var gb = [topLeftY, topLeftX, (Number(topLeftY) + Number(height)), (Number(topLeftX) + Number(width))];

            rect.geometricBounds = gb;

            // Import the PDF and place it inside

            var mydoc =  app.activeDocument;

            var myframe = mydoc.rectangles[0];

            var img = myframe.place(new File("location/to/the/PDF/"+fileName));

        }

    }

};

main();

TOPICS
Scripting

Views

2.6K

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

Advisor , Jul 04, 2017 Jul 04, 2017

You shoud not be "happy when it works".

The problem when copying and pasting snippets of code without understanding them is that it usually does not work, and when it does work, it does not work reliably. You "write" the script, it works for the initial tests (which usually involve the same data you used to develop the script), you put it into production, and somewhere, somehow, in page 230 in a 600 pages document something goes wrong and everyting is messed up. Someone goes through the file, see

...

Votes

Translate

Translate
Advisor ,
Jul 03, 2017 Jul 03, 2017

Copy link to clipboard

Copied

Quite a few issues with your code there, but the big one that is causing you to have wrong results is in lines 60 to 63.

You are placing the pdf in the first rectangle of the active document (mydoc.rectangles[0]) instead of into the rectangle you added at line 55!

How many different scripts have you frankensteined in this? I count at least 3.

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
New Here ,
Jul 04, 2017 Jul 04, 2017

Copy link to clipboard

Copied

Caught! Indeed, it's all duct-taped together. Allthough I like things neat and performant on other fields, these are my first steps into javascript, so I'm happy when it works.

The rectangles that should appear on page 2 are also created on the first page, so I think it starts to go wrong on line 55. It makes sense what you say, but I've run out of google searches and I have no idea where to take from here.

Am I persuing the right way like this:

Line 50: I tried to activate the newly added page (Can't find anything that works)

Line 55: Should be: Draw the rectangle on the active page (Also no luck in finding a solution)

Thanks again, Vamitul, for your 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
Advisor ,
Jul 04, 2017 Jul 04, 2017

Copy link to clipboard

Copied

You shoud not be "happy when it works".

The problem when copying and pasting snippets of code without understanding them is that it usually does not work, and when it does work, it does not work reliably. You "write" the script, it works for the initial tests (which usually involve the same data you used to develop the script), you put it into production, and somewhere, somehow, in page 230 in a 600 pages document something goes wrong and everyting is messed up. Someone goes through the file, sees that the first few oages are ok, then the next 100 pages are ok so ... ok... and the file gets to the printer then to market and you are suddenly in a big hole! It is exactly what happend to me when I had just started with scripting and "wrote" (as in copy-pasted a bunch of stuff I had no idea how it worked) a script that did some extensive text manipulations based mostly on GREP patterns. One of the things it was supposed to do was to remove all spaces inside specially marked anchored text frames. But, in some 1%-chance of happening circumstances bug, it also removed all the spaces in the parent story of the anchored frame. The company I worked for back then had to pay damages to the customer of over 45000 euros because documents diseminated and printed in about 20 different countries around the globe had 20-30 pages of text in them whithout any spaces in.

Now that the rant is over I'm gonna do something I very rarely do these days and give you the whole solution In the hope that you will actually learn how it works and use it to go forward.

First step is to read and understand the requirements: you need to read data from a CSV file and use that data to create and paginate a new document. You should already see two distinctive parts (READ and PAGINATE) connected by a common thread (DATA).

/*

First step is to read and understand the requirements: you need to read data from a CSV file and use that data to create and paginate a new document. You should already see two distinctive parts (READ and PAGINATE) connected by a common thread (DATA). So let's start with the data. There are many many ways to structure your data (some better than others), but for this a simple array of objects somewhat mimicking the csv structure should suffice:

data=[

{

page:Number,

adFile:String,

geometricBounds:[Number,Number,Number,Number]

}]

Next up is reading data:

*/

(function() { //IIFE is always better than "main" crap: https://stackoverflow.com/questions/8228281/what-is-the-function-construct-in-javascript

function readCSV() {

// Open a dialog to import the CSV file 

var f = File.openDialog("Please select the CSV File…", function(f) {

return /\.csv$/i.test(f.name);

}); //do you understand how that inline function works?

if (!f) {

return; //the user hit cancel on the dialog. Nothing to do!

}

// we need some more variables and it's best to declare them early.

var line, //the current csv line entry

ret = [], //the return array that will contain all of the data

lineIndex = 1, //the current csv line number, used for error reporting. We start from "1" because that is how non-programmers (and some Pascal and older BASIC programmers) count.

gb, //the geometric bounds (as used by InDesign of the csv entry)

obj; //the full entry object. Just to make code more readable.

            f.open('r');

//first line is the headers, we ignore them.

line = f.readln();

while (!f.eof) { //this means while we havenot reached the End Of File

line = f.readln().split(';'); //walk and chew gum at the same time: read a line of text from the file and convert it to an array

lineIndex++; //increment the line index, this can be read as lineIndex=lineIndex+1;

if (line.length !== 6) {

// this entry in the csv is wrong. you can either ingore it or quit the whole thing. your choice, comment and uncomment as needed.

throw 'Invalid csv data on line ' + lineIndex + ' (' + line.join(';') + ')'; //can you explain what this does?

//other choice:

//continue;

}

//csv entry is: Page;AdName;Width(mm);Height(mm);X-value;Y-value

//canonic format of geometric bounds is [y0,x0,y1,x1]:

gb = [

parseFloat(line[5]), //Y-value

parseFloat(line[4]), //X-value

parseFloat(line[5]) + parseFloat(line[3]), //y+height

parseFloat(line[4]) + parseFloat(line[2]), //x+width

];

obj = {

page: parseInt(line[0]) - 1, //remember that programmers count from 0?

adFile: File("/Users/vlad/Downloads/" + line[1]),

geometricBounds: gb

};

//add the object to the return array

ret.push(obj);

}

//at this point we have all our data. But because the program works on a page by page basis it is good to sort it as such. See https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

return ret.sort(function(a, b) {

return a.page - b.page;

});

r }

/* we now need a function that will paginate the data*/

function paginate(data) {

//always declare your variables!

var doc, page, frame;

doc = app.documents.length ? app.documents[0] : app.documents.add();

/*see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator for the above statement. It is a shorthandend "if": if there are documents (documents.length>=0, use the front-most one (documents[0]), otherwise create a new one */

//because the data is in mm let's make sure the script will use mm as a measurement (but i strongly recommend you start dealing with point asap!)

app.scriptPreferences.measurementUnit=MeasurementUnits.MILLIMETERS;

//first let's make sure our document has enough pages. Since we have the data storted knowing how many pages we need is easy. Just look at the last data entry. But we do need to make sure we don't acidentally remove pages!!

doc.documentPreferences.pagesPerDocument = Math.max(doc.pages.length, data[data.length-1].page + 1);

/*things to note in the above statement: by using Math.max we are getting the bigger number between the number of currently existing nr of pages in the document and the biggest page number in our data (+1 because .. see above about counting)*/

//now let's go through out data. To keep code simpler we'll use another function "paginateData" (see below)

for (var i = 0; i < data.length; i++) {

page = doc.pages[data.page];

paginateData(page, data);

}

}

//this function will paginate one entry on a set page

function paginateData(page, entry) {

var rect = page.rectangles.add();

rect.geometricBounds = entry.geometricBounds;

//what if the ad file is not available? Let's convert it to text and add a message!

if (!entry.adFile.exists) {

rect.contentType = ContentType.TEXT_TYPE; // force to text frame

rect = page.textFrames.itemByID(rect.id);

rect.contents = 'File not found: ' + entry.adFile;

return;

}

rect.place(entry.adFile);

}

/*now let's tie everything up togheter. Not that much to do */

var data = readCSV();

if (!data) { //user canceled

return;

}

paginate(data);

alert('All done!\nYou can go outside and play now!');

}());

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 ,
Jul 06, 2017 Jul 06, 2017

Copy link to clipboard

Copied

Hi Vamitul,

I hope, that this time my post will make it to the forums. it's my third try 😞

For a couple of days I see errors like:

System Error

We're sorry but a serious error has occurred in the system.

when trying to access posts or to log in. That's a Forum-Software-Jive bug not resolved yet.

Ok. Here my comment on your code:

Rather than changing app.scriptPreferences.measurementUnit I would change the document's viewPreferences :

doc.viewPreferences.properties =

{

    horizontalMeasurementUnits : MeasurementUnits.MILLIMETERS ,

    verticalMeasurementUnits : MeasurementUnits.MILLIMETERS ,

    rulerOrigin : RulerOrigin.PAGE_ORIGIN

};

For predictable results also with facing pages documents I would reset rulerOrigin always to RulerOrigin.PAGE_ORIGIN when working with geometric bounds that are meant for individual pages.

And additionally to that one should also reset the zero point.

doc.zeroPoint = [ 0,0 ] ;

Regards,

Uwe

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
Advisor ,
Jul 06, 2017 Jul 06, 2017

Copy link to clipboard

Copied

Hi Uwe,

The forum software is crapping on me also. Wiping all adobe related cookies seems to have helped.

So, about the measurements: app.scriptPreferences.measurementUnit will trump the document's measurement units unless it's set to AUTO. And, on of my systems it is set to AUTO (because of consistency and other stuff), so I feel it's very important to set it up front. And once you do, you don't need to worry about changing the document's settings and the switching them back. I completely agree with the rulers and zero point, but that's a bit advanced for the OP.

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 ,
Jul 06, 2017 Jul 06, 2017

Copy link to clipboard

Copied

Hm, yes…

I always hesitate to set app.scriptPreferences.measurementUnit other than to points ( and working on with points doing conversions with input units using UnitValue ). But that's a discussion on its own, I think.

About your comment, that setting rulers and zero point:
It might be a bit advanced for the OP, but it is absolutely necessary that he understands why this is needed.

See his comment:

… A thing I noticed when testing is that pages 3, 5, 7, ... stayed empty, but I've learned that the zero point is on the page before it. I can easily fix that by updating the coordinates for the ads on those pages. …

@Yannick, do not update the coordinates in your CSV file!

No change of the coordinates is needed, if rulerOrigin will be changed to RulerOrigin.PAGE_ORIGIN.

( Here we have that case: A facing pages document. )

Just add two lines before adding the rectangles to get consistent results:

doc.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;

doc.zeroPoint = [ 0,0 ];

Regards,
Uwe

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
New Here ,
Jul 06, 2017 Jul 06, 2017

Copy link to clipboard

Copied

LATEST

Hey Uwe,

Thanks for the addition. It works like a charm now.

Thanks a lot guys, this script will save us hours each week, as we handplace all ads for now.

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
New Here ,
Jul 06, 2017 Jul 06, 2017

Copy link to clipboard

Copied

Wow Vamitul,

I've tested and read the script and it works perfectly. Thanks a million times for going the extra mile! I'm overwhelmed!

Reading the last line to get the number of pages, is clever. Also the line where you compare the number of current pages with the desired pages is also very nice. Thinking ahead.

I've learned a whole bunch, but I'm pretty sure I couldn't come up with this by my own. (I've never done anything in javascript before, but I know a little(!) bit of PHP so I knew how to make a loop etc.)

About line 34: I'd think it would throw an error when the line in the CSV isn't 6 columns. I've tested this, but I got a JS errormessage instead.

A thing I noticed when testing is that pages 3, 5, 7, ... stayed empty, but I've learned that the zero point is on the page before it. I can easily fix that by updating the coordinates for the ads on those pages.

I also love the 'errorhandling'. I will try to add these 'not found' errormessages to the alert in the end so I get a list of them when it finished.

Thanks again, this is amazing.

Yannick

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