使用itext java在pdf上叠加图像

时间:2017-07-18 16:49:31

标签: java pdf itext

我正在尝试在PDF页面上叠加图像。当我尝试使用adobe acrobat并选择从顶部和左侧的垂直距离等于0时,然后在所需位置正确覆盖图像。

我正在尝试使用iText API实现相同功能,但似乎无法将图像定位在pdf上的正确位置。

位置的值是跟踪和错误。 pdf的大小是612​​X792,图像的大小是1699.0x817.0,所以我缩放图像以适合pdf大小。

图像的左侧和pdf正确对齐,但顶部有问题。我尝试了所有的值,并以某种方式792/2 + 100匹配,但如果我得到一个不同的PDF或图像再次将改变。

不知何故,adobe reader能够做到这一点。有没有办法在iText或任何其他库中对齐左侧和顶部。

pdf是从其他来源生成的现有pdf。

更新了源代码

public void manipulatePdfNoTransparency(String inputFileName,
        String outputfileName, String overlayFilePath, 
        int altPage) throws IOException, DocumentException {

    System.out.println("outputfileName :"+outputfileName);
    PdfReader reader = new PdfReader(inputFileName);
    int n = reader.getNumberOfPages();
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputfileName));

    stamper.setRotateContents(false);
    // image watermark

    Image img = Image.getInstance(overlayFilePath);

    float yOffset=calculateYOffset(reader.getPageSize(1).getWidth(), reader.getPageSize(1)
            .getHeight(),img.getWidth(),img.getHeight());

    img.scaleToFit(reader.getPageSize(1).getWidth(), reader.getPageSize(1)
            .getHeight());
    Rectangle pagesize;
    float x, y;
    // loop over every page

    //int i=1;

    pagesize = reader.getPageSize(1);
    x = (pagesize.getLeft() + pagesize.getRight()) / 2;
    y = (pagesize.getTop() + pagesize.getBottom()) / 2;
    img.setAbsolutePosition(0,yOffset);

    for (int i = 1; i <= n; i = i + altPage) {
        stamper.getUnderContent(i).addImage(img);
    }
    stamper.close();
    reader.close();
    System.out.println("File created at "+outputfileName);
}

public static float calculateYOffset(float pdfWidth,float pdfHeight, float originalImageWidth,float originalImageHeight) {
    // size of image 1699.0x817.0
    // size of pdf 612X792
    //This means that the scaled image has a height of 817 * (612/1699) = ca. 294.3 PDF coordinate system units.
    System.out.println("pdfWidth : "+pdfWidth+ " pdfHeight : "+pdfHeight+" originalImageWidth : "+originalImageWidth+" originalImageHeight : "+originalImageHeight);

    float scaledImageHeight = originalImageHeight*pdfWidth / originalImageWidth;
    //The image shall be positioned on the page by putting its top left corner onto the top left corner of the page. 
    //Thus, the x coordinate of its lower left corner is 0, and the y coordinate of its lower left corner is 
    //the y coordinate of the upper left corner of the page minus the height of the scaled image, 
    //i.e. ca. 792 - 294.3 = 497.7.

    float yOffset = pdfHeight-scaledImageHeight;
    System.out.println("yoffset : "+ yOffset);
    return yOffset;

}

2 个答案:

答案 0 :(得分:1)

首先让我们来看看这一行:

img.scaleToFit(
    reader.getPageSize(1).getWidth(),
    reader.getPageSize(1).getHeight());

scaleToFit()方法调整图像的大小,保持宽高比不变。你似乎忽略了这一点,所以让我举一个例子来说明保持宽高比的完整性。

假设您有一个用于测量400 x 600个用户单位的图像img400x600,并且您将该图像缩放为适合200 x 10,000个用户单位的矩形:

 img400x600.scaleToFit(200, 10000);

image400x600的大小是多少?您似乎认为大小将是200 x 10,000,但这种假设是不正确的。图像的新大小为200 x 300,因为宽高比为width = 0.66666 * height

您抱怨使用scaleToFit()时图像的大小不等于页面的大小,但如果图像的宽高比不同于图像的宽高比,则这是正常的。页。

如果您确实希望图片具有相同的页面大小,则需要使用scaleAbsolute()方法:

img.scaleAbsolute(
    reader.getPageSize(1).getWidth(),
    reader.getPageSize(1).getHeight());

然而,这可能会导致图像失真,因为scaleAbsolute()并不尊重宽高比。例如:我见过开发人员在人物肖像上使用scaleAbsolute(),结果是这些人的照片变得丑陋;他们的头部变得非常肥胖,或者根据长宽比的不同而变得非常薄。

现在让我们来看看这一行:

img.setAbsolutePosition(0,y+100);

这是一条非常奇怪的路线。您假设左下角的x坐标为0;我了解y + 100是通过反复试验获得的。

让我们看看官方文档中有关定义添加到现有PDF文档的对象的偏移量的内容。有关此主题的几个常见问题项目:

您目前只查看/MediaBox的值(使用getPageSize()方法获取此值),并忽略/CropBox(如果它存在)。< / p>

如果我是你,我会这样做:

Rectangle pageSize = reader.getCropBox(pageNumber);
if (pageSize == null)
    pageSize = reader.getPageSize(pageNumber);

获得pageSize后,您需要在添加内容时添加考虑偏移量。原点可能与(0, 0)坐标不一致:

img.setAbsolutePosition(pageSize.getLeft(), pageSize.getBottom());

正如您所看到的:不需要反复试验。您可以计算所需的所有值。

<强>更新

在评论中,@ mkl澄清@Gagan希望图像完全符合高度。这很容易实现。

如果需要保留纵横比,那么足以按比例缩放高度:

img.scaleToFit(100000f, pageSize.getHeight());

在这种情况下,图像不会变形,但部分图像将不可见。

如果不需要保留纵横比,可以像这样缩放图像:

img.scaleAbsolute(pageSize.getWidth(), pageSize.getHeight());

如果这个仍然没有回答这个问题,我建议OP澄清一下不清楚数学的含义。

答案 1 :(得分:0)

在对我提到的问题的评论中

  

以某种方式792/2 + 100匹配此 - 实际上是大约1.7。你只需要非常简单的数学来计算它。

并且OP回复了

  

当你说它被1.7关闭时,需要简单的数学来计算它。你能不能让我知道数学以及你是如何到达1.7的。

这个答案解释了数学。

假设要求

从OP的问题和后来的评论我推断出这些要求:

  • 图像应覆盖在PDF页面上。
  • 此图像应按比例缩放,保持其纵横比。缩放后,它应完全适合页面,并且至少一个维度应等于相应的页面尺寸。
  • 它的左上角应放在页面的左上角,不应该旋转。
  • PDF页面的裁剪框与媒体框重合。

手头的计算

在目前的情况下, pdf的大小为612X792,图像的大小为1699.0x817.0 。此外,OP的评论意味着页面的左下角实际上是坐标系的原点。

要缩放图像的水平范围以精确适合页面,必须按比例缩放612/1699。要缩放垂直范围以精确适合页面,必须按比例缩放792/817。为了使整个图像适合保持纵横比的页面,必须使用较小的比例因子612/1699。 OP就是这个

img.scaleToFit(reader.getPageSize(1).getWidth(),reader.getPageSize(1).getHeight());

,假设裁剪框与媒体框重合。

这意味着缩放图像的高度为817 *(612/1699)= ca. 294.3 PDF坐标系单位。

在PDF页面上定位图像时,通常会给出图像左下角的坐标。

图像应位于页面上,方法是将其左上角放在页面的左上角。因此,其左下角的 x 坐标为0,其左下角的 y 坐标为上部的 y 坐标页面左下角减去缩放图像的高度,即大约792 - 294.3 = 497.7。

因此,缩放后的图像应位于(0, 497.7)

通过试验和错误找到的数字对于 x 为0,中间高度对于 y 为100。中间高度是(792 + 0)/ 2 = 396.因此,他使用坐标(0, 496),其中(见上文)垂直偏离大约。 1.7。