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

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