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.

DataStream.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  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.afp.modca;
  19. import java.awt.Color;
  20. import java.io.IOException;
  21. import java.io.OutputStream;
  22. import java.util.Iterator;
  23. import java.util.Map;
  24. import org.apache.commons.logging.Log;
  25. import org.apache.commons.logging.LogFactory;
  26. import org.apache.fop.render.afp.AFPFontAttributes;
  27. import org.apache.fop.render.afp.AFPResourceLevel;
  28. import org.apache.fop.render.afp.AFPTextDataInfo;
  29. import org.apache.fop.render.afp.LineDataInfo;
  30. import org.apache.fop.render.afp.fonts.AFPFont;
  31. import org.apache.fop.render.afp.modca.triplets.FullyQualifiedNameTriplet;
  32. /**
  33. * A data stream is a continuous ordered stream of data elements and objects
  34. * conforming to a given format. Application programs can generate data streams
  35. * destined for a presentation service, archive library, presentation device or
  36. * another application program. The strategic presentation data stream
  37. * architectures used is Mixed Object Document Content Architecture (MO:DCA).
  38. *
  39. * The MO:DCA architecture defines the data stream used by applications to
  40. * describe documents and object envelopes for interchange with other
  41. * applications and application services. Documents defined in the MO:DCA format
  42. * may be archived in a database, then later retrieved, viewed, annotated and
  43. * printed in local or distributed systems environments. Presentation fidelity
  44. * is accommodated by including resource objects in the documents that reference
  45. * them.
  46. */
  47. public class DataStream {
  48. /** Static logging instance */
  49. protected static Log log = LogFactory.getLog("org.apache.fop.render.afp.modca");
  50. /** Boolean completion indicator */
  51. private boolean complete = false;
  52. /** The application producing the AFP document */
  53. // not used
  54. // private String producer = null;
  55. /** The AFP document object */
  56. private Document document = null;
  57. /** The current page group object */
  58. private PageGroup currentPageGroup = null;
  59. /** The current page object */
  60. private PageObject currentPageObject = null;
  61. /** The current overlay object */
  62. private Overlay currentOverlay = null;
  63. /** The current page */
  64. private AbstractPageObject currentPage = null;
  65. /** The portrait rotation */
  66. private int portraitRotation = 0;
  67. /** The landscape rotation */
  68. private int landscapeRotation = 270;
  69. /** The rotation */
  70. private int orientation;
  71. /** The MO:DCA interchange set in use (default to MO:DCA-P IS/2 set) */
  72. private InterchangeSet interchangeSet
  73. = InterchangeSet.valueOf(InterchangeSet.MODCA_PRESENTATION_INTERCHANGE_SET_2);
  74. private final Factory factory;
  75. private OutputStream outputStream;
  76. /**
  77. * Default constructor for the AFPDocumentStream.
  78. *
  79. * @param factory the resource factory
  80. * @param outputStream the outputstream to write to
  81. */
  82. public DataStream(Factory factory, OutputStream outputStream) {
  83. this.factory = factory;
  84. this.outputStream = outputStream;
  85. }
  86. /**
  87. * Returns the outputstream
  88. *
  89. * @return the outputstream
  90. */
  91. public OutputStream getOutputStream() {
  92. return this.outputStream;
  93. }
  94. /**
  95. * Returns the document object
  96. *
  97. * @return the document object
  98. */
  99. private Document getDocument() {
  100. return this.document;
  101. }
  102. /**
  103. * Returns the current page
  104. *
  105. * @return the current page
  106. */
  107. public AbstractPageObject getCurrentPage() {
  108. return this.currentPage;
  109. }
  110. /**
  111. * The document is started by invoking this method which creates an instance
  112. * of the AFP Document object.
  113. *
  114. * @param name
  115. * the name of this document.
  116. */
  117. public void setDocumentName(String name) {
  118. if (name != null) {
  119. getDocument().setFullyQualifiedName(
  120. FullyQualifiedNameTriplet.TYPE_BEGIN_DOCUMENT_REF,
  121. FullyQualifiedNameTriplet.FORMAT_CHARSTR, name);
  122. }
  123. }
  124. /** {@inheritDoc} */
  125. public void endDocument() throws IOException {
  126. if (complete) {
  127. String msg = "Invalid state - document already ended.";
  128. log.warn("endDocument():: " + msg);
  129. throw new IllegalStateException(msg);
  130. }
  131. if (currentPageObject != null) {
  132. // End the current page if necessary
  133. endPage();
  134. }
  135. if (currentPageGroup != null) {
  136. // End the current page group if necessary
  137. endPageGroup();
  138. }
  139. // Write out document
  140. if (document != null) {
  141. document.endDocument();
  142. document.writeToStream(this.outputStream);
  143. }
  144. this.outputStream.flush();
  145. this.complete = true;
  146. this.document = null;
  147. this.outputStream = null;
  148. }
  149. /**
  150. * Start a new page. When processing has finished on the current page, the
  151. * {@link #endPage()}method must be invoked to mark the page ending.
  152. *
  153. * @param pageWidth
  154. * the width of the page
  155. * @param pageHeight
  156. * the height of the page
  157. * @param pageRotation
  158. * the rotation of the page
  159. * @param pageWidthRes
  160. * the width resolution of the page
  161. * @param pageHeightRes
  162. * the height resolution of the page
  163. */
  164. public void startPage(int pageWidth, int pageHeight, int pageRotation,
  165. int pageWidthRes, int pageHeightRes) {
  166. currentPageObject = factory.createPage(pageWidth, pageHeight,
  167. pageRotation, pageWidthRes, pageHeightRes);
  168. currentPage = currentPageObject;
  169. currentOverlay = null;
  170. }
  171. /**
  172. * Start a new overlay. When processing has finished on the current overlay,
  173. * the {@link #endOverlay()}method must be invoked to mark the overlay
  174. * ending.
  175. *
  176. * @param x
  177. * the x position of the overlay on the page
  178. * @param y
  179. * the y position of the overlay on the page
  180. * @param width
  181. * the width of the overlay
  182. * @param height
  183. * the height of the overlay
  184. * @param widthRes
  185. * the width resolution of the overlay
  186. * @param heightRes
  187. * the height resolution of the overlay
  188. * @param overlayRotation
  189. * the rotation of the overlay
  190. */
  191. public void startOverlay(int x, int y, int width, int height, int widthRes,
  192. int heightRes, int overlayRotation) {
  193. this.currentOverlay = factory.createOverlay(
  194. width, height, widthRes, heightRes, overlayRotation);
  195. String overlayName = currentOverlay.getName();
  196. currentPageObject.createIncludePageOverlay(overlayName, x, y, 0);
  197. currentPage = currentOverlay;
  198. }
  199. /**
  200. * Helper method to mark the end of the current overlay.
  201. *
  202. * @throws IOException thrown if an I/O exception of some sort has occurred
  203. */
  204. public void endOverlay() throws IOException {
  205. if (currentOverlay != null) {
  206. currentOverlay.endPage();
  207. currentOverlay = null;
  208. currentPage = currentPageObject;
  209. }
  210. }
  211. /**
  212. * Helper method to save the current page.
  213. *
  214. * @return current page object that was saved
  215. */
  216. public PageObject savePage() {
  217. PageObject pageObject = currentPageObject;
  218. if (currentPageGroup != null) {
  219. currentPageGroup.addPage(currentPageObject);
  220. } else {
  221. document.addPage(currentPageObject);
  222. }
  223. currentPageObject = null;
  224. currentPage = null;
  225. return pageObject;
  226. }
  227. /**
  228. * Helper method to restore the current page.
  229. *
  230. * @param pageObject
  231. * page object
  232. */
  233. public void restorePage(PageObject pageObject) {
  234. currentPageObject = pageObject;
  235. currentPage = pageObject;
  236. }
  237. /**
  238. * Helper method to mark the end of the current page.
  239. *
  240. * @throws IOException thrown if an I/O exception of some sort has occurred
  241. */
  242. public void endPage() throws IOException {
  243. if (currentPageObject != null) {
  244. currentPageObject.endPage();
  245. if (currentPageGroup != null) {
  246. currentPageGroup.addPage(currentPageObject);
  247. currentPageGroup.writeToStream(this.outputStream);
  248. } else {
  249. document.addPage(currentPageObject);
  250. document.writeToStream(this.outputStream);
  251. }
  252. currentPageObject = null;
  253. currentPage = null;
  254. }
  255. }
  256. /**
  257. * Sets the offsets to be used for element positioning
  258. *
  259. * @param xOff
  260. * the offset in the x direction
  261. * @param yOff
  262. * the offset in the y direction
  263. * @param orientation
  264. * the rotation
  265. * @deprecated offsets are no longer used, use setOrientation() for setting the orientation
  266. */
  267. public void setOffsets(int xOff, int yOff, int orientation) {
  268. setOrientation(orientation);
  269. }
  270. /**
  271. * Sets the orientation to be used for element positioning
  272. *
  273. * @param orientation
  274. * the orientation used for element positioning
  275. */
  276. public void setOrientation(int orientation) {
  277. this.orientation = orientation;
  278. }
  279. /**
  280. * Creates the given page fonts in the current page
  281. *
  282. * @param pageFonts
  283. * a collection of AFP font attributes
  284. */
  285. public void addFontsToCurrentPage(Map pageFonts) {
  286. Iterator iter = pageFonts.values().iterator();
  287. while (iter.hasNext()) {
  288. AFPFontAttributes afpFontAttributes = (AFPFontAttributes) iter
  289. .next();
  290. createFont(afpFontAttributes.getFontReference(), afpFontAttributes
  291. .getFont(), afpFontAttributes.getPointSize());
  292. }
  293. }
  294. /**
  295. * Helper method to create a map coded font object on the current page, this
  296. * method delegates the construction of the map coded font object to the
  297. * active environment group on the current page.
  298. *
  299. * @param fontReference
  300. * the font number used as the resource identifier
  301. * @param font
  302. * the font
  303. * @param size
  304. * the point size of the font
  305. */
  306. public void createFont(int fontReference, AFPFont font, int size) {
  307. currentPage.createFont(fontReference, font, size);
  308. }
  309. /**
  310. * Helper method to create text on the current page, this method delegates
  311. * to the current presentation text object in order to construct the text.
  312. *
  313. * @param textDataInfo
  314. * the afp text data
  315. */
  316. public void createText(AFPTextDataInfo textDataInfo) {
  317. textDataInfo.setOrientation(orientation);
  318. currentPage.createText(textDataInfo);
  319. }
  320. /**
  321. * Method to create a line on the current page.
  322. *
  323. * @param lineDataInfo the line data information.
  324. */
  325. public void createLine(LineDataInfo lineDataInfo) {
  326. lineDataInfo.setOrientation(orientation);
  327. currentPage.createLine(lineDataInfo);
  328. }
  329. /**
  330. * This method will create shading on the page using the specified
  331. * coordinates (the shading contrast is controlled via the red, green, blue
  332. * parameters, by converting this to grey scale).
  333. *
  334. * @param x
  335. * the x coordinate of the shading
  336. * @param y
  337. * the y coordinate of the shading
  338. * @param w
  339. * the width of the shaded area
  340. * @param h
  341. * the height of the shaded area
  342. * @param col
  343. * the shading color
  344. */
  345. public void createShading(int x, int y, int w, int h, Color col) {
  346. currentPageObject.createShading(x, y, w, h, col.getRed(), col.getGreen(), col.getBlue());
  347. }
  348. /**
  349. * Helper method which allows creation of the MPO object, via the AEG. And
  350. * the IPO via the Page. (See actual object for descriptions.)
  351. *
  352. * @param name
  353. * the name of the static overlay
  354. */
  355. public void createIncludePageOverlay(String name) {
  356. currentPageObject.createIncludePageOverlay(name, 0, 0, orientation);
  357. currentPageObject.getActiveEnvironmentGroup().createOverlay(name);
  358. }
  359. /**
  360. * Helper method which allows creation of the IMM object.
  361. *
  362. * @param name
  363. * the name of the medium map
  364. */
  365. public void createInvokeMediumMap(String name) {
  366. currentPageGroup.createInvokeMediumMap(name);
  367. }
  368. /**
  369. * Creates an IncludePageSegment on the current page.
  370. *
  371. * @param name
  372. * the name of the include page segment
  373. * @param x
  374. * the x coordinate for the overlay
  375. * @param y
  376. * the y coordinate for the overlay
  377. */
  378. public void createIncludePageSegment(String name, int x, int y) {
  379. int xOrigin;
  380. int yOrigin;
  381. switch (orientation) {
  382. case 90:
  383. xOrigin = currentPage.getWidth() - y;
  384. yOrigin = x;
  385. break;
  386. case 180:
  387. xOrigin = currentPage.getWidth() - x;
  388. yOrigin = currentPage.getHeight() - y;
  389. break;
  390. case 270:
  391. xOrigin = y;
  392. yOrigin = currentPage.getHeight() - x;
  393. break;
  394. default:
  395. xOrigin = x;
  396. yOrigin = y;
  397. break;
  398. }
  399. currentPage.createIncludePageSegment(name, xOrigin, yOrigin);
  400. }
  401. /**
  402. * Creates a TagLogicalElement on the current page.
  403. *
  404. * @param attributes
  405. * the array of key value pairs.
  406. */
  407. public void createPageTagLogicalElement(TagLogicalElementBean[] attributes) {
  408. for (int i = 0; i < attributes.length; i++) {
  409. String name = attributes[i].getKey();
  410. String value = attributes[i].getValue();
  411. currentPage.createTagLogicalElement(name, value);
  412. }
  413. }
  414. /**
  415. * Creates a TagLogicalElement on the current page group.
  416. *
  417. * @param attributes
  418. * the array of key value pairs.
  419. */
  420. public void createPageGroupTagLogicalElement(TagLogicalElementBean[] attributes) {
  421. for (int i = 0; i < attributes.length; i++) {
  422. String name = attributes[i].getKey();
  423. String value = attributes[i].getValue();
  424. currentPageGroup.createTagLogicalElement(name, value);
  425. }
  426. }
  427. /**
  428. * Creates a TagLogicalElement on the current page or page group
  429. *
  430. * @param name
  431. * The tag name
  432. * @param value
  433. * The tag value
  434. */
  435. public void createTagLogicalElement(String name, String value) {
  436. if (currentPageGroup != null) {
  437. currentPageGroup.createTagLogicalElement(name, value);
  438. } else {
  439. currentPage.createTagLogicalElement(name, value);
  440. }
  441. }
  442. /**
  443. * Creates a NoOperation item
  444. *
  445. * @param content
  446. * byte data
  447. */
  448. public void createNoOperation(String content) {
  449. currentPage.createNoOperation(content);
  450. }
  451. /**
  452. * Returns the current page group
  453. *
  454. * @return the current page group
  455. */
  456. public PageGroup getCurrentPageGroup() {
  457. return this.currentPageGroup;
  458. }
  459. /**
  460. * Start a new document.
  461. *
  462. * @throws IOException thrown if an I/O exception of some sort has occurred
  463. */
  464. public void startDocument() throws IOException {
  465. this.document = factory.createDocument();
  466. document.writeToStream(this.outputStream);
  467. }
  468. /**
  469. * Start a new page group. When processing has finished on the current page
  470. * group the {@link #endPageGroup()}method must be invoked to mark the page
  471. * group ending.
  472. *
  473. * @throws IOException thrown if an I/O exception of some sort has occurred
  474. */
  475. public void startPageGroup() throws IOException {
  476. endPageGroup();
  477. this.currentPageGroup = factory.createPageGroup();
  478. }
  479. /**
  480. * Helper method to mark the end of the page group.
  481. *
  482. * @throws IOException thrown if an I/O exception of some sort has occurred
  483. */
  484. public void endPageGroup() throws IOException {
  485. if (currentPageGroup != null) {
  486. currentPageGroup.endPageGroup();
  487. document.addPageGroup(currentPageGroup);
  488. document.writeToStream(outputStream);
  489. currentPageGroup = null;
  490. }
  491. }
  492. /**
  493. * Sets the rotation to be used for portrait pages, valid values are 0
  494. * (default), 90, 180, 270.
  495. *
  496. * @param pageRotation the rotation in degrees.
  497. */
  498. public void setPortraitRotation(int pageRotation) {
  499. if (pageRotation == 0 || pageRotation == 90 || pageRotation == 180
  500. || pageRotation == 270) {
  501. this.portraitRotation = pageRotation;
  502. } else {
  503. throw new IllegalArgumentException(
  504. "The portrait rotation must be one of the values 0, 90, 180, 270");
  505. }
  506. }
  507. /**
  508. * Sets the rotation to be used for landscape pages, valid values are 0, 90,
  509. * 180, 270 (default).
  510. *
  511. * @param pageRotation the rotation in degrees.
  512. */
  513. public void setLandscapeRotation(int pageRotation) {
  514. if (pageRotation == 0 || pageRotation == 90 || pageRotation == 180
  515. || pageRotation == 270) {
  516. this.landscapeRotation = pageRotation;
  517. } else {
  518. throw new IllegalArgumentException(
  519. "The landscape rotation must be one of the values 0, 90, 180, 270");
  520. }
  521. }
  522. /**
  523. * Sets the MO:DCA interchange set to use
  524. *
  525. * @param interchangeSet the MO:DCA interchange set
  526. */
  527. public void setInterchangeSet(InterchangeSet interchangeSet) {
  528. this.interchangeSet = interchangeSet;
  529. }
  530. /**
  531. * Returns the MO:DCA interchange set in use
  532. *
  533. * @return the MO:DCA interchange set in use
  534. */
  535. public InterchangeSet getInterchangeSet() {
  536. return this.interchangeSet;
  537. }
  538. /**
  539. * Returns the resource group for a given resource info
  540. *
  541. * @param level a resource level
  542. * @return a resource group for the given resource info
  543. */
  544. public ResourceGroup getResourceGroup(AFPResourceLevel level) {
  545. ResourceGroup resourceGroup = null;
  546. if (level.isDocument()) {
  547. resourceGroup = document.getResourceGroup();
  548. } else if (level.isPageGroup()) {
  549. resourceGroup = currentPageGroup.getResourceGroup();
  550. } else if (level.isPage()) {
  551. resourceGroup = currentPageObject.getResourceGroup();
  552. }
  553. return resourceGroup;
  554. }
  555. }