sexta-feira, 4 de março de 2011

Convertendo arquivos do microsoft office para PDF em Java

PROBLEMA:
Como converter um arquivo do MS-Office para o formato Adobe PDF de dentro de uma aplicação Java?

Depois de procurar um pouco e ler sobre bibliotecas como iText e POI, vou resumir aqui o que pude aprender.

A maioria das "soluções" que encontrei na web ou são propagandas de produtos comerciais ou são simples demais (por não converterem corretamente coisas básicas, como imagens e/ou tabelas). Um problema recorrente em muitos fóruns é a desinformação. Muitas postagens indicam bibliotecas como iText e o POI para resolver o problema.

O iText é uma biblioteca livre usada para criar e/ou alterar arquivos PDF's existentes. É o caminho quando se trata de juntar arquivos PDF em um único documento, por exemplo.

O POI é um projeto da Apache Software Foundation e também tem por objetivo criar e/ou editar documentos do MS Office.

Ou seja, se alguém soubesse como mapear arquivos do Office para PDF, provavelmente usaria essas duas bibliotecas para implementar o algoritmo de conversão. Falando de forma mais enfática:

"iText ou POI não convertem diretamente um arquivo do ms office para PDF."


JODConverter

Um projeto livre que trata o problema e que se mostrou o mais confiável(pelo menos em termos de suporte à conversão) é o JODConverter . Este projeto fornece uma biblioteca java que delega para o OpenOffice a tarefa de converter o arquivo.

Bom, quem já usou o OpenOffice para abrir documentos do Word ou Excel sabe que nem sempre a conversão é perfeita, principalmente em relação a versões mais recentes do MS-Office. Entretanto, a conversão feita pelo OpenOffice é talvez a melhor que existe no mercado (livre e pago).

Para fazer um teste rápido, siga os passos:

1) Fazer download do JODConverter e adicionar ao classpath da sua aplicação.
Pra quem usa Maven:

<dependency>
<groupid>com.artofsolving</groupid>
<artifactid>jodconverter</artifactid>
<version>2.2.1</version>
</dependency>


2) Iniciar OpenOffice em uma porta da máquina.
No Linux, abrir um terminal e executar o comando:

/usr/bin/soffice "-accept=socket,host=localhost,port=8100;urp;StarOffice.ServiceManager" -nologo -headless -nofirststartwizard &

* Repare que a porta usada é a 8100.
** Se o executável do OpenOffice (soffice) na sua instalação estiver em outra pasta, modifique o comando.

3) Rodar o programa de teste.
Convertendo um arquivo .doc para .pdf.

public class TestJODConverter {
public static void main(String[] args) throws ConnectException {
final File inputFile = new File("/home/meu_user/meu_documento.doc");
final File outputFile = new File("/home/meu_user/meu_novo_documento.pdf");

// connect to an OpenOffice.org instance running on port 8100
final OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
connection.connect();

// convert
final DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
converter.convert(inputFile, outputFile);

// close the connection
connection.disconnect();

}
}

Se ao invés de trabalhar com "arquivos", você precise converter para bytes use o exemplo do código abaixo:

public class TestJODConverterByteArray {
public static void main(String[] args) throws ConnectException {
final File inputFile = new File("/home/meu_user/meu_documento.doc");
final InputStream inputStream = new FileInputStream(inputFile);

final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

final OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
connection.connect();

// convert
final DocumentConverter converter =
new StreamOpenOfficeDocumentConverter(connection);
final DocumentFormat inputFormat =
new DocumentFormat("Microsoft Word", DocumentFamily.TEXT,
"application/msword", "doc");
final DocumentFormat outputFormat =
new DocumentFormat("Portable Document Format", "application/pdf", "pdf");
converter.convert(inputStream, inputFormat, byteArrayOutputStream, outputFormat);

// close the connection
connection.disconnect();
//
inputStream.close();
//
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
// faz algo com os bytes - como enviar para um cliente
System.out.println(byteArrayOutputStream.toByteArray());

}
}

Concluindo

No momento, minha pesquisa terminou por aqui.
Não sabemos se vamos adotar o JODConverter. Na verdade, estamos tentando matar esse problema na raiz: os requisitos :D

Se não conseguirmos, posto aqui que solução adotamos.



Um comentário:

  1. Massa, a melhor resposta para esse problema até agora. Me responde só uma coisa serve para todos os documentos? Tipo Visio, Excel, PowerPoint...?

    Grato.

    ResponderExcluir