简体   繁体   English

使用itext Java在pdf上叠加图像

[英]Image overlay on pdf using itext java

I am trying to overlay an image on PDF pages. 我正在尝试在PDF页面上覆盖图像。 When I try to do that using adobe acrobat and select vertical distance from top and left equal to 0, then image overlays correctly at the required location. 当我尝试使用Adobe Acrobat做到这一点并选择上下左右的垂直距离等于0时,则图像会正确覆盖在所需位置。

I am trying to achieve the same using iText API but can't seem to position the image at correct location on the pdf. 我正在尝试使用iText API实现相同的功能,但似乎无法将图像定位在pdf上的正确位置。

The values for position are trail and error. 位置的值是跟踪和错误。 The size of the pdf is 612X792 and the size of the image is 1699.0x817.0 so I scaled the image to fit the pdf size. pdf的大小为612X792,图像的大小为1699.0x817.0,因此我按比例缩放图像以适合pdf大小。

The left of the image and pdf align correctly but the tops have issue. 图片和pdf的左侧正确对齐,但顶部出现问题。 I tried with all the values and somehow 792/2+100 matches this but again will change in case I get a different pdf or image. 我尝试了所有值,以某种方式792/2 + 100与此匹配,但是如果我得到不同的pdf或图像,它将再次更改。

Somehow adobe reader is able to do that. Adobe Reader能够以某种方式做到这一点。 Is there a way to align left and top in iText or any other library. 有没有一种方法可以在iText或任何其他库中向左和向左对齐。

The pdf is existing pdf generated from some other source. pdf是从其他来源生成的现有pdf。

Updated source code 更新的源代码

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;

}

First let's take a look at this line: 首先让我们看一下这一行:

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

The scaleToFit() method resizes an images keeping the aspect ratio intact . scaleToFit()方法调整图像的大小, 使长宽比保持不变 You seem to overlook that, so let me give you an example of what it means to keep the aspect ratio intact. 您似乎忽略了这一点,所以让我举一个例子说明保持纵横比完整的含义。

Suppose that you have an image img400x600 that measures 400 x 600 user units, and you scale that image to fit a rectangle of 200 x 10,000 user units: 假设您有一个图像img400x600 ,其尺寸为400 x 600用户单位,并且对该图像进行缩放以适合200 x 10,000用户单位的矩形:

 img400x600.scaleToFit(200, 10000);

What will be the size of image400x600 ? image400x600的大小是image400x600 You seem to think that the size will be 200 x 10,000, but that assumption is incorrect. 您似乎认为大小为200 x 10,000,但是这种假设是不正确的。 The new size of the image will be 200 x 300, because the aspect ratio is width = 0.66666 * height . 图片的新尺寸将为200 x 300,因为宽高比为width = 0.66666 * height

You complain that the size of the image doesn't equal the size of the page when you use scaleToFit() , but that is normal if the aspect ratio of the image is different from the aspect ratio of the page. 您抱怨使用scaleToFit()时图像的大小不等于页面的大小,但是如果图像的纵横比与页面的纵横比不同,这是正常的。

If you really want the image to have the same size of the page, you need to use the scaleAbsolute() method: 如果您确实希望图像具有与页面相同的大小,则需要使用scaleAbsolute()方法:

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

However, this might result in really distorted images, because scaleAbsolute() doesn't respect the aspect ratio. 但是,这可能会导致图像真正失真,因为scaleAbsolute()不遵守纵横比。 For instance: I have seen developers who used scaleAbsolute() on portraits of people, and the result was that the picture of these people became ugly; 例如:我见过一些在人物肖像上使用scaleAbsolute()开发人员,结果是这些人的照片变得丑陋。 either their head became extremely fat, or it became extremely thin depending on the different in aspect ratio. 根据长宽比的不同,他们的头部变得非常胖,或者变得非常瘦。

Now let's take a look at this line: 现在让我们看一下这一行:

img.setAbsolutePosition(0,y+100);

That is a very strange line. 那是一条很奇怪的线。 You are making the assumption that the x coordinate of the lower left corner is 0 ; 您假设左下角的x坐标为0 I understand that y + 100 was obtained through trial and error. 我了解y + 100是通过反复试验得出的。

Let's see what the official documentation has to say about defining the offset of objects added to an existing PDF document. 让我们看看官方文档对定义添加到现有PDF文档中的对象的偏移量有何看法。 There are several FAQ items on this subject: 关于此主题,有几个常见问题解答:

You currently only look at the value of the /MediaBox (you obtain this value using the getPageSize() method), and you ignore the /CropBox (in case it is present). 当前,您仅查看/MediaBox值(使用getPageSize()方法获取此值),而忽略/CropBox (如果存在)。

If I were you, I'd do this: 如果我是你,我会这样做:

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

