You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RTFHandler.java 62KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.render.rtf;
  19. // Java
  20. import java.awt.Dimension;
  21. import java.awt.Rectangle;
  22. import java.awt.geom.Point2D;
  23. import java.io.FileNotFoundException;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.io.OutputStream;
  27. import java.io.OutputStreamWriter;
  28. import java.util.Iterator;
  29. import java.util.Map;
  30. import org.w3c.dom.Document;
  31. import org.xml.sax.SAXException;
  32. import org.apache.commons.io.IOUtils;
  33. import org.apache.commons.logging.Log;
  34. import org.apache.commons.logging.LogFactory;
  35. import org.apache.xmlgraphics.image.loader.Image;
  36. import org.apache.xmlgraphics.image.loader.ImageException;
  37. import org.apache.xmlgraphics.image.loader.ImageFlavor;
  38. import org.apache.xmlgraphics.image.loader.ImageInfo;
  39. import org.apache.xmlgraphics.image.loader.ImageManager;
  40. import org.apache.xmlgraphics.image.loader.ImageSessionContext;
  41. import org.apache.xmlgraphics.image.loader.ImageSize;
  42. import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
  43. import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
  44. import org.apache.xmlgraphics.image.loader.util.ImageUtil;
  45. import org.apache.fop.ResourceEventProducer;
  46. import org.apache.fop.apps.FOPException;
  47. import org.apache.fop.apps.FOUserAgent;
  48. import org.apache.fop.datatypes.LengthBase;
  49. import org.apache.fop.datatypes.PercentBaseContext;
  50. import org.apache.fop.fo.Constants;
  51. import org.apache.fop.fo.FOEventHandler;
  52. import org.apache.fop.fo.FONode;
  53. import org.apache.fop.fo.FOText;
  54. import org.apache.fop.fo.FObj;
  55. import org.apache.fop.fo.XMLObj;
  56. import org.apache.fop.fo.flow.AbstractGraphics;
  57. import org.apache.fop.fo.flow.BasicLink;
  58. import org.apache.fop.fo.flow.Block;
  59. import org.apache.fop.fo.flow.BlockContainer;
  60. import org.apache.fop.fo.flow.Character;
  61. import org.apache.fop.fo.flow.ExternalGraphic;
  62. import org.apache.fop.fo.flow.Footnote;
  63. import org.apache.fop.fo.flow.FootnoteBody;
  64. import org.apache.fop.fo.flow.Inline;
  65. import org.apache.fop.fo.flow.InstreamForeignObject;
  66. import org.apache.fop.fo.flow.Leader;
  67. import org.apache.fop.fo.flow.ListBlock;
  68. import org.apache.fop.fo.flow.ListItem;
  69. import org.apache.fop.fo.flow.ListItemBody;
  70. import org.apache.fop.fo.flow.ListItemLabel;
  71. import org.apache.fop.fo.flow.PageNumber;
  72. import org.apache.fop.fo.flow.PageNumberCitation;
  73. import org.apache.fop.fo.flow.PageNumberCitationLast;
  74. import org.apache.fop.fo.flow.table.Table;
  75. import org.apache.fop.fo.flow.table.TableBody;
  76. import org.apache.fop.fo.flow.table.TableCell;
  77. import org.apache.fop.fo.flow.table.TableColumn;
  78. import org.apache.fop.fo.flow.table.TableFooter;
  79. import org.apache.fop.fo.flow.table.TableHeader;
  80. import org.apache.fop.fo.flow.table.TablePart;
  81. import org.apache.fop.fo.flow.table.TableRow;
  82. import org.apache.fop.fo.pagination.Flow;
  83. import org.apache.fop.fo.pagination.PageSequence;
  84. import org.apache.fop.fo.pagination.PageSequenceMaster;
  85. import org.apache.fop.fo.pagination.Region;
  86. import org.apache.fop.fo.pagination.SimplePageMaster;
  87. import org.apache.fop.fo.pagination.StaticContent;
  88. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  89. import org.apache.fop.fo.properties.EnumLength;
  90. import org.apache.fop.fonts.FontSetup;
  91. import org.apache.fop.layoutmgr.inline.ImageLayout;
  92. import org.apache.fop.layoutmgr.table.ColumnSetup;
  93. import org.apache.fop.render.DefaultFontResolver;
  94. import org.apache.fop.render.RendererEventProducer;
  95. import org.apache.fop.render.rtf.rtflib.exceptions.RtfException;
  96. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfAfterContainer;
  97. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfBeforeContainer;
  98. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfListContainer;
  99. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfTableContainer;
  100. import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfTextrunContainer;
  101. import org.apache.fop.render.rtf.rtflib.rtfdoc.ITableAttributes;
  102. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAfter;
  103. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes;
  104. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfBefore;
  105. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfDocumentArea;
  106. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfElement;
  107. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfExternalGraphic;
  108. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFile;
  109. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFootnote;
  110. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfHyperLink;
  111. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfList;
  112. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem;
  113. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel;
  114. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfPage;
  115. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfSection;
  116. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTable;
  117. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableCell;
  118. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableRow;
  119. import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTextrun;
  120. import org.apache.fop.render.rtf.rtflib.tools.BuilderContext;
  121. import org.apache.fop.render.rtf.rtflib.tools.PercentContext;
  122. import org.apache.fop.render.rtf.rtflib.tools.TableContext;
  123. /**
  124. * RTF Handler: generates RTF output using the structure events from
  125. * the FO Tree sent to this structure handler.
  126. */
  127. public class RTFHandler extends FOEventHandler {
  128. private RtfFile rtfFile;
  129. private final OutputStream os;
  130. private static Log log = LogFactory.getLog(RTFHandler.class);
  131. private RtfSection sect;
  132. private RtfDocumentArea docArea;
  133. private boolean bDefer; //true, if each called handler shall be
  134. //processed at later time.
  135. private boolean bPrevHeaderSpecified = false; //true, if there has been a
  136. //header in any page-sequence
  137. private boolean bPrevFooterSpecified = false; //true, if there has been a
  138. //footer in any page-sequence
  139. private boolean bHeaderSpecified = false; //true, if there is a header
  140. //in current page-sequence
  141. private boolean bFooterSpecified = false; //true, if there is a footer
  142. //in current page-sequence
  143. private BuilderContext builderContext = new BuilderContext(null);
  144. private SimplePageMaster pagemaster;
  145. private int nestedTableDepth = 1;
  146. private PercentContext percentManager = new PercentContext();
  147. /**
  148. * Creates a new RTF structure handler.
  149. * @param userAgent the FOUserAgent for this process
  150. * @param os OutputStream to write to
  151. */
  152. public RTFHandler(FOUserAgent userAgent, OutputStream os) {
  153. super(userAgent);
  154. this.os = os;
  155. bDefer = true;
  156. FontSetup.setup(fontInfo, null, new DefaultFontResolver(userAgent));
  157. }
  158. /**
  159. * Central exception handler for I/O exceptions.
  160. * @param ioe IOException to handle
  161. */
  162. protected void handleIOTrouble(IOException ioe) {
  163. RendererEventProducer eventProducer = RendererEventProducer.Provider.get(
  164. getUserAgent().getEventBroadcaster());
  165. eventProducer.ioError(this, ioe);
  166. }
  167. /** {@inheritDoc} */
  168. public void startDocument() throws SAXException {
  169. // TODO sections should be created
  170. try {
  171. rtfFile = new RtfFile(new OutputStreamWriter(os));
  172. docArea = rtfFile.startDocumentArea();
  173. } catch (IOException ioe) {
  174. // TODO could we throw Exception in all FOEventHandler events?
  175. throw new SAXException(ioe);
  176. }
  177. }
  178. /** {@inheritDoc} */
  179. public void endDocument() throws SAXException {
  180. try {
  181. rtfFile.flush();
  182. } catch (IOException ioe) {
  183. // TODO could we throw Exception in all FOEventHandler events?
  184. throw new SAXException(ioe);
  185. }
  186. }
  187. /** {@inheritDoc} */
  188. public void startPageSequence(PageSequence pageSeq) {
  189. try {
  190. //This is needed for region handling
  191. if (this.pagemaster == null) {
  192. String reference = pageSeq.getMasterReference();
  193. this.pagemaster
  194. = pageSeq.getRoot().getLayoutMasterSet().getSimplePageMaster(reference);
  195. if (this.pagemaster == null) {
  196. RTFEventProducer eventProducer = RTFEventProducer.Provider.get(
  197. getUserAgent().getEventBroadcaster());
  198. eventProducer.onlySPMSupported(this, reference, pageSeq.getLocator());
  199. PageSequenceMaster master
  200. = pageSeq.getRoot().getLayoutMasterSet().getPageSequenceMaster(reference);
  201. this.pagemaster = master.getNextSimplePageMaster(
  202. false, false, false, false);
  203. }
  204. }
  205. if (bDefer) {
  206. return;
  207. }
  208. sect = docArea.newSection();
  209. //read page size and margins, if specified
  210. //only simple-page-master supported, so pagemaster may be null
  211. if (pagemaster != null) {
  212. sect.getRtfAttributes().set(
  213. PageAttributesConverter.convertPageAttributes(
  214. pagemaster));
  215. } else {
  216. RTFEventProducer eventProducer = RTFEventProducer.Provider.get(
  217. getUserAgent().getEventBroadcaster());
  218. eventProducer.noSPMFound(this, pageSeq.getLocator());
  219. }
  220. builderContext.pushContainer(sect);
  221. //Calculate usable page width for this flow
  222. int useAblePageWidth = pagemaster.getPageWidth().getValue()
  223. - pagemaster.getCommonMarginBlock().marginLeft.getValue()
  224. - pagemaster.getCommonMarginBlock().marginRight.getValue()
  225. - sect.getRtfAttributes().getValueAsInteger(RtfPage.MARGIN_LEFT).intValue()
  226. - sect.getRtfAttributes().getValueAsInteger(RtfPage.MARGIN_RIGHT).intValue();
  227. percentManager.setDimension(pageSeq, useAblePageWidth);
  228. bHeaderSpecified = false;
  229. bFooterSpecified = false;
  230. } catch (IOException ioe) {
  231. handleIOTrouble(ioe);
  232. }
  233. }
  234. /** {@inheritDoc} */
  235. public void endPageSequence(PageSequence pageSeq) {
  236. if (bDefer) {
  237. //If endBlock was called while SAX parsing, and the passed FO is Block
  238. //nested within another Block, stop deferring.
  239. //Now process all deferred FOs.
  240. bDefer = false;
  241. recurseFONode(pageSeq);
  242. this.pagemaster = null;
  243. bDefer = true;
  244. return;
  245. } else {
  246. builderContext.popContainer();
  247. this.pagemaster = null;
  248. }
  249. }
  250. /** {@inheritDoc} */
  251. public void startFlow(Flow fl) {
  252. if (bDefer) {
  253. return;
  254. }
  255. try {
  256. log.debug("starting flow: " + fl.getFlowName());
  257. boolean handled = false;
  258. Region regionBody = pagemaster.getRegion(Constants.FO_REGION_BODY);
  259. Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE);
  260. Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER);
  261. if (fl.getFlowName().equals(regionBody.getRegionName())) {
  262. // if there is no header in current page-sequence but there has been
  263. // a header in a previous page-sequence, insert an empty header.
  264. if (bPrevHeaderSpecified && !bHeaderSpecified) {
  265. RtfAttributes attr = new RtfAttributes();
  266. attr.set(RtfBefore.HEADER);
  267. final IRtfBeforeContainer contBefore
  268. = (IRtfBeforeContainer)builderContext.getContainer
  269. (IRtfBeforeContainer.class, true, this);
  270. contBefore.newBefore(attr);
  271. }
  272. // if there is no footer in current page-sequence but there has been
  273. // a footer in a previous page-sequence, insert an empty footer.
  274. if (bPrevFooterSpecified && !bFooterSpecified) {
  275. RtfAttributes attr = new RtfAttributes();
  276. attr.set(RtfAfter.FOOTER);
  277. final IRtfAfterContainer contAfter
  278. = (IRtfAfterContainer)builderContext.getContainer
  279. (IRtfAfterContainer.class, true, this);
  280. contAfter.newAfter(attr);
  281. }
  282. handled = true;
  283. } else if (regionBefore != null
  284. && fl.getFlowName().equals(regionBefore.getRegionName())) {
  285. bHeaderSpecified = true;
  286. bPrevHeaderSpecified = true;
  287. final IRtfBeforeContainer c
  288. = (IRtfBeforeContainer)builderContext.getContainer(
  289. IRtfBeforeContainer.class,
  290. true, this);
  291. RtfAttributes beforeAttributes = ((RtfElement)c).getRtfAttributes();
  292. if (beforeAttributes == null) {
  293. beforeAttributes = new RtfAttributes();
  294. }
  295. beforeAttributes.set(RtfBefore.HEADER);
  296. RtfBefore before = c.newBefore(beforeAttributes);
  297. builderContext.pushContainer(before);
  298. handled = true;
  299. } else if (regionAfter != null
  300. && fl.getFlowName().equals(regionAfter.getRegionName())) {
  301. bFooterSpecified = true;
  302. bPrevFooterSpecified = true;
  303. final IRtfAfterContainer c
  304. = (IRtfAfterContainer)builderContext.getContainer(
  305. IRtfAfterContainer.class,
  306. true, this);
  307. RtfAttributes afterAttributes = ((RtfElement)c).getRtfAttributes();
  308. if (afterAttributes == null) {
  309. afterAttributes = new RtfAttributes();
  310. }
  311. afterAttributes.set(RtfAfter.FOOTER);
  312. RtfAfter after = c.newAfter(afterAttributes);
  313. builderContext.pushContainer(after);
  314. handled = true;
  315. }
  316. if (!handled) {
  317. log.warn("A " + fl.getLocalName() + " has been skipped: " + fl.getFlowName());
  318. }
  319. } catch (IOException ioe) {
  320. handleIOTrouble(ioe);
  321. } catch (Exception e) {
  322. log.error("startFlow: " + e.getMessage());
  323. throw new RuntimeException(e.getMessage());
  324. }
  325. }
  326. /** {@inheritDoc} */
  327. public void endFlow(Flow fl) {
  328. if (bDefer) {
  329. return;
  330. }
  331. try {
  332. Region regionBody = pagemaster.getRegion(Constants.FO_REGION_BODY);
  333. Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE);
  334. Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER);
  335. if (fl.getFlowName().equals(regionBody.getRegionName())) {
  336. //just do nothing
  337. } else if (regionBefore != null
  338. && fl.getFlowName().equals(regionBefore.getRegionName())) {
  339. builderContext.popContainer();
  340. } else if (regionAfter != null
  341. && fl.getFlowName().equals(regionAfter.getRegionName())) {
  342. builderContext.popContainer();
  343. }
  344. } catch (Exception e) {
  345. log.error("endFlow: " + e.getMessage());
  346. throw new RuntimeException(e.getMessage());
  347. }
  348. }
  349. /** {@inheritDoc} */
  350. public void startBlock(Block bl) {
  351. if (bDefer) {
  352. return;
  353. }
  354. try {
  355. RtfAttributes rtfAttr
  356. = TextAttributesConverter.convertAttributes(bl);
  357. IRtfTextrunContainer container
  358. = (IRtfTextrunContainer)builderContext.getContainer(
  359. IRtfTextrunContainer.class,
  360. true, this);
  361. RtfTextrun textrun = container.getTextrun();
  362. textrun.addParagraphBreak();
  363. textrun.pushBlockAttributes(rtfAttr);
  364. textrun.addBookmark(bl.getId());
  365. } catch (IOException ioe) {
  366. handleIOTrouble(ioe);
  367. } catch (Exception e) {
  368. log.error("startBlock: " + e.getMessage());
  369. throw new RuntimeException("Exception: " + e);
  370. }
  371. }
  372. /** {@inheritDoc} */
  373. public void endBlock(Block bl) {
  374. if (bDefer) {
  375. return;
  376. }
  377. try {
  378. IRtfTextrunContainer container
  379. = (IRtfTextrunContainer)builderContext.getContainer(
  380. IRtfTextrunContainer.class,
  381. true, this);
  382. RtfTextrun textrun = container.getTextrun();
  383. textrun.addParagraphBreak();
  384. int breakValue = toRtfBreakValue(bl.getBreakAfter());
  385. textrun.popBlockAttributes(breakValue);
  386. } catch (IOException ioe) {
  387. handleIOTrouble(ioe);
  388. } catch (Exception e) {
  389. log.error("startBlock:" + e.getMessage());
  390. throw new RuntimeException(e.getMessage());
  391. }
  392. }
  393. /** {@inheritDoc} */
  394. public void startBlockContainer(BlockContainer blc) {
  395. if (bDefer) {
  396. return;
  397. }
  398. try {
  399. RtfAttributes rtfAttr
  400. = TextAttributesConverter.convertBlockContainerAttributes(blc);
  401. IRtfTextrunContainer container
  402. = (IRtfTextrunContainer)builderContext.getContainer(
  403. IRtfTextrunContainer.class,
  404. true, this);
  405. RtfTextrun textrun = container.getTextrun();
  406. textrun.addParagraphBreak();
  407. textrun.pushBlockAttributes(rtfAttr);
  408. } catch (IOException ioe) {
  409. handleIOTrouble(ioe);
  410. } catch (Exception e) {
  411. log.error("startBlock: " + e.getMessage());
  412. throw new RuntimeException("Exception: " + e);
  413. }
  414. }
  415. /** {@inheritDoc} */
  416. public void endBlockContainer(BlockContainer bl) {
  417. if (bDefer) {
  418. return;
  419. }
  420. try {
  421. IRtfTextrunContainer container
  422. = (IRtfTextrunContainer)builderContext.getContainer(
  423. IRtfTextrunContainer.class,
  424. true, this);
  425. RtfTextrun textrun = container.getTextrun();
  426. textrun.addParagraphBreak();
  427. int breakValue = toRtfBreakValue(bl.getBreakAfter());
  428. textrun.popBlockAttributes(breakValue);
  429. } catch (IOException ioe) {
  430. handleIOTrouble(ioe);
  431. } catch (Exception e) {
  432. log.error("startBlock:" + e.getMessage());
  433. throw new RuntimeException(e.getMessage());
  434. }
  435. }
  436. private int toRtfBreakValue(int foBreakValue) {
  437. switch (foBreakValue) {
  438. case Constants.EN_PAGE:
  439. return RtfTextrun.BREAK_PAGE;
  440. case Constants.EN_EVEN_PAGE:
  441. return RtfTextrun.BREAK_EVEN_PAGE;
  442. case Constants.EN_ODD_PAGE:
  443. return RtfTextrun.BREAK_ODD_PAGE;
  444. case Constants.EN_COLUMN:
  445. return RtfTextrun.BREAK_COLUMN;
  446. default:
  447. return RtfTextrun.BREAK_NONE;
  448. }
  449. }
  450. /** {@inheritDoc} */
  451. public void startTable(Table tbl) {
  452. if (bDefer) {
  453. return;
  454. }
  455. // create an RtfTable in the current table container
  456. TableContext tableContext = new TableContext(builderContext);
  457. try {
  458. final IRtfTableContainer tc
  459. = (IRtfTableContainer)builderContext.getContainer(
  460. IRtfTableContainer.class, true, null);
  461. RtfAttributes atts
  462. = TableAttributesConverter.convertTableAttributes(tbl);
  463. RtfTable table = tc.newTable(atts, tableContext);
  464. table.setNestedTableDepth(nestedTableDepth);
  465. nestedTableDepth++;
  466. CommonBorderPaddingBackground border = tbl.getCommonBorderPaddingBackground();
  467. RtfAttributes borderAttributes = new RtfAttributes();
  468. BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.BEFORE,
  469. borderAttributes, ITableAttributes.CELL_BORDER_TOP);
  470. BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.AFTER,
  471. borderAttributes, ITableAttributes.CELL_BORDER_BOTTOM);
  472. BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.START,
  473. borderAttributes, ITableAttributes.CELL_BORDER_LEFT);
  474. BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.END,
  475. borderAttributes, ITableAttributes.CELL_BORDER_RIGHT);
  476. table.setBorderAttributes(borderAttributes);
  477. builderContext.pushContainer(table);
  478. } catch (IOException ioe) {
  479. handleIOTrouble(ioe);
  480. } catch (Exception e) {
  481. log.error("startTable:" + e.getMessage());
  482. throw new RuntimeException(e.getMessage());
  483. }
  484. builderContext.pushTableContext(tableContext);
  485. }
  486. /** {@inheritDoc} */
  487. public void endTable(Table tbl) {
  488. if (bDefer) {
  489. return;
  490. }
  491. nestedTableDepth--;
  492. builderContext.popTableContext();
  493. builderContext.popContainer();
  494. }
  495. /** {@inheritDoc} */
  496. public void startColumn(TableColumn tc) {
  497. if (bDefer) {
  498. return;
  499. }
  500. try {
  501. int iWidth = tc.getColumnWidth().getValue(percentManager);
  502. percentManager.setDimension(tc, iWidth);
  503. //convert to twips
  504. Float width = new Float(FoUnitsConverter.getInstance().convertMptToTwips(iWidth));
  505. builderContext.getTableContext().setNextColumnWidth(width);
  506. builderContext.getTableContext().setNextColumnRowSpanning(
  507. new Integer(0), null);
  508. builderContext.getTableContext().setNextFirstSpanningCol(false);
  509. } catch (Exception e) {
  510. log.error("startColumn: " + e.getMessage());
  511. throw new RuntimeException(e.getMessage());
  512. }
  513. }
  514. /** {@inheritDoc} */
  515. public void endColumn(TableColumn tc) {
  516. if (bDefer) {
  517. return;
  518. }
  519. }
  520. /** {@inheritDoc} */
  521. public void startHeader(TableHeader header) {
  522. startPart(header);
  523. }
  524. /** {@inheritDoc} */
  525. public void endHeader(TableHeader header) {
  526. endPart(header);
  527. }
  528. /** {@inheritDoc} */
  529. public void startFooter(TableFooter footer) {
  530. startPart(footer);
  531. }
  532. /** {@inheritDoc} */
  533. public void endFooter(TableFooter footer) {
  534. endPart(footer);
  535. }
  536. /** {@inheritDoc} */
  537. public void startInline(Inline inl) {
  538. if (bDefer) {
  539. return;
  540. }
  541. try {
  542. RtfAttributes rtfAttr
  543. = TextAttributesConverter.convertCharacterAttributes(inl);
  544. IRtfTextrunContainer container
  545. = (IRtfTextrunContainer)builderContext.getContainer(
  546. IRtfTextrunContainer.class, true, this);
  547. RtfTextrun textrun = container.getTextrun();
  548. textrun.pushInlineAttributes(rtfAttr);
  549. textrun.addBookmark(inl.getId());
  550. } catch (IOException ioe) {
  551. handleIOTrouble(ioe);
  552. } catch (FOPException fe) {
  553. log.error("startInline:" + fe.getMessage());
  554. throw new RuntimeException(fe.getMessage());
  555. } catch (Exception e) {
  556. log.error("startInline:" + e.getMessage());
  557. throw new RuntimeException(e.getMessage());
  558. }
  559. }
  560. /** {@inheritDoc} */
  561. public void endInline(Inline inl) {
  562. if (bDefer) {
  563. return;
  564. }
  565. try {
  566. IRtfTextrunContainer container
  567. = (IRtfTextrunContainer)builderContext.getContainer(
  568. IRtfTextrunContainer.class, true, this);
  569. RtfTextrun textrun = container.getTextrun();
  570. textrun.popInlineAttributes();
  571. } catch (IOException ioe) {
  572. handleIOTrouble(ioe);
  573. } catch (Exception e) {
  574. log.error("startInline:" + e.getMessage());
  575. throw new RuntimeException(e.getMessage());
  576. }
  577. }
  578. private void startPart(TablePart part) {
  579. if (bDefer) {
  580. return;
  581. }
  582. try {
  583. RtfAttributes atts = TableAttributesConverter.convertTablePartAttributes(part);
  584. RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class, true, this);
  585. tbl.setHeaderAttribs(atts);
  586. } catch (IOException ioe) {
  587. handleIOTrouble(ioe);
  588. } catch (Exception e) {
  589. log.error("startPart: " + e.getMessage());
  590. throw new RuntimeException(e.getMessage());
  591. }
  592. }
  593. private void endPart(TablePart tb) {
  594. if (bDefer) {
  595. return;
  596. }
  597. try {
  598. RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class, true, this);
  599. tbl.setHeaderAttribs(null);
  600. } catch (IOException ioe) {
  601. handleIOTrouble(ioe);
  602. } catch (Exception e) {
  603. log.error("endPart: " + e.getMessage());
  604. throw new RuntimeException(e.getMessage());
  605. }
  606. }
  607. /**
  608. * {@inheritDoc}
  609. */
  610. public void startBody(TableBody body) {
  611. startPart(body);
  612. }
  613. /** {@inheritDoc} */
  614. public void endBody(TableBody body) {
  615. endPart(body);
  616. }
  617. /**
  618. * {@inheritDoc}
  619. */
  620. public void startRow(TableRow tr) {
  621. if (bDefer) {
  622. return;
  623. }
  624. try {
  625. // create an RtfTableRow in the current RtfTable
  626. final RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class,
  627. true, null);
  628. RtfAttributes atts = TableAttributesConverter.convertRowAttributes(tr,
  629. tbl.getHeaderAttribs());
  630. if (tr.getParent() instanceof TableHeader) {
  631. atts.set(ITableAttributes.ATTR_HEADER);
  632. }
  633. builderContext.pushContainer(tbl.newTableRow(atts));
  634. // reset column iteration index to correctly access column widths
  635. builderContext.getTableContext().selectFirstColumn();
  636. } catch (IOException ioe) {
  637. handleIOTrouble(ioe);
  638. } catch (Exception e) {
  639. log.error("startRow: " + e.getMessage());
  640. throw new RuntimeException(e.getMessage());
  641. }
  642. }
  643. /** {@inheritDoc} */
  644. public void endRow(TableRow tr) {
  645. if (bDefer) {
  646. return;
  647. }
  648. try {
  649. TableContext tctx = builderContext.getTableContext();
  650. final RtfTableRow row = (RtfTableRow)builderContext.getContainer(RtfTableRow.class,
  651. true, null);
  652. //while the current column is in row-spanning, act as if
  653. //a vertical merged cell would have been specified.
  654. while (tctx.getNumberOfColumns() > tctx.getColumnIndex()
  655. && tctx.getColumnRowSpanningNumber().intValue() > 0) {
  656. RtfTableCell vCell = row.newTableCellMergedVertically(
  657. (int)tctx.getColumnWidth(),
  658. tctx.getColumnRowSpanningAttrs());
  659. if (!tctx.getFirstSpanningCol()) {
  660. vCell.setHMerge(RtfTableCell.MERGE_WITH_PREVIOUS);
  661. }
  662. tctx.selectNextColumn();
  663. }
  664. } catch (IOException ioe) {
  665. handleIOTrouble(ioe);
  666. } catch (Exception e) {
  667. log.error("endRow: " + e.getMessage());
  668. throw new RuntimeException(e.getMessage());
  669. }
  670. builderContext.popContainer();
  671. builderContext.getTableContext().decreaseRowSpannings();
  672. }
  673. /** {@inheritDoc} */
  674. public void startCell(TableCell tc) {
  675. if (bDefer) {
  676. return;
  677. }
  678. try {
  679. TableContext tctx = builderContext.getTableContext();
  680. final RtfTableRow row = (RtfTableRow)builderContext.getContainer(RtfTableRow.class,
  681. true, null);
  682. int numberRowsSpanned = tc.getNumberRowsSpanned();
  683. int numberColumnsSpanned = tc.getNumberColumnsSpanned();
  684. //while the current column is in row-spanning, act as if
  685. //a vertical merged cell would have been specified.
  686. while (tctx.getNumberOfColumns() > tctx.getColumnIndex()
  687. && tctx.getColumnRowSpanningNumber().intValue() > 0) {
  688. RtfTableCell vCell = row.newTableCellMergedVertically(
  689. (int)tctx.getColumnWidth(),
  690. tctx.getColumnRowSpanningAttrs());
  691. if (!tctx.getFirstSpanningCol()) {
  692. vCell.setHMerge(RtfTableCell.MERGE_WITH_PREVIOUS);
  693. }
  694. tctx.selectNextColumn();
  695. }
  696. //get the width of the currently started cell
  697. float width = tctx.getColumnWidth();
  698. // create an RtfTableCell in the current RtfTableRow
  699. RtfAttributes atts = TableAttributesConverter.convertCellAttributes(tc);
  700. RtfTableCell cell = row.newTableCell((int)width, atts);
  701. //process number-rows-spanned attribute
  702. if (numberRowsSpanned > 1) {
  703. // Start vertical merge
  704. cell.setVMerge(RtfTableCell.MERGE_START);
  705. // set the number of rows spanned
  706. tctx.setCurrentColumnRowSpanning(new Integer(numberRowsSpanned),
  707. cell.getRtfAttributes());
  708. } else {
  709. tctx.setCurrentColumnRowSpanning(
  710. new Integer(numberRowsSpanned), null);
  711. }
  712. //process number-columns-spanned attribute
  713. if (numberColumnsSpanned > 0) {
  714. // Get the number of columns spanned
  715. tctx.setCurrentFirstSpanningCol(true);
  716. // We widthdraw one cell because the first cell is already created
  717. // (it's the current cell) !
  718. for (int i = 0; i < numberColumnsSpanned - 1; ++i) {
  719. tctx.selectNextColumn();
  720. //aggregate width for further elements
  721. width += tctx.getColumnWidth();
  722. tctx.setCurrentFirstSpanningCol(false);
  723. RtfTableCell hCell = row.newTableCellMergedHorizontally(
  724. 0, null);
  725. if (numberRowsSpanned > 1) {
  726. // Start vertical merge
  727. hCell.setVMerge(RtfTableCell.MERGE_START);
  728. // set the number of rows spanned
  729. tctx.setCurrentColumnRowSpanning(
  730. new Integer(numberRowsSpanned),
  731. cell.getRtfAttributes());
  732. } else {
  733. tctx.setCurrentColumnRowSpanning(
  734. new Integer(numberRowsSpanned), cell.getRtfAttributes());
  735. }
  736. }
  737. }
  738. //save width of the cell, convert from twips to mpt
  739. percentManager.setDimension(tc, (int)width * 50);
  740. builderContext.pushContainer(cell);
  741. } catch (IOException ioe) {
  742. handleIOTrouble(ioe);
  743. } catch (Exception e) {
  744. log.error("startCell: " + e.getMessage());
  745. throw new RuntimeException(e.getMessage());
  746. }
  747. }
  748. /** {@inheritDoc} */
  749. public void endCell(TableCell tc) {
  750. if (bDefer) {
  751. return;
  752. }
  753. builderContext.popContainer();
  754. builderContext.getTableContext().selectNextColumn();
  755. }
  756. // Lists
  757. /** {@inheritDoc} */
  758. public void startList(ListBlock lb) {
  759. if (bDefer) {
  760. return;
  761. }
  762. try {
  763. // create an RtfList in the current list container
  764. final IRtfListContainer c
  765. = (IRtfListContainer)builderContext.getContainer(
  766. IRtfListContainer.class, true, this);
  767. final RtfList newList = c.newList(
  768. ListAttributesConverter.convertAttributes(lb));
  769. builderContext.pushContainer(newList);
  770. } catch (IOException ioe) {
  771. handleIOTrouble(ioe);
  772. } catch (FOPException fe) {
  773. log.error("startList: " + fe.getMessage());
  774. throw new RuntimeException(fe.getMessage());
  775. } catch (Exception e) {
  776. log.error("startList: " + e.getMessage());
  777. throw new RuntimeException(e.getMessage());
  778. }
  779. }
  780. /** {@inheritDoc} */
  781. public void endList(ListBlock lb) {
  782. if (bDefer) {
  783. return;
  784. }
  785. builderContext.popContainer();
  786. }
  787. /** {@inheritDoc} */
  788. public void startListItem(ListItem li) {
  789. if (bDefer) {
  790. return;
  791. }
  792. // create an RtfListItem in the current RtfList
  793. try {
  794. RtfList list = (RtfList)builderContext.getContainer(
  795. RtfList.class, true, this);
  796. /**
  797. * If the current list already contains a list item, then close the
  798. * list and open a new one, so every single list item gets its own
  799. * list. This allows every item to have a different list label.
  800. * If all the items would be in the same list, they had all the
  801. * same label.
  802. */
  803. //TODO: do this only, if the labels content <> previous labels content
  804. if (list.getChildCount() > 0) {
  805. this.endListBody(null);
  806. this.endList((ListBlock) li.getParent());
  807. this.startList((ListBlock) li.getParent());
  808. this.startListBody(null);
  809. list = (RtfList)builderContext.getContainer(
  810. RtfList.class, true, this);
  811. }
  812. builderContext.pushContainer(list.newListItem());
  813. } catch (IOException ioe) {
  814. handleIOTrouble(ioe);
  815. } catch (Exception e) {
  816. log.error("startList: " + e.getMessage());
  817. throw new RuntimeException(e.getMessage());
  818. }
  819. }
  820. /** {@inheritDoc} */
  821. public void endListItem(ListItem li) {
  822. if (bDefer) {
  823. return;
  824. }
  825. builderContext.popContainer();
  826. }
  827. /** {@inheritDoc} */
  828. public void startListLabel(ListItemLabel listItemLabel) {
  829. if (bDefer) {
  830. return;
  831. }
  832. try {
  833. RtfListItem item
  834. = (RtfListItem)builderContext.getContainer(RtfListItem.class, true, this);
  835. RtfListItemLabel label = item.new RtfListItemLabel(item);
  836. builderContext.pushContainer(label);
  837. } catch (IOException ioe) {
  838. handleIOTrouble(ioe);
  839. } catch (Exception e) {
  840. log.error("startPageNumber: " + e.getMessage());
  841. throw new RuntimeException(e.getMessage());
  842. }
  843. }
  844. /** {@inheritDoc} */
  845. public void endListLabel(ListItemLabel listItemLabel) {
  846. if (bDefer) {
  847. return;
  848. }
  849. builderContext.popContainer();
  850. }
  851. /** {@inheritDoc} */
  852. public void startListBody(ListItemBody listItemBody) {
  853. }
  854. /** {@inheritDoc} */
  855. public void endListBody(ListItemBody listItemBody) {
  856. }
  857. // Static Regions
  858. /** {@inheritDoc} */
  859. public void startStatic(StaticContent staticContent) {
  860. }
  861. /** {@inheritDoc} */
  862. public void endStatic(StaticContent statisContent) {
  863. }
  864. /** {@inheritDoc} */
  865. public void startMarkup() {
  866. }
  867. /** {@inheritDoc} */
  868. public void endMarkup() {
  869. }
  870. /** {@inheritDoc} */
  871. public void startLink(BasicLink basicLink) {
  872. if (bDefer) {
  873. return;
  874. }
  875. try {
  876. IRtfTextrunContainer container
  877. = (IRtfTextrunContainer)builderContext.getContainer(
  878. IRtfTextrunContainer.class, true, this);
  879. RtfTextrun textrun = container.getTextrun();
  880. RtfHyperLink link = textrun.addHyperlink(new RtfAttributes());
  881. if (basicLink.hasExternalDestination()) {
  882. link.setExternalURL(basicLink.getExternalDestination());
  883. } else {
  884. link.setInternalURL(basicLink.getInternalDestination());
  885. }
  886. builderContext.pushContainer(link);
  887. } catch (IOException ioe) {
  888. handleIOTrouble(ioe);
  889. } catch (Exception e) {
  890. log.error("startLink: " + e.getMessage());
  891. throw new RuntimeException(e.getMessage());
  892. }
  893. }
  894. /** {@inheritDoc} */
  895. public void endLink(BasicLink basicLink) {
  896. if (bDefer) {
  897. return;
  898. }
  899. builderContext.popContainer();
  900. }
  901. /** {@inheritDoc} */
  902. public void image(ExternalGraphic eg) {
  903. if (bDefer) {
  904. return;
  905. }
  906. String uri = eg.getURL();
  907. ImageInfo info = null;
  908. try {
  909. //set image data
  910. FOUserAgent userAgent = eg.getUserAgent();
  911. ImageManager manager = userAgent.getFactory().getImageManager();
  912. info = manager.getImageInfo(uri, userAgent.getImageSessionContext());
  913. putGraphic(eg, info);
  914. } catch (ImageException ie) {
  915. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  916. getUserAgent().getEventBroadcaster());
  917. eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null);
  918. } catch (FileNotFoundException fe) {
  919. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  920. getUserAgent().getEventBroadcaster());
  921. eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null);
  922. } catch (IOException ioe) {
  923. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  924. getUserAgent().getEventBroadcaster());
  925. eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null);
  926. }
  927. }
  928. /** {@inheritDoc} */
  929. public void endInstreamForeignObject(InstreamForeignObject ifo) {
  930. if (bDefer) {
  931. return;
  932. }
  933. try {
  934. XMLObj child = ifo.getChildXMLObj();
  935. Document doc = child.getDOMDocument();
  936. String ns = child.getNamespaceURI();
  937. ImageInfo info = new ImageInfo(null, null);
  938. // Set the resolution to that of the FOUserAgent
  939. FOUserAgent ua = ifo.getUserAgent();
  940. ImageSize size = new ImageSize();
  941. size.setResolution(ua.getSourceResolution());
  942. // Set the image size to the size of the svg.
  943. Point2D csize = new Point2D.Float(-1, -1);
  944. Point2D intrinsicDimensions = child.getDimension(csize);
  945. if (intrinsicDimensions == null) {
  946. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  947. getUserAgent().getEventBroadcaster());
  948. eventProducer.ifoNoIntrinsicSize(this, child.getLocator());
  949. return;
  950. }
  951. size.setSizeInMillipoints(
  952. (int)Math.round(intrinsicDimensions.getX() * 1000),
  953. (int)Math.round(intrinsicDimensions.getY() * 1000));
  954. size.calcPixelsFromSize();
  955. info.setSize(size);
  956. ImageXMLDOM image = new ImageXMLDOM(info, doc, ns);
  957. FOUserAgent userAgent = ifo.getUserAgent();
  958. ImageManager manager = userAgent.getFactory().getImageManager();
  959. Map hints = ImageUtil.getDefaultHints(ua.getImageSessionContext());
  960. Image converted = manager.convertImage(image, FLAVORS, hints);
  961. putGraphic(ifo, converted);
  962. } catch (ImageException ie) {
  963. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  964. getUserAgent().getEventBroadcaster());
  965. eventProducer.imageError(this, null, ie, null);
  966. } catch (IOException ioe) {
  967. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  968. getUserAgent().getEventBroadcaster());
  969. eventProducer.imageIOError(this, null, ioe, null);
  970. }
  971. }
  972. private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
  973. ImageFlavor.RAW_EMF, ImageFlavor.RAW_PNG, ImageFlavor.RAW_JPEG
  974. };
  975. /**
  976. * Puts a graphic/image into the generated RTF file.
  977. * @param abstractGraphic the graphic (external-graphic or instream-foreign-object)
  978. * @param info the image info object
  979. * @throws IOException In case of an I/O error
  980. */
  981. private void putGraphic(AbstractGraphics abstractGraphic, ImageInfo info)
  982. throws IOException {
  983. try {
  984. FOUserAgent userAgent = abstractGraphic.getUserAgent();
  985. ImageManager manager = userAgent.getFactory().getImageManager();
  986. ImageSessionContext sessionContext = userAgent.getImageSessionContext();
  987. Map hints = ImageUtil.getDefaultHints(sessionContext);
  988. Image image = manager.getImage(info, FLAVORS, hints, sessionContext);
  989. putGraphic(abstractGraphic, image);
  990. } catch (ImageException ie) {
  991. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  992. getUserAgent().getEventBroadcaster());
  993. eventProducer.imageError(this, null, ie, null);
  994. }
  995. }
  996. /**
  997. * Puts a graphic/image into the generated RTF file.
  998. * @param abstractGraphic the graphic (external-graphic or instream-foreign-object)
  999. * @param image the image
  1000. * @throws IOException In case of an I/O error
  1001. */
  1002. private void putGraphic(AbstractGraphics abstractGraphic, Image image)
  1003. throws IOException {
  1004. byte[] rawData = null;
  1005. final ImageInfo info = image.getInfo();
  1006. if (image instanceof ImageRawStream) {
  1007. ImageRawStream rawImage = (ImageRawStream)image;
  1008. InputStream in = rawImage.createInputStream();
  1009. try {
  1010. rawData = IOUtils.toByteArray(in);
  1011. } finally {
  1012. IOUtils.closeQuietly(in);
  1013. }
  1014. }
  1015. if (rawData == null) {
  1016. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  1017. getUserAgent().getEventBroadcaster());
  1018. eventProducer.imageWritingError(this, null);
  1019. return;
  1020. }
  1021. //Set up percentage calculations
  1022. this.percentManager.setDimension(abstractGraphic);
  1023. PercentBaseContext pContext = new PercentBaseContext() {
  1024. public int getBaseLength(int lengthBase, FObj fobj) {
  1025. switch (lengthBase) {
  1026. case LengthBase.IMAGE_INTRINSIC_WIDTH:
  1027. return info.getSize().getWidthMpt();
  1028. case LengthBase.IMAGE_INTRINSIC_HEIGHT:
  1029. return info.getSize().getHeightMpt();
  1030. default:
  1031. return percentManager.getBaseLength(lengthBase, fobj);
  1032. }
  1033. }
  1034. };
  1035. ImageLayout layout = new ImageLayout(abstractGraphic, pContext,
  1036. image.getInfo().getSize().getDimensionMpt());
  1037. final IRtfTextrunContainer c
  1038. = (IRtfTextrunContainer)builderContext.getContainer(
  1039. IRtfTextrunContainer.class, true, this);
  1040. final RtfExternalGraphic rtfGraphic = c.getTextrun().newImage();
  1041. //set URL
  1042. if (info.getOriginalURI() != null) {
  1043. rtfGraphic.setURL(info.getOriginalURI());
  1044. }
  1045. rtfGraphic.setImageData(rawData);
  1046. FoUnitsConverter converter = FoUnitsConverter.getInstance();
  1047. Dimension viewport = layout.getViewportSize();
  1048. Rectangle placement = layout.getPlacement();
  1049. int cropLeft = Math.round(converter.convertMptToTwips(-placement.x));
  1050. int cropTop = Math.round(converter.convertMptToTwips(-placement.y));
  1051. int cropRight = Math.round(converter.convertMptToTwips(
  1052. -1 * (viewport.width - placement.x - placement.width)));
  1053. int cropBottom = Math.round(converter.convertMptToTwips(
  1054. -1 * (viewport.height - placement.y - placement.height)));
  1055. rtfGraphic.setCropping(cropLeft, cropTop, cropRight, cropBottom);
  1056. int width = Math.round(converter.convertMptToTwips(viewport.width));
  1057. int height = Math.round(converter.convertMptToTwips(viewport.height));
  1058. width += cropLeft + cropRight;
  1059. height += cropTop + cropBottom;
  1060. rtfGraphic.setWidthTwips(width);
  1061. rtfGraphic.setHeightTwips(height);
  1062. //TODO: make this configurable:
  1063. // int compression = m_context.m_options.getRtfExternalGraphicCompressionRate ();
  1064. int compression = 0;
  1065. if (compression != 0) {
  1066. if (!rtfGraphic.setCompressionRate(compression)) {
  1067. log.warn("The compression rate " + compression
  1068. + " is invalid. The value has to be between 1 and 100 %.");
  1069. }
  1070. }
  1071. }
  1072. /** {@inheritDoc} */
  1073. public void pageRef() {
  1074. }
  1075. /** {@inheritDoc} */
  1076. public void startFootnote(Footnote footnote) {
  1077. if (bDefer) {
  1078. return;
  1079. }
  1080. try {
  1081. IRtfTextrunContainer container
  1082. = (IRtfTextrunContainer)builderContext.getContainer(
  1083. IRtfTextrunContainer.class,
  1084. true, this);
  1085. RtfTextrun textrun = container.getTextrun();
  1086. RtfFootnote rtfFootnote = textrun.addFootnote();
  1087. builderContext.pushContainer(rtfFootnote);
  1088. } catch (IOException ioe) {
  1089. handleIOTrouble(ioe);
  1090. } catch (Exception e) {
  1091. log.error("startFootnote: " + e.getMessage());
  1092. throw new RuntimeException("Exception: " + e);
  1093. }
  1094. }
  1095. /** {@inheritDoc} */
  1096. public void endFootnote(Footnote footnote) {
  1097. if (bDefer) {
  1098. return;
  1099. }
  1100. builderContext.popContainer();
  1101. }
  1102. /** {@inheritDoc} */
  1103. public void startFootnoteBody(FootnoteBody body) {
  1104. if (bDefer) {
  1105. return;
  1106. }
  1107. try {
  1108. RtfFootnote rtfFootnote
  1109. = (RtfFootnote)builderContext.getContainer(
  1110. RtfFootnote.class,
  1111. true, this);
  1112. rtfFootnote.startBody();
  1113. } catch (IOException ioe) {
  1114. handleIOTrouble(ioe);
  1115. } catch (Exception e) {
  1116. log.error("startFootnoteBody: " + e.getMessage());
  1117. throw new RuntimeException("Exception: " + e);
  1118. }
  1119. }
  1120. /** {@inheritDoc} */
  1121. public void endFootnoteBody(FootnoteBody body) {
  1122. if (bDefer) {
  1123. return;
  1124. }
  1125. try {
  1126. RtfFootnote rtfFootnote
  1127. = (RtfFootnote)builderContext.getContainer(
  1128. RtfFootnote.class,
  1129. true, this);
  1130. rtfFootnote.endBody();
  1131. } catch (IOException ioe) {
  1132. handleIOTrouble(ioe);
  1133. } catch (Exception e) {
  1134. log.error("endFootnoteBody: " + e.getMessage());
  1135. throw new RuntimeException("Exception: " + e);
  1136. }
  1137. }
  1138. /** {@inheritDoc} */
  1139. public void startLeader(Leader l) {
  1140. if (bDefer) {
  1141. return;
  1142. }
  1143. try {
  1144. percentManager.setDimension(l);
  1145. RtfAttributes rtfAttr = TextAttributesConverter.convertLeaderAttributes(
  1146. l, percentManager);
  1147. IRtfTextrunContainer container
  1148. = (IRtfTextrunContainer)builderContext.getContainer(
  1149. IRtfTextrunContainer.class, true, this);
  1150. RtfTextrun textrun = container.getTextrun();
  1151. textrun.addLeader(rtfAttr);
  1152. } catch (Exception e) {
  1153. log.error("startLeader: " + e.getMessage());
  1154. throw new RuntimeException(e.getMessage());
  1155. }
  1156. }
  1157. /**
  1158. * @param text FOText object
  1159. * @param characters CharSequence of the characters to process.
  1160. */
  1161. public void text(FOText text, CharSequence characters) {
  1162. if (bDefer) {
  1163. return;
  1164. }
  1165. try {
  1166. IRtfTextrunContainer container
  1167. = (IRtfTextrunContainer)builderContext.getContainer(
  1168. IRtfTextrunContainer.class, true, this);
  1169. RtfTextrun textrun = container.getTextrun();
  1170. RtfAttributes rtfAttr
  1171. = TextAttributesConverter.convertCharacterAttributes(text);
  1172. textrun.pushInlineAttributes(rtfAttr);
  1173. textrun.addString(characters.toString());
  1174. textrun.popInlineAttributes();
  1175. } catch (IOException ioe) {
  1176. handleIOTrouble(ioe);
  1177. } catch (Exception e) {
  1178. log.error("characters:" + e.getMessage());
  1179. throw new RuntimeException(e.getMessage());
  1180. }
  1181. }
  1182. /** {@inheritDoc} */
  1183. public void startPageNumber(PageNumber pagenum) {
  1184. if (bDefer) {
  1185. return;
  1186. }
  1187. try {
  1188. RtfAttributes rtfAttr
  1189. = TextAttributesConverter.convertCharacterAttributes(
  1190. pagenum);
  1191. IRtfTextrunContainer container
  1192. = (IRtfTextrunContainer)builderContext.getContainer(
  1193. IRtfTextrunContainer.class, true, this);
  1194. RtfTextrun textrun = container.getTextrun();
  1195. textrun.addPageNumber(rtfAttr);
  1196. } catch (IOException ioe) {
  1197. handleIOTrouble(ioe);
  1198. } catch (Exception e) {
  1199. log.error("startPageNumber: " + e.getMessage());
  1200. throw new RuntimeException(e.getMessage());
  1201. }
  1202. }
  1203. /** {@inheritDoc} */
  1204. public void endPageNumber(PageNumber pagenum) {
  1205. if (bDefer) {
  1206. return;
  1207. }
  1208. }
  1209. /** {@inheritDoc} */
  1210. public void startPageNumberCitation(PageNumberCitation l) {
  1211. if (bDefer) {
  1212. return;
  1213. }
  1214. try {
  1215. IRtfTextrunContainer container
  1216. = (IRtfTextrunContainer)builderContext.getContainer(
  1217. IRtfTextrunContainer.class, true, this);
  1218. RtfTextrun textrun = container.getTextrun();
  1219. textrun.addPageNumberCitation(l.getRefId());
  1220. } catch (Exception e) {
  1221. log.error("startPageNumberCitation: " + e.getMessage());
  1222. throw new RuntimeException(e.getMessage());
  1223. }
  1224. }
  1225. /** {@inheritDoc} */
  1226. public void startPageNumberCitationLast(PageNumberCitationLast l) {
  1227. if (bDefer) {
  1228. return;
  1229. }
  1230. try {
  1231. IRtfTextrunContainer container
  1232. = (IRtfTextrunContainer)builderContext.getContainer(
  1233. IRtfTextrunContainer.class, true, this);
  1234. RtfTextrun textrun = container.getTextrun();
  1235. textrun.addPageNumberCitation(l.getRefId());
  1236. } catch (RtfException e) {
  1237. log.error("startPageNumberCitationLast: " + e.getMessage());
  1238. throw new RuntimeException(e.getMessage());
  1239. } catch (IOException e) {
  1240. log.error("startPageNumberCitationLast: " + e.getMessage());
  1241. throw new RuntimeException(e.getMessage());
  1242. }
  1243. }
  1244. private void prepareTable(Table tab) {
  1245. // Allows to receive the available width of the table
  1246. percentManager.setDimension(tab);
  1247. // Table gets expanded by half of the border on each side inside Word
  1248. // When using wide borders the table gets cut off
  1249. int tabDiff = tab.getCommonBorderPaddingBackground().getBorderStartWidth(false) / 2
  1250. + tab.getCommonBorderPaddingBackground().getBorderEndWidth(false);
  1251. // check for "auto" value
  1252. if (!(tab.getInlineProgressionDimension().getMaximum(null).getLength()
  1253. instanceof EnumLength)) {
  1254. // value specified
  1255. percentManager.setDimension(tab,
  1256. tab.getInlineProgressionDimension().getMaximum(null)
  1257. .getLength().getValue(percentManager)
  1258. - tabDiff);
  1259. } else {
  1260. // set table width again without border width
  1261. percentManager.setDimension(tab, percentManager.getBaseLength(
  1262. LengthBase.CONTAINING_BLOCK_WIDTH, tab) - tabDiff);
  1263. }
  1264. ColumnSetup columnSetup = new ColumnSetup(tab);
  1265. //int sumOfColumns = columnSetup.getSumOfColumnWidths(percentManager);
  1266. float tableWidth = percentManager.getBaseLength(LengthBase.CONTAINING_BLOCK_WIDTH, tab);
  1267. float tableUnit = columnSetup.computeTableUnit(percentManager, Math.round(tableWidth));
  1268. percentManager.setTableUnit(tab, Math.round(tableUnit));
  1269. }
  1270. /**
  1271. * Calls the appropriate event handler for the passed FObj.
  1272. *
  1273. * @param foNode FO node whose event is to be called
  1274. * @param bStart TRUE calls the start handler, FALSE the end handler
  1275. */
  1276. private void invokeDeferredEvent(FONode foNode, boolean bStart) { // CSOK: MethodLength
  1277. if (foNode instanceof PageSequence) {
  1278. if (bStart) {
  1279. startPageSequence( (PageSequence) foNode);
  1280. } else {
  1281. endPageSequence( (PageSequence) foNode);
  1282. }
  1283. } else if (foNode instanceof Flow) {
  1284. if (bStart) {
  1285. startFlow( (Flow) foNode);
  1286. } else {
  1287. endFlow( (Flow) foNode);
  1288. }
  1289. } else if (foNode instanceof StaticContent) {
  1290. if (bStart) {
  1291. startStatic(null);
  1292. } else {
  1293. endStatic(null);
  1294. }
  1295. } else if (foNode instanceof ExternalGraphic) {
  1296. if (bStart) {
  1297. image( (ExternalGraphic) foNode );
  1298. }
  1299. } else if (foNode instanceof InstreamForeignObject) {
  1300. if (bStart) {
  1301. endInstreamForeignObject( (InstreamForeignObject) foNode );
  1302. }
  1303. } else if (foNode instanceof Block) {
  1304. if (bStart) {
  1305. startBlock( (Block) foNode);
  1306. } else {
  1307. endBlock( (Block) foNode);
  1308. }
  1309. } else if (foNode instanceof BlockContainer) {
  1310. if (bStart) {
  1311. startBlockContainer( (BlockContainer) foNode);
  1312. } else {
  1313. endBlockContainer( (BlockContainer) foNode);
  1314. }
  1315. } else if (foNode instanceof BasicLink) {
  1316. //BasicLink must be placed before Inline
  1317. if (bStart) {
  1318. startLink( (BasicLink) foNode);
  1319. } else {
  1320. endLink(null);
  1321. }
  1322. } else if (foNode instanceof Inline) {
  1323. if (bStart) {
  1324. startInline( (Inline) foNode);
  1325. } else {
  1326. endInline( (Inline) foNode);
  1327. }
  1328. } else if (foNode instanceof FOText) {
  1329. if (bStart) {
  1330. FOText text = (FOText) foNode;
  1331. text(text, text.getCharSequence());
  1332. }
  1333. } else if (foNode instanceof Character) {
  1334. if (bStart) {
  1335. Character c = (Character) foNode;
  1336. character(c);
  1337. }
  1338. } else if (foNode instanceof PageNumber) {
  1339. if (bStart) {
  1340. startPageNumber( (PageNumber) foNode);
  1341. } else {
  1342. endPageNumber( (PageNumber) foNode);
  1343. }
  1344. } else if (foNode instanceof Footnote) {
  1345. if (bStart) {
  1346. startFootnote( (Footnote) foNode);
  1347. } else {
  1348. endFootnote( (Footnote) foNode);
  1349. }
  1350. } else if (foNode instanceof FootnoteBody) {
  1351. if (bStart) {
  1352. startFootnoteBody( (FootnoteBody) foNode);
  1353. } else {
  1354. endFootnoteBody( (FootnoteBody) foNode);
  1355. }
  1356. } else if (foNode instanceof ListBlock) {
  1357. if (bStart) {
  1358. startList( (ListBlock) foNode);
  1359. } else {
  1360. endList( (ListBlock) foNode);
  1361. }
  1362. } else if (foNode instanceof ListItemBody) {
  1363. if (bStart) {
  1364. startListBody(null);
  1365. } else {
  1366. endListBody(null);
  1367. }
  1368. } else if (foNode instanceof ListItem) {
  1369. if (bStart) {
  1370. startListItem( (ListItem) foNode);
  1371. } else {
  1372. endListItem( (ListItem) foNode);
  1373. }
  1374. } else if (foNode instanceof ListItemLabel) {
  1375. if (bStart) {
  1376. startListLabel(null);
  1377. } else {
  1378. endListLabel(null);
  1379. }
  1380. } else if (foNode instanceof Table) {
  1381. if (bStart) {
  1382. startTable( (Table) foNode);
  1383. } else {
  1384. endTable( (Table) foNode);
  1385. }
  1386. } else if (foNode instanceof TableHeader) {
  1387. if (bStart) {
  1388. startHeader( (TableHeader) foNode);
  1389. } else {
  1390. endHeader( (TableHeader) foNode);
  1391. }
  1392. } else if (foNode instanceof TableFooter) {
  1393. if (bStart) {
  1394. startFooter( (TableFooter) foNode);
  1395. } else {
  1396. endFooter( (TableFooter) foNode);
  1397. }
  1398. } else if (foNode instanceof TableBody) {
  1399. if (bStart) {
  1400. startBody( (TableBody) foNode);
  1401. } else {
  1402. endBody( (TableBody) foNode);
  1403. }
  1404. } else if (foNode instanceof TableColumn) {
  1405. if (bStart) {
  1406. startColumn( (TableColumn) foNode);
  1407. } else {
  1408. endColumn( (TableColumn) foNode);
  1409. }
  1410. } else if (foNode instanceof TableRow) {
  1411. if (bStart) {
  1412. startRow( (TableRow) foNode);
  1413. } else {
  1414. endRow( (TableRow) foNode);
  1415. }
  1416. } else if (foNode instanceof TableCell) {
  1417. if (bStart) {
  1418. startCell( (TableCell) foNode);
  1419. } else {
  1420. endCell( (TableCell) foNode);
  1421. }
  1422. } else if (foNode instanceof Leader) {
  1423. if (bStart) {
  1424. startLeader((Leader) foNode);
  1425. }
  1426. } else if (foNode instanceof PageNumberCitation) {
  1427. if (bStart) {
  1428. startPageNumberCitation((PageNumberCitation) foNode);
  1429. } else {
  1430. endPageNumberCitation((PageNumberCitation) foNode);
  1431. }
  1432. } else if (foNode instanceof PageNumberCitationLast) {
  1433. if (bStart) {
  1434. startPageNumberCitationLast((PageNumberCitationLast) foNode);
  1435. } else {
  1436. endPageNumberCitationLast((PageNumberCitationLast) foNode);
  1437. }
  1438. } else {
  1439. RTFEventProducer eventProducer = RTFEventProducer.Provider.get(
  1440. getUserAgent().getEventBroadcaster());
  1441. eventProducer.ignoredDeferredEvent(this, foNode, bStart, foNode.getLocator());
  1442. }
  1443. }
  1444. /**
  1445. * Calls the event handlers for the passed FONode and all its elements.
  1446. *
  1447. * @param foNode FONode object which shall be recursed
  1448. */
  1449. private void recurseFONode(FONode foNode) {
  1450. invokeDeferredEvent(foNode, true);
  1451. if (foNode instanceof PageSequence) {
  1452. PageSequence pageSequence = (PageSequence) foNode;
  1453. Region regionBefore = pagemaster.getRegion(Constants.FO_REGION_BEFORE);
  1454. if (regionBefore != null) {
  1455. FONode staticBefore = (FONode) pageSequence.getFlowMap().get(
  1456. regionBefore.getRegionName());
  1457. if (staticBefore != null) {
  1458. recurseFONode(staticBefore);
  1459. }
  1460. }
  1461. Region regionAfter = pagemaster.getRegion(Constants.FO_REGION_AFTER);
  1462. if (regionAfter != null) {
  1463. FONode staticAfter = (FONode) pageSequence.getFlowMap().get(
  1464. regionAfter.getRegionName());
  1465. if (staticAfter != null) {
  1466. recurseFONode(staticAfter);
  1467. }
  1468. }
  1469. recurseFONode( pageSequence.getMainFlow() );
  1470. } else if (foNode instanceof Table) {
  1471. Table table = (Table) foNode;
  1472. //recurse all table-columns
  1473. if (table.getColumns() != null) {
  1474. //Calculation for column-widths which are not set
  1475. prepareTable(table);
  1476. for (Iterator it = table.getColumns().iterator(); it.hasNext();) {
  1477. recurseFONode( (FONode) it.next() );
  1478. }
  1479. } else {
  1480. //TODO Implement implicit column setup handling!
  1481. RTFEventProducer eventProducer = RTFEventProducer.Provider.get(
  1482. getUserAgent().getEventBroadcaster());
  1483. eventProducer.explicitTableColumnsRequired(this, table.getLocator());
  1484. }
  1485. //recurse table-header
  1486. if (table.getTableHeader() != null) {
  1487. recurseFONode( table.getTableHeader() );
  1488. }
  1489. //recurse table-footer
  1490. if (table.getTableFooter() != null) {
  1491. recurseFONode( table.getTableFooter() );
  1492. }
  1493. if (foNode.getChildNodes() != null) {
  1494. for (Iterator it = foNode.getChildNodes(); it.hasNext();) {
  1495. recurseFONode( (FONode) it.next() );
  1496. }
  1497. }
  1498. } else if (foNode instanceof ListItem) {
  1499. ListItem item = (ListItem) foNode;
  1500. recurseFONode(item.getLabel());
  1501. recurseFONode(item.getBody());
  1502. } else if (foNode instanceof Footnote) {
  1503. Footnote fn = (Footnote)foNode;
  1504. recurseFONode(fn.getFootnoteCitation());
  1505. recurseFONode(fn.getFootnoteBody());
  1506. } else {
  1507. //Any other FO-Object: Simply recurse through all childNodes.
  1508. if (foNode.getChildNodes() != null) {
  1509. for (Iterator it = foNode.getChildNodes(); it.hasNext();) {
  1510. FONode fn = (FONode)it.next();
  1511. if (log.isTraceEnabled()) {
  1512. log.trace(" ChildNode for " + fn + " (" + fn.getName() + ")");
  1513. }
  1514. recurseFONode(fn);
  1515. }
  1516. }
  1517. }
  1518. invokeDeferredEvent(foNode, false);
  1519. }
  1520. }