如何使用iText将图形绘制为PDF?

时间:2023-02-09 16:19:01

I am trying to complete an example that draws graphics and writes them to PDF, but I keep getting errors that the PDF has no pages. if I add something simple with document.add() after opening it works fine, I just never see the graphics. Here is my code:

我正在尝试完成一个绘制图形并将其写入PDF的示例,但我不断收到PDF没有页面的错误。如果我在打开后用document.add()添加一些简单的东西就可以正常工作,我只是看不到图形。这是我的代码:

Document document = new Document();
PdfWriter writer = new PdfWriter();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition",
    " attachment; filename=\"Design.pdf\"");

writer = PdfWriter.getInstance(document, response.getOutputStream());

document.open();    
PdfContentByte cb = writer.getDirectContent();
Graphics2D graphics2D = cb.createGraphics(36, 54);
graphics2D.drawString("Hello World", 36, 54);
graphics2D.dispose();   
document.close();

Do I have to do something else to add the graphic to the document or is my syntax incorrect?

我是否必须执行其他操作才能将图形添加到文档中,或者我的语法不正确?

6 个解决方案

#1


4  

Does Document doc = new Document(PageSize.A4); make any difference?

Document doc = new Document(PageSize.A4);有什么区别?

I don't know if you need to add a Paragraph like this:

我不知道你是否需要添加这样的Paragraph:

doc.add(new Paragraph(...));

Also we use doc.add(ImgRaw); to add images.

我们也使用doc.add(ImgRaw);添加图像。

#2


6  

I am not an expert in IText, but last week I tryed to draw some circles with it. So this is what I have noticed during my tests:

我不是IText的专家,但上周我试着用它画一些圈子。所以这是我在测试中注意到的:

If you draw graphics, you must (or lets say I must when I tryed it) "wrap" the graphics commands in a section starting with saveState() and ending with restoreState(), es well as I needed to invoke fillStroke() -- if I do not invoke fillStroke() then nothing was drawn.

如果你绘制图形,你必须(或者说我必须在尝试它时)将图形命令“包装”在以saveState()开头并以restoreState()结尾的部分中,以及我需要调用fillStroke() - - 如果我不调用fillStroke()那么什么都没画出来。

Example

private void circle(float x, float y, PdfWriter writer) {
    PdfContentByte canvas = writer.getDirectContent();

    canvas.saveState();
    canvas.setColorStroke(GrayColor.BLACK);
    canvas.setColorFill(GrayColor.BLACK);
    canvas.circle(x, y, 2);
    canvas.fillStroke();

    canvas.restoreState();
}

@Test
public void testPossition() throws DocumentException, IOException {
    OutputStream outputStream = FileUtil.openOutputStream("testPosition.pdf");
    //this is my personal file util, but it does not anything more
    //then creating a file and opening the file stream.

    Document document = new Document(PageSize.A4, 50, 50, 50, 50);
    PdfWriter writer = PdfWriter.getInstance(document, outputStream);
    document.open();

    markPosition(100, 100, writer);
    document.add(new Paragraph("Total: 595 x 842 -- 72pt (1 inch)"));

    document.close();
    outputStream.flush();
    outputStream.close();
}

