Criando arquivos PDF em Java

Criando arquivos PDF em Java

1. Introdução

Neste artigo rápido, vamos nos concentrar na criação de documentos PDF do zero com base na popular biblioteca iText e PdfBox.

2. Dependências do Maven

Vamos dar uma olhada nas dependências do Maven, que precisam ser incluídas em nosso projeto:


    com.itextpdf
    itextpdf
    5.5.10


    org.apache.pdfbox
    pdfbox
    2.0.4

A última versão das bibliotecas pode ser encontrada aqui:iTextePdfBox.

É necessário adicionar uma dependência extra, caso nosso arquivo precise ser criptografado. O pacote Bounty Castle Provider contém implementações de algoritmos criptográficos e é exigido pelas duas bibliotecas:


    org.bouncycastle
    bcprov-jdk15on
    1.56

A versão mais recente da biblioteca pode ser encontrada aqui:The Bounty Castle Provider.

3. Visão geral

Tanto o iText quanto o PdfBox são bibliotecas java usadas para criação / manipulação de arquivos pdf. Embora a saída final das bibliotecas seja a mesma, elas operam de maneira um pouco diferente. Vamos dar uma olhada neles.

4. Criar Pdf em IText

4.1. Inserir Texto em Pdf

Vejamos como um novo arquivo com o texto “Hello World” é inserido no arquivo pdf

Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextHelloWorld.pdf"));

document.open();
Font font = FontFactory.getFont(FontFactory.COURIER, 16, BaseColor.BLACK);
Chunk chunk = new Chunk("Hello World", font);

document.add(chunk);
document.close();

A criação de um pdf com o uso da biblioteca iText é baseada na manipulação de objetos que implementam a interfaceElements emDocument (na versão 5.5.10 existem 45 dessas implementações).

O menor elemento que pode ser adicionado ao documento e usado é chamadoChunk, que é basicamente uma string com a fonte aplicada.

Além disso,Chunk's podem ser combinados com outros elementos comoParagraphs,Section etc. resultando em documentos com boa aparência.

4.2. Inserindo Imagem

A biblioteca iText fornece uma maneira fácil de adicionar uma imagem ao documento. Simplesmente precisamos criar uma instânciaImage e adicioná-la aDocument.

Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());

Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextImageExample.pdf"));
document.open();
Image img = Image.getInstance(path.toAbsolutePath().toString());
document.add(img);

document.close();

4.3. Inserindo Tabela

Podemos enfrentar um problema quando gostaríamos de adicionar uma tabela ao nosso pdf. Felizmente, o iText fornece essa funcionalidade pronta para uso.

Primeiro, o que precisamos fazer é criar um objetoPdfTable e, no construtor, fornecer várias colunas para nossa tabela. Agora podemos simplesmente adicionar uma nova célula chamando

Agora podemos simplesmente adicionar uma nova célula chamando o métodoaddCell no objeto de tabela recém-criado. O iText criará linhas da tabela desde que todas as células necessárias sejam definidas, o que significa que, depois de criar uma tabela com 3 colunas e adicionar 8 células, apenas 2 linhas com 3 células serão exibidas.

Vejamos o exemplo:

Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextTable.pdf"));

document.open();

PdfPTable table = new PdfPTable(3);
addTableHeader(table);
addRows(table);
addCustomRows(table);

document.add(table);
document.close();

Criamos uma nova tabela com 3 colunas e 3 linhas. A primeira linha será tratada como um cabeçalho da tabela com uma cor de fundo e largura de borda alteradas:

private void addTableHeader(PdfPTable table) {
    Stream.of("column header 1", "column header 2", "column header 3")
      .forEach(columnTitle -> {
        PdfPCell header = new PdfPCell();
        header.setBackgroundColor(BaseColor.LIGHT_GRAY);
        header.setBorderWidth(2);
        header.setPhrase(new Phrase(columnTitle));
        table.addCell(header);
    });
}

A segunda linha será composta de três células apenas com texto, sem formatação extra.

private void addRows(PdfPTable table) {
    table.addCell("row 1, col 1");
    table.addCell("row 1, col 2");
    table.addCell("row 1, col 3");
}

Podemos incluir não apenas texto nas células, mas também imagens. Além disso, cada célula pode ser formatada individualmente, no exemplo apresentado abaixo, aplicamos ajustes de alinhamento horizontal e vertical:

private void addCustomRows(PdfPTable table)
  throws URISyntaxException, BadElementException, IOException {
    Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());
    Image img = Image.getInstance(path.toAbsolutePath().toString());
    img.scalePercent(10);

    PdfPCell imageCell = new PdfPCell(img);
    table.addCell(imageCell);

    PdfPCell horizontalAlignCell = new PdfPCell(new Phrase("row 2, col 2"));
    horizontalAlignCell.setHorizontalAlignment(Element.ALIGN_CENTER);
    table.addCell(horizontalAlignCell);

    PdfPCell verticalAlignCell = new PdfPCell(new Phrase("row 2, col 3"));
    verticalAlignCell.setVerticalAlignment(Element.ALIGN_BOTTOM);
    table.addCell(verticalAlignCell);
}