Once you have the pageSize, you need to add the take into account the offset when adding content. 一旦有了pageSize,就需要添加添加内容时要考虑的偏移量。 The origin might not coincide with the (0, 0) coordinate: 原点可能与(0, 0)坐标不一致:

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

As you can see: there is no need for trial and error. 如您所见:无需反复试验。 All the values that you need can be calculated. 可以计算出您需要的所有值。

Update: 更新:

In the comments, @mkl clarifies that @Gagan wants the image to fit the height exactly. 在评论中,@ mkl阐明了@Gagan希望图像完全适合高度。 That is easy to achieve. 这很容易实现。

If the aspect ratio needs to be preserved, it's sufficient to scaleToFit the height like this: 如果需要保留长宽比,则可以使用scaleToFit这样的高度就足够了:

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

In this case, the image won't be deformed, but part of the image will not be visible. 在这种情况下,图像不会变形,但是部分图像将不可见。

If the aspect ratio doesn't need to be preserved, the image can be scaled like this: 如果不需要保留宽高比,则可以像这样缩放图像:

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

If this still doesn't answer the question, I suggest that the OP clarifies what it is that is unclear about the math. 如果仍然不能解决问题,我建议OP澄清数学上不清楚的内容。

In a comment to the question I mentioned 在我提到的问题的评论中

somehow 792/2+100 matches this - actually that is off by about 1.7. 792/2 + 100以某种方式与之匹配 -实际上相差约1.7。 You only need very simple math to calculate this. 您只需要非常简单的数学就可以计算出来。

and the OP responded 而OP回应

when you say it is off by 1.7 and simple math is required to calculate this. 当您说它偏离1.7时,需要简单的数学计算。 could you please let me know what math and how you arrived at 1.7. 您能否让我知道什么数学以及如何达到1.7。

This answer explains that math. 这个答案解释了那个数学。

Assumed requirements 假设要求

From the question and later comments by the OP I deduced these requirements: 从OP的问题和后来的评论中,我得出了以下要求:

  • An image shall be overlayed over a PDF page. 图像应覆盖在PDF页面上。
  • The image for this shall be scaled, keeping its aspect ratio. 图像应按比例缩放,并保持其长宽比。 After scaling it shall completely fit onto the page and at least one dimension shall equal the corresponding page dimension. 缩放后,它应完全适合页面,并且至少一个尺寸应等于相应的页面尺寸。
  • It shall be positioned on the page by putting its top left corner onto the top left corner of the page, no rotation shall be applied. 应通过将其左上角放在页面的左上角上来将其放置在页面上,不得旋转。
  • The crop box of the PDF page coincides with the media box. PDF页面的裁剪框与媒体框重合。

Calculation at hand 计算在手

In the case at hand, the size of the pdf is 612X792 and the size of the image is 1699.0x817.0 . 在当前情况下, pdf的大小为612X792,图像的大小为1699.0x817.0 Furthermore, the OP's comments imply that the bottom left corner of the page actually is the origin of the coordinate system. 此外,OP的注释暗示页面的左下角实际上是坐标系的原点。

To scale the horizontal extent of the image to exactly fit the page, one has to scale by 612/1699. 要缩放图像的水平范围以使其完全适合页面,必须按612/1699进行缩放。 To scale the vertical extent to exactly fit the page, one has to scale by 792/817. 要缩放垂直范围以完全适合页面,必须按792/817进行缩放。 To make the whole image fit the page with aspect ration kept, one has to use the smaller scaling factor, 612/1699. 为了使整个图像适合页面并保持宽高比,必须使用较小的缩放系数612/1699。 This is what the OP's 这就是OP的

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

does, assuming the crop box coincides with the media box. 假设裁剪框与媒体框重合。

This means that the scaled image has a height of 817 * (612/1699) = ca. 这意味着缩放后的图像的高度为817 *(612/1699)=ca。 294.3 PDF coordinate system units. 294.3 PDF坐标系单位。

When positioning an image on a PDF page, you usually do that by giving the coordinates where the bottom left corner of the image shall go. 将图像放置在PDF页面上时,通常可以通过给出图像左下角的坐标来实现。

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, ie ca. 因此,在x它的左下角的坐标为0,并且在页面的左上角减去经缩放的图像,即约的高度的y坐标的左下角的y坐标 792 - 294.3 = 497.7. 792-294.3 = 497.7。

Thus, the scaled image shall be positioned at (0, 497.7) . 因此,缩放后的图像应位于(0, 497.7)

The numbers the OP found by trial and error are 0 for x and middle height plus 100 for y . 通过反复试验发现的OP的值是x和中间高度分别为0和y为100。 The middle height is (792 + 0)/2 = 396. Thus, he uses the coordinates (0, 496) which (see above) vertically are off by ca. 中间高度为(792 + 0)/ 2 =396。因此,他使用的坐标(0, 496) (垂直)相差约ca。 1.7. 1.7。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM