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.

PtocaBuilder.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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.ptoca;
  19. import java.awt.Color;
  20. import java.awt.color.ColorSpace;
  21. import java.io.IOException;
  22. import java.io.OutputStream;
  23. import org.apache.commons.io.output.ByteArrayOutputStream;
  24. import org.apache.xmlgraphics.java2d.color.CIELabColorSpace;
  25. import org.apache.xmlgraphics.java2d.color.ColorUtil;
  26. import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
  27. import org.apache.fop.afp.fonts.CharactersetEncoder.EncodedChars;
  28. import org.apache.fop.afp.modca.AxisOrientation;
  29. import org.apache.fop.afp.ptoca.TransparentDataControlSequence.TransparentData;
  30. /**
  31. * Generator class for PTOCA data structures.
  32. */
  33. public abstract class PtocaBuilder implements PtocaConstants {
  34. private ByteArrayOutputStream baout = new ByteArrayOutputStream(256);
  35. /** the current x coordinate. */
  36. private int currentX = -1;
  37. /** the current y coordinate */
  38. private int currentY = -1;
  39. /** the current font */
  40. private int currentFont = Integer.MIN_VALUE;
  41. /** the current orientation */
  42. private int currentOrientation;
  43. /** the current color */
  44. private Color currentColor = Color.BLACK;
  45. /** the current variable space increment */
  46. private int currentVariableSpaceCharacterIncrement;
  47. /** the current inter character adjustment */
  48. private int currentInterCharacterAdjustment;
  49. /**
  50. * Returns an {@link OutputStream} for the next control sequence. This gives a subclass a
  51. * chance to do chunking of control sequences into multiple presentation text data objects.
  52. * @param length the length of the following control sequence
  53. * @return the output stream where the control sequence will be written to
  54. */
  55. protected abstract OutputStream getOutputStreamForControlSequence(int length);
  56. private static byte chained(byte functionType) {
  57. return (byte)(functionType | CHAIN_BIT);
  58. }
  59. private void newControlSequence() {
  60. baout.reset();
  61. }
  62. private void commit(byte functionType) throws IOException {
  63. int length = baout.size() + 2;
  64. assert length < 256;
  65. OutputStream out = getOutputStreamForControlSequence(length);
  66. out.write(length);
  67. out.write(functionType);
  68. baout.writeTo(out);
  69. }
  70. private void writeBytes(int... data) {
  71. for (int d : data) {
  72. baout.write(d);
  73. }
  74. }
  75. private void writeShort(int data) {
  76. baout.write((data >>> 8) & 0xFF);
  77. baout.write(data & 0xFF);
  78. }
  79. /**
  80. * Writes the introducer for a chained control sequence.
  81. * @throws IOException if an I/O error occurs
  82. */
  83. public void writeIntroducer() throws IOException {
  84. OutputStream out = getOutputStreamForControlSequence(ESCAPE.length);
  85. out.write(ESCAPE);
  86. }
  87. /**
  88. * The Set Coded Font Local control sequence activates a coded font and
  89. * specifies the character attributes to be used.
  90. * <p>
  91. * This is a modal control sequence.
  92. *
  93. * @param font The font local identifier.
  94. * @throws IOException if an I/O error occurs
  95. */
  96. public void setCodedFont(byte font) throws IOException {
  97. // Avoid unnecessary specification of the font
  98. if (currentFont == font) {
  99. return;
  100. } else {
  101. currentFont = font;
  102. }
  103. newControlSequence();
  104. writeBytes(font);
  105. commit(chained(SCFL));
  106. }
  107. /**
  108. * Establishes the current presentation position on the baseline at a new
  109. * I-axis coordinate, which is a specified number of measurement units from
  110. * the B-axis. There is no change to the current B-axis coordinate.
  111. *
  112. * @param coordinate The coordinate for the inline move.
  113. * @throws IOException if an I/O error occurs
  114. */
  115. public void absoluteMoveInline(int coordinate) throws IOException {
  116. if (coordinate == this.currentX) {
  117. return;
  118. }
  119. newControlSequence();
  120. writeShort(coordinate);
  121. commit(chained(AMI));
  122. currentX = coordinate;
  123. }
  124. /**
  125. * Moves the inline coordinate of the presentation position relative to the current
  126. * inline position.
  127. * @param increment the increment in 1/1440 inch units
  128. * @throws IOException if an I/O error occurs
  129. */
  130. public void relativeMoveInline(int increment) throws IOException {
  131. newControlSequence();
  132. writeShort(increment);
  133. commit(chained(RMI));
  134. }
  135. /**
  136. * Establishes the baseline and the current presentation position at a new
  137. * B-axis coordinate, which is a specified number of measurement units from
  138. * the I-axis. There is no change to the current I-axis coordinate.
  139. *
  140. * @param coordinate The coordinate for the baseline move.
  141. * @throws IOException if an I/O error occurs
  142. */
  143. public void absoluteMoveBaseline(int coordinate) throws IOException {
  144. if (coordinate == this.currentY) {
  145. return;
  146. }
  147. newControlSequence();
  148. writeShort(coordinate);
  149. commit(chained(AMB));
  150. currentY = coordinate;
  151. currentX = -1;
  152. }
  153. /**
  154. * The Transparent Data control sequence contains a sequence of code points
  155. * that are presented without a scan for embedded control sequences. If the data is larger
  156. * than fits in one chunk, additional chunks are automatically generated.
  157. *
  158. * @param encodedChars The encoded text data to add.
  159. * @throws IOException if an I/O error occurs
  160. */
  161. public void addTransparentData(EncodedChars encodedChars) throws IOException {
  162. for (TransparentData trn : new TransparentDataControlSequence(encodedChars)) {
  163. newControlSequence();
  164. trn.writeTo(baout);
  165. commit(chained(TRN));
  166. }
  167. }
  168. /**
  169. * Draws a line of specified length and specified width in the B-direction
  170. * from the current presentation position. The location of the current
  171. * presentation position is unchanged.
  172. *
  173. * @param length The length of the rule.
  174. * @param width The width of the rule.
  175. * @throws IOException if an I/O error occurs
  176. */
  177. public void drawBaxisRule(int length, int width) throws IOException {
  178. newControlSequence();
  179. writeShort(length); // Rule length
  180. writeShort(width); // Rule width
  181. writeBytes(0); // Rule width fraction is always null. enough?
  182. commit(chained(DBR));
  183. }
  184. /**
  185. * Draws a line of specified length and specified width in the I-direction
  186. * from the current presentation position. The location of the current
  187. * presentation position is unchanged.
  188. *
  189. * @param length The length of the rule.
  190. * @param width The width of the rule.
  191. * @throws IOException if an I/O error occurs
  192. */
  193. public void drawIaxisRule(int length, int width) throws IOException {
  194. newControlSequence();
  195. writeShort(length); // Rule length
  196. writeShort(width); // Rule width
  197. writeBytes(0); // Rule width fraction is always null. enough?
  198. commit(chained(DIR));
  199. }
  200. /**
  201. * The Set Text Orientation control sequence establishes the I-direction and
  202. * B-direction for the subsequent text. This is a modal control sequence.
  203. *
  204. * Semantics: This control sequence specifies the I-axis and B-axis
  205. * orientations with respect to the Xp-axis for the current Presentation
  206. * Text object. The orientations are rotational values expressed in degrees
  207. * and minutes.
  208. *
  209. * @param orientation The text orientation (0, 90, 180, 270).
  210. * @throws IOException if an I/O error occurs
  211. */
  212. public void setTextOrientation(int orientation) throws IOException {
  213. if (orientation == this.currentOrientation) {
  214. return;
  215. }
  216. newControlSequence();
  217. AxisOrientation.getRightHandedAxisOrientationFor(orientation).writeTo(baout);
  218. commit(chained(STO));
  219. this.currentOrientation = orientation;
  220. currentX = -1;
  221. currentY = -1;
  222. }
  223. /**
  224. * The Set Extended Text Color control sequence specifies a color value and
  225. * defines the color space and encoding for that value. The specified color
  226. * value is applied to foreground areas of the text presentation space.
  227. * <p>
  228. * This is a modal control sequence.
  229. *
  230. * @param col The color to be set.
  231. * @throws IOException if an I/O error occurs
  232. */
  233. public void setExtendedTextColor(Color col) throws IOException {
  234. if (ColorUtil.isSameColor(col, currentColor)) {
  235. return;
  236. }
  237. if (col instanceof ColorWithAlternatives) {
  238. ColorWithAlternatives cwa = (ColorWithAlternatives)col;
  239. Color alt = cwa.getFirstAlternativeOfType(ColorSpace.TYPE_CMYK);
  240. if (alt != null) {
  241. col = alt;
  242. }
  243. }
  244. ColorSpace cs = col.getColorSpace();
  245. newControlSequence();
  246. if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) {
  247. // Color space - 0x04 = CMYK, all else are reserved and must be zero
  248. writeBytes(0x00, 0x04, 0x00, 0x00, 0x00, 0x00);
  249. writeBytes(8, 8, 8, 8); // Number of bits in component 1, 2, 3 & 4 respectively
  250. float[] comps = col.getColorComponents(null);
  251. assert comps.length == 4;
  252. for (int i = 0; i < 4; i++) {
  253. int component = Math.round(comps[i] * 255);
  254. writeBytes(component);
  255. }
  256. } else if (cs instanceof CIELabColorSpace) {
  257. // Color space - 0x08 = CIELAB, all else are reserved and must be zero
  258. writeBytes(0x00, 0x08, 0x00, 0x00, 0x00, 0x00);
  259. writeBytes(8, 8, 8, 0); // Number of bits in component 1,2,3 & 4
  260. //Sadly, 16 bit components don't seem to work
  261. float[] colorComponents = col.getColorComponents(null);
  262. int l = Math.round(colorComponents[0] * 255f);
  263. int a = Math.round(colorComponents[1] * 255f) - 128;
  264. int b = Math.round(colorComponents[2] * 255f) - 128;
  265. writeBytes(l, a, b); // l*, a* and b*
  266. } else {
  267. // Color space - 0x01 = RGB, all else are reserved and must be zero
  268. writeBytes(0x00, 0x01, 0x00, 0x00, 0x00, 0x00);
  269. writeBytes(8, 8, 8, 0); // Number of bits in component 1, 2, 3 & 4 respectively
  270. writeBytes(col.getRed(), col.getGreen(), col.getBlue()); // RGB intensity
  271. }
  272. commit(chained(SEC));
  273. this.currentColor = col;
  274. }
  275. /**
  276. * Sets the variable space character increment.
  277. * <p>
  278. * This is a modal control sequence.
  279. *
  280. * @param incr The increment to be set (positive integer, 1/1440 inch)
  281. * @throws IOException if an I/O error occurs
  282. */
  283. public void setVariableSpaceCharacterIncrement(int incr) throws IOException {
  284. if (incr == this.currentVariableSpaceCharacterIncrement) {
  285. return;
  286. }
  287. assert incr >= 0 && incr < (1 << 16);
  288. newControlSequence();
  289. writeShort(Math.abs(incr)); //Increment
  290. commit(chained(SVI));
  291. this.currentVariableSpaceCharacterIncrement = incr;
  292. }
  293. /**
  294. * Sets the intercharacter adjustment (additional increment or decrement between graphic
  295. * characters).
  296. * <p>
  297. * This is a modal control sequence.
  298. *
  299. * @param incr The increment to be set (1/1440 inch)
  300. * @throws IOException if an I/O error occurs
  301. */
  302. public void setInterCharacterAdjustment(int incr) throws IOException {
  303. if (incr == this.currentInterCharacterAdjustment) {
  304. return;
  305. }
  306. assert incr >= Short.MIN_VALUE && incr <= Short.MAX_VALUE;
  307. newControlSequence();
  308. writeShort(Math.abs(incr)); //Increment
  309. writeBytes(incr >= 0 ? 0 : 1); // Direction
  310. commit(chained(SIA));
  311. this.currentInterCharacterAdjustment = incr;
  312. }
  313. /**
  314. * A control sequence is a sequence of bytes that specifies a control
  315. * function. A control sequence consists of a control sequence introducer
  316. * and zero or more parameters. The control sequence can extend multiple
  317. * presentation text data objects, but must eventually be terminated. This
  318. * method terminates the control sequence (by using a NOP command).
  319. *
  320. * @throws IOException if an I/O error occurs
  321. */
  322. public void endChainedControlSequence() throws IOException {
  323. newControlSequence();
  324. commit(NOP);
  325. }
  326. }