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.

AFPPaintingState.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  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.Point;
  20. import org.apache.commons.logging.Log;
  21. import org.apache.commons.logging.LogFactory;
  22. import org.apache.xmlgraphics.java2d.color.ColorConverter;
  23. import org.apache.xmlgraphics.java2d.color.DefaultColorConverter;
  24. import org.apache.fop.afp.fonts.AFPPageFonts;
  25. import org.apache.fop.util.AbstractPaintingState;
  26. /**
  27. * This keeps information about the current painting state when writing to an
  28. * AFP datastream.
  29. */
  30. public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState implements
  31. Cloneable {
  32. private static final long serialVersionUID = 8206711712452344473L;
  33. private static Log log = LogFactory.getLog("org.apache.xmlgraphics.afp");
  34. /** the portrait rotation */
  35. private int portraitRotation = 0;
  36. /** the landscape rotation */
  37. private int landscapeRotation = 270;
  38. /** color image support */
  39. private boolean colorImages = false;
  40. /** dithering quality setting (0.0f..1.0f) */
  41. private float ditheringQuality;
  42. /** color image handler */
  43. private ColorConverter colorConverter = GrayScaleColorConverter.getInstance();
  44. /**
  45. * true if certain image formats may be embedded unchanged in their native
  46. * format.
  47. */
  48. private boolean nativeImagesSupported = false;
  49. /**
  50. * true if CMYK images (requires IOCA FS45 suppport on the target platform)
  51. * may be generated
  52. */
  53. private boolean cmykImagesSupported;
  54. /** default value for image depth */
  55. private int bitsPerPixel = 8;
  56. /** the output resolution */
  57. private int resolution = 240; // 240 dpi
  58. /** determines whether GOCA is enabled or disabled */
  59. private boolean gocaEnabled = true;
  60. /** determines whether to stroke text in GOCA mode or to use text operators where possible */
  61. private boolean strokeGocaText = false;
  62. /** the current page */
  63. private transient AFPPagePaintingState pagePaintingState = new AFPPagePaintingState();
  64. // /** reference orientation */
  65. // private int orientation = 0;
  66. /** a unit converter */
  67. private final transient AFPUnitConverter unitConv = new AFPUnitConverter(this);
  68. /**
  69. * Sets the rotation to be used for portrait pages, valid values are 0
  70. * (default), 90, 180, 270.
  71. *
  72. * @param rotation
  73. * The rotation in degrees.
  74. */
  75. public void setPortraitRotation(int rotation) {
  76. if (rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270) {
  77. portraitRotation = rotation;
  78. } else {
  79. throw new IllegalArgumentException("The portrait rotation must be one"
  80. + " of the values 0, 90, 180, 270");
  81. }
  82. }
  83. /**
  84. * Returns the rotation to be used for portrait pages
  85. *
  86. * @return the rotation to be used for portrait pages
  87. */
  88. protected int getPortraitRotation() {
  89. return this.portraitRotation;
  90. }
  91. /**
  92. * Sets the rotation to be used for landscape pages, valid values are 0, 90,
  93. * 180, 270 (default).
  94. *
  95. * @param rotation
  96. * The rotation in degrees.
  97. */
  98. public void setLandscapeRotation(int rotation) {
  99. if (rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270) {
  100. landscapeRotation = rotation;
  101. } else {
  102. throw new IllegalArgumentException("The landscape rotation must be one"
  103. + " of the values 0, 90, 180, 270");
  104. }
  105. }
  106. /**
  107. * Returns the landscape rotation
  108. *
  109. * @return the landscape rotation
  110. */
  111. protected int getLandscapeRotation() {
  112. return this.landscapeRotation;
  113. }
  114. /**
  115. * Sets the number of bits used per pixel
  116. *
  117. * @param bitsPerPixel
  118. * number of bits per pixel
  119. */
  120. public void setBitsPerPixel(int bitsPerPixel) {
  121. switch (bitsPerPixel) {
  122. case 1:
  123. case 4:
  124. case 8:
  125. this.bitsPerPixel = bitsPerPixel;
  126. break;
  127. default:
  128. log.warn("Invalid bits_per_pixel value, must be 1, 4 or 8.");
  129. this.bitsPerPixel = 8;
  130. break;
  131. }
  132. }
  133. /**
  134. * Returns the number of bits per pixel
  135. *
  136. * @return the number of bits per pixel
  137. */
  138. public int getBitsPerPixel() {
  139. return this.bitsPerPixel;
  140. }
  141. /**
  142. * Sets whether images are color or not and instantiates a ColorHandler
  143. *
  144. * @param colorImages
  145. * color image output
  146. */
  147. public void setColorImages(boolean colorImages) {
  148. this.colorImages = colorImages;
  149. if (colorImages) {
  150. this.colorConverter = DefaultColorConverter.getInstance();
  151. }
  152. }
  153. /**
  154. * Returns true if color images are to be used
  155. *
  156. * @return true if color images are to be used
  157. */
  158. public boolean isColorImages() {
  159. return this.colorImages;
  160. }
  161. /**
  162. * Used to convert color in respect of the colorImages flag
  163. *
  164. * @return the color converter
  165. */
  166. public ColorConverter getColorConverter() {
  167. return this.colorConverter;
  168. }
  169. /**
  170. * Sets whether images are natively supported or not in the AFP environment
  171. *
  172. * @param nativeImagesSupported
  173. * true if images are natively supported in this AFP environment
  174. */
  175. public void setNativeImagesSupported(boolean nativeImagesSupported) {
  176. this.nativeImagesSupported = nativeImagesSupported;
  177. }
  178. /**
  179. * Returns true if images are supported natively in this AFP environment
  180. *
  181. * @return true if images are supported natively in this AFP environment
  182. */
  183. public boolean isNativeImagesSupported() {
  184. return this.nativeImagesSupported;
  185. }
  186. /**
  187. * Controls whether CMYK images (IOCA FS45) are enabled. By default, support
  188. * is disabled for wider compatibility. When disabled, any CMYK image is
  189. * converted to the selected color format.
  190. *
  191. * @param value
  192. * true to enabled CMYK images
  193. */
  194. public void setCMYKImagesSupported(boolean value) {
  195. this.cmykImagesSupported = value;
  196. }
  197. /**
  198. * Indicates whether CMYK images (IOCA FS45) are enabled.
  199. *
  200. * @return true if IOCA FS45 is enabled
  201. */
  202. public boolean isCMYKImagesSupported() {
  203. return this.cmykImagesSupported;
  204. }
  205. /**
  206. * Gets the dithering quality setting to use when converting images to monochrome images.
  207. * @return the dithering quality (a value between 0.0f and 1.0f)
  208. */
  209. public float getDitheringQuality() {
  210. return this.ditheringQuality;
  211. }
  212. /**
  213. * Sets the dithering quality setting to use when converting images to monochrome images.
  214. * @param quality Defines the desired quality level for the conversion.
  215. * Valid values: a value between 0.0f (fastest) and 1.0f (best)
  216. */
  217. public void setDitheringQuality(float quality) {
  218. quality = Math.max(quality, 0.0f);
  219. quality = Math.min(quality, 1.0f);
  220. this.ditheringQuality = quality;
  221. }
  222. /**
  223. * Sets the output/device resolution
  224. *
  225. * @param resolution
  226. * the output resolution (dpi)
  227. */
  228. public void setResolution(int resolution) {
  229. if (log.isDebugEnabled()) {
  230. log.debug("renderer-resolution set to: " + resolution + "dpi");
  231. }
  232. this.resolution = resolution;
  233. }
  234. /**
  235. * Returns the output/device resolution.
  236. *
  237. * @return the resolution in dpi
  238. */
  239. public int getResolution() {
  240. return this.resolution;
  241. }
  242. /**
  243. * Controls whether GOCA is enabled or disabled.
  244. * @param enabled true if GOCA is enabled, false if it is disabled
  245. */
  246. public void setGOCAEnabled(boolean enabled) {
  247. this.gocaEnabled = enabled;
  248. }
  249. /**
  250. * Indicates whether GOCA is enabled or disabled.
  251. * @return true if GOCA is enabled, false if GOCA is disabled
  252. */
  253. public boolean isGOCAEnabled() {
  254. return this.gocaEnabled;
  255. }
  256. /**
  257. * Controls whether to stroke text in GOCA mode or to use text operators where possible.
  258. * @param stroke true to stroke, false to paint with text operators where possible
  259. */
  260. public void setStrokeGOCAText(boolean stroke) {
  261. this.strokeGocaText = stroke;
  262. }
  263. /**
  264. * Indicates whether to stroke text in GOCA mode or to use text operators where possible.
  265. * @return true to stroke, false to paint with text operators where possible
  266. */
  267. public boolean isStrokeGOCAText() {
  268. return this.strokeGocaText;
  269. }
  270. /** {@inheritDoc} */
  271. @Override
  272. protected AbstractData instantiateData() {
  273. return new AFPData();
  274. }
  275. /** {@inheritDoc} */
  276. @Override
  277. protected AbstractPaintingState instantiate() {
  278. return new AFPPaintingState();
  279. }
  280. /**
  281. * Returns the painting state of the current page
  282. *
  283. * @return the painting state of the current page
  284. */
  285. protected AFPPagePaintingState getPagePaintingState() {
  286. return this.pagePaintingState;
  287. }
  288. /**
  289. * Gets the current page fonts
  290. *
  291. * @return the current page fonts
  292. */
  293. public AFPPageFonts getPageFonts() {
  294. return pagePaintingState.getFonts();
  295. }
  296. /**
  297. * Sets the page width
  298. *
  299. * @param pageWidth
  300. * the page width
  301. */
  302. public void setPageWidth(int pageWidth) {
  303. pagePaintingState.setWidth(pageWidth);
  304. }
  305. /**
  306. * Returns the page width
  307. *
  308. * @return the page width
  309. */
  310. public int getPageWidth() {
  311. return pagePaintingState.getWidth();
  312. }
  313. /**
  314. * Sets the page height
  315. *
  316. * @param pageHeight
  317. * the page height
  318. */
  319. public void setPageHeight(int pageHeight) {
  320. pagePaintingState.setHeight(pageHeight);
  321. }
  322. /**
  323. * Returns the page height
  324. *
  325. * @return the page height
  326. */
  327. public int getPageHeight() {
  328. return pagePaintingState.getHeight();
  329. }
  330. /**
  331. * Returns the page rotation
  332. *
  333. * @return the page rotation
  334. */
  335. public int getPageRotation() {
  336. return pagePaintingState.getOrientation();
  337. }
  338. /**
  339. * Sets the uri of the current image
  340. *
  341. * @param uri
  342. * the uri of the current image
  343. */
  344. public void setImageUri(String uri) {
  345. ((AFPData) getData()).imageUri = uri;
  346. }
  347. /**
  348. * Gets the uri of the current image
  349. *
  350. * @return the uri of the current image
  351. */
  352. public String getImageUri() {
  353. return ((AFPData) getData()).imageUri;
  354. }
  355. /**
  356. * Returns the currently derived rotation
  357. *
  358. * @return the currently derived rotation
  359. */
  360. public int getRotation() {
  361. return getData().getDerivedRotation();
  362. }
  363. /**
  364. * Returns the unit converter
  365. *
  366. * @return the unit converter
  367. */
  368. public AFPUnitConverter getUnitConverter() {
  369. return this.unitConv;
  370. }
  371. /**
  372. * Returns a point on the current page, taking the current painting state
  373. * into account.
  374. *
  375. * @param x
  376. * the X-coordinate
  377. * @param y
  378. * the Y-coordinate
  379. * @return a point on the current page
  380. */
  381. public Point getPoint(int x, int y) {
  382. Point p = new Point();
  383. int rotation = getRotation();
  384. switch (rotation) {
  385. case 90:
  386. p.x = y;
  387. p.y = getPageWidth() - x;
  388. break;
  389. case 180:
  390. p.x = getPageWidth() - x;
  391. p.y = getPageHeight() - y;
  392. break;
  393. case 270:
  394. p.x = getPageHeight() - y;
  395. p.y = x;
  396. break;
  397. default:
  398. p.x = x;
  399. p.y = y;
  400. break;
  401. }
  402. return p;
  403. }
  404. /** {@inheritDoc} */
  405. @Override
  406. public Object clone() {
  407. AFPPaintingState paintingState = (AFPPaintingState) super.clone();
  408. paintingState.pagePaintingState = (AFPPagePaintingState) this.pagePaintingState.clone();
  409. paintingState.portraitRotation = this.portraitRotation;
  410. paintingState.landscapeRotation = this.landscapeRotation;
  411. paintingState.bitsPerPixel = this.bitsPerPixel;
  412. paintingState.colorImages = this.colorImages;
  413. paintingState.colorConverter = this.colorConverter;
  414. paintingState.resolution = this.resolution;
  415. return paintingState;
  416. }
  417. /** {@inheritDoc} */
  418. @Override
  419. public String toString() {
  420. return "AFPPaintingState{" + "portraitRotation=" + portraitRotation
  421. + ", landscapeRotation=" + landscapeRotation + ", colorImages=" + colorImages
  422. + ", bitsPerPixel=" + bitsPerPixel + ", resolution=" + resolution + ", pageState="
  423. + pagePaintingState + super.toString() + "}";
  424. }
  425. /**
  426. * Page level state data
  427. */
  428. private class AFPPagePaintingState implements Cloneable {
  429. /** page width */
  430. private int width = 0;
  431. /** page height */
  432. private int height = 0;
  433. /** page fonts */
  434. private AFPPageFonts fonts = new AFPPageFonts();
  435. /** page font count */
  436. private int fontCount = 0;
  437. /** page orientation */
  438. private int orientation = 0;
  439. /**
  440. * Returns the page width
  441. *
  442. * @return the page width
  443. */
  444. protected int getWidth() {
  445. return width;
  446. }
  447. /**
  448. * Sets the page width
  449. *
  450. * @param width
  451. * the page width
  452. */
  453. protected void setWidth(int width) {
  454. this.width = width;
  455. }
  456. /**
  457. * Returns the page height
  458. *
  459. * @return the page height
  460. */
  461. protected int getHeight() {
  462. return height;
  463. }
  464. /**
  465. * Sets the page height
  466. *
  467. * @param height
  468. * the page height
  469. */
  470. protected void setHeight(int height) {
  471. this.height = height;
  472. }
  473. /**
  474. * Returns the page fonts
  475. *
  476. * @return the page fonts
  477. */
  478. protected AFPPageFonts getFonts() {
  479. return fonts;
  480. }
  481. /**
  482. * Sets the current page fonts
  483. *
  484. * @param fonts
  485. * the current page fonts
  486. */
  487. protected void setFonts(AFPPageFonts fonts) {
  488. this.fonts = fonts;
  489. }
  490. /**
  491. * Increments and returns the current page font count
  492. *
  493. * @return increment and return the current page font count
  494. */
  495. protected int incrementFontCount() {
  496. return ++fontCount;
  497. }
  498. /**
  499. * Returns the current page orientation
  500. *
  501. * @return the current page orientation
  502. */
  503. protected int getOrientation() {
  504. return orientation;
  505. }
  506. /**
  507. * Sets the current page orientation
  508. *
  509. * @param orientation
  510. * the current page orientation
  511. */
  512. protected void setOrientation(int orientation) {
  513. this.orientation = orientation;
  514. }
  515. /** {@inheritDoc} */
  516. @Override
  517. public Object clone() {
  518. AFPPagePaintingState state = new AFPPagePaintingState();
  519. state.width = this.width;
  520. state.height = this.height;
  521. state.orientation = this.orientation;
  522. state.fonts = new AFPPageFonts(this.fonts);
  523. state.fontCount = this.fontCount;
  524. return state;
  525. }
  526. /** {@inheritDoc} */
  527. @Override
  528. public String toString() {
  529. return "AFPPagePaintingState{width=" + width + ", height=" + height + ", orientation="
  530. + orientation + ", fonts=" + fonts + ", fontCount=" + fontCount + "}";
  531. }
  532. }
  533. /**
  534. * Block level state data
  535. */
  536. private class AFPData extends org.apache.fop.util.AbstractPaintingState.AbstractData {
  537. private static final long serialVersionUID = -1789481244175275686L;
  538. /** The current fill status */
  539. private boolean filled = false;
  540. private String imageUri = null;
  541. /** {@inheritDoc} */
  542. @Override
  543. public Object clone() {
  544. AFPData obj = (AFPData) super.clone();
  545. obj.filled = this.filled;
  546. obj.imageUri = this.imageUri;
  547. return obj;
  548. }
  549. /** {@inheritDoc} */
  550. @Override
  551. public String toString() {
  552. return "AFPData{" + super.toString() + ", filled=" + filled + ", imageUri=" + imageUri
  553. + "}";
  554. }
  555. /** {@inheritDoc} */
  556. @Override
  557. protected AbstractData instantiate() {
  558. return new AFPData();
  559. }
  560. }
  561. }