【问题标题】:Stamp on certain location of pdf using iText使用 iText 在 pdf 的特定位置上盖章
【发布时间】:2019-01-20 20:31:03
【问题描述】:

我试图使用 javascript 获取位置并传递坐标以在图章上应用图章,但它无法正常工作。 下面是我用来捕捉鼠标指针坐标的函数。

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
}

下面是使用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();
  }
}

这是我要盖章的位置:

输出不是我预期的:

【问题讨论】:

  • 您错误地假设 PDF 中的测量以像素为单位 (px)。请阅读常见问题解答以了解有关 PDF 中测量单位的更多信息:developers.itextpdf.com/content/…
  • 不仅如此,由于忽略了页面旋转或自定义坐标系原点,它看起来也是一个问题。
  • 我需要获取pdf的dpi吗?

标签: javascript java itext itext7 pdfstamper


【解决方案1】:

此代码使用窗口的百分比将其转换为用户单位。

更新:

document.getElementById("data").innerHTML = "mouse_top:" + mouse_top
+ "<br>mouse_left:" + mouse_left

document.getElementById("data").innerHTML = "mouse_top:" +
(mouse_top\window.innerHeight) + "<br>mouse_left:" + (mouse_left\window.innerWidth)

在后端:

Rectange size = doc.getPage(1).getPageSize();
Rectangle rect = new Rectangle(mouseX*size.getHeight(),mouseY*size.getWidth(),w,h);

【讨论】:

  • 我刚刚更新了img。实际上pdf显示在浏览器上,不幸的是它在实现window.innerHeightwindow.innerWidth后仍然不起作用
  • 您可以将innerWidth 更新为显示内容的宽度(以像素为单位)。目标是获得一个百分比,然后您可以使用它来动态放置它
  • @rossfrank 你什么意思?
  • @CookieMonster 这个想法是将点作为区域的百分比,以便可以轻松地将其转换为不同大小的区域并保留相同的点。例如,如果您有一个 2 x 2 的正方形,并且您得到中间的点 (1, 1)。百分比将是 50%。如果然后将其转换为 8 x 8 的区域,则将其相乘后会得到 (4, 4),它仍然是较大区域的中心。
  • @rossfrank 我明白了。那么在这种情况下,你上面的答案就行不通了?
【解决方案2】:

问题的关键在于能够确定要包含在 PDF 中的图章相对于 PDF 页面的位置和大小,以百分比表示。这正是@rossfrank 在他的回答和 cmets 中试图解释的内容。

如果您可以控制用于计算印章放置位置的 PDF 预览的位置,这将非常容易,例如,只需考虑某个框架甚至 div 的宽度和高度,如果您正在使用某种自定义元素来预览 pdf 的不同页面,或者非常复杂,如果它取决于实际浏览器大小、应用的缩放级别等。最好的建议是尝试控制预览 PDF 的位置。

您可能还需要将此参考宽度和高度传递给您的 servlet,因为您似乎只知道后端图像的尺寸。如果有必要防止溢出等。

一旦获得这些值,代码应该很简单:

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);
//...

这个相关的SO answer 提供了对该问题的进一步见解。

【讨论】:

  • @jcccapanero 你好,提出这个问题,因为我有同样的问题我不知道你是否能看到我的问题stackoverflow.com/questions/68581702/…
  • 嗨@SebastianRuiz。当然。我在您自己的问题中包含了一个新的相关答案。我希望它有所帮助。
  • 您好@jccampanero,如果它对 x 的位置有所帮助,但它们仍然不正确,我已经用我提到的代码更新了问题
  • 嗨@SebastianRuiz。非常感谢您的反馈。我在你自己的答案中回复了你。我希望它有所帮助。
  • 嗨@jccampanero 我已经更新了问题以显示我得到了什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多