選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

PtocaBuilder.java 14KB

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