private void markPosition(float x, float y, PdfWriter writer)
        throws DocumentException, IOException {
    placeChunck("x: " + x + " y: " + y, x, y, writer);
    circle(x, y, writer);
}

 private void placeChunck(String text, float x, float y, PdfWriter writer)
       throws DocumentException, IOException {
    PdfContentByte canvas = writer.getDirectContent();
    BaseFont font = BaseFont.createFont(BaseFont.HELVETICA,
                  BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
    canvas.saveState();
    canvas.beginText();
    canvas.moveText(x, y);
    canvas.setFontAndSize(font, 9);
    canvas.showText(text);
    canvas.endText();
    canvas.restoreState();
}

But PdfContentByte (canvas) has much more functions, for example rectangle.

但是PdfContentByte(canvas)有更多的功能,例如矩形。

#3


3  

Without going too far into it, I think your general approach is fine. I think what might be happening here is that the Graphics2D origin is different from the PDF origin, so maybe you need to change the call to drawString() so it uses 0,0 as the location??

不要太过分,我认为你的一般方法很好。我认为这里可能发生的是Graphics2D原点不同于PDF原点,所以你可能需要更改对drawString()的调用,所以它使用0,0作为位置?

#4


3  

I think the problem is that directcontent writes directly to the page object. This way you can add backgrounds or backdrop images. Try adding a new page (doc.newPage()) before writing to the directcontent.

我认为问题是directcontent直接写入页面对象。这样您就可以添加背景或背景图像。在写入directcontent之前尝试添加新页面(doc.newPage())。

#5


3  

Have you tried drawing operations on the g2d object that just use shapes instead of text? That would eliminate the possibility of something odd going on with font selection or something like that.

您是否尝试过仅使用形状而不是文本的g2d对象进行绘图操作?这将消除字体选择或其他类似事情发生奇怪的可能性。

iText In Action Chapter 12 has exactly what you are looking for - it really is worth picking up. Preview of Chapter 12

iText In Action第12章正是您所寻找的 - 它确实值得一试。第12章的预览

#6


1  

I just put together the following unit test against the latest HEAD of iText:

我只是针对最新的iText HEAD进行了以下单元测试:

    Document document = new Document();
    PdfWriter writer = new PdfWriter();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    writer = PdfWriter.getInstance(document, baos);

    document.open();    
    PdfContentByte cb = writer.getDirectContent();
    Graphics2D graphics2D = cb.createGraphics(36, 54);
    graphics2D.setColor(Color.black);
    graphics2D.drawRect(0, 0, 18, 27);

    Font font = new Font("Serif", Font.PLAIN, 10);
    graphics2D.setFont(font);

    graphics2D.drawString("Yo Adrienne", 0, 54); 


    graphics2D.dispose();   
    document.close();

    TestResourceUtils.openBytesAsPdf(baos.toByteArray());

And it works fine - I get a small black rectangle in the lower left hand corner of the page, plus text. Note that I am specifying X=0 for my drawString method (you were specifying 36 which causes the text to render outside of the image bounds). Note also that I explicitly specified a font - if I leave that out, it still renders, but it's usually a great idea to not trust the defaults for that sort of thing. Finally, I explicitly set the foreground color - again, not truly necessary, but trusting defaults can be scary.

它工作正常 - 我在页面的左下角有一个小的黑色矩形,加上文字。请注意,我为我的drawString方法指定了X = 0(您指定了36,这导致文本在图像边界之外渲染)。还要注意我明确指定了一种字体 - 如果我把它留下来,它仍然会渲染,但通常不相信这种东西的默认值通常是个好主意。最后,我明确地设置了前景色 - 再次,并非真正必要,但信任默认值可能是可怕的。

So I'd have to say that the core issue here was the placement of the text at x=36.

所以我不得不说这里的核心问题是在x = 36处放置文本。

In none of my tests was I able to create an error saying that the PDF has no pages - can you post the stack trace of the exception you are getting?

在我的测试中没有一个我能够创建一个错误,说PDF没有页面 - 你能发布你得到的异常的堆栈跟踪吗?

I can't imagine that adding a paragraph to the document makes any difference to this (that's the sort of bug that would have gotten taken care of long, long ago)

我无法想象在文档中添加一个段落会对此产生任何影响(这就是那种很久以前就会得到解决的bug)

#1


4  

Does Document doc = new Document(PageSize.A4); make any difference?

Document doc = new Document(PageSize.A4);有什么区别?

I don't know if you need to add a Paragraph like this:

我不知道你是否需要添加这样的Paragraph:

doc.add(new Paragraph(...));

Also we use doc.add(ImgRaw); to add images.

我们也使用doc.add(ImgRaw);添加图像。

#2


6  

I am not an expert in IText, but last week I tryed to draw some circles with it. So this is what I have noticed during my tests:

我不是IText的专家,但上周我试着用它画一些圈子。所以这是我在测试中注意到的:

If you draw graphics, you must (or lets say I must when I tryed it) "wrap" the graphics commands in a section starting with saveState() and ending with restoreState(), es well as I needed to invoke fillStroke() -- if I do not invoke fillStroke() then nothing was drawn.

如果你绘制图形,你必须(或者说我必须在尝试它时)将图形命令“包装”在以saveState()开头并以restoreState()结尾的部分中,以及我需要调用fillStroke() - - 如果我不调用fillStroke()那么什么都没画出来。

Example

private void circle(float x, float y, PdfWriter writer) {
    PdfContentByte canvas = writer.getDirectContent();

    canvas.saveState();
    canvas.setColorStroke(GrayColor.BLACK);
    canvas.setColorFill(GrayColor.BLACK);
    canvas.circle(x, y, 2);
    canvas.fillStroke();

    canvas.restoreState();
}

