Skip to content

Instantly share code, notes, and snippets.

@BenoitDuffez
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BenoitDuffez/b132d45747ef8c2e9e7c to your computer and use it in GitHub Desktop.
Save BenoitDuffez/b132d45747ef8c2e9e7c to your computer and use it in GitHub Desktop.
Apache POI issue when embedding images in header.
package net.bicou.upcab.ui.docs.export;
import net.bicou.upcab.model.docs.Document;
import net.bicou.upcab.model.docs.DocumentImage;
import net.bicou.upcab.model.docs.EditableTextLineStyle;
import net.bicou.upcab.model.docs.EditableTextSectionType;
import net.bicou.upcab.model.docs.EditableTextStyleRange;
import net.bicou.upcab.model.docs.TextFormatInfo;
import net.bicou.upcab.sqlite.DocumentsDbAdapter;
import net.bicou.upcab.ui.docs.DocumentCreator;
import net.bicou.upcab.util.L;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* <b>Document creator</b>
* <p/>
* Merges a template with sqlite source instances, and creates the output file in a specific file format.
* <p/>
* Usage:
* <pre>
* // Prepare document ID and file path
* long documentId = 12; // example
* String filePath = "/path/to/file.pdf";
* ExportFormat exportFormat = ExportFormat.PDF;
*
* // Export file
* Exporter exporter = Exporter.create(exportFormat);
* if (exporter == null) {
* // Unsupported file format
* } else {
* String errorMessage = exporter.export(documentId, filePath);
* if (errorMessage != null) {
* // Handle error
* } else {
* // Success!
* }
* }
* </pre>
* This class is independent of the implementation. API implementations should extend this class and register the implementation in {@link
* #create(net.bicou.upcab.ui.docs.export.Exporter.ExportFormat)}
*
* @author bicou
*/
public abstract class Exporter {
static final Color sCellHeaderBackgroundColor = new Color(0xE6, 0xE6, 0xE6);
static final String CELL_HEADER_BACKGROUND_COLOR_RRGGBB = "E6E6E6";
Document mDocument;
private final List<String> mErrors = new ArrayList<String>();
EditableTextSectionType mCurrentSection;
int mImageIdInCurrentSection;
public enum ExportFormat {
DOCX,
PDF,
RTF,
}
public enum TextAlignment {
LEFT,
RIGHT,
CENTER,
JUSTIFY,
}
public enum ImageFormat {
PNG,
JPG,
}
/**
* Export the specific document to the desired file path
*
* @param docId The document ID
* @param filePath The target file path
*
* @return The error messages, if any
*/
public List<String> export(final long docId, final String filePath) {
loadDocument(docId);
if (mErrors.size() > 0) {
return mErrors;
}
// Create the document
createDocument(filePath);
if (mErrors.size() > 0) {
return mErrors;
}
// Set document header
mCurrentSection = EditableTextSectionType.HEADER;
mImageIdInCurrentSection = 0;
startHeader();
parseText(mDocument.header, mDocument.headerFormat);
endHeader();
if (mErrors.size() > 0) {
return mErrors;
}
// Set document footer
mCurrentSection = EditableTextSectionType.FOOTER;
mImageIdInCurrentSection = 0;
startFooter();
parseText(mDocument.footer, mDocument.footerFormat);
endFooter();
if (mErrors.size() > 0) {
return mErrors;
}
// Open the document
mCurrentSection = EditableTextSectionType.BODY;
mImageIdInCurrentSection = 0;
openDocument();
parseText(mDocument.body, mDocument.bodyFormat);
if (mErrors.size() > 0) {
return mErrors;
}
// Close the document
closeDocument();
if (mErrors.size() > 0) {
return mErrors;
}
return null;
}
@Override
public String toString() {
return "Exporter{" +
"mDocument=" + mDocument +
", mErrors=" + mErrors +
", mCurrentSection=" + mCurrentSection +
'}';
}
}
2014/05/15 00:45:15.261 [D] PoiExporter#createDocument(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:47)
2014/05/15 00:45:15.959 [D] PoiExporter#startHeader(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:54)
2014/05/15 00:45:15.960 [D] Exporter#parseText(): ---------------------------------------------------------------- (in net/bicou/upcab/ui/docs/export/Exporter.java:408)
2014/05/15 00:45:15.960 [D] Exporter#parseText(): Text is:
Benoit Duffez (in net/bicou/upcab/ui/docs/export/Exporter.java:409)
2014/05/15 00:45:15.960 [D] Exporter#parseText(): ---------------------------------------------------------------- (in net/bicou/upcab/ui/docs/export/Exporter.java:410)
2014/05/15 00:45:15.964 [D] PoiExporter#createParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:117)
2014/05/15 00:45:16.023 [D] PoiExporter#addImage(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:140)
2014/05/15 00:45:16.153 [D] PoiExporter#setParagraphAlignment(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:181)
2014/05/15 00:45:16.193 [D] PoiExporter#endParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:203)
2014/05/15 00:45:16.194 [D] PoiExporter#createParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:117)
2014/05/15 00:45:16.194 [D] PoiExporter#addParagraphChunk(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:127)
2014/05/15 00:45:16.423 [D] PoiExporter#addParagraphChunk(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:127)
2014/05/15 00:45:16.425 [D] PoiExporter#setParagraphAlignment(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:181)
2014/05/15 00:45:16.426 [D] PoiExporter#endParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:203)
2014/05/15 00:45:16.426 [D] PoiExporter#createParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:117)
2014/05/15 00:45:16.427 [D] PoiExporter#addParagraphChunk(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:127)
2014/05/15 00:45:16.428 [D] PoiExporter#setParagraphAlignment(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:181)
2014/05/15 00:45:16.441 [D] PoiExporter#endParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:203)
2014/05/15 00:45:16.444 [D] PoiExporter#createParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:117)
2014/05/15 00:45:16.445 [D] PoiExporter#addParagraphChunk(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:127)
2014/05/15 00:45:16.447 [D] PoiExporter#setParagraphAlignment(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:181)
2014/05/15 00:45:16.449 [D] PoiExporter#endParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:203)
2014/05/15 00:45:16.450 [D] PoiExporter#endHeader(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:59)
2014/05/15 00:45:16.556 [D] PoiExporter#startFooter(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:73)
2014/05/15 00:45:16.556 [D] Exporter#parseText(): ---------------------------------------------------------------- (in net/bicou/upcab/ui/docs/export/Exporter.java:408)
2014/05/15 00:45:16.556 [D] Exporter#parseText(): Text is:
15/05/2014 (in net/bicou/upcab/ui/docs/export/Exporter.java:409)
2014/05/15 00:45:16.556 [D] Exporter#parseText(): ---------------------------------------------------------------- (in net/bicou/upcab/ui/docs/export/Exporter.java:410)
2014/05/15 00:45:16.557 [D] PoiExporter#createParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:117)
2014/05/15 00:45:16.557 [D] PoiExporter#addParagraphChunk(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:127)
2014/05/15 00:45:16.559 [D] PoiExporter#setParagraphAlignment(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:181)
2014/05/15 00:45:16.559 [D] PoiExporter#endParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:203)
2014/05/15 00:45:16.560 [D] PoiExporter#endFooter(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:78)
2014/05/15 00:45:16.572 [D] PoiExporter#openDocument(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:92)
2014/05/15 00:45:16.572 [D] Exporter#parseText(): ---------------------------------------------------------------- (in net/bicou/upcab/ui/docs/export/Exporter.java:408)
2014/05/15 00:45:16.573 [D] Exporter#parseText(): Text is:
Rennes, le 15/05/2014
(in net/bicou/upcab/ui/docs/export/Exporter.java:409)
2014/05/15 00:45:16.573 [D] Exporter#parseText(): ---------------------------------------------------------------- (in net/bicou/upcab/ui/docs/export/Exporter.java:410)
2014/05/15 00:45:16.573 [D] PoiExporter#addNewLine(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:214)
2014/05/15 00:45:16.577 [D] PoiExporter#addNewLine(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:214)
2014/05/15 00:45:16.578 [D] PoiExporter#addNewLine(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:214)
2014/05/15 00:45:16.579 [D] PoiExporter#createParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:117)
2014/05/15 00:45:16.579 [D] PoiExporter#addParagraphChunk(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:127)
2014/05/15 00:45:16.581 [D] PoiExporter#setParagraphAlignment(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:181)
2014/05/15 00:45:16.581 [D] PoiExporter#endParagraph(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:203)
2014/05/15 00:45:16.581 [D] PoiExporter#addNewLine(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:214)
2014/05/15 00:45:16.582 [D] PoiExporter#addNewLine(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:214)
2014/05/15 00:45:16.584 [D] PoiExporter#addNewLine(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:214)
2014/05/15 00:45:16.585 [D] PoiExporter#closeDocument(): (in net/bicou/upcab/ui/docs/export/PoiExporter.java:97)
package net.bicou.upcab.ui.docs.export;
import net.bicou.upcab.model.docs.EditableTextSectionType;
import net.bicou.upcab.util.L;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.xmlbeans.XmlException;
import org.eclipse.swt.graphics.Rectangle;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Apache POI implementation, in order to export to .docx file format
* <p/>
* Created by bicou on 20/08/13.
*/
public class PoiExporter extends Exporter {
private String mFileName;
private UCXWPFDocument mXWPFDocument;
private XWPFParagraph mCurrentParagraph;
private final List<XWPFParagraph> mHeaderParagraphs;
private final List<XWPFParagraph> mFooterParagraphs;
private String[] mRowData;
public PoiExporter() {
mHeaderParagraphs = new ArrayList<XWPFParagraph>();
mFooterParagraphs = new ArrayList<XWPFParagraph>();
}
@Override
protected void createDocument(final String fileName) {
mFileName = fileName;
mXWPFDocument = new UCXWPFDocument();
}
@Override
protected void startHeader() {
}
@Override
protected void endHeader() {
try {
final CTSectPr sectPr = mXWPFDocument.getDocument().getBody().addNewSectPr();
final XWPFHeaderFooterPolicy hfPolicy = new PoiHeaderFooterPolicy(mXWPFDocument, sectPr);
hfPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, mHeaderParagraphs.toArray(new XWPFParagraph[mHeaderParagraphs.size()]));
} catch (final IOException e) {
L.e("Couldn't end header", e, L.Severity.FUNCTIONAL_FAILURE);
} catch (final XmlException e) {
L.e("Couldn't end header", e, L.Severity.FUNCTIONAL_FAILURE);
}
}
@Override
protected void startFooter() {
}
@Override
protected void endFooter() {
try {
final CTSectPr sectPr = mXWPFDocument.getDocument().getBody().getSectPr();
final XWPFHeaderFooterPolicy hfPolicy = new PoiHeaderFooterPolicy(mXWPFDocument, sectPr);
hfPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, mFooterParagraphs.toArray(new XWPFParagraph[mFooterParagraphs.size()]));
} catch (final IOException e) {
L.e("Coudln't end footer", e, L.Severity.FUNCTIONAL_FAILURE);
} catch (final XmlException e) {
L.e("Coudln't end footer", e, L.Severity.FUNCTIONAL_FAILURE);
}
}
@Override
protected void openDocument() {
}
@Override
protected void closeDocument() {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(mFileName));
mXWPFDocument.write(fos);
} catch (final IOException e) {
handleError(e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (final IOException e) {
// Don't care
}
}
}
}
@Override
protected void createParagraph() {
if (mCurrentSection == EditableTextSectionType.BODY) {
mCurrentParagraph = mXWPFDocument.createParagraph();
} else {
mCurrentParagraph = new XWPFParagraph(CTP.Factory.newInstance(), mXWPFDocument);
}
}
@Override
protected void addParagraphChunk(final String chunk, final TextDecoration style) {
final XWPFRun xwpfRun = mCurrentParagraph.createRun();
xwpfRun.setText(chunk);
xwpfRun.setBold((style.style & TextDecoration.STYLE_BOLD) > 0);
xwpfRun.setItalic((style.style & TextDecoration.STYLE_ITALIC) > 0);
if ((style.style & TextDecoration.STYLE_UNDERLINE) > 0) {
xwpfRun.setUnderline(UnderlinePatterns.SINGLE);
}
xwpfRun.setFontSize(style.fontSize);
}
@Override
protected void addImage(final ImageFormat imageFormat, final String filePath, final Rectangle bounds) {
// Get picture format
final int pictureType;
switch (imageFormat) {
case PNG:
pictureType = Document.PICTURE_TYPE_PNG;
break;
case JPG:
pictureType = Document.PICTURE_TYPE_JPEG;
break;
default:
throw new IllegalStateException("Can't use anything else than PNG/JPG in Apache POI");
}
// Add it
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
final XWPFRun xwpfRun = mCurrentParagraph.createRun();
final String blipId = mXWPFDocument.addPictureData(inputStream, pictureType);
final int nextPicNameNumber = mXWPFDocument.getNextPicNameNumber(pictureType);
mXWPFDocument.insertPicture(xwpfRun, blipId, nextPicNameNumber, bounds.width, bounds.height);
} catch (final InvalidFormatException e) {
L.e("Unable to add image to XWPF document", e, L.Severity.FUNCTIONAL_FAILURE);
} catch (final IOException e) {
L.e("Unable to add image to XWPF document", e, L.Severity.FUNCTIONAL_FAILURE);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (final IOException e) {
L.e("Unable to close IS", e, L.Severity.WARNING);
}
}
}
}
@Override
protected void setParagraphAlignment(final TextAlignment alignment) {
final ParagraphAlignment align;
switch (alignment) {
case CENTER:
align = ParagraphAlignment.CENTER;
break;
case RIGHT:
align = ParagraphAlignment.RIGHT;
break;
case JUSTIFY:
align = ParagraphAlignment.BOTH;
break;
default:
case LEFT:
align = ParagraphAlignment.LEFT;
break;
}
mCurrentParagraph.setAlignment(align);
}
@Override
protected void endParagraph() {
if (mCurrentSection == EditableTextSectionType.HEADER) {
mHeaderParagraphs.add(mCurrentParagraph);
} else if (mCurrentSection == EditableTextSectionType.FOOTER) {
mFooterParagraphs.add(mCurrentParagraph);
}
mCurrentParagraph = null;
}
@Override
protected void addNewLine() {
mXWPFDocument.createParagraph().createRun().setText("");
}
@Override
protected void createTable(final String[] rowData) {
mRowData = rowData;
}
@Override
protected void addTableRows(final String[][] cells) {
final int cols = mRowData.length;
final int rows = cells.length + 1;
XWPFParagraph p;
XWPFRun run;
XWPFTableCell cell;
String text;
final XWPFTable table = mXWPFDocument.createTable(rows, cols);
// First row
for (int col = 0; col < cols; col++) {
cell = table.getRow(1).getCell(col + 1);
p = cell.getParagraphs().get(0);
run = p.createRun();
text = mRowData[col];
if (text.startsWith("_")) {
cell.setColor(CELL_HEADER_BACKGROUND_COLOR_RRGGBB);
text = text.substring(1);
}
run.setText(text);
}
// Other rows
for (int row = 0; row < cells.length; row++) {
for (int col = 0; col < cols; col++) {
cell = table.getRow(row + 2).getCell(col + 1);
p = cell.getParagraphs().get(0);
run = p.createRun();
run.setText(cells[row][col]);
}
}
}
@Override
public String toString() {
return "PoiExporter{" +
"mFileName='" + mFileName + '\'' +
", mXWPFDocument=" + mXWPFDocument +
", mCurrentParagraph=" + mCurrentParagraph +
", mHeaderParagraphs=" + mHeaderParagraphs +
", mFooterParagraphs=" + mFooterParagraphs +
", mRowData=" + Arrays.toString(mRowData) +
'}';
}
}
package net.bicou.upcab.ui.docs.export;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFFactory;
import org.apache.poi.xwpf.usermodel.XWPFFooter;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.apache.poi.xwpf.usermodel.XWPFHeaderFooter;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRelation;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.FtrDocument;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.HdrDocument;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr.Enum;
import schemasMicrosoftComOfficeOffice.CTLock;
import schemasMicrosoftComOfficeOffice.STConnectType;
import schemasMicrosoftComVml.CTFormulas;
import schemasMicrosoftComVml.CTGroup;
import schemasMicrosoftComVml.CTH;
import schemasMicrosoftComVml.CTHandles;
import schemasMicrosoftComVml.CTPath;
import schemasMicrosoftComVml.CTShape;
import schemasMicrosoftComVml.CTShapetype;
import schemasMicrosoftComVml.CTTextPath;
import schemasMicrosoftComVml.STExt;
import schemasMicrosoftComVml.STTrueFalse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A .docx file can have no headers/footers, the same header/footer on each page, odd/even page footers, and optionally also a different header/footer on the first
* page. This class handles sorting out what there is, and giving you the right headers and footers for the document.
*/
class PoiHeaderFooterPolicy extends XWPFHeaderFooterPolicy {
private final XWPFDocument doc;
private XWPFHeader firstPageHeader;
private XWPFFooter firstPageFooter;
private XWPFHeader evenPageHeader;
private XWPFFooter evenPageFooter;
private XWPFHeader defaultHeader;
private XWPFFooter defaultFooter;
/**
* Figures out the policy for the given document, and creates any header and footer objects as required.
*/
public PoiHeaderFooterPolicy(final XWPFDocument doc, final CTSectPr sectPr) throws IOException, XmlException {
super(doc, sectPr);
// Grab what headers and footers have been defined
// For now, we don't care about different ranges, as it
// doesn't seem that .docx properly supports that
// feature of the file format yet
this.doc = doc;
for (int i = 0; i < sectPr.sizeOfHeaderReferenceArray(); i++) {
// Get the header
final CTHdrFtrRef ref = sectPr.getHeaderReferenceArray(i);
final POIXMLDocumentPart relatedPart = doc.getRelationById(ref.getId());
XWPFHeader hdr = null;
if (relatedPart != null && relatedPart instanceof XWPFHeader) {
hdr = (XWPFHeader) relatedPart;
}
// Assign it
final Enum type = ref.getType();
assignHeader(hdr, type);
}
for (int i = 0; i < sectPr.sizeOfFooterReferenceArray(); i++) {
// Get the footer
final CTHdrFtrRef ref = sectPr.getFooterReferenceArray(i);
final POIXMLDocumentPart relatedPart = doc.getRelationById(ref.getId());
XWPFFooter ftr = null;
if (relatedPart != null && relatedPart instanceof XWPFFooter) {
ftr = (XWPFFooter) relatedPart;
}
// Assign it
final Enum type = ref.getType();
assignFooter(ftr, type);
}
}
private void assignFooter(final XWPFFooter ftr, final Enum type) {
if (type == STHdrFtr.FIRST) {
firstPageFooter = ftr;
} else if (type == STHdrFtr.EVEN) {
evenPageFooter = ftr;
} else {
defaultFooter = ftr;
}
}
private void assignHeader(final XWPFHeader hdr, final Enum type) {
if (type == STHdrFtr.FIRST) {
firstPageHeader = hdr;
} else if (type == STHdrFtr.EVEN) {
evenPageHeader = hdr;
} else {
defaultHeader = hdr;
}
}
public XWPFHeader createHeader(final Enum type) throws IOException {
return createHeader(type, null);
}
public XWPFHeader createHeader(final Enum type, final XWPFParagraph[] pars) throws IOException {
final XWPFRelation relation = XWPFRelation.HEADER;
final String pStyle = "Header";
final int i = getRelationIndex(relation);
final HdrDocument hdrDoc = HdrDocument.Factory.newInstance();
final XWPFHeader wrapper = (XWPFHeader) doc.createRelationship(relation, XWPFFactory.getInstance(), i);
final CTHdrFtr hdr = buildHdr(type, pStyle, wrapper, pars);
wrapper.setHeaderFooter(hdr);
final OutputStream outputStream = wrapper.getPackagePart().getOutputStream();
hdrDoc.setHdr(hdr);
final XmlOptions xmlOptions = commit(wrapper);
assignHeader(wrapper, type);
// hdrDoc.save(outputStream, xmlOptions);
outputStream.close();
return wrapper;
}
public XWPFFooter createFooter(final Enum type) throws IOException {
return createFooter(type, null);
}
public XWPFFooter createFooter(final Enum type, final XWPFParagraph[] pars) throws IOException {
final XWPFRelation relation = XWPFRelation.FOOTER;
final String pStyle = "Footer";
final int i = getRelationIndex(relation);
final FtrDocument ftrDoc = FtrDocument.Factory.newInstance();
final XWPFFooter wrapper = (XWPFFooter) doc.createRelationship(relation, XWPFFactory.getInstance(), i);
final CTHdrFtr ftr = buildFtr(type, pStyle, wrapper, pars);
wrapper.setHeaderFooter(ftr);
final OutputStream outputStream = wrapper.getPackagePart().getOutputStream();
ftrDoc.setFtr(ftr);
final XmlOptions xmlOptions = commit(wrapper);
assignFooter(wrapper, type);
// ftrDoc.save(outputStream, xmlOptions);
outputStream.close();
return wrapper;
}
private int getRelationIndex(final XWPFRelation relation) {
final List<POIXMLDocumentPart> relations = doc.getRelations();
int i = 1;
for (Iterator<POIXMLDocumentPart> it = relations.iterator(); it.hasNext(); ) {
final POIXMLDocumentPart item = it.next();
if (item.getPackageRelationship().getRelationshipType().equals(relation.getRelation())) {
i++;
}
}
return i;
}
private CTHdrFtr buildFtr(final Enum type, final String pStyle, final XWPFHeaderFooter wrapper, final XWPFParagraph[] pars) {
//CTHdrFtr ftr = buildHdrFtr(pStyle, pars); // MB 24 May 2010
final CTHdrFtr ftr = buildHdrFtr(pStyle, pars, wrapper); // MB 24 May 2010
setFooterReference(type, wrapper);
return ftr;
}
private CTHdrFtr buildHdr(final Enum type, final String pStyle, final XWPFHeaderFooter wrapper, final XWPFParagraph[] pars) {
//CTHdrFtr hdr = buildHdrFtr(pStyle, pars); // MB 24 May 2010
final CTHdrFtr hdr = buildHdrFtr(pStyle, pars, wrapper); // MB 24 May 2010
setHeaderReference(type, wrapper);
return hdr;
}
private CTHdrFtr buildHdrFtr(final String pStyle, final XWPFParagraph[] paragraphs) {
final CTHdrFtr ftr = CTHdrFtr.Factory.newInstance();
if (paragraphs != null) {
for (int i = 0; i < paragraphs.length; i++) {
final CTP p = ftr.addNewP();
//ftr.setPArray(0, paragraphs[i].getCTP()); // MB 23 May 2010
ftr.setPArray(i, paragraphs[i].getCTP()); // MB 23 May 2010
}
} else {
final CTP p = ftr.addNewP();
final byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
final byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
p.setRsidP(rsidr);
p.setRsidRDefault(rsidrdefault);
final CTPPr pPr = p.addNewPPr();
pPr.addNewPStyle().setVal(pStyle);
}
return ftr;
}
/**
* MB 24 May 2010. Created this overloaded buildHdrFtr() method because testing demonstrated that the XWPFFooter or XWPFHeader object returned by calls to the
* createHeader(int, XWPFParagraph[]) and createFooter(int, XWPFParagraph[]) methods or the getXXXXXHeader/Footer methods where headers or footers had been
* added
* to a document since it had been created/opened, returned an object that contained no XWPFParagraph objects even if the header/footer itself did contain text.
* The reason was that this line of code; CTHdrFtr ftr = CTHdrFtr.Factory.newInstance(); created a brand new instance of the CTHDRFtr class which was then
* populated with sqlite when it should have recovered the CTHdrFtr object encapsulated within the XWPFHeaderFooter object that had previoulsy been
* instantiated in
* the createHeader(int, XWPFParagraph[]) or createFooter(int, XWPFParagraph[]) methods.
*/
private CTHdrFtr buildHdrFtr(final String pStyle, final XWPFParagraph[] paragraphs, final XWPFHeaderFooter wrapper) {
final CTHdrFtr ftr = wrapper._getHdrFtr();
if (paragraphs != null) {
for (int i = 0; i < paragraphs.length; i++) {
final CTP p = ftr.addNewP();
ftr.setPArray(i, paragraphs[i].getCTP());
}
} else {
final CTP p = ftr.addNewP();
final byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
final byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
p.setRsidP(rsidr);
p.setRsidRDefault(rsidrdefault);
final CTPPr pPr = p.addNewPPr();
pPr.addNewPStyle().setVal(pStyle);
}
return ftr;
}
private void setFooterReference(final Enum type, final XWPFHeaderFooter wrapper) {
final CTHdrFtrRef ref = doc.getDocument().getBody().getSectPr().addNewFooterReference();
ref.setType(type);
ref.setId(wrapper.getPackageRelationship().getId());
}
private void setHeaderReference(final Enum type, final XWPFHeaderFooter wrapper) {
final CTHdrFtrRef ref = doc.getDocument().getBody().getSectPr().addNewHeaderReference();
ref.setType(type);
ref.setId(wrapper.getPackageRelationship().getId());
}
private XmlOptions commit(final XWPFHeaderFooter wrapper) {
final XmlOptions xmlOptions = new XmlOptions(wrapper.DEFAULT_XML_OPTIONS);
final Map<String, String> map = new HashMap<String, String>();
map.put("http://schemas.openxmlformats.org/officeDocument/2006/math", "m");
map.put("urn:schemas-microsoft-com:office:office", "o");
map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r");
map.put("urn:schemas-microsoft-com:vml", "v");
map.put("http://schemas.openxmlformats.org/markup-compatibility/2006", "ve");
map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w");
map.put("urn:schemas-microsoft-com:office:word", "w10");
map.put("http://schemas.microsoft.com/office/word/2006/wordml", "wne");
map.put("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", "wp");
xmlOptions.setSaveSuggestedPrefixes(map);
return xmlOptions;
}
public XWPFHeader getFirstPageHeader() {
return firstPageHeader;
}
public XWPFFooter getFirstPageFooter() {
return firstPageFooter;
}
/**
* Returns the odd page header. This is also the same as the default one...
*/
public XWPFHeader getOddPageHeader() {
return defaultHeader;
}
/**
* Returns the odd page footer. This is also the same as the default one...
*/
public XWPFFooter getOddPageFooter() {
return defaultFooter;
}
public XWPFHeader getEvenPageHeader() {
return evenPageHeader;
}
public XWPFFooter getEvenPageFooter() {
return evenPageFooter;
}
public XWPFHeader getDefaultHeader() {
return defaultHeader;
}
public XWPFFooter getDefaultFooter() {
return defaultFooter;
}
/**
* Get the header that applies to the given (1 based) page.
*
* @param pageNumber The one based page number
*/
public XWPFHeader getHeader(final int pageNumber) {
if (pageNumber == 1 && firstPageHeader != null) {
return firstPageHeader;
}
if (pageNumber % 2 == 0 && evenPageHeader != null) {
return evenPageHeader;
}
return defaultHeader;
}
/**
* Get the footer that applies to the given (1 based) page.
*
* @param pageNumber The one based page number
*/
public XWPFFooter getFooter(final int pageNumber) {
if (pageNumber == 1 && firstPageFooter != null) {
return firstPageFooter;
}
if (pageNumber % 2 == 0 && evenPageFooter != null) {
return evenPageFooter;
}
return defaultFooter;
}
public void createWatermark(final String text) {
final XWPFParagraph[] pars = new XWPFParagraph[1];
try {
pars[0] = getWatermarkParagraph(text, 1);
createHeader(DEFAULT, pars);
pars[0] = getWatermarkParagraph(text, 2);
createHeader(FIRST, pars);
pars[0] = getWatermarkParagraph(text, 3);
createHeader(EVEN, pars);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* This is the default Watermark paragraph; the only variable is the text message
* TODO: manage all the other variables
*/
private XWPFParagraph getWatermarkParagraph(final String text, final int idx) {
final CTP p = CTP.Factory.newInstance();
final byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
final byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
p.setRsidP(rsidr);
p.setRsidRDefault(rsidrdefault);
final CTPPr pPr = p.addNewPPr();
pPr.addNewPStyle().setVal("Header");
// start watermark paragraph
final CTR r = p.addNewR();
final CTRPr rPr = r.addNewRPr();
rPr.addNewNoProof();
final CTPicture pict = r.addNewPict();
final CTGroup group = CTGroup.Factory.newInstance();
final CTShapetype shapetype = group.addNewShapetype();
shapetype.setId("_x0000_t136");
shapetype.setCoordsize("1600,21600");
shapetype.setSpt(136);
shapetype.setAdj("10800");
shapetype.setPath2("m@7,0l@8,0m@5,21600l@6,21600e");
final CTFormulas formulas = shapetype.addNewFormulas();
formulas.addNewF().setEqn("sum #0 0 10800");
formulas.addNewF().setEqn("prod #0 2 1");
formulas.addNewF().setEqn("sum 21600 0 @1");
formulas.addNewF().setEqn("sum 0 0 @2");
formulas.addNewF().setEqn("sum 21600 0 @3");
formulas.addNewF().setEqn("if @0 @3 0");
formulas.addNewF().setEqn("if @0 21600 @1");
formulas.addNewF().setEqn("if @0 0 @2");
formulas.addNewF().setEqn("if @0 @4 21600");
formulas.addNewF().setEqn("mid @5 @6");
formulas.addNewF().setEqn("mid @8 @5");
formulas.addNewF().setEqn("mid @7 @8");
formulas.addNewF().setEqn("mid @6 @7");
formulas.addNewF().setEqn("sum @6 0 @5");
final CTPath path = shapetype.addNewPath();
path.setTextpathok(STTrueFalse.T);
path.setConnecttype(STConnectType.CUSTOM);
path.setConnectlocs("@9,0;@10,10800;@11,21600;@12,10800");
path.setConnectangles("270,180,90,0");
final CTTextPath shapeTypeTextPath = shapetype.addNewTextpath();
shapeTypeTextPath.setOn(STTrueFalse.T);
shapeTypeTextPath.setFitshape(STTrueFalse.T);
final CTHandles handles = shapetype.addNewHandles();
final CTH h = handles.addNewH();
h.setPosition("#0,bottomRight");
h.setXrange("6629,14971");
final CTLock lock = shapetype.addNewLock();
lock.setExt(STExt.EDIT);
final CTShape shape = group.addNewShape();
shape.setId("PowerPlusWaterMarkObject" + idx);
shape.setSpid("_x0000_s102" + (4 + idx));
shape.setType("#_x0000_t136");
shape.setStyle("position:absolute;margin-left:0;margin-top:0;width:415pt;height:207.5pt;z-index:-251654144;mso-wrap-edited:f;" +
"mso-position-horizontal:center;mso-position-horizontal-relative:margin;mso-position-vertical:center;mso-position-vertical-relative:margin");
shape.setWrapcoords("616 5068 390 16297 39 16921 -39 17155 7265 17545 7186 17467 -39 17467 18904 17467 10507 17467 8710 17545 18904 17077 18787 16843 " +
"18358" + " 16297 18279 12554 19178 12476 20701 11774 20779 11228 21131 10059 21248 8811 21248 7563 20975 6316 20935 5380 19490 5146 14022 5068 " +
"2616 5068");
shape.setFillcolor("black");
shape.setStroked(STTrueFalse.FALSE);
final CTTextPath shapeTextPath = shape.addNewTextpath();
shapeTextPath.setStyle("font-family:&quot;Cambria&quot;;font-size:1pt");
shapeTextPath.setString(text);
pict.set(group);
// end watermark paragraph
return new XWPFParagraph(p, doc);
}
}
package net.bicou.upcab.ui.docs.export;
import net.bicou.upcab.util.L;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
/**
* Extension of the default {@link org.apache.poi.xwpf.usermodel.XWPFDocument} class, in order to fix support for embedded images
* Found at http://stackoverflow.com/a/17849834/334493
* Created by bicou on 14/05/2014.
*/
public class UCXWPFDocument extends XWPFDocument {
public UCXWPFDocument() {
}
/**
* Insert a picture in the provided run.
*
* @param run The run to add the picture to
* @param blipId The picture blip ID
* @param id The picture ID
* @param width The picture width, in pixels (do NOT convert it to EMU)
* @param height The picture height, in pixels (do NOT convert it to EMU)
*/
public void insertPicture(final XWPFRun run, final String blipId, final int id, int width, int height) {
width = Units.toEMU(width);
height = Units.toEMU(height);
final CTInline inline = run.getCTR().addNewDrawing().addNewInline();
final String picXml = "" +
"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
" <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
" <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
" <pic:nvPicPr>" +
" <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
" <pic:cNvPicPr/>" +
" </pic:nvPicPr>" +
" <pic:blipFill><a:blip r:embed=\"" + blipId + "\" />" +
" <a:stretch>" +
" <a:fillRect/>" +
" </a:stretch>" +
" </pic:blipFill>" +
" <pic:spPr>" +
" <a:xfrm>" +
" <a:off x=\"0\" y=\"0\"/>" +
" <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +
" </a:xfrm>" +
" <a:prstGeom prst=\"rect\">" +
" <a:avLst/>" +
" </a:prstGeom>" +
" </pic:spPr>" +
" </pic:pic>" +
" </a:graphicData>" +
"</a:graphic>";
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch (final XmlException xe) {
L.e("Unable to parse XML", xe, L.Severity.FUNCTIONAL_FAILURE);
}
inline.set(xmlToken);
inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);
final CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height);
final CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("Picture " + id);
docPr.setDescr("Generated");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment