With build 367.0 this tool also works for Ink annotations.
I've made a slightly more snazzy version below that adds a button to the Add-in toolbar. As before, copy the script and save as a text file with .js suffix to this folder:
C:\Users\[your user name]\AppData\Roaming\Tracker Software\PDFXEditor\3.0\Javascripts\mirror annotations tool.js
or you can run it from the javascript window but the toolbar button will go away next time you run PDFxchange.
Code: Select all
// script minified using http://jscompress.com/ also need to escape all backslashes
// tool data and custom icon
var iconSet_mirrorTool = { mirror:
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFC0C0C00000000000000000FF91C8F6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFC9C9C9FFB5B5B50000000000000000FF7BBFF6FFA1D0F50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFB6B6B6FFB5B5B50000000000000000FF7BBFF7FF7DBFF60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFB1B1B1FFB5B5B50000000000000000FF7BBFF7FF70BBF7FFBAD8F5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFB4B4B4FFB1B1B1FFB5B5B50000000000000000FF7BBFF6FF71BBF7FF77BDF70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFBBBBBBFFB1B1B1FFB1B1B1FFB5B5B50000000000000000FF7BBFF7FF71BBF7FF71BBF7FF87C4F600000000000000000000000000000000000000000000000000000000000000000000000000000000FFAFAFAFFFB1B1B1FFB1B1B1FFB5B5B50000000000000000FF7BBFF7FF71BBF7FF71BBF7FF6FB9F6000000000000000000000000000000000000000000000000000000000000000000000000FFB6B6B6FF989898FFAAAAAAFFB1B1B1FFB6B6B60000000000000000FF7BBFF7FF71BBF7FF63B4F6FF42A5F5FF84BFF50000000000000000000000000000000000000000000000000000000000000000FF999999FF989898FF999999FFAAAAAAFFB6B6B60000000000000000FF7BBFF7FF63B4F6FF45A6F5FF42A5F5FF43A5F500000000000000000000000000000000000000000000000000000000FF9B9B9BFF989898FF989898FF989898FF999999FFAEAEAE0000000000000000FF6FB8F6FF43A6F5FF42A5F5FF42A5F5FF42A5F5FF7AB7F50000000000000000000000000000000000000000FFCCCCCCFF9A9A9AFF989898FF989898FF989898FF989898FFA2A2A20000000000000000FF58ADF5FF42A5F5FF42A5F5FF42A5F5FF42A5F5FF45A6F5FFAED2F500000000000000000000000000000000FFA2A2A2FF989898FF989898FF989898FF989898FF989898FFA1A1A10000000000000000FF57ADF5FF42A5F5FF42A5F5FF42A5F5FF42A5F5FF42A5F5FF58AEF4000000000000000000000000FFB2B2B2FF989898FF989898FF989898FF989898FF989898FF989898FFA1A1A10000000000000000FF56ACF5FF42A5F5FF42A5F5FF42A5F5FF42A5F5FF42A5F5FF42A5F5FF7CBCF50000000000000000FFA4A4A4FF989898FF989898FF989898FF989898FF989898FF989898FFA1A1A10000000000000000FF56ADF5FF41A5F5FF41A5F5FF41A5F5FF41A5F5FF41A5F5FF41A5F5FF5FAFF500000000FFCBCBCBFFAFAFAFFFAFAFAFFFAFAFAFFFB0B0B0FFAFAFAFFFAFAFAFFFB0B0B0FFB5B5B50000000000000000FF7EBEF5FF71B9F5FF71B9F5FF71B9F4FF71B9F5FF70B9F5FF71B9F5FF71B9F6FFA7D0F500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
script: 'var flipDir,flipAxis,flipCopy;(function(a){var b={selAnnots:[],initialize:function(b){if(b&&0<b.length){this.selAnnots=b,null==flipDir&&(flipDir={horiz:!0,vert:!1});var c=a.getPageRotation({nPage:this.selAnnots[0].page});for(a.viewState.pageViewRotation&&(c+=a.viewState.pageViewRotation),0>c&&(c=360-c);360<=c;)c-=360;return this.flipDialog.pageRotation=c,app.execDialog(this.flipDialog)}return"No Annotations selected."},doFlip:function(){var a=this.getBounds(this.selAnnots),b=this.getAxisPt(a,flipAxis);this.flipAnns(b,this.selAnnots)},getAxisPt:function(a,c){var d=[a.slice(0,2),a.slice(2,4)],b={AxTL:[[0,0],[1,1]],AxTC:[[0,1],[1,1]],AxTR:[[1,1],[1,1]],AxML:[[0,0],[0,1]],AxMC:[[0,1],[0,1]],AxMR:[[1,1],[0,1]],AxBL:[[0,0],[0,0]],AxBC:[[0,1],[0,0]],AxBR:[[1,1],[0,0]]}[c],e=[(+d[b[0][0]][0]+d[b[0][1]][0])/2,(+d[b[1][0]][1]+d[b[1][1]][1])/2];return e},rotatePoint:function(a,b,c){var d=c*Math.PI/180,e=a[0],f=a[1],g=b[0],h=b[1],i=(e-g)*Math.cos(d)-(f-h)*Math.sin(d)+g,j=(e-g)*Math.sin(d)+(f-h)*Math.cos(d)+h;return[i,j]},rotateRect:function(a,b,c){if(b){void 0===c&&(c=[(a[0]+a[2])/2,(a[1]+a[3])/2]);var d=[];for(let e=0;e<a.length-1;e+=2)d=d.concat(this.rotatePoint([a[e],a[e+1]],c,b));return d}return a},toFlatArray:function(b){var a,c=[];for(let d in b)a=b[d],"object"==typeof a[0]&&(a=this.toFlatArray(a)),c=c.concat(a);return c},getBounds:function(a){var b=[],c=[],d=[];for(let e in a){switch(c=a[e].rect,d=this.getAxisPt(c,"AxMC"),a[e].type){case"PolyLine":case"Polygon":c=this.toFlatArray(a[e].vertices);break;case"Ink":c=this.toFlatArray(a[e].gestures);break;default:a[e].callout&&0<a[e].callout.length&&(c=c.concat(a[e].callout));}c=this.rotateRect(c,a[e].rotation,d);for(let a=0;a<c.length-1;a+=2)("undefined"==typeof b[0]||c[a]<b[0])&&(b[0]=c[a]),("undefined"==typeof b[2]||c[a]>b[2])&&(b[2]=c[a]),("undefined"==typeof b[1]||c[a+1]<b[1])&&(b[1]=c[a+1]),("undefined"==typeof b[3]||c[a+1]>b[3])&&(b[3]=c[a+1])}return b},flipLine:function(a,b){for(let c=0;c<b.length;c++)b[c]=this.moveLineArray(a,b[c]);return b},moveLineArray(a,b){for(let c=0;c<b.length;c+=2)flipDir.horiz&&(b[c]=2*a[0]-b[c]),flipDir.vert&&(b[c+1]=2*a[1]-b[c+1]);return b},doRotation:function(a){return flipDir.horiz&&(a=-a),flipDir.vert&&(a=-a),a},flipTextAlign:function(a){var b=a.alignment;return flipDir.horiz&&1!=b&&(b=2-b),b},flipAnns:function(b,c){var d=[],e={};for(let g in c)switch(flipCopy?(e=c[g].getProps(),!e.richContents.length&&delete e.richContents,e=a.addAnnot(e)):e=c[g],e.type){case"Line":d=this.flipLine(b,e.points),e.leaderLength&&flipDir.vert&&(e.leaderLength=-e.leaderLength),"LineDimension"==e.intent&&flipDir.horiz&&(d=d.slice(1,2).concat(d.slice(0,1))),e.points=d;break;case"PolyLine":case"Polygon":e.setProps({vertices:this.flipLine(b,e.vertices),rotation:this.doRotation(e.rotation)});break;case"FreeText":e.callout&&0<e.callout.length&&(e.callout=this.moveLineArray(b,e.callout)),e.alignment=this.flipTextAlign(e);case"Circle":case"Stamp":case"Text":case"Square":case"Squiggly":e.setProps({rect:this.moveLineArray(b,e.rect),rotation:this.doRotation(e.rotation)});break;case"Ink":for(var f in d=e.gestures,d)d[f]=this.flipLine(b,d[f]);e.setProps({gestures:d,rotation:this.doRotation(e.rotation)});}},flipDialog:{pageRotation:0,getUp:function(a,b){var c={v:a,h:b};switch(this.pageRotation){case 90:case 270:c={v:b,h:a};}return c},getAxDir:function(a,b){var c=["AxTL","AxTC","AxTR","AxMR","AxBR","AxBC","AxBL","AxML"],d=c.indexOf(a);if(-1<d){switch(this.pageRotation){case 90:d+=2*(b?-1:1);break;case 180:d+=4*(b?-1:1);break;case 270:d+=6*(b?-1:1);}return d+=7<d?-8:0,d+=0>d?8:0,c[d]}return"AxMC"},initialize:function(a){var b=this.getUp(flipDir.vert,flipDir.horiz),c={vDir:b.v,hDir:b.h,copy:flipCopy};c[this.getAxDir(flipAxis,!1)]=!0,a.load(c)},commit:function(a){var b=a.store(),c=this.getUp(b.vDir,b.hDir);flipDir.vert=c.v,flipDir.horiz=c.h;var d=["AxTL","AxTC","AxTR","AxML","AxMC","AxMR","AxBL","AxBC","AxBR"];for(let c in d)b[d[c]]&&(flipAxis=this.getAxDir(d[c],!0));flipCopy=b.copy},description:{name:"Mirror Annotations",align_children:"align_left",width:350,elements:[{type:"cluster",name:"Mirror Direction",align_children:"align_left",elements:[{type:"check_box",name:"Mirror Horizontally",item_id:"hDir"},{type:"check_box",name:"Mirror Vertically",item_id:"vDir"}]},{type:"cluster",name:"Mirror Location",align_children:"align_left",elements:[{type:"view",align_children:"align_row",elements:[{type:"radio",groupid:"Axes",item_id:"AxTL"},{type:"radio",groupid:"Axes",item_id:"AxTC"},{type:"radio",groupid:"Axes",item_id:"AxTR"}]},{type:"view",align_children:"align_row",elements:[{type:"radio",groupid:"Axes",item_id:"AxML"},{type:"radio",groupid:"Axes",item_id:"AxMC"},{type:"radio",groupid:"Axes",item_id:"AxMR"}]},{type:"view",align_children:"align_row",elements:[{type:"radio",groupid:"Axes",item_id:"AxBL"},{type:"radio",groupid:"Axes",item_id:"AxBC"},{type:"radio",groupid:"Axes",item_id:"AxBR"}]}]},{type:"check_box",name:"Copy and Mirror Selection",item_id:"copy"},{alignment:"align_right",type:"ok_cancel",ok_name:"Ok",cancel_name:"Cancel"}]}}},c=b.initialize(a.selectedAnnots);return"ok"==c&&b.doFlip(),c})(this);',
iconStream:function(val){var data=this[val];
return {count:0, width:20, height:20, read:function(nBytes){return data.slice(this.count,this.count+=2*nBytes)}}}
};
// This adds a button to the Add-on Tools toolbar
app.addToolButton( {
cName: "mirrorAnnotationsTool",
cLabel: "Mirror",
oIcon: iconSet_mirrorTool.iconStream("mirror"),
cTooltext: "Flip/Mirror Comments…",
cEnable: "event.rc = (this.selectedAnnots && this.selectedAnnots.length)",
cExec: iconSet_mirrorTool.script }
);
// This adds a menu item to the edit menu
app.addMenuItem( {
cName: "mirrorAnnotations",
cUser: "Flip/Mirror Comments…",
oIcon: iconSet_mirrorTool.iconStream("mirror"),
cParent: "Edit",
nPos: 13,
cEnable: "event.rc = (this.selectedAnnots && this.selectedAnnots.length)",
cExec: iconSet_mirrorTool.script }
);