@Test
public void testPossition() throws DocumentException, IOException {
    OutputStream outputStream = FileUtil.openOutputStream("testPosition.pdf");
    //this is my personal file util, but it does not anything more
    //then creating a file and opening the file stream.

    Document document = new Document(PageSize.A4, 50, 50, 50, 50);
    PdfWriter writer = PdfWriter.getInstance(document, outputStream);
    document.open();

    markPosition(100, 100, writer);
    document.add(new Paragraph("Total: 595 x 842 -- 72pt (1 inch)"));

    document.close();
    outputStream.flush();
    outputStream.close();
}

private void markPosition(float x, float y, PdfWriter writer)
        throws DocumentException, IOException {
    placeChunck("x: " + x + " y: " + y, x, y, writer);
    circle(x, y, writer);
}

 private void placeChunck(String text, float x, float y, PdfWriter writer)
       throws DocumentException, IOException {
    PdfContentByte canvas = writer.getDirectContent();
    BaseFont font = BaseFont.createFont(BaseFont.HELVETICA,
                  BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
    canvas.saveState();
    canvas.beginText();
    canvas.moveText(x, y);
    canvas.setFontAndSize(font, 9);
    canvas.showText(text);
    canvas.endText();
    canvas.restoreState();
}

But PdfContentByte (canvas) has much more functions, for example rectangle.

但是PdfContentByte(canvas)有更多的功能,例如矩形。

#3


3  

Without going too far into it, I think your general approach is fine. I think what might be happening here is that the Graphics2D origin is different from the PDF origin, so maybe you need to change the call to drawString() so it uses 0,0 as the location??

不要太过分,我认为你的一般方法很好。我认为这里可能发生的是Graphics2D原点不同于PDF原点,所以你可能需要更改对drawString()的调用,所以它使用0,0作为位置?

#4


3  

I think the problem is that directcontent writes directly to the page object. This way you can add backgrounds or backdrop images. Try adding a new page (doc.newPage()) before writing to the directcontent.

我认为问题是directcontent直接写入页面对象。这样您就可以添加背景或背景图像。在写入directcontent之前尝试添加新页面(doc.newPage())。

#5


3  

Have you tried drawing operations on the g2d object that just use shapes instead of text? That would eliminate the possibility of something odd going on with font selection or something like that.

您是否尝试过仅使用形状而不是文本的g2d对象进行绘图操作?这将消除字体选择或其他类似事情发生奇怪的可能性。

iText In Action Chapter 12 has exactly what you are looking for - it really is worth picking up. Preview of Chapter 12

iText In Action第12章正是您所寻找的 - 它确实值得一试。第12章的预览

#6


1  

I just put together the following unit test against the latest HEAD of iText:

我只是针对最新的iText HEAD进行了以下单元测试:

    Document document = new Document();
    PdfWriter writer = new PdfWriter();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    writer = PdfWriter.getInstance(document, baos);

    document.open();    
    PdfContentByte cb = writer.getDirectContent();
    Graphics2D graphics2D = cb.createGraphics(36, 54);
    graphics2D.setColor(Color.black);
    graphics2D.drawRect(0, 0, 18, 27);

    Font font = new Font("Serif", Font.PLAIN, 10);
    graphics2D.setFont(font);

    graphics2D.drawString("Yo Adrienne", 0, 54); 


    graphics2D.dispose();   
    document.close();

    TestResourceUtils.openBytesAsPdf(baos.toByteArray());

And it works fine - I get a small black rectangle in the lower left hand corner of the page, plus text. Note that I am specifying X=0 for my drawString method (you were specifying 36 which causes the text to render outside of the image bounds). Note also that I explicitly specified a font - if I leave that out, it still renders, but it's usually a great idea to not trust the defaults for that sort of thing. Finally, I explicitly set the foreground color - again, not truly necessary, but trusting defaults can be scary.

它工作正常 - 我在页面的左下角有一个小的黑色矩形,加上文字。请注意,我为我的drawString方法指定了X = 0(您指定了36,这导致文本在图像边界之外渲染)。还要注意我明确指定了一种字体 - 如果我把它留下来,它仍然会渲染,但通常不相信这种东西的默认值通常是个好主意。最后,我明确地设置了前景色 - 再次,并非真正必要,但信任默认值可能是可怕的。

So I'd have to say that the core issue here was the placement of the text at x=36.

所以我不得不说这里的核心问题是在x = 36处放置文本。

In none of my tests was I able to create an error saying that the PDF has no pages - can you post the stack trace of the exception you are getting?

在我的测试中没有一个我能够创建一个错误,说PDF没有页面 - 你能发布你得到的异常的堆栈跟踪吗?

I can't imagine that adding a paragraph to the document makes any difference to this (that's the sort of bug that would have gotten taken care of long, long ago)

我无法想象在文档中添加一个段落会对此产生任何影响(这就是那种很久以前就会得到解决的bug)