The main problem with this is that those PdfOptions
and PdfConverter
are not part of the apache poi
project. They are developed by opensagres
and first versions were badly named org.apache.poi.xwpf.converter.pdf.PdfOptions
and org.apache.poi.xwpf.converter.pdf.PdfConverter
. Those old classes were not updated since 2014 and needs version 3.9
of apache poi
to be used.
But the same developers provide fr.opensagres.poi.xwpf.converter.pdf, which is much more current and works using the latest stable release apache poi 3.17
. So we should using this.
But since even those newer PdfOptions
and PdfConverter
are not part of the apache poi
project, apache poi
will not testing those with their releases. And so the default *.docx
documents created by apache poi
lacks some content which PdfConverter
needs.
There must be a styles document, even if it is empty.
There must be section properties for the page having at least the page size set.
Tables must have a table grid set.
To fulfilling this we must add some code additionally in our program. Unfortunately this then needs the full jar of all of the schemas ooxml-schemas-1.3.jar
as mentioned in Faq-N10025.
And because we need changing the underlaying low level objects, the document must be written so underlaying objects will be committed. Else the XWPFDocument
which we hand over the PdfConverter
will be incomplete.
Example:
import java.io.*;
import java.math.BigInteger;
//needed jars: fr.opensagres.poi.xwpf.converter.core-2.0.1.jar,
// fr.opensagres.poi.xwpf.converter.pdf-2.0.1.jar,
// fr.opensagres.xdocreport.itext.extension-2.0.1.jar,
// itext-2.1.7.jar
import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions;
import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter;
//needed jars: apache poi and it's dependencies
// and additionally: ooxml-schemas-1.3.jar
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.util.Units;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
public class XWPFToPDFConverterSampleMin {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
// there must be a styles document, even if it is empty
XWPFStyles styles = document.createStyles();
// there must be section properties for the page having at least the page size set
CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
CTPageSz pageSz = sectPr.addNewPgSz();
pageSz.setW(BigInteger.valueOf(12240)); //12240 Twips = 12240/20 = 612 pt = 612/72 = 8.5"
pageSz.setH(BigInteger.valueOf(15840)); //15840 Twips = 15840/20 = 792 pt = 792/72 = 11"
// filling the body
XWPFParagraph paragraph = document.createParagraph();
//create table
XWPFTable table = document.createTable();
//create first row
XWPFTableRow tableRowOne = table.getRow(0);
tableRowOne.getCell(0).setText("col one, row one");
tableRowOne.addNewTableCell().setText("col two, row one");
tableRowOne.addNewTableCell().setText("col three, row one");
//create CTTblGrid for this table with widths of the 3 columns.
//necessary for Libreoffice/Openoffice and PdfConverter to accept the column widths.
//values are in unit twentieths of a point (1/1440 of an inch)
//first column = 2 inches width
table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(2*1440));
//other columns (2 in this case) also each 2 inches width
for (int col = 1 ; col < 3; col++) {
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(2*1440));
}
//create second row
XWPFTableRow tableRowTwo = table.createRow();
tableRowTwo.getCell(0).setText("col one, row two");
tableRowTwo.getCell(1).setText("col two, row two");
tableRowTwo.getCell(2).setText("col three, row two");
//create third row
XWPFTableRow tableRowThree = table.createRow();
tableRowThree.getCell(0).setText("col one, row three");
tableRowThree.getCell(1).setText("col two, row three");
tableRowThree.getCell(2).setText("col three, row three");
paragraph = document.createParagraph();
//trying picture
XWPFRun run = paragraph.createRun();
run.setText("The picture in line: ");
InputStream in = new FileInputStream("samplePict.jpeg");
run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(100), Units.toEMU(30));
in.close();
run.setText(" text after the picture.");
paragraph = document.createParagraph();
//document must be written so underlaaying objects will be committed
ByteArrayOutputStream out = new ByteArrayOutputStream();
document.write(out);
document.close();
document = new XWPFDocument(new ByteArrayInputStream(out.toByteArray()));
PdfOptions options = PdfOptions.create();
PdfConverter converter = (PdfConverter)PdfConverter.getInstance();
converter.convert(document, new FileOutputStream("XWPFToPDFConverterSampleMin.pdf"), options);
document.close();
}
}
Using XDocReport
Another way would be using the newest version of opensagres/xdocreport as described in Converter only with ConverterRegistry:
import java.io.*;
import java.math.BigInteger;
//needed jars: xdocreport-2.0.1.jar,
// odfdom-java-0.8.7.jar,
// itext-2.1.7.jar
import fr.opensagres.xdocreport.converter.Options;
import fr.opensagres.xdocreport.converter.IConverter;
import fr.opensagres.xdocreport.converter.ConverterRegistry;
import fr.opensagres.xdocreport.converter.ConverterTypeTo;
import fr.opensagres.xdocreport.core.document.DocumentKind;
//needed jars: apache poi and it's dependencies
// and additionally: ooxml-schemas-1.3.jar
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.util.Units;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
public class XWPFToPDFXDocReport {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
// there must be a styles document, even if it is empty
XWPFStyles styles = document.createStyles();
// there must be section properties for the page having at least the page size set
CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
CTPageSz pageSz = sectPr.addNewPgSz();
pageSz.setW(BigInteger.valueOf(12240)); //12240 Twips = 12240/20 = 612 pt = 612/72 = 8.5"
pageSz.setH(BigInteger.valueOf(15840)); //15840 Twips = 15840/20 = 792 pt = 792/72 = 11"
// filling the body
XWPFParagraph paragraph = document.createParagraph();
//create table
XWPFTable table = document.createTable();
//create first row
XWPFTableRow tableRowOne = table.getRow(0);
tableRowOne.getCell(0).setText("col one, row one");
tableRowOne.addNewTableCell().setText("col two, row one");
tableRowOne.addNewTableCell().setText("col three, row one");
//create CTTblGrid for this table with widths of the 3 columns.
//necessary for Libreoffice/Openoffice and PdfConverter to accept the column widths.
//values are in unit twentieths of a point (1/1440 of an inch)
//first column = 2 inches width
table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(2*1440));
//other columns (2 in this case) also each 2 inches width
for (int col = 1 ; col < 3; col++) {
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(2*1440));
}
//create second row
XWPFTableRow tableRowTwo = table.createRow();
tableRowTwo.getCell(0).setText("col one, row two");
tableRowTwo.getCell(1).setText("col two, row two");
tableRowTwo.getCell(2).setText("col three, row two");
//create third row
XWPFTableRow tableRowThree = table.createRow();
tableRowThree.getCell(0).setText("col one, row three");
tableRowThree.getCell(1).setText("col two, row three");
tableRowThree.getCell(2).setText("col three, row three");
paragraph = document.createParagraph();
//trying picture
XWPFRun run = paragraph.createRun();
run.setText("The picture in line: ");
InputStream in = new FileInputStream("samplePict.jpeg");
run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(100), Units.toEMU(30));
in.close();
run.setText(" text after the picture.");
paragraph = document.createParagraph();
//document must be written so underlaaying objects will be committed
ByteArrayOutputStream out = new ByteArrayOutputStream();
document.write(out);
document.close();
// 1) Create options DOCX 2 PDF to select well converter form the registry
Options options = Options.getFrom(DocumentKind.DOCX).to(ConverterTypeTo.PDF);
// 2) Get the converter from the registry
IConverter converter = ConverterRegistry.getRegistry().getConverter(options);
// 3) Convert DOCX 2 PDF
InputStream docxin= new ByteArrayInputStream(out.toByteArray());
OutputStream pdfout = new FileOutputStream(new File("XWPFToPDFXDocReport.pdf"));
converter.convert(docxin, pdfout, options);
docxin.close();
pdfout.close();
}
}
October 2018:
This code works using apache poi 3.17
. It cannot work using apache poi 4.0.0
due to changings in apache poi
which were not taken in account until now in fr.opensagres.poi.xwpf.converter
as well as in fr.opensagres.xdocreport.converter
.
February 2019:
Works for me now using the newest apache poi
version 4.0.1
and the newest version 2.0.2
of fr.opensagres.poi.xwpf.converter.core and consorts.
June 2021:
Works using apache poi
version 4.1.2
and the newest version 2.0.2
of fr.opensagres.poi.xwpf.converter.core and consorts.
Cannot work using apache poi
version 5.0.0
because XDocReport
needs ooxml-schemas
which apache poi 5
does not support anymore.