Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
298 views
in Technique[技术] by (71.8m points)

javascript - Java Stamp on certain location of pdf using iText

I am making a web application using Javascript for the front end and this is how it works:

  1. I start the application and it opens a web page via my browser.

  2. It displays a PDF page obtained from my directory.

  3. I have the option to click on a stamp and drag and move around the pdf and place where ever I want.

  4. When I'm done, I could click Save and it automatically saves the pdf file in my directory.

  5. I can open the pdf file in my folder to view the updated PDF along with the stamp added.

The problem is when I open the PDF file to view, the positioning is not identical to the positioning of the stamp in the web browser.

   

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 = sbDataX / w;
    var left = sbDataY / h;
    var width = sbOuterWidth / w;
    var height = sbOuterHeight / h;

    document.getElementById("widthValue").value = width;
    document.getElementById("heightValue").value = height;
    document.getElementById("coorX").value = top;
    document.getElementById("coorY").value = left;
}
@charset "UTF-8";

#content{
    text-align: center;
}

#pdf-container {
    display: inline-block;
    width: 100%;
    user-select: none;
}

#pdf-page {
    width: 100%;
}

.signer-box {
    background: url('../images/pen_icon.png') #29e no-repeat 50% 50%;
    background-size: 50%;
    color: white;
    font-size: 20px;
    font-family: sans-serif;
    border-radius: 8px;
    width: 180px;
    height: 150px;
    position:absolute;
    opacity: .8;
    box-sizing: border-box;
    box-shadow: rgb(0, 0, 0, 0.7) 0.2em 0.2em 0.5em;
    -ms-touch-action: none;
    touch-action: none; 
}
  
#signature-pad {
    position: relative;
    width: 100%;
    height: 160px;
    -moz-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

#signatureImg{
    width: 100%;
}
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
   
        <div id="content">
            <div class="wrap">
                   <hr style="border:15px;"><hr style="border:2px;">
                    
                    <div id="wrapper">
                        <div id="content">
                            <div id="pdf-container" >                   
                                <div id="signers-list">
                                   <div id="signer-1" class="signer-box"></div>
                                </div>                  
                                <img id="pdf-page" src="data:image/png;base64,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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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):

PDF coordinate system

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...