4.4. Criptografia de arquivo

Para aplicar a permissão usando a biblioteca iText, precisamos ter já criado um documento em pdf. Em nosso exemplo, usaremos nosso arquivoiTextHelloWorld.pdf gerado anteriormente.

Depois de carregar o arquivo usandoPdfReader, precisamos criar umPdfStamper que é usado para aplicar conteúdo adicional ao arquivo, como metadados, criptografia, etc:

PdfReader pdfReader = new PdfReader("HelloWorld.pdf");
PdfStamper pdfStamper
  = new PdfStamper(pdfReader, new FileOutputStream("encryptedPdf.pdf"));

pdfStamper.setEncryption(
  "userpass".getBytes(),
  ".getBytes(),
  0,
  PdfWriter.ENCRYPTION_AES_256
);

pdfStamper.close();

Em nosso exemplo, criptografamos o arquivo com duas senhas. A senha do usuário (“userpass”) em que um usuário tem apenas o direito somente leitura, sem possibilidade de imprimi-la, e a senha do proprietário (“ownerpass”) que é usada como chave mestra, permitindo que uma pessoa tenha acesso total ao pdf.

Se quisermos permitir que o usuário imprima pdf, em vez de 0 (terceiro parâmetro desetEncryption) podemos passar:

PdfWriter.ALLOW_PRINTING

Obviamente, podemos misturar permissões diferentes, como:

PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY

Lembre-se de que, ao usar o iText para definir permissões de acesso, também estamos criando um pdf temporário que deve ser excluído e, caso contrário, pode ser totalmente acessível a qualquer pessoa.

5. Crie Pdf em PdfBox

5.1. Inserir Texto em Pdf

Ao contrário deiText, a bibliotecaPdfBox fornece API que é baseada na manipulação de fluxo. Não há classes comoChunk /Paragraph etc. A classePDDocument é uma representação Pdf na memória onde o usuário grava dados manipulando a classePDPageContentStream.

Vamos dar uma olhada no exemplo de código:

PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);

PDPageContentStream contentStream = new PDPageContentStream(document, page);

contentStream.setFont(PDType1Font.COURIER, 12);
contentStream.beginText();
contentStream.showText("Hello World");
contentStream.endText();
contentStream.close();

document.save("pdfBoxHelloWorld.pdf");
document.close();

5.2. Inserindo Imagem

A inserção de imagens é simples.

Primeiro, precisamos carregar um arquivo e criar umPDImageXObject, posteriormente desenhá-lo no documento (é necessário fornecer as coordenadas x, y exatas).

Isso é tudo:

PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);

Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());
PDPageContentStream contentStream = new PDPageContentStream(document, page);
PDImageXObject image
  = PDImageXObject.createFromFile(path.toAbsolutePath().toString(), document);
contentStream.drawImage(image, 0, 0);
contentStream.close();

document.save("pdfBoxImage.pdf");
document.close();

5.3. Inserindo uma Tabela

Infelizmente,PdfBox não fornece nenhum método pronto para uso que permita a criação de tabelas. O que podemos fazer em tal situação é desenhá-lo manualmente - literalmente, desenhe cada linha até que nosso desenho se pareça com a nossa mesa sonhada.

5.4. Criptografia de arquivo

A bibliotecaPdfBox oferece a possibilidade de criptografar e ajustar a permissão de arquivo para o usuário. Comparando comiText, não requer o uso de um arquivo já existente, pois simplesmente usamosPDDocument. As permissões de arquivo PDF são gerenciadas pela classeAccessPermission, onde podemos definir se um usuário será capaz de modificar, extrair conteúdo ou imprimir um arquivo.

Posteriormente, criamos um objetoStandardProtectionPolicy que adiciona proteção baseada em senha ao documento. Podemos especificar dois tipos de senha. A senha do usuário, após a qual a pessoa poderá abrir um arquivo com permissões de acesso aplicadas e senha do proprietário (sem limitações para o arquivo):

PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);

AccessPermission accessPermission = new AccessPermission();
accessPermission.setCanPrint(false);
accessPermission.setCanModify(false);

StandardProtectionPolicy standardProtectionPolicy
  = new StandardProtectionPolicy("ownerpass", "userpass", accessPermission);
document.protect(standardProtectionPolicy);
document.save("pdfBoxEncryption.pdf");
document.close();

Nosso exemplo apresenta uma situação em que, se um usuário fornecer uma senha de usuário, o arquivo não poderá ser modificado e impresso.

6. Conclusões

Neste tutorial, discutimos maneiras de criar um arquivo pdf em duas bibliotecas Java populares.

Exemplos completos podem ser encontrados no projeto baseado em Mavenover on GitHub.