Copy link to clipboard
Copied
I'm trying to write a script that, given an InDesign file, is able to compute the image dimensions of every image in the document. I need the original image dimensions, so the image link I believe. The problem is when I try to pull out tiff:ImageHeight and tiff:ImageWeight from the linkXmp, it never returns a value. Is there some easier way to do this without having to look into the image metadata?
Are you trying to get the actual (unscaled) pixel dimensions? An image has the effective ppi resolution property, so if the document units are set to inches, you can get the pixel dimensions. This gets the actual pixel (or inch) dimensions of a selected image:
var doc = app.activeDocument;
doc.viewPreferences.properties = {horizontalMeasurementUnits:MeasurementUnits.INCHES, verticalMeasurementUnits:MeasurementUnits.INCHES}
//a selected image
var sel = doc.selection[0];
//the actual pixel d
...
You can get the scale by dividing the Effective by Actual Res. Direct select an image and try this:
var s = app.activeDocument.selection[0]
//width and height as na array
var d = getWidthHeight(s);
if (s.constructor.name == "Image") {
var ep = s.effectivePpi
var ap = s.actualPpi
var w = (ep[0]/ap[0]) * d[0];
var h = (ep[1]/ap[1]) * d[1]
alert(w.toFixed (3) + " x " + h.toFixed (3))
} else {alert("Select an Image")}
/**
* Get a page item’s width and height
* @ param the page
...
Copy link to clipboard
Copied
Hi Peter,
There seems to be no direct property that provides the actual dimensions of the placed image, also reading the xmp would work only if you can make sure that the data is added into it correctly in the first place. I tried to put together a few lines of code that should do the trick, the idea is to clear any transformations applied to the image, use visual bounds property to calculate the height and width and then reverting the tranformation clear operation.
var image = app.documents[0].links[0].parent
image.clearTransformations()
var width = image.visibleBounds[3] - image.visibleBounds[1]
var height = image.visibleBounds[2] - image.visibleBounds[0]
app.documents[0].undo()
I have used just the first link of the document, you can add in the logic to loop ovver every link
-Manan
Copy link to clipboard
Copied
Hi Manan,
I tried this previously but did not get a return in pixels. I essentially need the same width x height numbers as the linked file. Is there a way to convert this?
Copy link to clipboard
Copied
Are you trying to get the actual (unscaled) pixel dimensions? An image has the effective ppi resolution property, so if the document units are set to inches, you can get the pixel dimensions. This gets the actual pixel (or inch) dimensions of a selected image:
var doc = app.activeDocument;
doc.viewPreferences.properties = {horizontalMeasurementUnits:MeasurementUnits.INCHES, verticalMeasurementUnits:MeasurementUnits.INCHES}
//a selected image
var sel = doc.selection[0];
//the actual pixel dimensions
$.writeln("Pixel Dimensions: " + getPixels(sel))
//returns Pixel Dimensions: 1920,1280
//the actual dimension in inches
var appi = sel.actualPpi
var aw = getPixels(sel)[0]/appi[0];
var ah = getPixels(sel)[1]/appi[1];
$.writeln("Actual Inch Dimensions: " + aw + " x " + ah)
/**
* returns the pixel dimensions of an image
* @param i an image
*/
function getPixels(i){
var r = i.effectivePpi;
var w = i.geometricBounds[3] - i.geometricBounds[1];
var h = i.geometricBounds[2] - i.geometricBounds[0];
var hpd = Math.round(w * (r[0]));
var vpd = Math.round(h * (r[1]));
return [hpd, vpd];
}
Copy link to clipboard
Copied
This worked perfectly, thank you so much!
Copy link to clipboard
Copied
Hi Peter,
If the result is needed in pixels you can easily set the mesurementunits of scriptpreferences to the desired unit. See the modified script that will get the height and width in pixels
app.scriptPreferences.measurementUnit = MeasurementUnits.PIXELS
var image = app.documents[0].links[0].parent
image.clearTransformations()
var width = image.visibleBounds[3] - image.visibleBounds[1]
var height = image.visibleBounds[2] - image.visibleBounds[0]
app.documents[0].undo()
-Manan
Copy link to clipboard
Copied
Hi Manan, I think Peter is looking for the image’s real or actual pixel dimensions.
InDesign’s Pixel ruler unit will measure an object in pixels, but InDesign defines the Pixel unit as a static 1/72". So here the Link panel shows the image’s actual pixel dimensions as 1920 x 1280, but InDesign’s transform panel measures the placed image as 345.6px x 230.4px:
When the rulers are set as inches the image’s width is 4.8", and 4.8*72=345.6.
Copy link to clipboard
Copied
Hi Rob,
Yes i also was working to get the actual dimension of the image which you highlighted in your screenshot. While i have used an algorithm similiar to the one you posted in one of my projects but the new algo that i wrote also seems to work correctly. See the video below, looking at your screenshot i am not sure why it is not working for you. Can you see anything that i am doing wrong?
-Manan
Copy link to clipboard
Copied
It's because the Effective resolution of your placed image is 72ppi, which happens to match InDesign’s 1/72" definition of a pixel dimension. I think if you try your script on a placed image that does not have an Actual Res of 72ppi, you will not get the image’s original pixel dimensions. The Effective resolution in my first example is 457ppi x 529ppi because of the scaling.
Copy link to clipboard
Copied
When I trace your width and height on my image with an Actual Resolution of 400ppi, I get 345.6 x 230.4, and not the 1920 x 1280 pixel dimensions listed in Link Info
$.writeln("Dimensions: " + width + " x " + height)
//Returns Dimensions: 345.6 x 230.4
Copy link to clipboard
Copied
// Select an image (NOT its frame) then run script.
var image = app.activeDocument.selection[0];
var hs = image.horizontalScale;
var vs = image.verticalScale;
var ppi = image.actualPpi;
var gb = image.geometricBounds;
var pixelsWide = Math.round((gb[3] - gb[1]) / (hs / 100) * ppi[0]);
var pixelsHigh = Math.round((gb[2] - gb[0]) / (vs / 100) * ppi[1]);
alert([pixelsWide, pixelsHigh]);
Some notes: flopped images will give negative results. Use Math.abs() on the results.
Also doesn't work for rotated images. For that, duplicate and clear rotation, take the measurment, then remove the duplicate.
I ran into this when wanting to add "pixel dimensions" to my script "Links Report." (https://www.marspremedia.com/software/indesign/links-report)
Not only rotated, but sheared throws it off, too, of course. I'll post here the function I came up with to handle both. For these cases I opted to make a new temp doc instead of duplicate the image in the current doc. I did this because I didn't want the dupe and clear showing in the undo menu of the target document. Here's my function...
function getPixelDimensions(image) {
var gb; // geometricBounds
var h; // height
var hs; // horizontalScale
var ppi; // pixels per inch
var td; // temp document
var tr; // temp rectangle
var tg; // temp graphic
var vs; // verticalScale
var w; // width
ppi = image.actualPpi;
hs = image.horizontalScale;
vs = image.verticalScale;
if (image.rotationAngle !== 0 || image.shearAngle !== 0) {
// Won't be correct if rotated or sheared.
// Copy to a temp doc and clear rotation and shear.
// Then measure, and dump the temp doc.
td = app.documents.add();
tr = image.parent.duplicate(td.pages[0]);
tg = tr.graphics[0];
tg.rotationAngle = 0;
tg.shearAngle = 0;
gb = tg.geometricBounds;
td.close(SaveOptions.NO);
} else {
gb = image.geometricBounds;
}
w = Math.abs(Math.round((gb[3] - gb[1]) / (hs / 100) * ppi[0]));
h = Math.abs(Math.round((gb[2] - gb[0]) / (vs / 100) * ppi[1]));
return [w, h];
// Returns array of two numbers, width and height.
// Width = array[0], height = array[1]
}
Copy link to clipboard
Copied
Hello.
Is there any way to put the unscaled dimensions of a link into a text box uner the image using these methods?
Copy link to clipboard
Copied
With some work, sure. Use the functions posted to get the array of pixels wide x tall, then make a text box under the graphic and update the contents with the values. I have a script that puts the name of graphics on them. It could be modified to add this information instead. Download here. It's open source, fully editable.
http://www.marspremedia.com/software/indesign/label-graphic-links
In the function 'processGraphic' at some point early in the function call the other code to get the pixel dimensions. Store it in a variable, or variables. Then replace the line
textFrame.contents = name;
with (for example)
textFrame.contents = width + "px X " + height + " px";
That sort of thing, or something similar. Whatever you like. Then to put it below the graphic, instead of on top of it, modify the code that positions the text frame at the end of the function. There are two vars gb1 and gb2. 1 is the graphic bounds. 2 is the text frame bounds. Adjust the text frame bounds so its top is at the bottom of the graphic frame.
You can see a video of the original script in action here: https://youtu.be/eluuL8PX6I8
Copy link to clipboard
Copied
Thankyou very much for this, it's a brilliant start.
I'm new to this and although i can see the function you mentioned and 'textFrame.contents' I have no idea how to call the pixel dimensions.
Seems i need to find a tutorial.
And as a matter of interest, on gb1, what do the 0,1,2 & 3 numbers do, are they y, x, height & width?
Appreciate the help so far.
Wx
Copy link to clipboard
Copied
Newby again - this is Javascript right? So i know where to direct my Google search!
Copy link to clipboard
Copied
Yes and no. Officially it is "ExtendScript" which is Adobe's implementation of JavaScript specific to automating Adobe applications. Thing is, while it is JavaScript, it's OLD JS without many modern additions browsers have. Best advice for learning JS for Adobe apps is get an old book published before 2009. It helps to not waste time learning a bunch of features that came after that, but Adobe apps are clueless about.
Copy link to clipboard
Copied
Wasn't sure your level of ExtendScript and JavaScript experience. Sorry I didn't make it simpler. First, to answer your question about gb1 and 2... those are 'Geometric Bounds' (made short, just 'gb'). This is a common property used many places in Adobe apps. The property is a 4 element array. It gets a little confusing because not all the apps the array indexes are the same meaning (still trips me up as I code one app then another). But for InDesign anyway, the bounds array is [top, left, bottom, right]. And InDesign (unlike Illustrator) coordinates are from top left, going down to right. So having the bounds of something (a rectangle, image frame, text frame, etc.) this is saying where it's located on the page.
This actually sounds like a good idea for a new script, so I'll likely take my Label Graphic Links script, or possibly another one "Image Names" (also open source... http://www.marspremedia.com/software/indesign/image-names) and modify one or the other to achive the result you describe. Trouble is, I can't get to it for a least a week with the current load of custom scripts at the moment.
About a tutorial, I also have that on YouTube. Start here: https://youtu.be/XjmWX_qfLSU
I'll say more in the response to your next post.
Copy link to clipboard
Copied
Hi @wobblewoo , a page item doesn’t have a width and height property, but you can write a function that extracts it from the geometricBounds property. I use this:
//a selected page item
var s = app.activeDocument.selection[0]
//width and height as an array
var d = getWidthHeight(s);
alert(d[0] + "x" + d[1])
/**
* Get a page item’s width and height
* @ param the page item
* @ return an array [width, height]
*
*/
function getWidthHeight(pi){
var wh = []
var gb = pi.geometricBounds
wh[0] = gb[3]-gb[1];
wh[1] = gb[2]-gb[0]
return wh
}
Copy link to clipboard
Copied
Thankyou, ill have a look through this but it's the size of the link im trying to put in a box. For instance i have a link thats 12x12 and i place it in InDesign at 50%, my understanding is that your script will return 6x6 and i need it to be 12x12.
Copy link to clipboard
Copied
You can get the scale by dividing the Effective by Actual Res. Direct select an image and try this:
var s = app.activeDocument.selection[0]
//width and height as na array
var d = getWidthHeight(s);
if (s.constructor.name == "Image") {
var ep = s.effectivePpi
var ap = s.actualPpi
var w = (ep[0]/ap[0]) * d[0];
var h = (ep[1]/ap[1]) * d[1]
alert(w.toFixed (3) + " x " + h.toFixed (3))
} else {alert("Select an Image")}
/**
* Get a page item’s width and height
* @ param the page item
* @ return an array [width, height]
*
*/
function getWidthHeight(pi){
var wh = []
var gb = pi.geometricBounds
wh[0] = gb[3]-gb[1];
wh[1] = gb[2]-gb[0]
return wh
}
Copy link to clipboard
Copied
Thanks both. Apologies for the delay, had a very busy few days.
The scaled image script works wonders for an image but i have Illustrator files which don't display acutal or effective PPI, so we cant find the scale. Can you get the imported scale some other way?
The attached AI file is 710 x 300mm and placed into ID at 18%.
The box displays (from your first script) as 127.8 x 54* and if i divide that by 0.18 i get, what i want, 710 x 300
I actually get a very precise 12 decimal place number 127.800145927429...
Copy link to clipboard
Copied
Hi @wobblewoo , I was assuming an image and getting the scale via the effective/actual res ratio, so we wouldn’t have to worry about transformation totals (could the link and its parent framed be scaled differently?). It could also work to set the transformationsAreTotals prefs to true and simply get the total scale. Try this:
var ot = app.transformPreferences.transformationsAreTotals
var doc = app.activeDocument
app.transformPreferences.transformationsAreTotals = true;
var s = doc.selection[0]
var d = getWidthHeight(s);
var sw = s.horizontalScale;
var sh = s.verticalScale;
var w = (100/sw) * d[0];
var h = (100/sh) * d[1];
app.transformPreferences.transformationsAreTotals = ot;
alert(w.toFixed (3) + " x " + h.toFixed (3))
/**
* Get a page item’s width and height
* @ param the page item
* @ return an array [width, height]
*
*/
function getWidthHeight(pi){
var wh = []
var gb = pi.geometricBounds
wh[0] = gb[3]-gb[1];
wh[1] = gb[2]-gb[0]
return wh
}
Copy link to clipboard
Copied
Copy link to clipboard
Copied
You have the container frame selected, select the placed AI file
Copy link to clipboard
Copied
Here’s a loop that adds a text frame with the dimensions in the upper left corner of the link—sets the dimensions in millimeters:
var ot = app.transformPreferences.transformationsAreTotals
app.scriptPreferences.measurementUnit = MeasurementUnits.MILLIMETERS;
app.transformPreferences.transformationsAreTotals = true;
var lnks = app.documents[0].links;
var p, d, b, pp, dt, tf;
for (var i = 0; i < lnks.length; i++){
p = lnks[i].parent;
d = getActualDim(p)
b = p.geometricBounds;
pp = p.parentPage;
dt = d[0].toFixed (3) + " x " + d[1].toFixed (3)
var tf = pp.textFrames.add({fillColor:"Paper", geometricBounds: [b[0]-5,b[1],b[0],b[3]], contents:dt});
};
app.transformPreferences.transformationsAreTotals = ot;
app.scriptPreferences.measurementUnit = AutoEnum.AUTO_VALUE;
/**
* Gets a link’s actual dimensions
* @ param the placed object
* @ return the object’s actual width and height as an array
*/
function getActualDim(lnk){
var d = getWidthHeight(lnk);
var sw = lnk.horizontalScale;
var sh = lnk.verticalScale;
var w = (100/sw) * d[0];
var h = (100/sh) * d[1];
return [w,h]
}
/**
* Get a page item’s width and height
* @ param the page item
* @ return an array [width, height]
*
*/
function getWidthHeight(pi){
var gb = pi.geometricBounds
return [gb[3]-gb[1], gb[2]-gb[0]]
}