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

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