I was trying to get the location using javascript and passed the coordinates to apply stamp on the stamp but it does not work properly. Below is the function I used to capture the coordinates of the mouse pointer.
function divMove(e){
var div = document.getElementById('stamp');
div.style.position = 'absolute';
//div.style.top = e.clientY + 'px';
//div.style.left = e.clientX + 'px';
var box = div.getBoundingClientRect();
mouse_top = e.clientY;
mouse_left = e.clientX;
var diff_x = mouse_left - box.left;
var diff_y = mouse_top - box.top;
div.style.top = ((Number(div.style.top.replace("px", "")) - 1) + diff_y) +"px";
div.style.left = ((Number(div.style.left.replace("px", "")) - 1) + diff_x) +"px";
document.getElementById("data").innerHTML =
"mouse_top:" + mouse_top + "<br>mouse_left:" + mouse_left
}
Below is the back-end code to handle the stamping part using iText:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Properties p = new Properties();
p.load(new FileInputStream("config.properties"));
String src = p.getProperty("src");
String dest = p.getProperty("dest");
String imgSrc = p.getProperty("stamp");
PdfDocument doc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
ImageData image = ImageDataFactory.create(imgSrc);
float w = image.getWidth();
float h = image.getHeight();
System.out.println("w: " + w + ", h: " + h);
float mouseX = Float.valueOf(request.getParameter("mouseTop"));
float mouseY = Float.valueOf(request.getParameter("mouseLeft"));
System.out.println("top: " + mouseX + ", left: " + mouseY);
//Rectangle rect = new Rectangle(Math.abs(mouseX-600)+w,Math.abs(mouseY-300)+h,w,h);
Rectangle rect = new Rectangle(mouseX,mouseY,w,h);
PdfStampAnnotation stamp = new PdfStampAnnotation(rect).setStampName(new PdfName("Approved"));
PdfFormXObject xObj = new PdfFormXObject(new Rectangle(w,h));
PdfCanvas canvas = new PdfCanvas(xObj,doc);
canvas.addImage(image,0,0,false);
//canvas.getGraphicsState();
stamp.setNormalAppearance(xObj.getPdfObject());
stamp.setFlags(PdfAnnotation.PRINT);
stamp.setFlags(PdfAnnotation.LOCKED);
for(int i=1;i<=doc.getNumberOfPages();i++) {
doc.getPage(i).addAnnotation(stamp);
}
//doc.getFirstPage().addAnnotation(stamp);
FileOutputStream out = new FileOutputStream("config.properties");
p.setProperty("src", dest);
p.setProperty("dest", src);
p.store(out, null);
out.close();
doc.close();
//first read the file to byte array
try {
File file = new File(dest);
if(file.canRead()) {
String base64File;
//define the byte array to store the file
byte[] byteFile = new byte[(int)file.length()];
//define the stream to read the pdf
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(file);
//convert the read file's stream byte to base64
//important for streaming the pdf bytes back to the front
Base64OutputStream baos = new Base64OutputStream(bytes);
int len;
//read the byte from file then write it through stream to byteFile variable
//read is reading one by one
while((len = fis.read(byteFile)) > 0){
baos.write(byteFile,0,len);
}
baos.flush();
// turn the read byte into string
base64File = bytes.toString("UTF-8");
bytes.close();
baos.close();
fis.close();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition","inline");
response.setCharacterEncoding("UTF-8");
response.setContentLength(base64File.length());
//write the base64 string to the response message body
response.getWriter().write(base64File,0,base64File.length());
//response.getOutputStream().write(base64File,0,base64File.length());
} else {
response.setCharacterEncoding("UTF-8");
response.getWriter().write("File is unreadable!");
}
} catch(FileNotFoundException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
This is the position I am going to stamp:
The output is not what I expected:
PdfStamper(PdfReader reader, OutputStream os, char pdfVersion) Starts the process of adding extra content to an existing PDF document. PdfStamper(PdfReader reader, OutputStream os, char pdfVersion, boolean append) Starts the process of adding extra content to an existing PDF document, possibly as a new revision.
iText 7 Community is a PDF library where free/open source software (F/OSS) allows you to read through the full-code API.
iText is a library for creating and manipulating PDF files in Java and.NET. iText was written by Bruno Lowagie. The source code was initially distributed as open source under the Mozilla Public License or the GNU Library General Public License open source licenses. However, as of version 5.0.
The whole point of the problem is to be able to determine the position and size of the stamp you want to include in the PDF relative to the PDF page, in percentages. This is exactly what @rossfrank tries to explain in his answer and comments.
If you have control above where the PDF preview you are using to compute where the stamp should be placed this can be very easy, for instance, just take into account the width and height of a certain frame or even a div if you are using some kind of custom element to preview the different pages of your pdf, or very complex, if it depends on the actual browser size, the level of zoom applied, etcetera. The best advice is try controlling the place in which you are previewing your PDF.
Probably you will need to pass this reference width and height to your servlet as well because it seems you only know the dimensions of your image in the backend. If should be necessary to prevent overflows, etcetera.
Once obtained these values, the code should be straightforward:
Properties p = new Properties();
p.load(new FileInputStream("config.properties"));
String src = p.getProperty("src");
String dest = p.getProperty("dest");
String imgSrc = p.getProperty("stamp");
PdfReader reader = new PdfReader(src);
PdfWriter writer = new PdfWriter(dest);
PdfDocument doc = new PdfDocument(reader, writer);
ImageData image = ImageDataFactory.create(imgSrc);
float w = image.getWidth();
float h = image.getHeight();
System.out.println("w: " + w + ", h: " + h);
float mouseX = Float.valueOf(request.getParameter("mouseTop"));
float mouseY = Float.valueOf(request.getParameter("mouseLeft"));
// As explained, get reference width and height values
// They can be a frame dimension, a div width and height, etcetera
float referenceWidth = Float.valueOf(request.getParameter("referenceWidth"));
float referenceHeight = Float.valueOf(request.getParameter("referenceHeight"));
// Normalize values: it can be done in the client side as well
float top = mouseY / referenceHeight;
float left = mouseX / referenceWidth;
float width = w / referenceWidth;
float height = h / referenceHeight;
// Just in case, take into account page rotation
Rectangle pdfRectangle = reader.getPageSizeWithRotation(1);
float pdfWidth = pdfRectangle.getWidth();
float pdfHeight = pdfRectangle.getHeight();
// Please, pay attention to this code, it seems that changed in itext7
// Any way, any change should be easy
float llx = pdfWidth * left;
float lly = pdfHeight * (1 - top - height);
float urx = llx + (pdfWidth * width);
float ury = lly + (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);
//...
This related SO answer provides further insights into the problem.
This code uses the percentage of the window to translate it into user units.
Update:
document.getElementById("data").innerHTML = "mouse_top:" + mouse_top
+ "<br>mouse_left:" + mouse_left
to
document.getElementById("data").innerHTML = "mouse_top:" +
(mouse_top\window.innerHeight) + "<br>mouse_left:" + (mouse_left\window.innerWidth)
On the backend:
Rectange size = doc.getPage(1).getPageSize();
Rectangle rect = new Rectangle(mouseX*size.getHeight(),mouseY*size.getWidth(),w,h);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With