/** * Copyright (C) 2011-2015 The XDocReport Team <xdocreport@googlegroups.com> * * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package fr.opensagres.poi.xwpf.converter.core.openxmlformats; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Stack; import org.apache.poi.util.IOUtils; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlTokenSource; import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject; import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData; import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTPosH; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTPosV; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTWrapSquare; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STRelFromH; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STRelFromV; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STWrapText; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTEmpty; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPTab; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRunTrackChange; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtBlock; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtCell; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtContentBlock; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtContentRun; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtRun; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSimpleField; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSmartTagRun; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTabs; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText; import org.openxmlformats.schemas.wordprocessingml.x2006.main.FtrDocument; import org.openxmlformats.schemas.wordprocessingml.x2006.main.HdrDocument; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBrType; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType; import fr.opensagres.poi.xwpf.converter.core.IImageExtractor; import fr.opensagres.poi.xwpf.converter.core.IMasterPageHandler; import fr.opensagres.poi.xwpf.converter.core.IXWPFMasterPage; import fr.opensagres.poi.xwpf.converter.core.ListItemContext; import fr.opensagres.poi.xwpf.converter.core.MasterPageManager; import fr.opensagres.poi.xwpf.converter.core.Options; import fr.opensagres.poi.xwpf.converter.core.styles.XWPFStylesDocument; import fr.opensagres.poi.xwpf.converter.core.utils.DxaUtil; import fr.opensagres.poi.xwpf.converter.core.utils.StringUtils; import fr.opensagres.poi.xwpf.converter.core.utils.XWPFRunHelper; import fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil; public abstract class OpenXMlFormatsVisitor<T, O extends Options, E extends IXWPFMasterPage> implements IMasterPageHandler<E> { private final IOpenXMLFormatsPartProvider provider; protected final O options; private final CTDocument1 document; private final MasterPageManager masterPageManager; private CTHdrFtr currentHeader; private CTHdrFtrRef currentHeaderRef; private CTHdrFtr currentFooter; private CTHdrFtrRef currentFooterRef; private boolean pageBreakOnNextParagraph; protected final XWPFStylesDocument stylesDocument; private final Stack<CTTbl> tables; public OpenXMlFormatsVisitor( IOpenXMLFormatsPartProvider provider, O options ) throws Exception { this.provider = provider; this.options = options; this.tables = new Stack<CTTbl>(); this.document = provider.getDocument(); this.stylesDocument = createStylesDocument( provider ); this.masterPageManager = new MasterPageManager( document, this ); } protected XWPFStylesDocument createStylesDocument( IOpenXMLFormatsPartProvider provider ) throws Exception { return new XWPFStylesDocument( provider ); } public XWPFStylesDocument getStylesDocument() { return stylesDocument; } public O getOptions() { return options; } public MasterPageManager getMasterPageManager() { return masterPageManager; } // ------------------------------ Start/End document visitor ----------- /** * Main entry for visit XWPFDocument. * * @param out * @throws Exception */ public void start() throws Exception { // start document T container = startVisitDocument(); // Create IText, XHTML element for each XWPF elements from the w:body visitBodyElements( document, container ); // end document endVisitDocument(); } /** * Start of visit document. * * @return * @throws Exception */ protected abstract T startVisitDocument() throws Exception; /** * End of visit document. * * @throws Exception */ protected abstract void endVisitDocument() throws Exception; // ------------------------------ OpenXMLFormats Elements visitor ----------- private void visitBodyElements( CTDocument1 document, T container ) throws Exception { visitBodyElements( document.getBody(), container ); } protected void visitBodyElements( XmlTokenSource token, T container ) throws Exception { if ( !masterPageManager.isInitialized() ) { // master page manager which hosts each <:w;sectPr declared in the word/document.xml // must be initialized. The initialization loop for each // <w:p paragraph to compute a list of <w:sectPr which contains information // about header/footer declared in the <w:headerReference/<w:footerReference masterPageManager.initialize(); } int i = 0; XmlCursor cursor = null; try { cursor = token.newCursor(); cursor.selectPath( "./*" ); while ( cursor.toNextSelection() ) { XmlObject o = cursor.getObject(); if ( o instanceof CTP ) { visitParagraph( (CTP) o, i, container ); i++; } else if ( o instanceof CTTbl ) { visitTable( (CTTbl) o, i, container ); i++; } else if ( o instanceof CTSdtBlock ) { // <w:sdt><w:sdtContent><p... CTSdtBlock block = (CTSdtBlock) o; CTSdtContentBlock contentBlock = block.getSdtContent(); if ( contentBlock != null ) { visitBodyElements( contentBlock, container ); } } } } finally { if ( cursor != null ) { cursor.dispose(); } } } protected void visitParagraph( CTP paragraph, int index, T container ) throws Exception { if ( isWordDocumentPartParsing() ) { // header/footer is not parsing. // It's the word/document.xml which is parsing // test if the current paragraph define a <w:sectPr // to update the header/footer declared in the <w:headerReference/<w:footerReference masterPageManager.update( paragraph ); } if ( pageBreakOnNextParagraph ) { pageBreak(); } this.pageBreakOnNextParagraph = false; ListItemContext itemContext = null; T paragraphContainer = startVisitParagraph( paragraph, itemContext, container ); visitParagraphBody( paragraph, index, paragraphContainer ); endVisitParagraph( paragraph, container, paragraphContainer ); } protected abstract void endVisitParagraph( CTP paragraph, T container, T paragraphContainer ) throws Exception; protected void visitParagraphBody( CTP paragraph, int index, T paragraphContainer ) throws Exception { boolean fldCharTypeParsing = false; boolean pageNumber = false; String url = null; List<XmlObject> rListAfterSeparate = null; XmlCursor cursor = null; try { cursor = paragraph.newCursor(); cursor.selectPath( "./*" ); while ( cursor.toNextSelection() ) { XmlObject o = cursor.getObject(); if ( o instanceof CTR ) { /* * Test if it's : <w:r> <w:rPr /> <w:fldChar w:fldCharType="begin" /> </w:r> */ CTR r = (CTR) o; STFldCharType.Enum fldCharType = XWPFRunHelper.getFldCharType( r ); if ( fldCharType != null ) { if ( fldCharType.equals( STFldCharType.BEGIN ) ) { process( paragraph, paragraphContainer, pageNumber, url, rListAfterSeparate ); fldCharTypeParsing = true; rListAfterSeparate = new ArrayList<XmlObject>(); pageNumber = false; url = null; } else if ( fldCharType.equals( STFldCharType.END ) ) { process( paragraph, paragraphContainer, pageNumber, url, rListAfterSeparate ); fldCharTypeParsing = false; rListAfterSeparate = null; pageNumber = false; url = null; } } else { if ( fldCharTypeParsing ) { String instrText = XWPFRunHelper.getInstrText( r ); if ( instrText != null ) { if ( StringUtils.isNotEmpty( instrText ) ) { // test if it's <w:r><w:instrText>PAGE</w:instrText></w:r> boolean instrTextPage = XWPFRunHelper.isInstrTextPage( instrText ); if ( !instrTextPage ) { // test if it's <w:instrText>HYPERLINK // "http://code.google.com/p/xdocrepor"</w:instrText> String instrTextHyperlink = XWPFRunHelper.getInstrTextHyperlink( instrText ); if ( instrTextHyperlink != null ) { url = instrTextHyperlink; } } else { pageNumber = true; } } } else { rListAfterSeparate.add( r ); } } else { visitRun( r, paragraph, false, null, paragraphContainer ); } } } else { if ( fldCharTypeParsing ) { rListAfterSeparate.add( o ); } else { visitRun( paragraph, o, paragraphContainer ); } } } } finally { if ( cursor != null ) { cursor.dispose(); } } } private void process( CTP paragraph, T paragraphContainer, boolean pageNumber, String url, List<XmlObject> rListAfterSeparate ) throws Exception { if ( rListAfterSeparate != null ) { for ( XmlObject oAfterSeparate : rListAfterSeparate ) { if ( oAfterSeparate instanceof CTR ) { CTR ctr = (CTR) oAfterSeparate; visitRun( ctr, paragraph, pageNumber, url, paragraphContainer ); } else { visitRun( paragraph, oAfterSeparate, paragraphContainer ); } } } } private void visitRun( CTP paragraph, XmlObject o, T paragraphContainer ) throws Exception { if ( o instanceof CTHyperlink ) { CTHyperlink link = (CTHyperlink) o; String anchor = link.getAnchor(); String href = null; // Test if the is an id for hyperlink String hyperlinkId = link.getId(); if ( StringUtils.isNotEmpty( hyperlinkId ) ) { // TODO // XWPFHyperlink hyperlink = document.getHyperlinkByID( hyperlinkId ); // href = hyperlink.getURL(); } for ( CTR r : link.getRList() ) { visitRun( r, paragraph, false, href != null ? href : "#" + anchor, paragraphContainer ); } } else if ( o instanceof CTSdtRun ) { CTSdtContentRun run = ( (CTSdtRun) o ).getSdtContent(); for ( CTR r : run.getRList() ) { visitRun( r, paragraph, false, null, paragraphContainer ); } } else if ( o instanceof CTRunTrackChange ) { for ( CTR r : ( (CTRunTrackChange) o ).getRList() ) { visitRun( r, paragraph, false, null, paragraphContainer ); } } else if ( o instanceof CTSimpleField ) { CTSimpleField simpleField = (CTSimpleField) o; String instr = simpleField.getInstr(); // 1) test if it's page number // <w:fldSimple w:instr=" PAGE \* MERGEFORMAT "> <w:r> <w:rPr> <w:noProof/> // </w:rPr> <w:t>- 1 -</w:t> </w:r> </w:fldSimple> boolean fieldPageNumber = XWPFRunHelper.isInstrTextPage( instr ); String fieldHref = null; if ( !fieldPageNumber ) { // not page number, test if it's hyperlink : // <w:instrText>HYPERLINK "http://code.google.com/p/xdocrepor"</w:instrText> fieldHref = XWPFRunHelper.getInstrTextHyperlink( instr ); } for ( CTR r : simpleField.getRList() ) { visitRun( r, paragraph, fieldPageNumber, fieldHref, paragraphContainer ); } } else if ( o instanceof CTSmartTagRun ) { // Smart Tags can be nested many times. // This implementation does not preserve the tagging information // buildRunsInOrderFromXml(o); } else if ( o instanceof CTBookmark ) { CTBookmark bookmark = (CTBookmark) o; visitBookmark( bookmark, paragraph, paragraphContainer ); } } protected abstract T startVisitParagraph( CTP paragraph, ListItemContext itemContext, T container ) throws Exception; protected abstract void pageBreak() throws Exception; protected void visitRun( CTR run, CTP paragraph, boolean pageNumber, String url, T paragraphContainer ) throws Exception { // Loop for each element of <w:run text, tab, image etc // to keep the order of thoses elements. XmlCursor c = run.newCursor(); c.selectPath( "./*" ); while ( c.toNextSelection() ) { XmlObject o = c.getObject(); if ( o instanceof CTText ) { CTText ctText = (CTText) o; String tagName = o.getDomNode().getNodeName(); // Field Codes (w:instrText, defined in spec sec. 17.16.23) // come up as instances of CTText, but we don't want them // in the normal text output if ( "w:instrText".equals( tagName ) ) { } else { visitText( ctText, pageNumber, paragraphContainer ); } } else if ( o instanceof CTPTab ) { visitTab( (CTPTab) o, paragraphContainer ); } else if ( o instanceof CTBr ) { visitBR( (CTBr) o, paragraphContainer ); } else if ( o instanceof CTEmpty ) { // Some inline text elements get returned not as // themselves, but as CTEmpty, owing to some odd // definitions around line 5642 of the XSDs // This bit works around it, and replicates the above // rules for that case String tagName = o.getDomNode().getNodeName(); if ( "w:tab".equals( tagName ) ) { CTTabs tabs = null;// stylesDocument.getParagraphTabs( paragraph ); visitTabs( tabs, paragraphContainer ); } if ( "w:br".equals( tagName ) ) { visitBR( null, paragraphContainer ); } if ( "w:cr".equals( tagName ) ) { visitBR( null, paragraphContainer ); } } else if ( o instanceof CTDrawing ) { visitDrawing( (CTDrawing) o, paragraphContainer ); } } c.dispose(); } protected abstract void visitText( CTText ctText, boolean pageNumber, T paragraphContainer ) throws Exception; protected abstract void visitTab( CTPTab o, T paragraphContainer ) throws Exception; protected abstract void visitTabs( CTTabs tabs, T paragraphContainer ) throws Exception; protected void visitBR( CTBr br, T paragraphContainer ) throws Exception { STBrType.Enum brType = XWPFRunHelper.getBrType( br ); if ( brType.equals( STBrType.PAGE ) ) { pageBreakOnNextParagraph = true; } else { addNewLine( br, paragraphContainer ); } } protected abstract void visitBookmark( CTBookmark bookmark, CTP paragraph, T paragraphContainer ) throws Exception; protected abstract void addNewLine( CTBr br, T paragraphContainer ) throws Exception; // --------------------- Table protected void visitTable( CTTbl table, int i, T container ) throws Exception { tables.push( table ); float[] colWidths = XWPFTableUtil.computeColWidths( table ); T tableContainer = startVisitTable( table, colWidths, container ); visitTableBody( table, colWidths, tableContainer ); endVisitTable( table, container, tableContainer ); tables.pop(); } protected abstract T startVisitTable( CTTbl table, float[] colWidths, T tableContainer ) throws Exception; protected abstract void endVisitTable( CTTbl table, T parentContainer, T tableContainer ) throws Exception; protected void visitTableBody( CTTbl table, float[] colWidths, T tableContainer ) throws Exception { XmlCursor cursor = null; try { cursor = table.newCursor(); cursor.selectPath( "./*" ); while ( cursor.toNextSelection() ) { XmlObject o = cursor.getObject(); if ( o instanceof CTRow ) { visitTableRow( (CTRow) o, tableContainer ); } } } finally { if ( cursor != null ) { cursor.dispose(); } } } protected void visitTableRow( CTRow row, T tableContainer ) throws Exception { boolean headerRow = stylesDocument.isTableRowHeader( row ); startVisitTableRow( row, tableContainer, headerRow ); XmlCursor cursor = null; try { cursor = row.newCursor(); cursor.selectPath( "./*" ); while ( cursor.toNextSelection() ) { XmlObject o = cursor.getObject(); if ( o instanceof CTTc ) { if ( o instanceof CTTc ) { CTTc cell = (CTTc) o; visitCell( cell, tableContainer ); } else if ( o instanceof CTSdtCell ) { CTSdtCell sdtCell = (CTSdtCell) o; List<CTTc> tcList = sdtCell.getSdtContent().getTcList(); for ( CTTc cell : tcList ) { visitCell( cell, tableContainer ); } } } } } finally { if ( cursor != null ) { cursor.dispose(); } } } protected abstract void startVisitTableRow( CTRow row, T tableContainer, boolean headerRow ) throws Exception; protected void visitCell( CTTc cell, T tableContainer ) throws Exception { T tableCellContainer = startVisitTableCell( cell, tableContainer ); visitTableCellBody( cell, tableCellContainer ); endVisitTableCell( cell, tableContainer, tableCellContainer ); } protected abstract T startVisitTableCell( CTTc cell, T tableContainer ) throws Exception; protected void visitTableCellBody( CTTc cell, T tableCellContainer ) throws Exception { visitBodyElements( cell, tableCellContainer ); } protected abstract void endVisitTableCell( CTTc cell, T tableContainer, T tableCellContainer ) throws Exception; // ------------------------ Image -------------- protected void visitDrawing( CTDrawing drawing, T parentContainer ) throws Exception { List<CTInline> inlines = drawing.getInlineList(); for ( CTInline inline : inlines ) { visitInline( inline, parentContainer ); } List<CTAnchor> anchors = drawing.getAnchorList(); for ( CTAnchor anchor : anchors ) { visitAnchor( anchor, parentContainer ); } } protected void visitAnchor( CTAnchor anchor, T parentContainer ) throws Exception { CTGraphicalObject graphic = anchor.getGraphic(); /* * wp:positionH relativeFrom="column"> <wp:posOffset>-898525</wp:posOffset> </wp:positionH> */ STRelFromH.Enum relativeFromH = null; Float offsetX = null; CTPosH positionH = anchor.getPositionH(); if ( positionH != null ) { relativeFromH = positionH.getRelativeFrom(); //offsetX = DxaUtil.emu2points( positionH.getPosOffset() ); } STRelFromV.Enum relativeFromV = null; Float offsetY = null; CTPosV positionV = anchor.getPositionV(); if ( positionV != null ) { relativeFromV = positionV.getRelativeFrom(); offsetY = DxaUtil.emu2points( positionV.getPosOffset() ); } STWrapText.Enum wrapText = null; CTWrapSquare wrapSquare = anchor.getWrapSquare(); if ( wrapSquare != null ) { wrapText = wrapSquare.getWrapText(); } visitGraphicalObject( parentContainer, graphic, offsetX, relativeFromH, offsetY, relativeFromV, wrapText ); } protected void visitInline( CTInline inline, T parentContainer ) throws Exception { CTGraphicalObject graphic = inline.getGraphic(); visitGraphicalObject( parentContainer, graphic, null, null, null, null, null ); } private void visitGraphicalObject( T parentContainer, CTGraphicalObject graphic, Float offsetX, STRelFromH.Enum relativeFromH, Float offsetY, STRelFromV.Enum relativeFromV, STWrapText.Enum wrapText ) throws Exception { if ( graphic != null ) { CTGraphicalObjectData graphicData = graphic.getGraphicData(); if ( graphicData != null ) { XmlCursor c = graphicData.newCursor(); c.selectPath( "./*" ); while ( c.toNextSelection() ) { XmlObject o = c.getObject(); if ( o instanceof CTPicture ) { CTPicture picture = (CTPicture) o; // extract the picture if needed IImageExtractor extractor = getImageExtractor(); if ( extractor != null ) { /* * XWPFPictureData pictureData = getPictureData( picture ); if ( pictureData != null ) { try * { extractor.extract( WORD_MEDIA + pictureData.getFileName(), pictureData.getData() ); } * catch ( Throwable e ) { LOGGER.log( Level.SEVERE, "Error while extracting the image " + * pictureData.getFileName(), e ); } } */ } // visit the picture. visitPicture( picture, offsetX, relativeFromH, offsetY, relativeFromV, wrapText, parentContainer ); } } c.dispose(); } } } protected abstract void visitPicture( CTPicture picture, Float offsetX, org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STRelFromH.Enum relativeFromH, Float offsetY, org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STRelFromV.Enum relativeFromV, STWrapText.Enum wrapText, T parentContainer ) throws Exception; // ------------------------------ Header/Footer visitor ----------- public void visitHeaderRef( CTHdrFtrRef headerRef, CTSectPr sectPr, E masterPage ) throws Exception { this.currentHeaderRef = headerRef; this.currentHeader = getHeader( headerRef ); visitHeader( currentHeader, headerRef, sectPr, masterPage ); this.currentHeader = null; this.currentHeaderRef = null; } protected abstract void visitHeader( CTHdrFtr currentHeader, CTHdrFtrRef headerRef, CTSectPr sectPr, E masterPage ) throws Exception; private CTHdrFtr getHeader( CTHdrFtrRef headerRef ) throws Exception { String relId = headerRef.getId(); HdrDocument hdrDoc = provider.getHdrDocumentByPartId( relId ); CTHdrFtr hdrFtr = hdrDoc.getHdr(); return hdrFtr; } public void visitFooterRef( CTHdrFtrRef footerRef, CTSectPr sectPr, E masterPage ) throws Exception { this.currentFooterRef = footerRef; this.currentFooter = getFooter( footerRef ); visitFooter( currentFooter, footerRef, sectPr, masterPage ); this.currentFooter = null; this.currentFooterRef = null; } protected abstract void visitFooter( CTHdrFtr currentFooter, CTHdrFtrRef footerRef, CTSectPr sectPr, E masterPage ) throws Exception; private CTHdrFtr getFooter( CTHdrFtrRef footerRef ) throws Exception { String relId = footerRef.getId(); FtrDocument hdrDoc = provider.getFtrDocumentByPartId( relId ); CTHdrFtr hdrFtr = hdrDoc.getFtr(); return hdrFtr; } /** * Returns the image extractor and null otherwise. * * @return */ protected IImageExtractor getImageExtractor() { return options.getExtractor(); } /** * Returns true if word/document.xml is parsing and false otherwise. * * @return true if word/document.xml is parsing and false otherwise. */ protected boolean isWordDocumentPartParsing() { return currentHeader == null && currentFooter == null; } public CTTbl getParentTable() { if ( tables.isEmpty() ) { return null; } return tables.peek(); } public byte[] getPictureBytes( CTPicture picture ) throws Exception { CTBlipFillProperties blipProps = picture.getBlipFill(); if ( blipProps == null || !blipProps.isSetBlip() ) { // return null if Blip data is missing return null; } String blipId = blipProps.getBlip().getEmbed(); InputStream in = provider.getInputStreamByRelId( getPartRelIdParsing(), blipId ); if ( in == null ) { return null; } return IOUtils.toByteArray( in ); } private String getPartRelIdParsing() { if ( currentHeaderRef != null ) { return currentHeaderRef.getId(); } if ( currentFooterRef != null ) { return currentFooterRef.getId(); } return null; } }