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.

XmlGraphicsCommonsImage.java 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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.image;
  19. import java.awt.Color;
  20. import java.awt.Transparency;
  21. import java.awt.image.ColorModel;
  22. import java.awt.image.IndexColorModel;
  23. import java.awt.image.RenderedImage;
  24. import java.awt.image.WritableRaster;
  25. import java.awt.image.BufferedImage;
  26. import java.io.IOException;
  27. import org.apache.xmlgraphics.image.GraphicsUtil;
  28. import org.apache.xmlgraphics.image.codec.util.SeekableStream;
  29. import org.apache.xmlgraphics.image.codec.util.MemoryCacheSeekableStream;
  30. import org.apache.xmlgraphics.image.codec.util.FileCacheSeekableStream;
  31. import org.apache.xmlgraphics.image.rendered.CachableRed;
  32. import org.apache.commons.io.IOUtils;
  33. /**
  34. * Abstract FopImage implementation which uses the internal codecs from XML Graphics Commons.
  35. *
  36. * @see AbstractFopImage
  37. * @see FopImage
  38. */
  39. public abstract class XmlGraphicsCommonsImage extends AbstractFopImage {
  40. private byte[] softMask = null;
  41. /**
  42. * The InputStream wrapped into a SeekableStream for decoding.
  43. */
  44. protected SeekableStream seekableInput = null;
  45. /**
  46. * The Batik representation of the image
  47. */
  48. protected CachableRed cr = null;
  49. /**
  50. * Constructs a new BatikImage instance.
  51. * @param imgReader basic metadata for the image
  52. */
  53. public XmlGraphicsCommonsImage(FopImage.ImageInfo imgReader) {
  54. super(imgReader);
  55. }
  56. /**
  57. * {@inheritDoc}
  58. */
  59. protected boolean loadDimensions() {
  60. if (seekableInput == null && inputStream != null) {
  61. try {
  62. seekableInput = new FileCacheSeekableStream(inputStream);
  63. } catch (IOException ioe) {
  64. seekableInput = new MemoryCacheSeekableStream(inputStream);
  65. }
  66. try {
  67. this.bitsPerPixel = 8;
  68. cr = decodeImage(seekableInput);
  69. this.height = cr.getHeight();
  70. this.width = cr.getWidth();
  71. this.isTransparent = false;
  72. this.softMask = null;
  73. ColorModel cm = cr.getColorModel();
  74. this.height = cr.getHeight();
  75. this.width = cr.getWidth();
  76. this.isTransparent = false;
  77. this.softMask = null;
  78. int transparencyType = cm.getTransparency();
  79. if (cm instanceof IndexColorModel) {
  80. if (transparencyType == Transparency.BITMASK) {
  81. // Use 'transparent color'.
  82. IndexColorModel icm = (IndexColorModel)cm;
  83. int numColor = icm.getMapSize();
  84. byte [] alpha = new byte[numColor];
  85. icm.getAlphas(alpha);
  86. for (int i = 0; i < numColor; i++) {
  87. if ((alpha[i] & 0xFF) == 0) {
  88. this.isTransparent = true;
  89. int red = (icm.getRed (i)) & 0xFF;
  90. int grn = (icm.getGreen(i)) & 0xFF;
  91. int blu = (icm.getBlue (i)) & 0xFF;
  92. this.transparentColor = new Color(red, grn, blu);
  93. break;
  94. }
  95. }
  96. }
  97. } else {
  98. cr = GraphicsUtil.convertTosRGB(cr);
  99. }
  100. // Get our current ColorModel
  101. cm = cr.getColorModel();
  102. if (this.colorSpace == null) {
  103. this.colorSpace = cm.getColorSpace();
  104. }
  105. } catch (IOException ioe) {
  106. log.error("Error while loading image (Batik): " + ioe.getMessage(), ioe);
  107. IOUtils.closeQuietly(seekableInput);
  108. IOUtils.closeQuietly(inputStream);
  109. seekableInput = null;
  110. inputStream = null;
  111. return false;
  112. }
  113. }
  114. return this.height != -1;
  115. }
  116. /**
  117. * {@inheritDoc}
  118. */
  119. protected boolean loadBitmap() {
  120. if (this.bitmaps == null) {
  121. loadImage();
  122. }
  123. return this.bitmaps != null;
  124. }
  125. /**
  126. * {@inheritDoc}
  127. */
  128. public boolean hasSoftMask() {
  129. if (this.bitmaps == null && this.raw == null) {
  130. loadImage();
  131. }
  132. return (this.softMask != null);
  133. }
  134. /**
  135. * {@inheritDoc}
  136. */
  137. public byte[] getSoftMask() {
  138. if (this.bitmaps == null) {
  139. loadImage();
  140. }
  141. return this.softMask;
  142. }
  143. /**
  144. * Decodes the image from the stream.
  145. * @param stream the stream to read the image from
  146. * @return the decoded image
  147. * @throws IOException in case an I/O problem occurs
  148. */
  149. protected abstract CachableRed decodeImage(SeekableStream stream) throws IOException;
  150. /**
  151. * Loads the image from the InputStream.
  152. */
  153. protected void loadImage() {
  154. if (loadDimensions()) {
  155. try {
  156. if (cr == null) {
  157. throw new IllegalStateException(
  158. "Can't load the bitmaps data without the CachableRed instance");
  159. }
  160. // Get our current ColorModel
  161. ColorModel cm = cr.getColorModel();
  162. // It has an alpha channel so generate a soft mask.
  163. if (!this.isTransparent && cm.hasAlpha()) {
  164. this.softMask = new byte[this.width * this.height];
  165. }
  166. this.bitmaps = new byte[this.width * this.height * 3];
  167. constructBitmaps(cr, this.bitmaps, this.softMask);
  168. } catch (Exception ex) {
  169. log.error("Error while loading image (Batik): " + ex.getMessage(), ex);
  170. } finally {
  171. // Make sure we clean up
  172. IOUtils.closeQuietly(seekableInput);
  173. IOUtils.closeQuietly(inputStream);
  174. seekableInput = null;
  175. inputStream = null;
  176. cr = null;
  177. }
  178. }
  179. }
  180. private static void constructBitmaps(RenderedImage red, byte[] bitmaps, byte[] softMask) {
  181. WritableRaster wr = (WritableRaster)red.getData();
  182. ColorModel cm = red.getColorModel();
  183. BufferedImage bi = new BufferedImage
  184. (cm, wr.createWritableTranslatedChild(0, 0),
  185. cm.isAlphaPremultiplied(), null);
  186. int width = red.getWidth();
  187. int height = red.getHeight();
  188. int [] tmpMap = new int[width];
  189. int idx = 0;
  190. int sfIdx = 0;
  191. for (int y = 0; y < height; y++) {
  192. tmpMap = bi.getRGB(0, y, width, 1, tmpMap, 0, width);
  193. if (softMask != null) {
  194. for (int x = 0; x < width; x++) {
  195. int pix = tmpMap[x];
  196. softMask[sfIdx++] = (byte)(pix >>> 24);
  197. bitmaps[idx++] = (byte)((pix >>> 16) & 0xFF);
  198. bitmaps[idx++] = (byte)((pix >>> 8) & 0xFF);
  199. bitmaps[idx++] = (byte)((pix) & 0xFF);
  200. }
  201. } else {
  202. for (int x = 0; x < width; x++) {
  203. int pix = tmpMap[x];
  204. bitmaps[idx++] = (byte)((pix >> 16) & 0xFF);
  205. bitmaps[idx++] = (byte)((pix >> 8) & 0xFF);
  206. bitmaps[idx++] = (byte)((pix) & 0xFF);
  207. }
  208. }
  209. }
  210. }
  211. }