Os gráficos vetoriais em iText PDF
Pergunta
Nós usamos o iText para gerar PDFs a partir de Java (com base, em parte, em recomendações sobre este site). No entanto, a incorporação de uma cópia do nosso logotipo em um formato de imagem como GIF resultado em que procura um pouco estranho como as pessoas zoom in e out.
Idealmente, gostaríamos de incorporar a imagem em um formato do vetor, como EPS, SVG ou apenas um modelo PDF. As site afirma que o apoio EPS foi derrubado, que a incorporação de um PDF ou PS dentro de um PDF pode resultar em erros, e nem sequer menciona SVG.
O nosso código usa a API Graphics2D em vez de iText diretamente, mas que estaria disposto a romper com o modo AWT e uso iText si mesmo se alcançado o resultado. Como isso pode ser feito?
Solução
De acordo com o href="http://itextdocs.lowagie.com/tutorial/objects/images/index.php" documentação iText suporta os seguintes formatos de imagem: JPEG , GIF, PNG, TIFF, BMP, WMF e EPS. Eu não sei se isso pode ser de alguma ajuda, mas eu tenho usado com sucesso iTextSharp para incorporar vector imagem WMF em um arquivo pdf:
C #:
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
public class Program
{
public static void Main()
{
Document document = new Document();
using (Stream outputPdfStream = new FileStream("output.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
using (Stream imageStream = new FileStream("test.wmf", FileMode.Open, FileAccess.Read, FileShare.Read))
{
PdfWriter.GetInstance(document, outputPdfStream);
Image wmf = Image.GetInstance(imageStream);
document.Open();
document.Add(wmf);
document.Close();
}
}
}
Outras dicas
Isto é o que eu derivado de mensagens que eu encontrei aqui e os exemplos oficiais:
/**
* Reads an SVG Image file into an com.itextpdf.text.Image instance to embed it into a PDF
* @param svgPath SVG filepath
* @param writer PdfWriter instance
* @return Instance of com.itextpdf.text.Image holding the SVG file
* @throws IOException
* @throws BadElementException
*/
private static Image getSVGImage(String svgPath, PdfWriter writer) throws IOException, BadElementException {
SVGDocument svgDoc = new SAXSVGDocumentFactory(null).createSVGDocument(null, new FileReader(svgPath));
// Try to read embedded height and width
float svgWidth = Float.parseFloat(svgDoc.getDocumentElement().getAttribute("width").replaceAll("[^0-9.,]",""));
float svgHeight = Float.parseFloat(svgDoc.getDocumentElement().getAttribute("height").replaceAll("[^0-9.,]",""));
PdfTemplate svgTempl = PdfTemplate.createTemplate(writer, svgWidth, svgHeight);
Graphics2D g2d = new PdfGraphics2D(svgTempl, svgTempl.getWidth(), svgTempl.getHeight());
GraphicsNode chartGfx = (new GVTBuilder()).build(new BridgeContext(new UserAgentAdapter()), svgDoc);
chartGfx.paint(g2d);
g2d.dispose();
return new ImgTemplate(svgTempl);
}
A instância imagem pode o ser adicionados facilmente ao pdf (no meu caso como uma assinatura).
Eu encontrei um par de exemplos pelo autor iText que usam a API Graphics2D ea biblioteca Apache Batik para desenhar o SVG em um PDF.
http://itextpdf.com/examples/iia.php?id=269
http://itextpdf.com/examples/iia.php?id=263
Para os meus propósitos, eu precisava tomar uma série de SVG e desenhar que, em um PDF em um determinado tamanho e localização, mantendo a natureza vector da imagem (sem rasterization).
Eu queria ignorar o arquivo SVG que parece prevalente nas funções SAXSVGDocumentFactory.createSVGDocument (). Achei o útil seguinte pós para usar uma cadeia de texto SVG em vez de um arquivo simples.
http: //batik.2283329.n4. nabble.com/Parse-SVG-from-String-td3539080.html
Você tem que criar um StringReader do seu Cordas e passar isso para o método SAXSVGDocumentFactory # createDocument (String, Reader). O URI que você passa como o primeiro parâmetro como uma String será o documento base URI do documento SVG. Isso só deve ser importante se o seu SVG referencia quaisquer arquivos externos.
Com os melhores cumprimentos,
Daniel
Java Fonte derivada dos exemplos iText:
// SVG as a text string.
String svg = "<svg>...</svg>";
// Create the PDF document.
// rootPath is the present working directory path.
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(new File(rootPath + "svg.pdf")));
document.open();
// Add paragraphs to the document...
document.add(new Paragraph("Paragraph 1"));
document.add(new Paragraph(" "));
// Boilerplate for drawing the SVG to the PDF.
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
PdfContentByte cb = writer.getDirectContent();
// Parse the SVG and draw it to the PDF.
Graphics2D g2d = new PdfGraphics2D(cb, 725, 400);
SVGDocument chart = factory.createSVGDocument(rootPath, new StringReader(svg));
GraphicsNode chartGfx = builder.build(ctx, chart);
chartGfx.paint(g2d);
g2d.dispose();
// Add paragraphs to the document...
document.add(new Paragraph("Paragraph 2"));
document.add(new Paragraph(" "));
document.close();
Note que este irá desenhar uma SVG para o PDF que você está trabalhando. O SVG aparece como uma camada flutuante acima do texto. Eu ainda estou trabalhando em mover / dimensioná-lo e tê-lo descansar em linha com texto, mas espero que esteja fora do alcance imediato da questão.
Espero que isso foi capaz de ajuda.
Felicidades
EDIT: eu era capaz de implementar o meu SVG como um objeto embutido usando o seguinte. As linhas comentadas são para adicionar uma borda rápida de verificar o posicionamento.
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
SVGDocument svgDoc = factory.createSVGDocument(rootPath, new StringReader(svg));
PdfTemplate svgTempl = PdfTemplate.createTemplate(writer, Float.parseFloat(svgDoc.getDocumentElement().getAttribute("width")), Float.parseFloat(svgDoc.getDocumentElement().getAttribute("height")));
Graphics2D g2d = new PdfGraphics2D(svgTempl, svgTempl.getWidth(), svgTempl.getHeight());
GraphicsNode chartGfx = builder.build(ctx, svgDoc);
chartGfx.paint(g2d);
g2d.dispose();
Image svgImg = new ImgTemplate(svgTempl);
svgImg.setAlignment(Image.ALIGN_CENTER);
//svgImg.setBorder(Image.BOX);
//svgImg.setBorderColor(new BaseColor(0xff, 0x00, 0x00));
//svgImg.setBorderWidth(1);
document.add(svgImg);
Eu aprendi recentemente que você pode enviar o seu objeto Graphics2D diretamente para iText, e os arquivos PDF resultantes são tão bons como gráficos vetoriais escaláveis. A partir do seu post, parece que isso pode resolver o seu problema.
Document document = new Document(PageSize.LETTER);
PdfWriter writer = null;
try {
writer = PdfWriter.getInstance(document, new FileOutputStream(your file name));
} catch (Exception e) {
// do something with exception
}
document.open();
PdfContentByte cb = writer.getDirectContent();
PdfTemplate tp = cb.createTemplate(width, height);
Graphics2D g2 = tp.createGraphics(width, height, new DefaultFontMapper());
// Create your graphics here - draw on the g2 Graphics object
g2.dispose();
cb.addTemplate(tp, 0, 100); // 0, 100 = x,y positioning of graphics in PDF page
document.close();
Isso funcionou para mim usando itext 7.1.3 para rendem a imagem SVG por SVGConverter.
PdfWriter writer = new PdfWriter(new FileOutputStream("/home/users/Documents/pdf/new.pdf"));
PdfDocument pdfDoc = new PdfDocument(writer);
Document doc = new Document(pdfDoc);
URL svgUrl = new File(svg).toURI().toURL();
doc.add(new Paragraph("new pikachu"));
Image image = SvgConverter.convertToImage(svgUrl.openStream(), pdfDoc);
doc.add(image);
doc.close();
A nova versão do iText está apoiando arquivos SVG também. Por favor, consulte desta página .