As indicated in this companion question, the goal is to be able to translate the position and dimension of your image relative to the PDF between its representation in the browser and in the actual PDF.
In this specific use case you already have a well defined structure of elements, in which your PDF preview image is displayed in a predictable way.
Following the advice of the aforementioned question, I think you need to take the relevant points of your signature box, say:
var $signatureBox = $('.signer-box');
var sbDataX = parseFloat($signatureBox.attr('data-x'));
var sbDataY = parseFloat($signatureBox.attr('data-y'));
var sbOuterWidth = $signatureBox.outerWidth();
var sbOuterHeight = $signatureBox.outerHeight();
And convert them to percentages relative to the width and height of your PDF image:
var w = $('#pdf-page').width();
var h = $('#pdf-page').height();
var top = sbDataY / h;
var left = sbDataX / w;
var width = sbOuterWidth / w;
var height = sbOuterHeight / h;
I have used values relative to the unit, please, feel free to multiply them by 100
if you prefer to work with percentages. Just take into consideration in the next step.
These relative values top
, left
, width
and height
will be sent to your backend.
This information can be computed in your different listeners. Consider for example the definition of a common function that will be used to defined the right form values when either a drag and drop or a resize event occur:
window.dragMoveListener = dragMoveListener;
interact('.signer-box')
.draggable({
onmove: dragMoveListener,
inertia: true,
autoScroll: true,
restrict: {
elementRect: {top: 0, left: 0, bottom: 1, right: 1}
}
})
.resizable({
onmove: resizeMoveListener,
inertia: true,
edges: {left: true, right: true, bottom: true, top: true}
})
function dragMoveListener(event) {
var target = event.target;
var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
target.style.webkitTransform = target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
computeSignerBoxPosition();
}
function resizeMoveListener(event) {
var target = event.target;
var x = (parseFloat(target.getAttribute('data-x')) || 0);
var y = (parseFloat(target.getAttribute('data-y')) || 0);
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.width = event.rect.width + 'px';
target.style.height = event.rect.height + 'px';
target.style.webkitTransform = target.style.transform = 'translate(' + x + 'px,' + y + 'px)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
computeSignerBoxPosition();
}
function computeSignerBoxPosition() {
var $signatureBox = $('.signer-box');
var sbDataX = parseFloat($signatureBox.attr('data-x'));
var sbDataY = parseFloat($signatureBox.attr('data-y'));
var sbOuterWidth = $signatureBox.outerWidth();
var sbOuterHeight = $signatureBox.outerHeight();
var w = $('#pdf-page').width();
var h = $('#pdf-page').height();
var top = sbDataY / h;
var left = sbDataX / w;
var width = sbOuterWidth / w;
var height = sbOuterHeight / h;
document.getElementById("widthValue").value = width;
document.getElementById("heightValue").value = height;
document.getElementById("coorX").value = left;
document.getElementById("coorY").value = top;
}
As mentioned, the idea is to compute the information that should be send to the backend when both listeners change. As an optimization, instead of computing the necessary information in the listener, please, consider attach to the button or visual element that you are using to submit your form a click listener that invoke the mentioned computeSignerBoxPosition
function prior sending the information to the backend as it is only necessary in that moment.
With that information, as indicated in the original answer, you can obtain the right position like this:
float top = Float.valueOf(request.getParameter("top"));
float left = Float.valueOf(request.getParameter("left"));
float width = Float.valueOf(request.getParameter("width"));
float height = Float.valueOf(request.getParameter("height"));
// Just in case, take into account page rotation
Rectangle pdfRectangle = reader.getPageSizeWithRotation(1);
float pdfWidth = pdfRectangle.getWidth();
float pdfHeight = pdfRectangle.getHeight();
float llx = pdfWidth * left;
float lly = pdfHeight * (1 - top - height);
// Until iText 5 this code should work
float urx = llx + (pdfWidth * width);
float ury = lly + (pdfHeight * height);
// It seems that changed in Itext7 to this (they use just width and height)
// If it is your use case, please, comment the block above
// and uncomment the following lines
// float urx = pdfWidth * width;
// float ury = pdfHeight * height;
Rectangle rect = new Rectangle(llx, lly, urx, ury);
PdfStampAnnotation stamp = new PdfStampAnnotation(rect).setStampName(new PdfName("Approved"));
PdfFormXObject xObj = new PdfFormXObject(new Rectangle(width,height));
PdfCanvas canvas = new PdfCanvas(xObj,doc);
canvas.addImage(image,0,0,false);
The algorithm takes into consideration that in PDF the lower-left corner of the page coincides with the origin of the coordinate system (0, 0)
, where positive x
values are to the right of the origin and positive y
values are above the origin (in contrast with the browser):
The credit for the image is for Bruno Lowagie when he describes how to interpret the coordinates of a rectangle in PDF and where is the origin of a PDF page.
It is important to note as well that the actual dimensions of your image and the PDF page in their representation in the browser and the actual PDF file should be constant, they need to preserve the proper aspect ratio; on the contrary, you need to correct your dimensions by the corresponding factor.