Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

PtocaBuilder.java 15KB

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