22 Replies Latest reply on Nov 3, 2010 9:17 AM by JGL79

# Square area percent of page report

Sure this is not the first time someone has looked for a way to do this, but I can't find a solution.

Script to find the square inch area of the each object in the whole document > make a new layer > place a tag on each object stating that object's square area > also generate the percentage of that object's area compared to the page size.

I'm a novice and have hobbled together a few scripts that I've found but can't connect them up. So far I've adjusted a script to return geometric bounds of a selected object. And I modified another script that generates labels on a separate layer (the labels display various attributes of each object, color space, name, link etc).

It seems that inserting my get geometric bounds script should be inserted into the labels script with the parts concerning object attributes but I can't see how (again major Novice).

Haven't figured out how to get the document bounds (though that seems fairly obvious) and how to translate my geometric bounds into inches and find the % of page. I did find an almost perfect script (at the bottom) but it is for Illustrator and doesn't work off the same structure.

My code below. Anything from a point in the right direction to a rewrite would be amazing! Though I really want to understand how so I can contribute, teaching myself but practical applications is not always the best place to learn.

Script #1: Code for geometric bounds (where can I insert this into script #2 to apply square inches and % of page to picture/text labels)

Object.prototype.height = function() {   var bds = this.geometricBounds; //not using visible bounds, can't see how that would help here but maybe I'm wrong   return [ b[3]-b[1] , b[2]-b[0] ]; }

Script #2: Code for labels (need to convert area from points to inches and find % of page)

Script #3: Code object area labels, but for Illustrator (basically what I want)

• ###### 1. Re: Square area percent of page report

Follow up: Sorry tried to insert code in the box but obviously got it wrong. Here is the Illustrator code (didn't fit)

```if ( app.documents.length > 0 && app.activeDocument.selection.length > 0 ) {
//Declare the variables.
var myDocument=app.activeDocument;
var pathRef=docRef.selection[0];
var pathRefArea=pathRef.area;
var myReturn="\r";
//Convert pathRefArea to other units of measure. Store them in a text variable named areaMessage.
var areaMessage="Square Points: "+Math.round(pathRefArea*100)/100+myReturn
+"Square Picas: "+(Math.round((pathRefArea/144)*100))/100+myReturn
+"Square Inches: "+(Math.round((pathRefArea/5184)*100))/100+myReturn
+"Square Millimeters: "+(Math.round((pathRefArea/8.037)*100))/100+myReturn
+"Square Centimeters: "+(Math.round((pathRefArea/803.520)*100))/100

//Create a textFrame and set its contents to areaMessage.
areaLabel.contents = areaMessage;
for(i=0;i<areaLabel.paragraphs.length;i++){
areaLabel.paragraphs[i].justification=Justification.CENTER;
}

//Position areaLabel at the center of the selected path.
areaLabel.top = pathRef.top-pathRef.height/2+areaLabel.height/2;
areaLabel.left = pathRef.left+pathRef.width/2-areaLabel.width/2;

//Create a temporary textFrame named squarePoints to hold just the value of pathRef's area in square points.
squarePoints.contents = Math.round(pathRefArea*100)/100;
//Deselect pathRef. Select squarePoints. Redraw. Cut squarePoints to the clipboard.
pathRef.selected=false;
squarePoints.selected=true;
redraw();
app.cut();
}

```

• ###### 2. Re: Square area percent of page report

> Code object area labels, but for Illustrator (basically what I want)

Is there no Illustrator scripting forum?

Peter

• ###### 3. Re: Square area percent of page report

Maybe I wasn't clear

The Illustrator script is what I want for InDesign. Please read the whole post.

Thanks

• ###### 4. Re: Square area percent of page report

You mentioned a layer -- it wasn't clear to me what you want with it.Combining bits of different scripts is always difficult. Better to start from scratch, rather than accommodating one part of a script to another. What I would do in your case is this:

- set your document to inches so that you don't need to do all those calculations (first store the current values, restore them later);

- calculate the page area;

- calculate the selected object's area;

- set the object's area (as a percentage of the page area) as the object's label.

This script does that with all page items in a document. It doesn't check any errors, so make sure all your work is saved.

`// reference to the documentdoc = app.documents[0];// store the doc's view preferencesview_prefs = doc.viewPreferences.properties;// set measurement units to inchesdoc.viewPreferences.verticalMeasurementUnits = doc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.inches;// calculate page areap_area = doc.documentPreferences.pageWidth * doc.documentPreferences.pageHeight;// reference to the document's page itemsall_objects = doc.pageItems.everyItem().getElements();// process them in turnfor (i = 0; i < all_objects.length; i++)    {    // calculate an object's page area    o_area = object_area (all_objects[i]);    // calculate its percentage of the page area    pct = (o_area * 100) / p_area;    // add this as a string to the object's label    all_objects[i].label = String (pct);    }// restore the doc's view preferencesdoc.viewPreferences.properties = view_prefs;function object_area (obj)    {    var gb = obj.geometricBounds;    var width = gb[3]-gb[1];    var height = gb[2]-gb[0];    return width * height    }`

You mentioned something about a layer, but it wasn't clear to me what you want with that.

Peter

• ###### 5. Re: Square area percent of page report

Read all, including that 500-line sample script? I think not. Oh, and you are the first one ever to request the relative size of an object, when compared to its page, in inches and on a new layer.

Rather than plough through that immensely long example and trying to fathom what's going on, I just read your question and wrote this. There are a couple of points you might want to find out more about, such as your 'height' prototype (you were about halfway there). Stuff like document page size can be found in the OMV Help, as well as in numerous samples in Adobe's own Scripting Guide.

There is no need to recalculate units between points and inches -- in InDesign, you get what you asked for, or rather, what you already have. So if your current document settings are set to inches, the values ID returns are also in inches.

(It gets complicated if you work in points and want to see results in inches, but ever so slightly: points to inches is divide by 72.)

Before I forget, here's a working script. Select an object on your page and run it to see that it works; read to see how it works

```if (app.selection.length != 1) exit(0);
bounds = app.selection[0].geometricBounds;
width = bounds[3] - bounds[1];
height = bounds[2] - bounds[0];
object_area = width * height;
page_area = app.activeDocument.documentPreferences.pageWidth * app.activeDocument.documentPreferences.pageHeight;
try {
} catch (_)
{
}
thatNewLayer = app.activeDocument.layers.item("Hey, a new layer");
frame.move (app.selection[0].parent);
frame.move ([app.selection[0].geometricBounds[1],app.selection[0].geometricBounds[0]]);
frame.contents = String(Math.round(object_area*10)/10)+" / "+String(Math.round((object_area*1000)/page_area)/10)+"%";
```
• ###### 6. Re: Square area percent of page report

First off, thank you both! I realize it was a very long post, but I thought more info than less might be better

I have a few follow up questions so I can understand better what is going on.

As I read Peter's script it makes a lot of sense (thank you for the comments in the script). When I run it I think I see where I didn't explain well. The labels are supposed to be visual labels over each object. Maybe I'm TOTALLY missing the how it works but it seems that this is setting the object's label (as you said above) but not displaying that on a layer.

Jongware's script does display on a layer, but only for the selected item.

With both your advice and scripts (a much better starting point for me) I'm going to try to understand and write the exact solution I need.

I'll post my script, or attempt, along with a pic of the result in layout.

Thank you both so much for your help.

• ###### 7. Re: Square area percent of page report

So I understand that Peter is putting the object area and the % of the area into a string called pct.

And that Jongware is writing the contents calculation inside the string.

So my first thought was to reference the string name in the frame contents (leaving out the stuff about new layer and frame creation)

```all_objects = doc.pageItems.everyItem().getElements();
// process them in turn
for (i = 0; i < all_objects.length; i++)
{
// calculate an object's page area
o_area = object_area (all_objects[i]);
// calculate its percentage of the page area
pct = (o_area * 100) / p_area;
// add this as a string to the object's label
all_objects[i].label = String (pct);
}

frame.contents = String(pct);

```

I'm obviously missing something here.

So next I tried leaving the string alone and just passing the object area into it. Complete try below. I understand that the function is defining object area and that the for loop should be getting the object area for all objects in the document. I get errors in the function though. Do I need to store the object area in a string within the loop and call to it later in frame contents, or is this missing the forest for the trees.

```// reference to the document
doc = app.documents[0];
// store the doc's view preferences
view_prefs = doc.viewPreferences.properties;
// set measurement units to inches
doc.viewPreferences.verticalMeasurementUnits = doc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.inches;
// calculate page area
p_area = doc.documentPreferences.pageWidth * doc.documentPreferences.pageHeight;

all_objects = doc.pageItems.everyItem().getElements();
for (i = 0; i < all_objects.length; i++);
{
object_area = object_area (all_objects[i]);
}

try {
} catch (_)
{
}
thatNewLayer = app.activeDocument.layers.item("Object Percent of Page");
frame.move (app.selection[0].parent);
frame.move ([app.selection[0].geometricBounds[1],app.selection[0].geometricBounds[0]]);
frame.fillColor = [10,10,100,10];
frame.fillTint = 50;
frame.contents = String(Math.round(object_area*10)/10)+" / "+String(Math.round((object_area*1000)/p_area)/10)+"%";

function object_area (obj)
{
var gb = obj.geometricBounds;
var width = gb[3]-gb[1];
var height = gb[2]-gb[0];
return width * height;
}
```
• ###### 8. Re: Square area percent of page report

Sorry, forgot to include the screen shot of the intended result. I guess to simplify Jongware's script

is perfect, I just want it to loop through all objects in the whole document (my attempt in above post).

• ###### 9. Re: Square area percent of page report

A couple of errors ...

``object_area = object_area (all_objects[i])``

object_area is a function but you get its value and assign it to .. a variable with the same name. Better to use Peter's example, and give the variable another name -- why not "o_area"?

The for.. loop gathers all data -> right. But then you end the for..loop (with the next } ) so you don't do anything with the value you got. See Peter's sample: in his loop, he calculates the area and then puts it into each object's label. It's at that point exactly where you want my stuff to kick in, and make a small text frame on top of the object with the area as its contents.

Similar to Peter's, let me show you how to write a function to create the new frame.

First off, the stuff to create a new layer is only needed once, so you can move these lines

``````try {
} catch (_)
{
}
thatNewLayer = app.activeDocument.layers.item("Object Percent of Page");``````

all the way to the top in your script. After asserting there is a layer called "Object Percent (etc.)", there is no need to try to re-create it for every next object. Since the variable 'thatNewLayer' gets declared outside all functions, it's therefore global, and can be used inside functions as well as outside.

For a description of the try..catch construction, google for "javascript try catch". (Suffice to say that if the first half fails, code in the next half will be called.)

So, you need a function that takes

1. a reference to an object, so the new frame can be created on top of it, and

2. a value to write in to that.

For functions, it's "best practice" to declare as much variables as possible locally, using the 'var' keyword, so they won't interfere with global variables with the same name. The rest is virtually unchanged -- app.selection[0], which acts on your current selected object, is replaced with the object that you'll have to feed it when calling.

Oh -- I see only one local variable is needed: "frame" is only used inside this function. All other variables are either the function arguments (forObject and value) or global ones declared earlier (thatNewLayer and p_area).

```function createTextFrame (forObject, value)
{
var frame;
frame.move (forObject.parent);
frame.move ([forObject.geometricBounds[1],forObject.geometricBounds[0]]);
frame.fillColor = [10,10,100,10];
frame.fillTint = 50;
frame.contents = String(Math.round(value*10)/10)+" / "+String(Math.round((value*1000)/p_area)/10)+"%";
}

```

-- and you call the function right after calculating the object area, like this

`createTextFrame(all_objects[i], o_area);`

inside the loop.

Hope it helps!

• ###### 10. Re: Square area percent of page report

Brilliant!

Thank you for taking the time to explain everything so detailed. I read it a few times to make sure that I understood. I knew better with placing the new layer in the loop, that was dumb of me.

This works perfectly.

```// reference to the document
doc = app.documents[0];
// store the doc's view preferences
view_prefs = doc.viewPreferences.properties;
// set measurement units to inches
doc.viewPreferences.verticalMeasurementUnits = doc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.inches;
// calculate page area
p_area = doc.documentPreferences.pageWidth * doc.documentPreferences.pageHeight;

//create new layer
try {
}
catch (_)
{
}
thatNewLayer = app.activeDocument.layers.item("Object Percent of Page");

// reference to the document's page items
all_objects = doc.pageItems.everyItem().getElements();

// process them in turn
for (i = 0; i < all_objects.length; i++)
{
// calculate an object's page area
o_area = object_area (all_objects[i]);
createTextFrame(all_objects[i], o_area);

function createTextFrame (forObject, value)
{
var frame;
frame.move (forObject.parent);
frame.move ([forObject.geometricBounds[1],forObject.geometricBounds[0]]);
//frame.fillColor = [10,10,100,10];
//frame.fillTint = 50;
frame.contents = String(Math.round(value*10)/10)+" / "+String(Math.round((value*1000)/p_area)/10)+"%";
}
}
// restore the doc's view preferences
doc.viewPreferences.properties = view_prefs;

function object_area (obj)
{
var gb = obj.geometricBounds;
var width = gb[3]-gb[1];
var height = gb[2]-gb[0];
return width * height
}
```

Two follow up questions so that I understand even more.

1. The function object_area (obj) at the end of the deocument defines what object_area does earlier in the script. Why does this not get placed earlier, wouldn't the loop need this definition?
2. My frame.fillColor is causing the error "expected swatch". While this isn't a critical need for the functionality of the script, it makes it easier to read the labels. I'm confused by this because this way worked before...so I'm going to try defining a swatch by name and go from there. Left it commented out in the script above.

Thanks again, you both have helped make a lot of smiles here today!

• ###### 11. Re: Square area percent of page report

```//label fill color
var frameColor = [0,15,100,0];
```

To the top so it would be a global variable for each frame label. The tried calling it just above frame contents. But getting the error "expected swatch".

```frame.fillColor = frameColor;
frame.contents = String(Math.round(value*10)/10)+"squ IN: "+ String(Math.round((value*1000)/p_area)/10)+"% of Total Page";
}
```

Should frameColor not be a Global variable?

• ###### 12. Re: Square area percent of page report

You want to get that function out of the for-loop and place it separately, e.g. at the end of the script:

`for (i = 0; i < all_objects.length; i++)    {    o_area = object_area (all_objects[i]);    createTextFrame(all_objects[i], o_area);    }// more script..// maybe more script function createTextFrame (forObject, value)   {   var frame;   frame = app.activeDocument.textFrames.add(thatNewLayer, {geometricBounds:[0,0,"5mm","20mm"]});   frame.move (forObject.parent);   frame.move ([forObject.geometricBounds[1],forObject.geometricBounds[0]]);   // colour: see below   frame.fillColor = colour;   frame.fillTint = 50;   frame.contents = String(Math.round(value*10)/10)+" / "+String(Math.round((value*1000)/p_area)/10)+"%";   }`

As to colour, you define that at the beginning of the script. Where Jongware checks/created the layer would be a good place, and the check looks the same:

`try    {    app.activeDocument.colors.add ({name: "pct_colour", space: ColorSpace.cmyk, colorValue: [10,10,100,10]})    }catch (_) {} // not interested in errors`

You would then later assign that colour to a text frame:

`frame.fillColor = app.activeDocument.swatches.item ("pct_colour");`

Peter

• ###### 13. Re: Square area percent of page report

Thank you, you're both awesome!

One more question (I debated starting a new post but thought it was so relvant to this one it probably belonged here):

I'd like to add the link name to the frame label. I thought if I followed the same logic of referencing all links in the document and then setting a loop to capture them all that I could reference it later in the frame.contents before the math string.

I'm sure that I have a few things wrong and I can't figure out  how to write the function to add the link names to the text frame. Putting it inside the createTextFrame function seems illogical, but with writing it into that function I'm at a loss.

I searched the Forums and turned up some interesting bits about extracting file names as a starting point (Peter, I think my all_links reference is from one of your posts). I also tried (but abondoned) referencing XMP.

```// reference to the document's page items
all_objects = doc.pageItems.everyItem().getElements();

//try 02 to reference all links
for (i = 0; i < all_links.length; i++)
{
}

// process each object in turn
for (i = 0; i < all_objects.length; i++)
{
// calculate an object's page area
o_area = object_area (all_objects[i]);
createTextFrame(all_objects[i], o_area);

function createTextFrame (forObject, value, myObject)
{
var frame;

/* frame code */
frame.contents = all_links, String(Math.round(value*10)/10)+"squ IN: "+ String(Math.round((value*1000)/p_area)/10)+"% of Total Page";
}
}
```

The rest of the script works perfectly and I understand the part about the fill color now, create a new color and name it while setting the value, then reference it inside the frame variable. Maybe I should do the same with the link name?

Thanks again

• ###### 14. Re: Square area percent of page report

Tried switching from all ojects to just the links, but I think I've got it wrong at the frame.contents point. Help?

```//new reference to all links
all_objects = app.activeDocument.allGraphics;

// process them in turn
for (i = 0; i < all_objects.length; i++)
{
// calculate an object's page area
o_area = object_area (all_objects[i]);
createTextFrame(all_objects[i], o_area);

/*try 02
for (i = 0; i < all_links.length; i++) */

function createTextFrame (forObject, value, myObject)
{
var frame;

frame.move (forObject.parent);
frame.move ([forObject.geometricBounds[1],forObject.geometricBounds[0]]);
//label fill color & tint
frame.fillColor = app.activeDocument.swatches.item ("pct_color");
frame.fillTint = 50;
frame.textFramePreferences.ignoreWrap = false;
}
}
```
• ###### 15. Re: Square area percent of page report

That function should not be declared inside the for loop. Always put all your functions outside everything else to make them globally available.

(.. I think that's all, without running the script ..)

[Add] Well, apart from this: the function is already called with your active object, so it's kinda "neat" if you also use

``frame.contents = forObject.itemLink.filePath, [etc.]``

I see you cast the filePath to a String -- according to my JS Help, it's already a string, and it doesn't have a .name property.

Again, that ought to be all ...

• ###### 16. Re: Square area percent of page report

Mmm, seems I'm still not understanding function placement with loops. I visited W3C to read up on it, but I think I also need more practice to make hte connection.

I placed the reference outside then tried calling to the string inside the for loop. I think I'm going wrong at the second declaration under the for loop. If so, where does that belong, or is it redundent?

```// reference to the document's page items
all_objects = doc.pageItems.everyItem().getElements();

// reference all graphics

// process them in turn
for (i = 0; i < all_objects.length; i++)

/*this is where I think I'm going wrong*/
(i = 0; i < all_links.length; i++);
{
// calculate an object's page area
o_area = object_area (all_objects[i]);

createTextFrame(all_objects[i], o_area);
function createTextFrame (forObject, value, myObject)
{
var frame;

frame.move (forObject.parent);
frame.move ([forObject.geometricBounds[1],forObject.geometricBounds[0]]);
//label fill color
frame.fillColor = app.activeDocument.swatches.item ("pct_color");
frame.fillTint = 50;
frame.textFramePreferences.ignoreWrap = false;
/*I added the name String but not sure it's right*/
}
}
```
• ###### 17. Re: Square area percent of page report

Okay, tried changing everything to only get the links but I error out at

```all_links = doc.allGraphics.getElements();
```

so, not getting far.

Total script below. I'll keep reading and working tomorrow, eyes hurt for now.

```// reference to the document's page items
/*all_objects = doc.pageItems.everyItem().getElements();*/

// reference all graphics

// process them in turn
/*for (i = 0; i < all_objects.length; i++)*/
for (i = 0; i < all_links.length; i++);
{
// calculate an object's page area

function createTextFrame (forObject, value, myObject)
{
var frame;

frame.move (forObject.parent);
frame.move ([forObject.geometricBounds[1],forObject.geometricBounds[0]]);
//label fill color
frame.fillColor = app.activeDocument.swatches.item ("pct_color");
frame.fillTint = 50;
frame.textFramePreferences.ignoreWrap = false;
}
}
// restore the doc's view preferences
doc.viewPreferences.properties = view_prefs;

function object_area (obj)
{
var gb = obj.geometricBounds;
var width = gb[3]-gb[1];
var height = gb[2]-gb[0];
return width * height
}
```

Really interested in where I'm going wrong. Thanks!

• ###### 18. Re: Square area percent of page report

Jongware, thanks for the added info.

I didn't see it before I added those posts. I'll back track and see if I can get it right from your advice. Thanks!

• ###### 19. Re: Square area percent of page report

Hello,

This "square area percent page report" is so very close to what I need for my project. The only difference is that instead of a percentage of each object in relation to the page, I need the actual size in square millimeters of each object on each page. My task is two draw boxes around every object. Copy and paste the height and width in a spreadsheet that multiplies the two measurements to give me the area. Of course I have to do this literally thousands of times! Do you know of a script that can assist me with this task? I appreciate any direction you can give.  Thank you.

• ###### 20. Re: Square area percent of page report

Mmm.

Peter's "object_area" function returns the actual object area, but it's in inches, rather than mm. You can work around that using the definition of one inch ("One Inch Equals 25.4 mm" -- it's official!), using

area_in_mm = object_area (all_objects[i]) * 25.4 * 25.4;

or -- easier -- just set the measurements to millimeters, near the top of his script! (All measurements "inside" a script are automatically converted to 'the active' units.)

But I don't get this

My task is two draw boxes around every object

or this

Copy and paste the height and width in a spreadsheet that multiplies the two measurements to give me the area

The scripts above don't draw the boxes; they use what's already there on the page. (And why "two"?)

And InDesign is horrible in copying information out of it into a spreadsheet. A typical solution would be to write the measurements into a simple text file, and import that into any other program to process.

• ###### 21. Re: Square area percent of page report

d

• ###### 22. Re: Square area percent of page report

The boxes are really frames. Every image on a page has a frame around it. The dimensions of this frame (width and height) gives me a very simple approximation of how much space the image takes up on the page. Because selecting the frame doesnt give me square area (only width and height) I multiply the two to give me the square area. It would save me a step and cut my time in half if I already had the square area of the object to copy and paste into my list. If InDesign just gave me the square area I wouldn't have this problem. Hope that makes more sense.