Thanks Daniel. Yes, the reason I made the script is that I keep running into cases where it would save time to be able to flip (mirror) markup. The script is a workaround, and it does it by moving all the points for polylines and polygons. For the things that it can't transform, it just changes the rotation and position. Here's a slightly updated version. I've attached a zip file with the compiled menu as explained above. Once the problem with gestures gets fixed, I'll post one that also handles them (for now it just rotates them).
Code: Select all
// flip selected annotations
var flipDir; // save dialog response for next time
(function(t) {
var _self;
var flipAnnotations = {
selAnnots: [],
initialize: function (anns) {
if (anns && anns.length>0){
//console.println("Found Annots: "+anns.length);
this.selAnnots = anns;
_self = this; // KLUDGE
if (flipDir == null) {
flipDir = { horiz: true, vert: false };
};
return app.execDialog(this.flipDialog);
}else{
return "No Annotations selected.";
};
},
doFlip: function () {
// get bounding box of annotations
var aRec = this.getBounds(this.selAnnots);
// get center point of annotations
var aCtr = [(aRec[0][0]+aRec[1][0])/2,(aRec[0][1]+aRec[1][1])/2];
// flip the annotations
this.flipAnns(aCtr,this.selAnnots);
},
// returns array containing [x min, ymin],[x max, y max]
getBounds: function (anns) {
var theBounds = [[],[]];
var aRec = [];
for (let tAnn in anns) {
// loop through all selected annotations
aRec = anns[tAnn].rect; // outer bounds of this annotation
for (let i = 0; i<2; i++) {
// assign min x value
if ( typeof theBounds[0][0] == "undefined" || aRec[i*2] < theBounds[0][0] ) {
theBounds[0][0]=aRec[i*2];
}
// assign max x value
if ( typeof theBounds[1][0] == "undefined" || aRec[i*2] > theBounds[1][0] ) {
theBounds[1][0]=aRec[i*2];
}
// assign min y value
if ( typeof theBounds[0][1] == "undefined" || aRec[i*2+1] < theBounds[0][1] ) {
theBounds[0][1]=aRec[i*2+1];
}
// assign max y value
if ( typeof theBounds[1][1] == "undefined" || aRec[i*2+1] > theBounds[1][1] ) {
theBounds[1][1]=aRec[i*2+1];
}
}
}
return theBounds;
},
// flip a line
flipLine: function ( flipPt, tPoints) {
for (let i=0;i<tPoints.length;i++) {
tPoints[i] = this.moveLineArray( flipPt, tPoints[i]);
}
return tPoints;
},
// move points in line array
moveLineArray ( flipPt, lPoints) {
// step through array in form [x1,y1,x2,y2,...]
for (let j=0;j<lPoints.length;j+=2) {
// flip in x direction
if (flipDir.horiz) {
lPoints[j]=flipPt[0]*2-lPoints[j];
}
// flip in y direction
if (flipDir.vert) {
lPoints[j+1]=flipPt[1]*2-lPoints[j+1];
}
}
return lPoints;
},
doRotation: function (r) {
if (flipDir.horiz) r = - r;
if (flipDir.vert) r = - r;
return r;
},
// flip the annotations
flipAnns: function (flipPt, anns) {
var tPoints = [];
var tRotation = 0;
for (let tAnn in anns) {
switch(anns[tAnn].type) {
case "Line":
tPoints = this.flipLine(flipPt,anns[tAnn].points);
// for dimension lines, need to change leaderlength
if (anns[tAnn].leaderLength && flipDir.vert) {
anns[tAnn].leaderLength = -anns[tAnn].leaderLength;
}
// also, for dimension lines, the point order affects which way up the leader text is
if ("LineDimension"==anns[tAnn].intent && flipDir.horiz) {
tPoints = tPoints.slice(1,2).concat(tPoints.slice(0,1));
}
anns[tAnn].points = tPoints;
break;
case "PolyLine":
case "Polygon":
anns[tAnn].vertices = this.flipLine(flipPt,anns[tAnn].vertices);
anns[tAnn].rotation = this.doRotation( anns[tAnn].rotation );
break;
case "FreeText":
// move callout arrow
if (anns[tAnn].callout && anns[tAnn].callout.length > 0) {
anns[tAnn].callout = this.moveLineArray( flipPt, anns[tAnn].callout );
}
// no break - need to also move center and rotate, same as other items
case "Circle":
case "Stamp":
case "Text":
case "Square":
case "Squiggly":
// move center
anns[tAnn].rect = this.moveLineArray( flipPt, anns[tAnn].rect );
// and rotate
anns[tAnn].rotation = this.doRotation( anns[tAnn].rotation );
break;
case "Ink":
console.println("Cannot flip Ink");
/* BUG: PDF creator reports only the x coordinate as both the x and y coordinate for gestures
tPoints = anns[tAnn].gestures;
for (var i in tPoints) {
tPoints[i] = this.flipLine(flipPt,tPoints[i]);
}
anns[tAnn].gestures = tPoints;
*/
anns[tAnn].rotation = this.doRotation( anns[tAnn].rotation );
// get all properties
for (let i in anns[tAnn]) {
console.println(i+" : "+anns[tAnn][i]);
}
break;
}
//console.println(anns[tAnn].type);
}
},
// try to figure out up or down based on document rotation
// I don't know how to determine if the view has been rotated, though, so if view is rotated, this will be wrong
getUp: function (v, h) {
var pageDir = {v:v,h:h};
switch(this.selAnnots[0].doc.getPageRotation( {nPage:this.selAnnots[0].page})) {
case 90:
case 270:
pageDir = {v:h,h:v};
}
return pageDir;
},
// dialog box to ask for mirror direction
flipDialog: {
initialize: function (dialog) {
//var defVert = dialog.store()["vDir"];
//var defHoriz = dialog.store()["hDir"];
var dir = _self.getUp(flipDir.vert,flipDir.horiz);
var defVert = dir.v;
var defHoriz = dir.h;
dialog.load({ "vDir": defVert, "hDir": defHoriz});
},
commit:function (dialog) { // called when OK pressed
var results = dialog.store();
// try to figure out which way is up
var dir = _self.getUp(results["vDir"],results["hDir"]);
flipDir.vert = dir.v;
flipDir.horiz = dir.h;
_self.doFlip();
},
description:
{
name: "Mirror Annotations", // Dialog box title
align_children: "align_left",
width: 350,
height: 200,
elements:
[
{
type: "cluster",
name: "Mirror Direction",
align_children: "align_left",
elements:
[
{
type: "check_box",
name: "Mirror Horizontally",
//char_width: 25,
item_id: "hDir"
},
{
type: "check_box",
name: "Mirror Vertically",
//char_width: 25,
item_id: "vDir"
},
]
},
{
alignment: "align_right",
type: "ok_cancel",
ok_name: "Ok",
cancel_name: "Cancel"
}
]
}
}
};
flipAnnotations.initialize(t.selectedAnnots);
})(this);
mirror annotations menu.zip
You do not have the required permissions to view the files attached to this post.