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 21KB

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