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 18KB

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