PageRenderTime 552ms CodeModel.GetById 32ms RepoModel.GetById 2ms app.codeStats 0ms

/thirdparties-extension/org.apache.poi.xwpf.converter.pdf/src/main/java/org/apache/poi/xwpf/converter/pdf/internal/PdfMapper.java

https://github.com/minstrelsy/xdocreport
Java | 1354 lines | 1061 code | 139 blank | 154 comment | 228 complexity | 5000f7cf0c2ae11266b40166c2a4f792 MD5 | raw file
  1. /**
  2. * Copyright (C) 2011-2012 The XDocReport Team <xdocreport@googlegroups.com>
  3. *
  4. * All rights reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining
  7. * a copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sublicense, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  21. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  22. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  23. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. */
  25. package org.apache.poi.xwpf.converter.pdf.internal;
  26. import static org.apache.poi.xwpf.converter.core.utils.DxaUtil.emu2points;
  27. import java.awt.Color;
  28. import java.io.OutputStream;
  29. import java.math.BigInteger;
  30. import java.util.List;
  31. import java.util.logging.Logger;
  32. import org.apache.poi.xwpf.converter.core.BorderSide;
  33. import org.apache.poi.xwpf.converter.core.IXWPFMasterPage;
  34. import org.apache.poi.xwpf.converter.core.ListItemContext;
  35. import org.apache.poi.xwpf.converter.core.ParagraphLineSpacing;
  36. import org.apache.poi.xwpf.converter.core.TableCellBorder;
  37. import org.apache.poi.xwpf.converter.core.TableHeight;
  38. import org.apache.poi.xwpf.converter.core.TableWidth;
  39. import org.apache.poi.xwpf.converter.core.XWPFDocumentVisitor;
  40. import org.apache.poi.xwpf.converter.core.styles.paragraph.ParagraphIndentationHangingValueProvider;
  41. import org.apache.poi.xwpf.converter.core.styles.paragraph.ParagraphIndentationLeftValueProvider;
  42. import org.apache.poi.xwpf.converter.core.utils.DxaUtil;
  43. import org.apache.poi.xwpf.converter.core.utils.StringUtils;
  44. import org.apache.poi.xwpf.converter.pdf.PdfOptions;
  45. import org.apache.poi.xwpf.converter.pdf.internal.elements.StylableAnchor;
  46. import org.apache.poi.xwpf.converter.pdf.internal.elements.StylableDocument;
  47. import org.apache.poi.xwpf.converter.pdf.internal.elements.StylableHeaderFooter;
  48. import org.apache.poi.xwpf.converter.pdf.internal.elements.StylableMasterPage;
  49. import org.apache.poi.xwpf.converter.pdf.internal.elements.StylableParagraph;
  50. import org.apache.poi.xwpf.converter.pdf.internal.elements.StylableTable;
  51. import org.apache.poi.xwpf.converter.pdf.internal.elements.StylableTableCell;
  52. import org.apache.poi.xwpf.usermodel.IBodyElement;
  53. import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
  54. import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
  55. import org.apache.poi.xwpf.usermodel.XWPFDocument;
  56. import org.apache.poi.xwpf.usermodel.XWPFFooter;
  57. import org.apache.poi.xwpf.usermodel.XWPFHeader;
  58. import org.apache.poi.xwpf.usermodel.XWPFParagraph;
  59. import org.apache.poi.xwpf.usermodel.XWPFPictureData;
  60. import org.apache.poi.xwpf.usermodel.XWPFRun;
  61. import org.apache.poi.xwpf.usermodel.XWPFTable;
  62. import org.apache.poi.xwpf.usermodel.XWPFTableCell;
  63. import org.apache.poi.xwpf.usermodel.XWPFTableRow;
  64. import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
  65. import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;
  66. import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STRelFromH;
  67. import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STRelFromV;
  68. import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STWrapText;
  69. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
  70. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
  71. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBr;
  72. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef;
  73. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl;
  74. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
  75. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPTab;
  76. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
  77. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
  78. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTabStop;
  79. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTabs;
  80. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
  81. import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTextDirection;
  82. import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTabJc;
  83. import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTabTlc;
  84. import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTextDirection;
  85. import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
  86. import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc.Enum;
  87. import com.lowagie.text.Chunk;
  88. import com.lowagie.text.DocumentException;
  89. import com.lowagie.text.Element;
  90. import com.lowagie.text.Font;
  91. import com.lowagie.text.Image;
  92. import com.lowagie.text.Paragraph;
  93. import com.lowagie.text.Rectangle;
  94. import com.lowagie.text.pdf.PdfPCell;
  95. import com.lowagie.text.pdf.PdfPTable;
  96. import com.lowagie.text.pdf.draw.DottedLineSeparator;
  97. import com.lowagie.text.pdf.draw.LineSeparator;
  98. import com.lowagie.text.pdf.draw.VerticalPositionMark;
  99. import fr.opensagres.xdocreport.itext.extension.ExtendedChunk;
  100. import fr.opensagres.xdocreport.itext.extension.ExtendedImage;
  101. import fr.opensagres.xdocreport.itext.extension.ExtendedParagraph;
  102. import fr.opensagres.xdocreport.itext.extension.ExtendedPdfPCell;
  103. import fr.opensagres.xdocreport.itext.extension.ExtendedPdfPTable;
  104. import fr.opensagres.xdocreport.itext.extension.IITextContainer;
  105. import fr.opensagres.xdocreport.itext.extension.font.FontGroup;
  106. public class PdfMapper
  107. extends XWPFDocumentVisitor<IITextContainer, PdfOptions, StylableMasterPage>
  108. {
  109. private static final String TAB = "\t";
  110. /**
  111. * Logger for this class
  112. */
  113. private static final Logger LOGGER = Logger.getLogger( PdfMapper.class.getName() );
  114. private final OutputStream out;
  115. // Instance of PDF document
  116. private StylableDocument pdfDocument;
  117. private Font currentRunFontAscii;
  118. private Font currentRunFontEastAsia;
  119. private Font currentRunFontHAnsi;
  120. private UnderlinePatterns currentRunUnderlinePatterns;
  121. private Color currentRunBackgroundColor;
  122. private Float currentRunX;
  123. private Float currentPageWidth;
  124. private StylableHeaderFooter pdfHeader;
  125. private StylableHeaderFooter pdfFooter;
  126. public PdfMapper( XWPFDocument document, OutputStream out, PdfOptions options )
  127. throws Exception
  128. {
  129. super( document, options != null ? options : PdfOptions.getDefault() );
  130. this.out = out;
  131. }
  132. // ------------------------- Document
  133. @Override
  134. protected IITextContainer startVisitDocument()
  135. throws Exception
  136. {
  137. // Create instance of PDF document
  138. this.pdfDocument = new StylableDocument( out );
  139. this.pdfDocument.setMasterPageManager( getMasterPageManager() );
  140. return pdfDocument;
  141. }
  142. @Override
  143. protected void endVisitDocument()
  144. throws Exception
  145. {
  146. pdfDocument.close();
  147. out.close();
  148. }
  149. // ------------------------- Header/Footer
  150. @Override
  151. protected void visitHeader( XWPFHeader header, CTHdrFtrRef headerRef, CTSectPr sectPr, StylableMasterPage masterPage )
  152. throws Exception
  153. {
  154. BigInteger headerY = sectPr.getPgMar() != null ? sectPr.getPgMar().getHeader() : null;
  155. this.currentPageWidth = sectPr.getPgMar() != null ? DxaUtil.dxa2points( sectPr.getPgSz().getW() ) : null;
  156. this.pdfHeader = new StylableHeaderFooter( pdfDocument, headerY, true );
  157. // List<IBodyElement> bodyElements = header.getBodyElements();
  158. List<IBodyElement> bodyElements = super.getBodyElements( header );
  159. StylableTableCell tableCell = getHeaderFooterTableCell( pdfHeader, bodyElements );
  160. visitBodyElements( bodyElements, tableCell );
  161. masterPage.setHeader( pdfHeader );
  162. this.currentPageWidth = null;
  163. this.pdfHeader = null;
  164. }
  165. @Override
  166. protected void visitFooter( XWPFFooter footer, CTHdrFtrRef footerRef, CTSectPr sectPr, StylableMasterPage masterPage )
  167. throws Exception
  168. {
  169. BigInteger footerY = sectPr.getPgMar() != null ? sectPr.getPgMar().getFooter() : null;
  170. this.currentPageWidth = sectPr.getPgMar() != null ? DxaUtil.dxa2points( sectPr.getPgSz().getW() ) : null;
  171. this.pdfFooter = new StylableHeaderFooter( pdfDocument, footerY, false );
  172. List<IBodyElement> bodyElements = super.getBodyElements( footer );
  173. StylableTableCell tableCell = getHeaderFooterTableCell( pdfFooter, bodyElements );
  174. visitBodyElements( bodyElements, tableCell );
  175. masterPage.setFooter( pdfFooter );
  176. this.currentPageWidth = null;
  177. this.pdfFooter = null;
  178. }
  179. private StylableTableCell getHeaderFooterTableCell( StylableHeaderFooter pdfHeaderFooter,
  180. List<IBodyElement> bodyElements )
  181. throws DocumentException
  182. {
  183. return pdfHeaderFooter.getTableCell();
  184. }
  185. @Override
  186. protected void setActiveMasterPage( StylableMasterPage masterPage )
  187. {
  188. pdfDocument.setActiveMasterPage( masterPage );
  189. }
  190. @Override
  191. protected IXWPFMasterPage createMasterPage( CTSectPr sectPr )
  192. {
  193. return new StylableMasterPage( sectPr );
  194. }
  195. // ------------------------- Paragraph
  196. @Override
  197. protected IITextContainer startVisitParagraph( XWPFParagraph docxParagraph, ListItemContext itemContext,
  198. IITextContainer pdfParentContainer )
  199. throws Exception
  200. {
  201. this.currentRunX = null;
  202. // create PDF paragraph
  203. StylableParagraph pdfParagraph = pdfDocument.createParagraph( pdfParentContainer );
  204. // indentation left
  205. Float indentationLeft = stylesDocument.getIndentationLeft( docxParagraph );
  206. if ( indentationLeft != null )
  207. {
  208. pdfParagraph.setIndentationLeft( indentationLeft );
  209. }
  210. // indentation right
  211. Float indentationRight = stylesDocument.getIndentationRight( docxParagraph );
  212. if ( indentationRight != null )
  213. {
  214. pdfParagraph.setIndentationRight( indentationRight );
  215. }
  216. // indentation first line
  217. Float indentationFirstLine = stylesDocument.getIndentationFirstLine( docxParagraph );
  218. if ( indentationFirstLine != null )
  219. {
  220. pdfParagraph.setFirstLineIndent( indentationFirstLine );
  221. }
  222. // indentation hanging (remove first line)
  223. Float indentationHanging = stylesDocument.getIndentationHanging( docxParagraph );
  224. if ( indentationHanging != null )
  225. {
  226. pdfParagraph.setFirstLineIndent( -indentationHanging );
  227. }
  228. // // spacing before
  229. Float spacingBefore = stylesDocument.getSpacingBefore( docxParagraph );
  230. if ( spacingBefore != null )
  231. {
  232. pdfParagraph.setSpacingBefore( spacingBefore );
  233. }
  234. // spacing after
  235. Float spacingAfter = stylesDocument.getSpacingAfter( docxParagraph );
  236. if ( spacingAfter != null )
  237. {
  238. pdfParagraph.setSpacingAfter( spacingAfter );
  239. }
  240. ParagraphLineSpacing lineSpacing = stylesDocument.getParagraphSpacing( docxParagraph );
  241. if ( lineSpacing != null )
  242. {
  243. if ( lineSpacing.getLeading() != null && lineSpacing.getMultipleLeading() != null )
  244. {
  245. pdfParagraph.setLeading( lineSpacing.getLeading(), lineSpacing.getMultipleLeading() );
  246. }
  247. else
  248. {
  249. if ( lineSpacing.getLeading() != null )
  250. {
  251. pdfParagraph.setLeading( lineSpacing.getLeading() );
  252. }
  253. if ( lineSpacing.getMultipleLeading() != null )
  254. {
  255. pdfParagraph.setMultipliedLeading( lineSpacing.getMultipleLeading() );
  256. }
  257. }
  258. }
  259. // text-align
  260. ParagraphAlignment alignment = stylesDocument.getParagraphAlignment( docxParagraph );
  261. if ( alignment != null )
  262. {
  263. switch ( alignment )
  264. {
  265. case LEFT:
  266. pdfParagraph.setAlignment( Element.ALIGN_LEFT );
  267. break;
  268. case RIGHT:
  269. pdfParagraph.setAlignment( Element.ALIGN_RIGHT );
  270. break;
  271. case CENTER:
  272. pdfParagraph.setAlignment( Element.ALIGN_CENTER );
  273. break;
  274. case BOTH:
  275. pdfParagraph.setAlignment( Element.ALIGN_JUSTIFIED );
  276. break;
  277. default:
  278. break;
  279. }
  280. }
  281. // background-color
  282. Color backgroundColor = stylesDocument.getBackgroundColor( docxParagraph );
  283. if ( backgroundColor != null )
  284. {
  285. pdfParagraph.setBackgroundColor( backgroundColor );
  286. }
  287. // border
  288. CTBorder borderTop = stylesDocument.getBorderTop( docxParagraph );
  289. pdfParagraph.setBorder( borderTop, Rectangle.TOP );
  290. CTBorder borderBottom = stylesDocument.getBorderBottom( docxParagraph );
  291. pdfParagraph.setBorder( borderBottom, Rectangle.BOTTOM );
  292. CTBorder borderLeft = stylesDocument.getBorderLeft( docxParagraph );
  293. pdfParagraph.setBorder( borderLeft, Rectangle.LEFT );
  294. CTBorder borderRight = stylesDocument.getBorderRight( docxParagraph );
  295. pdfParagraph.setBorder( borderRight, Rectangle.RIGHT );
  296. if ( itemContext != null )
  297. {
  298. CTLvl lvl = itemContext.getLvl();
  299. CTPPr lvlPPr = lvl.getPPr();
  300. if ( lvlPPr != null )
  301. {
  302. if ( ParagraphIndentationLeftValueProvider.INSTANCE.getValue( docxParagraph.getCTP().getPPr() ) == null )
  303. {
  304. // search the indentation from the level properties only if paragraph has not override it
  305. // see https://code.google.com/p/xdocreport/issues/detail?id=239
  306. Float indLeft = ParagraphIndentationLeftValueProvider.INSTANCE.getValue( lvlPPr );
  307. if ( indLeft != null )
  308. {
  309. pdfParagraph.setIndentationLeft( indLeft );
  310. }
  311. }
  312. if ( ParagraphIndentationHangingValueProvider.INSTANCE.getValue( docxParagraph.getCTP().getPPr() ) == null )
  313. {
  314. // search the hanging from the level properties only if paragraph has not override it
  315. // see https://code.google.com/p/xdocreport/issues/detail?id=239
  316. Float hanging = stylesDocument.getIndentationHanging( lvlPPr );
  317. if ( hanging != null )
  318. {
  319. pdfParagraph.setFirstLineIndent( -hanging );
  320. }
  321. }
  322. }
  323. CTRPr lvlRPr = lvl.getRPr();
  324. if ( lvlRPr != null )
  325. {
  326. // Font family
  327. String listItemFontFamily = stylesDocument.getFontFamilyAscii( lvlRPr );
  328. // Get font size
  329. Float listItemFontSize = stylesDocument.getFontSize( lvlRPr );
  330. // Get font style
  331. int listItemFontStyle = Font.NORMAL;
  332. Boolean bold = stylesDocument.getFontStyleBold( lvlRPr );
  333. if ( bold != null && bold )
  334. {
  335. listItemFontStyle |= Font.BOLD;
  336. }
  337. Boolean italic = stylesDocument.getFontStyleItalic( lvlRPr );
  338. if ( italic != null && italic )
  339. {
  340. listItemFontStyle |= Font.ITALIC;
  341. }
  342. Boolean strike = stylesDocument.getFontStyleStrike( lvlRPr );
  343. if ( strike != null && strike )
  344. {
  345. listItemFontStyle |= Font.STRIKETHRU;
  346. }
  347. // Font color
  348. Color listItemFontColor = stylesDocument.getFontColor( lvlRPr );
  349. pdfParagraph.setListItemFontFamily( listItemFontFamily );
  350. pdfParagraph.setListItemFontSize( listItemFontSize );
  351. pdfParagraph.setListItemFontStyle( listItemFontStyle );
  352. pdfParagraph.setListItemFontColor( listItemFontColor );
  353. }
  354. pdfParagraph.setListItemText( itemContext.getText() );
  355. }
  356. return pdfParagraph;
  357. }
  358. @Override
  359. protected void endVisitParagraph( XWPFParagraph docxParagraph, IITextContainer pdfParentContainer,
  360. IITextContainer pdfParagraphContainer )
  361. throws Exception
  362. {
  363. // add the iText paragraph in the current parent container.
  364. ExtendedParagraph pdfParagraph = (ExtendedParagraph) pdfParagraphContainer;
  365. pdfParentContainer.addElement( pdfParagraph.getElement() );
  366. this.currentRunX = null;
  367. }
  368. // ------------------------- Run
  369. @Override
  370. protected void visitEmptyRun( IITextContainer pdfParagraphContainer )
  371. throws Exception
  372. {
  373. StylableParagraph paragraph = (StylableParagraph) pdfParagraphContainer;
  374. IITextContainer parent = paragraph.getParent();
  375. if ( parent instanceof StylableTableCell )
  376. {
  377. StylableTableCell cell = (StylableTableCell) parent;
  378. if ( cell.getRotation() > 0 )
  379. {
  380. // Run paragraph belongs to Cell which has rotation, ignore the empty run.
  381. return;
  382. }
  383. }
  384. // Add new PDF line
  385. pdfParagraphContainer.addElement( Chunk.NEWLINE );
  386. }
  387. @Override
  388. protected void visitRun( XWPFRun docxRun, boolean pageNumber, String url, IITextContainer pdfParagraphContainer )
  389. throws Exception
  390. {
  391. // Font family
  392. String fontFamilyAscii = stylesDocument.getFontFamilyAscii( docxRun );
  393. String fontFamilyEastAsia = stylesDocument.getFontFamilyEastAsia( docxRun );
  394. String fontFamilyHAnsi = stylesDocument.getFontFamilyHAnsi( docxRun );
  395. // Get font size
  396. Float fontSize = stylesDocument.getFontSize( docxRun );
  397. if ( fontSize == null )
  398. {
  399. fontSize = -1f;
  400. }
  401. // Get font style
  402. int fontStyle = Font.NORMAL;
  403. Boolean bold = stylesDocument.getFontStyleBold( docxRun );
  404. if ( bold != null && bold )
  405. {
  406. fontStyle |= Font.BOLD;
  407. }
  408. Boolean italic = stylesDocument.getFontStyleItalic( docxRun );
  409. if ( italic != null && italic )
  410. {
  411. fontStyle |= Font.ITALIC;
  412. }
  413. Boolean strike = stylesDocument.getFontStyleStrike( docxRun );
  414. if ( strike != null && strike )
  415. {
  416. fontStyle |= Font.STRIKETHRU;
  417. }
  418. // Font color
  419. Color fontColor = stylesDocument.getFontColor( docxRun );
  420. // Font
  421. this.currentRunFontAscii = getFont( fontFamilyAscii, fontSize, fontStyle, fontColor );
  422. this.currentRunFontEastAsia = getFont( fontFamilyEastAsia, fontSize, fontStyle, fontColor );
  423. this.currentRunFontHAnsi = getFont( fontFamilyHAnsi, fontSize, fontStyle, fontColor );
  424. // Underline patterns
  425. this.currentRunUnderlinePatterns = stylesDocument.getUnderline( docxRun );
  426. // background color
  427. this.currentRunBackgroundColor = stylesDocument.getBackgroundColor( docxRun );
  428. // highlight
  429. if ( currentRunBackgroundColor == null )
  430. {
  431. this.currentRunBackgroundColor = stylesDocument.getTextHighlighting( docxRun );
  432. }
  433. StylableParagraph pdfParagraph = (StylableParagraph) pdfParagraphContainer;
  434. pdfParagraph.adjustMultipliedLeading( currentRunFontAscii );
  435. // addd symbol list item chunk if needed.
  436. String listItemText = pdfParagraph.getListItemText();
  437. if ( StringUtils.isNotEmpty( listItemText ) )
  438. {
  439. // FIXME: add some space after the list item
  440. listItemText += " ";
  441. String listItemFontFamily = pdfParagraph.getListItemFontFamily();
  442. Float listItemFontSize = pdfParagraph.getListItemFontSize();
  443. int listItemFontStyle = pdfParagraph.getListItemFontStyle();
  444. Color listItemFontColor = pdfParagraph.getListItemFontColor();
  445. Font listItemFont =
  446. options.getFontProvider().getFont( listItemFontFamily != null ? listItemFontFamily : fontFamilyAscii,
  447. options.getFontEncoding(),
  448. listItemFontSize != null ? listItemFontSize : fontSize,
  449. listItemFontStyle != Font.NORMAL ? listItemFontStyle : fontStyle,
  450. listItemFontColor != null ? listItemFontColor : fontColor );
  451. Chunk symbol =
  452. createTextChunk( listItemText, false, listItemFont, currentRunUnderlinePatterns,
  453. currentRunBackgroundColor );
  454. pdfParagraph.add( symbol );
  455. pdfParagraph.setListItemText( null );
  456. }
  457. IITextContainer container = pdfParagraphContainer;
  458. if ( url != null )
  459. {
  460. // URL is not null, generate a PDF hyperlink.
  461. StylableAnchor pdfAnchor = new StylableAnchor();
  462. pdfAnchor.setReference( url );
  463. pdfAnchor.setITextContainer( container );
  464. container = pdfAnchor;
  465. }
  466. super.visitRun( docxRun, pageNumber, url, container );
  467. if ( url != null )
  468. {
  469. // URL is not null, add the PDF hyperlink in the PDF paragraph
  470. pdfParagraphContainer.addElement( (StylableAnchor) container );
  471. }
  472. this.currentRunFontAscii = null;
  473. this.currentRunFontEastAsia = null;
  474. this.currentRunFontHAnsi = null;
  475. this.currentRunUnderlinePatterns = null;
  476. this.currentRunBackgroundColor = null;
  477. }
  478. private Font getFont( String fontFamily, Float fontSize, int fontStyle, Color fontColor )
  479. {
  480. String fontToUse = stylesDocument.getFontNameToUse( fontFamily );
  481. if ( StringUtils.isNotEmpty( fontToUse ) )
  482. {
  483. return options.getFontProvider().getFont( fontToUse, options.getFontEncoding(), fontSize, fontStyle,
  484. fontColor );
  485. }
  486. Font font =
  487. options.getFontProvider().getFont( fontFamily, options.getFontEncoding(), fontSize, fontStyle, fontColor );
  488. if ( !isFontExists( font ) )
  489. {
  490. // font is not found
  491. try
  492. {
  493. List<String> altNames = stylesDocument.getFontsAltName( fontFamily );
  494. if ( altNames != null )
  495. {
  496. // Loop for each alternative names font (from the fontTable.xml) to find the well font.
  497. for ( String altName : altNames )
  498. {
  499. font = getFont( altName, fontSize, fontStyle, fontColor );
  500. if ( isFontExists( font ) )
  501. {
  502. stylesDocument.setFontNameToUse( fontFamily, altName );
  503. return font;
  504. }
  505. }
  506. }
  507. }
  508. catch ( Exception e )
  509. {
  510. LOGGER.severe( e.getMessage() );
  511. }
  512. }
  513. return font;
  514. }
  515. /**
  516. * Returns true if the iText font exists and false otherwise.
  517. *
  518. * @param font
  519. * @return
  520. */
  521. private boolean isFontExists( Font font )
  522. {
  523. // FIXME : is it like this to test that font exists?
  524. return font != null && font.getBaseFont() != null;
  525. }
  526. @Override
  527. protected void visitText( CTText docxText, boolean pageNumber, IITextContainer pdfParagraphContainer )
  528. throws Exception
  529. {
  530. Font font = currentRunFontAscii;
  531. Font fontAsian = currentRunFontEastAsia;
  532. Font fontComplex = currentRunFontHAnsi;
  533. createAndAddChunks( pdfParagraphContainer, docxText.getStringValue(), currentRunUnderlinePatterns,
  534. currentRunBackgroundColor, pageNumber, font, fontAsian, fontComplex );
  535. }
  536. private Chunk createTextChunk( String text, boolean pageNumber, Font currentRunFont,
  537. UnderlinePatterns currentRunUnderlinePatterns, Color currentRunBackgroundColor )
  538. {
  539. Chunk textChunk =
  540. pageNumber ? new ExtendedChunk( pdfDocument, true, currentRunFont ) : new Chunk( text, currentRunFont );
  541. if ( currentRunUnderlinePatterns != null )
  542. {
  543. // underlined
  544. boolean singleUnderlined = false;
  545. switch ( currentRunUnderlinePatterns )
  546. {
  547. case SINGLE:
  548. singleUnderlined = true;
  549. break;
  550. default:
  551. break;
  552. }
  553. if ( singleUnderlined )
  554. {
  555. textChunk.setUnderline( 1, -2 );
  556. }
  557. }
  558. // background color
  559. if ( currentRunBackgroundColor != null )
  560. {
  561. textChunk.setBackground( currentRunBackgroundColor );
  562. }
  563. if ( currentRunX != null )
  564. {
  565. this.currentRunX += textChunk.getWidthPoint();
  566. }
  567. return textChunk;
  568. }
  569. private void createAndAddChunks( IITextContainer parent, String textContent, UnderlinePatterns underlinePatterns,
  570. Color backgroundColor, boolean pageNumber, Font font, Font fontAsian,
  571. Font fontComplex )
  572. {
  573. StringBuilder sbuf = new StringBuilder();
  574. FontGroup currentGroup = FontGroup.WESTERN;
  575. for ( int i = 0; i < textContent.length(); i++ )
  576. {
  577. char ch = textContent.charAt( i );
  578. FontGroup group = FontGroup.getUnicodeGroup( ch, font, fontAsian, fontComplex );
  579. if ( sbuf.length() == 0 || currentGroup.equals( group ) )
  580. {
  581. // continue current chunk
  582. sbuf.append( ch );
  583. }
  584. else
  585. {
  586. // end chunk
  587. Font chunkFont = getFont( font, fontAsian, fontComplex, currentGroup );
  588. Chunk chunk =
  589. createTextChunk( sbuf.toString(), pageNumber, chunkFont, underlinePatterns, backgroundColor );
  590. parent.addElement( chunk );
  591. // start new chunk
  592. sbuf.setLength( 0 );
  593. sbuf.append( ch );
  594. }
  595. currentGroup = group;
  596. }
  597. // end chunk
  598. Font chunkFont = getFont( font, fontAsian, fontComplex, currentGroup );
  599. Chunk chunk = createTextChunk( sbuf.toString(), pageNumber, chunkFont, underlinePatterns, backgroundColor );
  600. parent.addElement( chunk );
  601. }
  602. private Font getFont( Font font, Font fontAsian, Font fontComplex, FontGroup group )
  603. {
  604. switch ( group )
  605. {
  606. case WESTERN:
  607. return font;
  608. case ASIAN:
  609. return fontAsian;
  610. case COMPLEX:
  611. return fontComplex;
  612. }
  613. return font;
  614. }
  615. @Override
  616. protected void visitTab( CTPTab tab, IITextContainer pdfParagraphContainer )
  617. throws Exception
  618. {
  619. // TODO manage this case.
  620. //
  621. // if ( tab == null )
  622. // {
  623. // float defaultTabStop = stylesDocument.getDefaultTabStop();
  624. // Chunk pdfTab = new Chunk( new VerticalPositionMark(), defaultTabStop, false );
  625. // pdfParagraphContainer.addElement( pdfTab );
  626. // }
  627. // else
  628. // {
  629. // Chunk pdfTab = new Chunk( new VerticalPositionMark() );
  630. // pdfParagraphContainer.addElement( pdfTab );
  631. // }
  632. }
  633. @Override
  634. protected void visitTabs( CTTabs tabs, IITextContainer pdfParagraphContainer )
  635. throws Exception
  636. {
  637. if ( currentRunX == null )
  638. {
  639. Paragraph paragraph = null;
  640. if ( pdfParagraphContainer instanceof Paragraph )
  641. {
  642. paragraph = (Paragraph) pdfParagraphContainer;
  643. }
  644. else
  645. {
  646. paragraph = (Paragraph) ( (StylableAnchor) pdfParagraphContainer ).getITextContainer();
  647. }
  648. currentRunX = paragraph.getFirstLineIndent();
  649. List<Chunk> chunks = paragraph.getChunks();
  650. for ( Chunk chunk : chunks )
  651. {
  652. currentRunX += chunk.getWidthPoint();
  653. }
  654. }
  655. else
  656. {
  657. if ( currentRunX >= pdfDocument.getPageWidth() )
  658. {
  659. currentRunX = 0f;
  660. }
  661. }
  662. Float tabPosition = null;
  663. STTabTlc.Enum tabLeader = null;
  664. STTabJc.Enum tabVal = null;
  665. boolean useDefaultTabStop = false;
  666. if ( tabs != null )
  667. {
  668. List<CTTabStop> tabList = tabs.getTabList();
  669. CTTabStop tabStop = getTabStop( tabList );
  670. if ( tabStop != null )
  671. {
  672. float lastX = DxaUtil.dxa2points( tabStop.getPos().floatValue() );
  673. if ( lastX > currentRunX )
  674. {
  675. tabPosition = lastX;
  676. tabLeader = tabStop.getLeader();
  677. tabVal = tabStop.getVal();
  678. }
  679. else
  680. {
  681. useDefaultTabStop = true;
  682. }
  683. }
  684. }
  685. if ( tabs == null || useDefaultTabStop )
  686. {
  687. // default tab
  688. float defaultTabStop = stylesDocument.getDefaultTabStop();
  689. float pageWidth = pdfDocument.getPageWidth();
  690. int nbInterval = (int) ( pageWidth / defaultTabStop );
  691. Float lastX = getTabStopPosition( currentRunX, defaultTabStop, nbInterval );
  692. if ( lastX != null )
  693. {
  694. tabPosition = lastX;
  695. }
  696. }
  697. if ( tabPosition != null )
  698. {
  699. currentRunX = tabPosition;
  700. // tab leader : Specifies the character which shall be used to fill in the space created by a tab
  701. // which
  702. // ends
  703. // at this custom tab stop. This character shall be repeated as required to completely fill the
  704. // tab spacing generated by the tab character.
  705. VerticalPositionMark mark = createVerticalPositionMark( tabLeader );
  706. Chunk pdfTab = null;
  707. if ( STTabJc.RIGHT.equals( tabVal ) )
  708. {
  709. pdfTab = new Chunk( mark );
  710. }
  711. else
  712. {
  713. pdfTab = new Chunk( mark, currentRunX );
  714. }
  715. pdfParagraphContainer.addElement( pdfTab );
  716. }
  717. }
  718. private Float getTabStopPosition( float currentPosition, float interval, int nbInterval )
  719. {
  720. Float nextPosition = null;
  721. float newPosition = 0f;
  722. for ( int i = 1; i < nbInterval; i++ )
  723. {
  724. newPosition = interval * i;
  725. if ( currentPosition < newPosition )
  726. {
  727. nextPosition = newPosition;
  728. break;
  729. }
  730. }
  731. return nextPosition;
  732. }
  733. private VerticalPositionMark createVerticalPositionMark( org.openxmlformats.schemas.wordprocessingml.x2006.main.STTabTlc.Enum leader )
  734. {
  735. if ( leader != null )
  736. {
  737. if ( leader == STTabTlc.DOT )
  738. {
  739. return new DottedLineSeparator();
  740. }
  741. else if ( leader == STTabTlc.UNDERSCORE )
  742. {
  743. return new LineSeparator();
  744. }
  745. }
  746. return new VerticalPositionMark();
  747. }
  748. private CTTabStop getTabStop( List<CTTabStop> tabList )
  749. {
  750. if ( tabList.size() == 1 )
  751. {
  752. CTTabStop tabStop = tabList.get( 0 );
  753. if ( isClearTab( tabStop ) )
  754. {
  755. return null;
  756. }
  757. return tabStop;
  758. }
  759. CTTabStop selectedTabStop = null;
  760. for ( CTTabStop tabStop : tabList )
  761. {
  762. if ( isClearTab( tabStop ) )
  763. {
  764. continue;
  765. }
  766. if ( canApplyTabStop( tabStop ) )
  767. {
  768. return tabStop;
  769. }
  770. //
  771. // if ( selectedTabStop == null )
  772. // {
  773. // selectedTabStop = tabStop;
  774. // }
  775. // else
  776. // {
  777. // if ( tabStop.getPos().floatValue() > selectedTabStop.getPos().floatValue() )
  778. // {
  779. // selectedTabStop = tabStop;
  780. // }
  781. // }
  782. }
  783. // TODO : retrieve the well tab stop according the current width of the line.
  784. return null;
  785. }
  786. private boolean canApplyTabStop( CTTabStop tabStop )
  787. {
  788. if ( tabStop.getVal().equals( STTabJc.LEFT ) )
  789. {
  790. if ( currentRunX < DxaUtil.dxa2points( tabStop.getPos().floatValue() ) )
  791. {
  792. return true;
  793. }
  794. }
  795. else if ( tabStop.getVal().equals( STTabJc.RIGHT ) )
  796. {
  797. if ( isWordDocumentPartParsing() )
  798. {
  799. if ( pdfDocument.getWidthLimit() - ( currentRunX + DxaUtil.dxa2points( tabStop.getPos().floatValue() ) ) <= 0 )
  800. {
  801. return true;
  802. }
  803. }
  804. else
  805. {
  806. if ( currentPageWidth == null )
  807. {
  808. return true;
  809. }
  810. if ( currentPageWidth.floatValue()
  811. - ( currentRunX + DxaUtil.dxa2points( tabStop.getPos().floatValue() ) ) <= 0 )
  812. {
  813. return true;
  814. }
  815. }
  816. }
  817. else if ( tabStop.getVal().equals( STTabJc.CENTER ) )
  818. {
  819. }
  820. return false;
  821. }
  822. private boolean isClearTab( CTTabStop tabStop )
  823. {
  824. org.openxmlformats.schemas.wordprocessingml.x2006.main.STTabJc.Enum tabVal = tabStop.getVal();
  825. if ( tabVal != null )
  826. {
  827. if ( tabVal.equals( STTabJc.CLEAR ) )
  828. {
  829. // Specifies that the current tab stop is cleared and shall be removed and ignored when processing
  830. // the contents of this document
  831. return true;
  832. }
  833. }
  834. return false;
  835. }
  836. @Override
  837. protected void addNewLine( CTBr br, IITextContainer pdfParagraphContainer )
  838. throws Exception
  839. {
  840. pdfParagraphContainer.addElement( Chunk.NEWLINE );
  841. }
  842. @Override
  843. protected void visitBR( CTBr br, IITextContainer paragraphContainer )
  844. throws Exception
  845. {
  846. currentRunX = 0f;
  847. super.visitBR( br, paragraphContainer );
  848. }
  849. @Override
  850. protected void pageBreak()
  851. throws Exception
  852. {
  853. pdfDocument.pageBreak();
  854. }
  855. @Override
  856. protected void visitBookmark( CTBookmark bookmark, XWPFParagraph paragraph, IITextContainer paragraphContainer )
  857. throws Exception
  858. {
  859. // destination for a local anchor
  860. // chunk with empty text does not work as local anchor
  861. // so we create chunk with invisible but not empty text content
  862. // if bookmark is the last chunk in a paragraph something must be added after or it does not work
  863. Chunk chunk = new Chunk( TAB );
  864. chunk.setLocalDestination( bookmark.getName() );
  865. paragraphContainer.addElement( chunk );
  866. }
  867. // ----------------- Table
  868. @Override
  869. protected IITextContainer startVisitTable( XWPFTable table, float[] colWidths, IITextContainer pdfParentContainer )
  870. throws Exception
  871. {
  872. StylableTable pdfPTable = createPDFTable( table, colWidths, pdfParentContainer );
  873. return pdfPTable;
  874. }
  875. private StylableTable createPDFTable( XWPFTable table, float[] colWidths, IITextContainer pdfParentContainer )
  876. throws DocumentException
  877. {
  878. // 2) Compute tableWith
  879. TableWidth tableWidth = stylesDocument.getTableWidth( table );
  880. StylableTable pdfPTable = pdfDocument.createTable( pdfParentContainer, colWidths.length );
  881. pdfPTable.setTotalWidth( colWidths );
  882. if ( tableWidth != null && tableWidth.width > 0 )
  883. {
  884. if ( tableWidth.percentUnit )
  885. {
  886. pdfPTable.setWidthPercentage( tableWidth.width );
  887. }
  888. else
  889. {
  890. pdfPTable.setTotalWidth( tableWidth.width );
  891. }
  892. }
  893. pdfPTable.setLockedWidth( true );
  894. // Table alignment
  895. ParagraphAlignment alignment = stylesDocument.getTableAlignment( table );
  896. if ( alignment != null )
  897. {
  898. switch ( alignment )
  899. {
  900. case LEFT:
  901. pdfPTable.setHorizontalAlignment( Element.ALIGN_LEFT );
  902. break;
  903. case RIGHT:
  904. pdfPTable.setHorizontalAlignment( Element.ALIGN_RIGHT );
  905. break;
  906. case CENTER:
  907. pdfPTable.setHorizontalAlignment( Element.ALIGN_CENTER );
  908. break;
  909. case BOTH:
  910. pdfPTable.setHorizontalAlignment( Element.ALIGN_JUSTIFIED );
  911. break;
  912. default:
  913. break;
  914. }
  915. }
  916. // Table indentation
  917. Float indentation = stylesDocument.getTableIndentation( table );
  918. if ( indentation != null )
  919. {
  920. pdfPTable.setPaddingLeft( indentation );
  921. }
  922. return pdfPTable;
  923. }
  924. @Override
  925. protected void endVisitTable( XWPFTable table, IITextContainer pdfParentContainer, IITextContainer pdfTableContainer )
  926. throws Exception
  927. {
  928. pdfParentContainer.addElement( ( (ExtendedPdfPTable) pdfTableContainer ).getElement() );
  929. }
  930. // ------------------------- Table Row
  931. @Override
  932. protected void startVisitTableRow( XWPFTableRow row, IITextContainer tableContainer, int rowIndex, boolean headerRow )
  933. throws Exception
  934. {
  935. if ( headerRow )
  936. {
  937. PdfPTable table = (PdfPTable) tableContainer;
  938. table.setHeaderRows( table.getHeaderRows() + 1 );
  939. }
  940. super.startVisitTableRow( row, tableContainer, rowIndex, headerRow );
  941. }
  942. // ------------------------- Table Cell
  943. @Override
  944. protected IITextContainer startVisitTableCell( final XWPFTableCell cell, IITextContainer pdfTableContainer,
  945. boolean firstRow, boolean lastRow, boolean firstCol,
  946. boolean lastCol, List<XWPFTableCell> vMergeCells )
  947. throws Exception
  948. {
  949. XWPFTableRow row = cell.getTableRow();
  950. XWPFTable table = row.getTable();
  951. // 1) store table cell info
  952. stylesDocument.getTableInfo( table ).addCellInfo( cell, firstRow, lastRow, firstCol, lastCol );
  953. // 2) create PDF cell
  954. StylableTable pdfPTable = (StylableTable) pdfTableContainer;
  955. StylableTableCell pdfPCell = pdfDocument.createTableCell( pdfPTable );
  956. // pdfPCell.setUseAscender( true );
  957. // pdfPCell.setUseDescender( true );
  958. XWPFTableCell lastVMergedCell = null;
  959. if ( vMergeCells != null )
  960. {
  961. pdfPCell.setRowspan( vMergeCells.size() );
  962. lastVMergedCell = vMergeCells.get( vMergeCells.size() - 1 );
  963. stylesDocument.getTableInfo( table ).addCellInfo( lastVMergedCell, false, lastRow, firstCol, lastCol );
  964. }
  965. // border-top
  966. TableCellBorder borderTop = stylesDocument.getTableCellBorderWithConflicts( cell, BorderSide.TOP );
  967. if ( borderTop != null )
  968. {
  969. boolean borderTopInside = stylesDocument.isBorderInside( cell, BorderSide.TOP );
  970. if ( borderTopInside )
  971. {
  972. // Manage conflict border with the adjacent border bottom
  973. }
  974. }
  975. pdfPCell.setBorderTop( borderTop, false );
  976. // border-bottom
  977. XWPFTableCell theCell = lastVMergedCell != null ? lastVMergedCell : cell;
  978. TableCellBorder borderBottom = stylesDocument.getTableCellBorderWithConflicts( theCell, BorderSide.BOTTOM );
  979. pdfPCell.setBorderBottom( borderBottom, stylesDocument.isBorderInside( theCell, BorderSide.BOTTOM ) );
  980. // border-left
  981. TableCellBorder borderLeft = stylesDocument.getTableCellBorderWithConflicts( cell, BorderSide.LEFT );
  982. pdfPCell.setBorderLeft( borderLeft, stylesDocument.isBorderInside( cell, BorderSide.LEFT ) );
  983. // border-right
  984. TableCellBorder borderRight = stylesDocument.getTableCellBorderWithConflicts( cell, BorderSide.RIGHT );
  985. pdfPCell.setBorderRight( borderRight, stylesDocument.isBorderInside( cell, BorderSide.RIGHT ) );
  986. // Text direction <w:textDirection
  987. CTTextDirection direction = stylesDocument.getTextDirection( cell );
  988. if ( direction != null )
  989. {
  990. int dir = direction.getVal().intValue();
  991. switch ( dir )
  992. {
  993. case STTextDirection.INT_BT_LR:
  994. pdfPCell.setRotation( 90 );
  995. break;
  996. case STTextDirection.INT_TB_RL:
  997. pdfPCell.setRotation( 270 );
  998. break;
  999. }
  1000. }
  1001. // Colspan
  1002. BigInteger gridSpan = stylesDocument.getTableCellGridSpan( cell );
  1003. if ( gridSpan != null )
  1004. {
  1005. pdfPCell.setColspan( gridSpan.intValue() );
  1006. }
  1007. // Background Color
  1008. Color backgroundColor = stylesDocument.getTableCellBackgroundColor( cell );
  1009. if ( backgroundColor != null )
  1010. {
  1011. pdfPCell.setBackgroundColor( backgroundColor );
  1012. }
  1013. // Vertical aligment
  1014. Enum jc = stylesDocument.getTableCellVerticalAlignment( cell );
  1015. if ( jc != null )
  1016. {
  1017. switch ( jc.intValue() )
  1018. {
  1019. case STVerticalJc.INT_BOTTOM:
  1020. pdfPCell.setVerticalAlignment( Element.ALIGN_BOTTOM );
  1021. break;
  1022. case STVerticalJc.INT_CENTER:
  1023. pdfPCell.setVerticalAlignment( Element.ALIGN_MIDDLE );
  1024. break;
  1025. case STVerticalJc.INT_TOP:
  1026. pdfPCell.setVerticalAlignment( Element.ALIGN_TOP );
  1027. break;
  1028. }
  1029. }
  1030. // Cell margin
  1031. Float marginTop = stylesDocument.getTableCellMarginTop( cell );
  1032. if ( marginTop == null )
  1033. {
  1034. marginTop = stylesDocument.getTableRowMarginTop( row );
  1035. if ( marginTop == null )
  1036. {
  1037. marginTop = stylesDocument.getTableMarginTop( table );
  1038. }
  1039. }
  1040. if ( marginTop != null )
  1041. {
  1042. pdfPCell.setPaddingTop( marginTop );
  1043. }
  1044. Float marginBottom = stylesDocument.getTableCellMarginBottom( cell );
  1045. if ( marginBottom == null )
  1046. {
  1047. marginBottom = stylesDocument.getTableRowMarginBottom( row );
  1048. if ( marginBottom == null )
  1049. {
  1050. marginBottom = stylesDocument.getTableMarginBottom( table );
  1051. }
  1052. }
  1053. if ( marginBottom != null && marginBottom > 0 )
  1054. {
  1055. pdfPCell.setPaddingBottom( marginBottom );
  1056. }
  1057. Float marginLeft = stylesDocument.getTableCellMarginLeft( cell );
  1058. if ( marginLeft == null )
  1059. {
  1060. marginLeft = stylesDocument.getTableRowMarginLeft( row );
  1061. if ( marginLeft == null )
  1062. {
  1063. marginLeft = stylesDocument.getTableMarginLeft( table );
  1064. }
  1065. }
  1066. if ( marginLeft != null )
  1067. {
  1068. pdfPCell.setPaddingLeft( marginLeft );
  1069. }
  1070. Float marginRight = stylesDocument.getTableCellMarginRight( cell );
  1071. if ( marginRight == null )
  1072. {
  1073. marginRight = stylesDocument.getTableRowMarginRight( row );
  1074. if ( marginRight == null )
  1075. {
  1076. marginRight = stylesDocument.getTableMarginRight( table );
  1077. }
  1078. }
  1079. if ( marginRight != null )
  1080. {
  1081. pdfPCell.setPaddingRight( marginRight );
  1082. }
  1083. // Row height
  1084. TableHeight tableHeight = stylesDocument.getTableRowHeight( row );
  1085. if ( tableHeight != null )
  1086. {
  1087. if ( tableHeight.minimum )
  1088. {
  1089. pdfPCell.setMinimumHeight( tableHeight.height );
  1090. }
  1091. else
  1092. {
  1093. pdfPCell.setFixedHeight( tableHeight.height );
  1094. }
  1095. }
  1096. // No wrap
  1097. Boolean noWrap = stylesDocument.getTableCellNoWrap( cell );
  1098. if ( noWrap != null )
  1099. {
  1100. pdfPCell.setNoWrap( noWrap );
  1101. }
  1102. return pdfPCell;
  1103. }
  1104. @Override
  1105. protected void endVisitTableCell( XWPFTableCell cell, IITextContainer tableContainer,
  1106. IITextContainer tableCellContainer )
  1107. {
  1108. ExtendedPdfPTable pdfPTable = (ExtendedPdfPTable) tableContainer;
  1109. ExtendedPdfPCell pdfPCell = (ExtendedPdfPCell) tableCellContainer;
  1110. pdfPTable.addCell( pdfPCell );
  1111. }
  1112. @Override
  1113. protected void visitPicture( CTPicture picture,
  1114. Float offsetX,
  1115. org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STRelFromH.Enum relativeFromH,
  1116. Float offsetY,
  1117. org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.STRelFromV.Enum relativeFromV,
  1118. STWrapText.Enum wrapText, IITextContainer pdfParentContainer )
  1119. throws Exception
  1120. {
  1121. CTPositiveSize2D ext = picture.getSpPr().getXfrm().getExt();
  1122. long x = ext.getCx();
  1123. long y = ext.getCy();
  1124. XWPFPictureData pictureData = super.getPictureData( picture );
  1125. if ( pictureData != null )
  1126. {
  1127. try
  1128. {
  1129. Image img = Image.getInstance( pictureData.getData() );
  1130. img.scaleAbsolute( emu2points( x ), emu2points( y ) );
  1131. IITextContainer parentOfParentContainer = pdfParentContainer.getITextContainer();
  1132. if ( parentOfParentContainer != null && parentOfParentContainer instanceof PdfPCell )
  1133. {
  1134. parentOfParentContainer.addElement( img );
  1135. }
  1136. else
  1137. {
  1138. float chunkOffsetX = 0;
  1139. if ( offsetX != null )
  1140. {
  1141. if ( STRelFromH.CHARACTER.equals( relativeFromH ) )
  1142. {
  1143. chunkOffsetX = offsetX;
  1144. }
  1145. else if ( STRelFromH.COLUMN.equals( relativeFromH ) )
  1146. {
  1147. chunkOffsetX = offsetX;
  1148. }
  1149. else if ( STRelFromH.INSIDE_MARGIN.equals( relativeFromH ) )
  1150. {
  1151. chunkOffsetX = offsetX;
  1152. }
  1153. else if ( STRelFromH.LEFT_MARGIN.equals( relativeFromH ) )
  1154. {
  1155. chunkOffsetX = offsetX;
  1156. }
  1157. else if ( STRelFromH.MARGIN.equals( relativeFromH ) )
  1158. {
  1159. chunkOffsetX = pdfDocument.left() + offsetX;
  1160. }
  1161. else if ( STRelFromH.OUTSIDE_MARGIN.equals( relativeFromH ) )
  1162. {
  1163. chunkOffsetX = offsetX;
  1164. }
  1165. else if ( STRelFromH.PAGE.equals( relativeFromH ) )
  1166. {
  1167. chunkOffsetX = offsetX - pdfDocument.left();
  1168. }
  1169. }
  1170. float chunkOffsetY = 0;
  1171. boolean useExtendedImage = false;
  1172. if ( STRelFromV.PARAGRAPH.equals( relativeFromV ) )
  1173. {
  1174. useExtendedImage = true;
  1175. }
  1176. if ( useExtendedImage )
  1177. {
  1178. ExtendedImage extImg = new ExtendedImage( img, -offsetY );
  1179. if ( STRelFromV.PARAGRAPH.equals( relativeFromV ) )
  1180. {
  1181. chunkOffsetY = -extImg.getScaledHeight();
  1182. }
  1183. Chunk chunk = new Chunk( extImg, chunkOffsetX, chunkOffsetY, false );
  1184. pdfParentContainer.addElement( chunk );
  1185. }
  1186. /*
  1187. * float chunkOffsetY = 0; if ( wrapText != null ) { chunkOffsetY = -img.getScaledHeight(); }
  1188. * boolean useExtendedImage = offsetY != null; // if ( STRelFromV.PARAGRAPH.equals( relativeFromV )
  1189. * ) // { // useExtendedImage = true; // } // if ( useExtendedImage ) { float imgY = -offsetY; if (
  1190. * pdfHeader != null ) { float headerY = pdfHeader.getY() != null ? pdfHeader.getY() : 0; imgY += -
  1191. * img.getScaledHeight() + headerY; } ExtendedImage extImg = new ExtendedImage( img, imgY ); // if (
  1192. * STRelFromV.PARAGRAPH.equals( relativeFromV ) ) // { // chunkOffsetY = -extImg.getScaledHeight();
  1193. * // } Chunk chunk = new Chunk( extImg, chunkOffsetX, chunkOffsetY, false );
  1194. * pdfParentContainer.addElement( chunk ); }
  1195. */
  1196. else
  1197. {
  1198. if ( pdfParentContainer instanceof Paragraph )
  1199. {
  1200. // I don't know why but we need add some spacing before in the paragraph
  1201. // otherwise the image cut the text of the below paragraph (see FormattingTests JUnit)?
  1202. Paragraph paragraph = (Paragraph) pdfParentContainer;
  1203. paragraph.setSpacingBefore( paragraph.getSpacingBefore() + 5f );
  1204. }
  1205. pdfParentContainer.addElement( new Chunk( img, chunkOffsetX, chunkOffsetY, false ) );
  1206. }
  1207. }
  1208. }
  1209. catch ( Exception e )
  1210. {
  1211. LOGGER.severe( e.getMessage() );
  1212. }
  1213. }
  1214. }
  1215. }