Copy link to clipboard
Copied
Hi,
I need to know which image have extended graphic frame.
Below coding is working fine for me:
app.activeDocument.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
app.activeDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.POINTS;
app.activeDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.POINTS;
var link, image, frame;
var doc = app.activeDocument;
var graphics = doc.allGraphics;
var graphicsname=[]
for (var i = 0; i < graphics.length; i++) {
link = graphics.itemLink;
image = link.parent;
frame = image.parent;
image0=Math.round(image.geometricBounds[0]);
image1=Math.round(image.geometricBounds[1]);
image2=Math.round(image.geometricBounds[2]);
image3=Math.round(image.geometricBounds[3]);
frame0=Math.round(frame.geometricBounds[0]);
frame1=Math.round(frame.geometricBounds[1]);
frame2=Math.round(frame.geometricBounds[2]);
frame3=Math.round(frame.geometricBounds[3]);
if((image0>frame0) || (image1>frame1) || (image2<frame2) || (frame3 >image3)){
graphicsname.push(link.name)
}
}
alert(graphicsname.join("\n"))
But the problem is when the image is shear or rotated in the graphic frame, it throw as error. Even the image box does not have empty space. Any suggestion i move forward?
Also if you have suggestions to improve my above coding that also great.
Thanks,
K
Copy link to clipboard
Copied
See Check if two line segments intersect · GitHub
and Calculating the intersection of two lines. - JSFiddle
If the brown inner frame is bigger than the blue outer frame and the lines don't intersect then there's no empty space.
If they intersect only on a non extreme point like the corner of the blue frame or the tops etc. and the browns bigger that it encapsulates the blue one then there's no empty space
if the 2 frames don't intersect and are on different parts of the screen then there's a lot of empty space
Here's a start
javascript - Check if polygon is inside a polygon - Stack Overflow
HTH
Trevor
Copy link to clipboard
Copied
Thanks Trevor. Got some idea. Let i try.
Regards,
K
Copy link to clipboard
Copied
Hi K,
to proof if and how two polygons ( closed path, but arbitrary shaped! ) intersect, one could use also InDesign's pathfinder functionality.
I did not test very much but the pathfinder operation addPaths() could help to determine if a graphic frame is filled totally by an image or not.
Cases and results:
Code:
/**
* @@@BUILDINFO@@@ Example-addPath()-DoesImageFillFrame.jsx !Version! Thu Nov 24 2016 20:29:09 GMT+0100
*/
/*
Uwe Laubender:
Test if image fills the graphic frame entirely.
Using pathfinder operation addPaths()
*/
// Graphic frame with image is selected:
var myGraphicFrame = app.selection[0];
var doesFillEntirely = doesImageFillsGraphicFrame(myGraphicFrame);
alert("image fills graphic frame: "+doesFillEntirely); // true or false
// Returns true or false
function doesImageFillsGraphicFrame(/*graphic frame*/graphicFrame)
{
// Duplicate the graphic frame and work with the duplicate:
var dupGraphicFrame = graphicFrame.duplicate();
// Duplicate the graphic
// NOTE: Not tested with graphics that contain clipping paths!!
var polygonOfGraphic = dupGraphicFrame.pageItems[0].duplicate();
// Do the pathpoint operation addPath:
var resultFrame = polygonOfGraphic.addPath(dupGraphicFrame);
// Path points length of all paths of the result:
var resultFramePPL = resultFrame.paths.everyItem().pathPoints.everyItem().getElements().length;
// Get rid of the added object:
resultFrame.remove();
// Test, if the pathfinder operation results in a frame, that
// consist of 4 path points entirely:
if(resultFramePPL == 4){return true}
else{return false};
// Maybe a better test would be to compare
// the result's entirePath Array with
// the polygonOfGraphic's entirePath Array.
};
Regards,
Uwe
Copy link to clipboard
Copied
Forget my code.
The final test is not good enough…
Nevertheless I think, doing something with pathfinder operations could be a solution.
Regards,
Uwe
Copy link to clipboard
Copied
HI Uwe,
I tried the coding you provided it is working good. May i know what will be the future problem encounter if i use this?
Thanks,
K
Copy link to clipboard
Copied
Hi K,
it's not working with a very simple case:
Just place an image and crop the frame.
From left to right:
1. Image placed, not cropped. => Script result is true | ok
2. Image placed, cropped at the right. => Script result is false | wrong test
3. resultFrame not removed,
image removed from resultFrame,
filled with "Yellow",
selected with the Direct Selection Tool to get the path points visible.
There are 6 path points.
The script is testing on 4 path points.
Similar cases:
So my test of the resultFrame's path points length is not sufficient.
What can be done? Additionally a test comparing the geometricBounds of the image and the resultFrame?
Maybe.
Regards,
Uwe
Copy link to clipboard
Copied
Hi Uwe,
Yes now i understood the problem. Checking path length will not help any more. In my coding i used geometrics bounds values to find out. I thought if any image have shear value then i need to find the one of rotate angle value
y value of object from trim and divided by shear degree value
so with this formula i can get one degree value, for example 1 degree of rotation is equal to 5 points
This will be multiplied with the geometric bounds to get the object as stright...
Little confused how to move forward
Now my condition is...
Thanks,
K
Copy link to clipboard
Copied
Hi,
Any suggestions please?
Copy link to clipboard
Copied
Hi,
Is your graphic frame always convex?
Has your graphic clipping path?
Assuming answers YES-NO --> it could be 'isPointInsidePolygon' algorithm in use.
I mean to check if each container vertix is inside polygon created by graphic.duplicate().
If always true --> graphic fills container with no space.
Jarek
Copy link to clipboard
Copied
Hi Jarek,
Thank you for the reply.
Yes, the convex and clipping path images may or may not present in the document.
isPointInsidePolygon is a new word just i heard. Let i make some research with this.
Regards,
K
Copy link to clipboard
Copied
Hi K,
in principle you already have a working solution.
Check, if a graphic frame containing an image is rotated or sheared.
Do a duplicate, unrotate and unshear the duplicate of the graphic frame.
graphicFrameDuplicate.rotationAngle = 0;
graphicFrameDuplicate.shearAngle = 0;
Then check, if its image is rotated other than 90°, 180°, 270° or 360° or if it is sheared.
If not, go with your method in your first post.
If yes, do with my method posted in answer 3.
Regards,
Uwe
Copy link to clipboard
Copied
Hi Uwe,
Thanks you for your valuable inputs. I will work and share the results soon.
Regards,
K
Copy link to clipboard
Copied
Hi Uwe,
Thanks Uwe, am close to finish this
I did as you suggested and it is working fine. Please validate the below code and give your feedbacks.
app.activeDocument.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
app.activeDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.POINTS;
app.activeDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.POINTS;
var link, image, frame;
var doc = app.activeDocument;
var graphics = doc.allGraphics;
var graphicsname=[]
for (var i = 0; i < graphics.length; i++) {
link = graphics.itemLink;
image = link.parent;
frame = image.parent;
var flgAngle=0,flgSheare=0;
if(image.rotationAngle!=0){flgAngle=1;}
if(frame.rotationAngle!=0){flgAngle=1;}
if(image.shearAngle!=0){flgSheare=1;}
if(frame.shearAngle!=0){flgSheare=1;}
if(flgAngle==0 && flgSheare==0){
image0=Math.round(image.geometricBounds[0]);
image1=Math.round(image.geometricBounds[1]);
image2=Math.round(image.geometricBounds[2]);
image3=Math.round(image.geometricBounds[3]);
frame0=Math.round(frame.geometricBounds[0]);
frame1=Math.round(frame.geometricBounds[1]);
frame2=Math.round(frame.geometricBounds[2]);
frame3=Math.round(frame.geometricBounds[3]);
if((image0>frame0) || (image1>frame1) || (image2<frame2) || (frame3 >image3)){
graphicsname.push(link.name)
}
}
else{uwe(frame);}
}
alert(graphicsname.join("\n"))
function uwe(imgFrame){
/**
* @@@BUILDINFO@@@ Example-addPath()-DoesImageFillFrame.jsx !Version! Thu Nov 24 2016 20:29:09 GMT+0100
*/
/*
Uwe Laubender:
Test if image fills the graphic frame entirely.
Using pathfinder operation addPaths()
*/
// Graphic frame with image is selected:
var myGraphicFrame = imgFrame;
var doesFillEntirely = doesImageFillsGraphicFrame(myGraphicFrame);
alert("image fills graphic frame: "+link.name); // true or false
// Returns true or false
function doesImageFillsGraphicFrame(/*graphic frame*/graphicFrame)
{
// Duplicate the graphic frame and work with the duplicate:
var dupGraphicFrame = graphicFrame.duplicate();
// Duplicate the graphic
// NOTE: Not tested with graphics that contain clipping paths!!
var polygonOfGraphic = dupGraphicFrame.pageItems[0].duplicate();
// Do the pathpoint operation addPath:
var resultFrame = polygonOfGraphic.addPath(dupGraphicFrame);
// Path points length of all paths of the result:
var resultFramePPL = resultFrame.paths.everyItem().pathPoints.everyItem().getElements().length;
// Get rid of the added object:
resultFrame.remove();
// Test, if the pathfinder operation results in a frame, that
// consist of 4 path points entirely:
if(resultFramePPL == 4){return true}
else{return false};
// Maybe a better test would be to compare
// the result's entirePath Array with
// the polygonOfGraphic's entirePath Array.
};
}
Regards,
K
Copy link to clipboard
Copied
Hi,
Just as 3rd pair of eyes remark:
Is your function targeted to rectangles only?
Is Uwe's function returning wrong result if frame's vertix touch image's edge?
Jarek
Copy link to clipboard
Copied
Hi Jarek,
Yes mostly it comes as rectangle.
@Uwe: Sorry i forget to check duplicated graphic frames Let i do
Thanks,
Karthi
Copy link to clipboard
Copied
HI Uwe,
I tried as you said. Yes it is also performing. But can't figure out the difference between the duplicate graphic frame and the answer in post 13.
Also the not sure the usage of using precision variable like var precision = 100;
Sorry, eagerly want to know if using this will two give the best results?
Regards,
K
Copy link to clipboard
Copied
Hi K,
I cannot see that you are testing with duplicated graphic frames.
That's necessary, if you like to do what I suggested:
1. Duplicate the graphic's parent and test with the duplicate.
2. Set the rotationAngle and the shearAngle to value 0 and continue testing:
Then ask: Is the image rotated or sheared?
No => Test the geometric bounds with your method.
Yes => Use my method.
3. After writing the result to your graphicsname array, remove the duplicate.
Also consider to refine your rounding process to be a bit more precise.
Currently you do rounding to full points. To one or two decimals could be better.
But be not too precise…
var precision = 100; // 100 for two decimals, 10 for one decimal: Could be sufficent.
image0=Math.round(image.geometricBounds[0]*precision);
// etc.pp.
frame0=Math.round(frame.geometricBounds[0]*precision);
// etc.pp.
Math.round() rounds to the nearest integer value.
Regards,
Uwe
Copy link to clipboard
Copied
Hi all,
And what about this way...:
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// made by Jump_Over mail: flylullabay@gmail.com
// This is to test if graphic fills its parent frame area (no space)
// ASSUMINGS:
// 1. target is selected
// 2. graphic has no clippingPath set
// 3. frame is a single object (not an union)
// 4. frame is a polygon (no curved lines)
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
main ();
function main ()
{
if (
!app.documents.length ||
!app.activeDocument.links.length ||
!app.selection.length ||
!app.selection[0].graphics.length)
{
alert ("no target detected");
exit();
}
var
mContainer = app.selection[0],
containerPath = mContainer.paths[0].pathPoints.everyItem().anchor,
mContents = mContainer.graphics[0].duplicate(),
contentsPath = mContents.paths[0].pathPoints.everyItem().anchor,
cPoint, X_coordi = [], Y_coordi = [],
mResult = "OK";
mContents.remove();
// prepare arrays for testing functions
while (cPoint = contentsPath.shift()) {
X_coordi.push(cPoint[0]); // array with x-coordi of polygon vertex
Y_coordi.push(cPoint[1]);
}
while (cPoint = containerPath.shift()) {
if ( !pointInPoly(X_coordi, Y_coordi, cPoint) &&
!pointAtPoly(X_coordi, Y_coordi, cPoint) ) mResult = "KO";
}
alert (mResult);
}
function pointAtPoly (vert_x, vert_y, testPoint)
{ // test if testPoint is at polygon edge
var
test_x = testPoint[0],
test_y = testPoint[1],
curr, prev, detMat;
for (curr = 0, prev = vert_x.length - 1; curr < vert_x.length; prev = curr++) {
detMat = vert_x[curr]*vert_y[prev] + vert_x[prev]*test_y + test_x*vert_y[curr] -
test_x*vert_y[prev] - vert_x[curr]*test_y - vert_x[prev]*vert_y[curr];
//
if ( (Math.abs(detMat) < 0.000001) && // check if these points are not collinear (with tollerance for rounded coordies)
( // check if edge currPoint<->prevPoint covers testPoint
(Math.min(vert_x[curr], vert_x[prev]) <= test_x) && (test_x <= Math.max(vert_x[curr], vert_x[prev]))
&&
(Math.min(vert_y[curr], vert_y[prev]) <= test_y) && (test_y <= Math.max(vert_y[curr], vert_y[prev]))
)
)
return true;
}
return false;
}
function pointInPoly(vert_x, vert_y, testPoint)
{ // test if testPoint is inside polygon
var
test_x = testPoint[0],
test_y = testPoint[1],
curr, prev,
res = false;
for (curr = 0, prev = vert_x.length - 1; curr < vert_x.length; prev = curr++)
{
if (
( (vert_y[curr] > test_y) != (vert_y[prev] > test_y) ) &&
( test_x < (vert_x[prev] - vert_x[curr]) * (test_y - vert_y[curr]) / (vert_y[prev] - vert_y[curr]) + vert_x[curr] )
) res = !res;
}
return res;
}
Jarek
Copy link to clipboard
Copied
Hi all,
In terms of bounding boxes the question could first be addressed as follows. To ensure that the parent container does not extend beyond the image area, it is sufficient to check that the parent inner box is contained within the image inner box. Which is satisfied if and only if each corner point of the parent box belongs to the child box. That specific problem can be solved very quickly using (u,v) coordinates of the respective boxes, without any transformation or Pathfinder operations.
However, the figure below shows that the condition, although sufficient, is not necessary:
Here we have a configuration where the child box does not contain the parent box (blue regions overlap) while the actual parent shape still entirely stands inside the child box. What would be great for addressing any possibility would be to handle the “in-child” box of the parent, that is, the visible bounding box of the parent framed in the perspective of the child coordinate space. Unfortunately, the DOM does not provide simple access to “in-child” boxes! One can access the in-parent box of the child, but not the in-child box of the parent 😞
Note. — At first you may think that checking the state of the in-parent box of the child relative to the parent inner box could be an indirect way of addressing the original problem. But this is definitely wrong. The figure below clearly shows that the in-parent box of the child can entirely contain the parent box while the polygonal shape extends beyond the image area.
So we need a workaround for really testing the parent shape bounding box seen in the perspective of the image space. (And, by the way, we need the visible box rather than the geometric box of the parent, in case rounded corners would be applied.)
Fortunately we have two interesting properties at hand. First, the fact of “extending beyond the image area” is invariant by any transformation. That is, if we transform the container in some way this doesn't change the state of the problem. Secondly, the whole image area by nature coincides with its inner box, which is a parallelogram in the perspective of the pasteboard. Therefore we can find a transformation T that, being applied to the parent, will change the image box into a rectangle in the pasteboard space. Then, we can consider the visible “in-board” box of the parent, that is, the rectangle that encloses the parent in the perspective of the pasteboard space. We know have two comparable rectangles Rchild and Rparent and the problem reduces to checking whether Rchild entirely contains Rparent.
The figure below summarizes the trick:
As usual, the implementation requires a “machine epsilon” (see my EPSILON constant) in order to prevent floating-point approximation errors which frequently occur in InDesign coordinate system. Here is the code I suggest:
const CS_BOARD = +CoordinateSpaces.pasteboardCoordinates,
BB_VISIBLE = +BoundingBoxLimits.outerStrokeBounds,
BB_PATH = +BoundingBoxLimits.geometricPathBounds;
const EPSILON = 1e-6;
var image = app.selection[0], // target image
parent = image.parent;
// Temporarily transform the container so that its image (inner) box
// be a rectangle in the perspective of the pasteboard.
// ---
var origin = image.resolve([[.5,.5],BB_PATH],CS_BOARD)[0],
mx = image.transformValuesOf(CS_BOARD)[0],
T = app.transformationMatrices.add(1,1,-mx.clockwiseShearAngle,-mx.counterclockwiseRotationAngle);
parent.transform(CS_BOARD,origin,T);
// Retrieve image corners in board coord space.
// ---
var iTL = image.resolve([[0,0],BB_PATH],CS_BOARD)[0],
iBR = image.resolve([[1,1],BB_PATH],CS_BOARD)[0];
// Retrieve parent *inboard box* corners in board coord space.
// ---
var pTL = parent.resolve([[0,0],BB_VISIBLE,CS_BOARD],CS_BOARD)[0],
pBR = parent.resolve([[1,1],BB_VISIBLE,CS_BOARD],CS_BOARD)[0];
// Revert the transformation.
// ---
parent.transform(CS_BOARD,origin,T.invertMatrix());
// Check whether the rectangle <pTL,pBR> is included in <iTL,iBR>
// ---
var r = pTL[0] >= iTL[0]-EPSILON && pTL[1] >= iTL[1]-EPSILON
&& pBR[0] <= iBR[0]+EPSILON && pBR[1] <= iBR[1]+EPSILON;
alert( r ? 'OK' : 'KO' );
And a few test screenshots:
@+
Marc
Copy link to clipboard
Copied
Hi Marc,
First i like to give a big THANKS for your wonderful explanation. I aware i have only 0.1% knowledge what you have done with your coding.
I blindly tried your coding with just place an image in indesign. But it always throws the alert KO even the image in correct position.
Could you please suggest?
PS: My head starts rounding after i read the explanation
Regards,
Karthi
Copy link to clipboard
Copied
Hi Karthi,
could you post a screenshot of a result that went wrong with Marc's script?
Or maybe even provide a packaged InDesign file with the case?
Hi Marc,
cool code. Just tested with my samples.
In all cases but one your method is working as expected.
However, there seems to be at least one case where it did not work.
Could be a "border case" perhaps.
Here a screenshot of the case:
And here the values for the geometric bounds of the image and the container frame:
Image:
41.2984310497206
23.8046101032331
122.578431049721
132.177943436566
Container frame:
41.2984310497206
23.8046101032331
110.700965911279
110.194786856753
rotationAngle and shearAngle values for image and container frame are 0 .
Below a link to my test files that also contain a special case with an image that is cropped by a PhotoShop path.
This case would result in a false positive with all scripting solutions presented in this thread. Another case we should tackle. I already have some ideas for that.
EDIT 220421 NEW LINK TO MY TEST FILE:
https://www.dropbox.com/s/7gok1uxklowpgvm/Marc%20Autret%20%20DoesImageFillFrameEntirely-v1.zip?dl=1
Tested with InDesign CS6 v8.1.0 on Mac OSX 10.6.8.
Did not test with a different version yet.
Thanks,
Uwe
Copy link to clipboard
Copied
Hi Uwe,
Thanks for your feedback. Looking closer at your "false negative" example (#20) it seems to me that that the container stroke slightly extends beyond the image area. So the visible box actually violates the condition and it's a true negative. Now in my code you can replace BB_VISIBLE by BB_PATH in pTL and pBR determination and then you will get OK, I think. The problem with using BB_PATH is mainly that it doesn't properly address rounded corners (the geometric box is larger than the visible box.)
Note. — The DOM provides no way (so far) to access a visible bounding box disregarding stroke weight.
@+,
Marc
Copy link to clipboard
Copied
Hi Marc,
then a clean way could be to test with your original unchanged code on a duplicated frame where the stroke weight is set to zero and the stroke color is set to "None". Just tested that and it's running as expected.
Thanks,
Uwe
Copy link to clipboard
Copied
Note. — The DOM provides no way (so far) to access a visible bounding box disregarding stroke weight.
Hm. Yes and no.
May we have a look into the following case:
The question is:
Can we get the empty area of the frame somehow?
The only answer I have to that is using the path of a text wrap on an empty frame and setting the offset of the wrap to the negative value of the stroke weight of the frame's border. That could work, but will imply some uncertenties for arbitray shapes. Is text wrap following a path precise enough?
Negative value of text wrap applied for an extreme shape:
The path of the wrap can be retrieved and a new shape can be build from that:
var entirePathOfWrap = app.selection[0].textWrapPreferences.paths[0].entirePath;
var textWrapShape = app.selection[0].parent.polygons.add({strokeWeight : 0 , fillColor : "None"});
textWrapShape.paths[0].entirePath = entirePathOfWrap;
Result:
And with that shape we could test the waters…
Regards,
Uwe