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.

AlphaRasterImage.java 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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.pdf;
  19. import java.awt.Graphics2D;
  20. import java.awt.image.BufferedImage;
  21. import java.awt.image.DataBuffer;
  22. import java.awt.image.Raster;
  23. import java.awt.image.RenderedImage;
  24. import java.awt.image.SampleModel;
  25. import java.awt.image.SinglePixelPackedSampleModel;
  26. import java.io.IOException;
  27. import java.io.OutputStream;
  28. import org.apache.xmlgraphics.image.GraphicsUtil;
  29. /**
  30. * PDFImage implementation for alpha channel "images".
  31. */
  32. public class AlphaRasterImage implements PDFImage {
  33. private int bitsPerComponent;
  34. private PDFDeviceColorSpace colorSpace;
  35. private Raster alpha;
  36. private String key;
  37. /**
  38. * Create a alpha channel image.
  39. * Creates a new bitmap image with the given data.
  40. *
  41. * @param k the key to be used to lookup the image
  42. * @param alpha the alpha channel raster
  43. */
  44. public AlphaRasterImage(String k, Raster alpha) {
  45. this.key = k;
  46. //Enable the commented line below if 16-bit alpha channels are desired.
  47. //Otherwise, we compress the alpha channel to 8 bit which should be sufficient.
  48. //this.bitsPerComponent = alpha.getSampleModel().getSampleSize(0);
  49. this.bitsPerComponent = 8;
  50. this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY);
  51. if (alpha == null) {
  52. throw new NullPointerException("Parameter alpha must not be null");
  53. }
  54. this.alpha = alpha;
  55. }
  56. /**
  57. * Create a alpha channel image.
  58. * Extracts the alpha channel from the RenderedImage and creates a new bitmap image
  59. * with the given data.
  60. *
  61. * @param k the key to be used to lookup the image
  62. * @param image the image (must have an alpha channel)
  63. */
  64. public AlphaRasterImage(String k, RenderedImage image) {
  65. this(k, getAlphaRaster(image));
  66. }
  67. /**
  68. * Extracts the Alpha Raster for the given image.
  69. * Also works for {@link java.awt.image.IndexColorModel}.
  70. */
  71. private static Raster getAlphaRaster(RenderedImage image) {
  72. Raster alphaRaster = GraphicsUtil.getAlphaRaster(image);
  73. /*
  74. * {@link GraphicsUtil#getAlphaRaster} calls internally
  75. * {@link java.awt.image.BufferedImage#getAlphRaster} which
  76. * will return <code>null</code> according to Java API
  77. * documentation for {@link java.awt.image.IndexColorModel}.
  78. *
  79. * In that case we create the raster drawing a hidden
  80. * image. That code might be better placed in
  81. * {@link java.awt.image.BufferedImage#getAlphRaster}
  82. * but since this is a different project and a change
  83. * to the interface semantics, it might break consumers.
  84. */
  85. if (alphaRaster == null) {
  86. BufferedImage bufferedImage = (BufferedImage) image;
  87. int w = bufferedImage.getWidth();
  88. int h = bufferedImage.getHeight();
  89. int type = BufferedImage.TYPE_INT_ARGB;
  90. BufferedImage bia = new BufferedImage(w, h, type);
  91. Graphics2D g = bia.createGraphics();
  92. g.drawImage(bufferedImage, 0, 0, null);
  93. g.dispose();
  94. alphaRaster = GraphicsUtil.getAlphaRaster(bia);
  95. }
  96. return alphaRaster;
  97. }
  98. /** {@inheritDoc} */
  99. public void setup(PDFDocument doc) {
  100. //nop
  101. }
  102. /** {@inheritDoc} */
  103. public String getKey() {
  104. return key;
  105. }
  106. /** {@inheritDoc} */
  107. public int getWidth() {
  108. return alpha.getWidth();
  109. }
  110. /** {@inheritDoc} */
  111. public int getHeight() {
  112. return alpha.getHeight();
  113. }
  114. /** {@inheritDoc} */
  115. public PDFDeviceColorSpace getColorSpace() {
  116. return colorSpace;
  117. }
  118. /** {@inheritDoc} */
  119. public int getBitsPerComponent() {
  120. return bitsPerComponent;
  121. }
  122. /** {@inheritDoc} */
  123. public boolean isTransparent() {
  124. return false;
  125. }
  126. /** {@inheritDoc} */
  127. public PDFColor getTransparentColor() {
  128. return null;
  129. }
  130. /** {@inheritDoc} */
  131. public String getMask() {
  132. return null;
  133. }
  134. /** @return null (unless overridden) */
  135. public String getSoftMask() {
  136. return null;
  137. }
  138. /** {@inheritDoc} */
  139. public PDFReference getSoftMaskReference() {
  140. return null;
  141. }
  142. /** {@inheritDoc} */
  143. public boolean isInverted() {
  144. return false;
  145. }
  146. /** {@inheritDoc} */
  147. public void outputContents(OutputStream out) throws IOException {
  148. int w = getWidth();
  149. int h = getHeight();
  150. //Check Raster
  151. int nbands = alpha.getNumBands();
  152. if (nbands != 1) {
  153. throw new UnsupportedOperationException(
  154. "Expected only one band/component for the alpha channel");
  155. }
  156. //...and write the Raster line by line with a reusable buffer
  157. int dataType = alpha.getDataBuffer().getDataType();
  158. if (dataType == DataBuffer.TYPE_BYTE) {
  159. byte[] line = new byte[nbands * w];
  160. for (int y = 0; y < h; y++) {
  161. alpha.getDataElements(0, y, w, 1, line);
  162. out.write(line);
  163. }
  164. } else if (dataType == DataBuffer.TYPE_USHORT) {
  165. short[] sline = new short[nbands * w];
  166. byte[] line = new byte[nbands * w];
  167. for (int y = 0; y < h; y++) {
  168. alpha.getDataElements(0, y, w, 1, sline);
  169. for (int i = 0; i < w; i++) {
  170. //this compresses a 16-bit alpha channel to 8 bits!
  171. //we probably don't ever need a 16-bit channel
  172. line[i] = (byte)(sline[i] >> 8);
  173. }
  174. out.write(line);
  175. }
  176. } else if (dataType == DataBuffer.TYPE_INT) {
  177. //Is there an better way to get a 8bit raster from a TYPE_INT raster?
  178. int shift = 24;
  179. SampleModel sampleModel = alpha.getSampleModel();
  180. if (sampleModel instanceof SinglePixelPackedSampleModel) {
  181. SinglePixelPackedSampleModel m = (SinglePixelPackedSampleModel)sampleModel;
  182. shift = m.getBitOffsets()[0];
  183. }
  184. int[] iline = new int[nbands * w];
  185. byte[] line = new byte[nbands * w];
  186. for (int y = 0; y < h; y++) {
  187. alpha.getDataElements(0, y, w, 1, iline);
  188. for (int i = 0; i < w; i++) {
  189. line[i] = (byte)(iline[i] >> shift);
  190. }
  191. out.write(line);
  192. }
  193. } else {
  194. throw new UnsupportedOperationException("Unsupported DataBuffer type: "
  195. + alpha.getDataBuffer().getClass().getName());
  196. }
  197. }
  198. /** {@inheritDoc} */
  199. public void populateXObjectDictionary(PDFDictionary dict) {
  200. //nop
  201. }
  202. /** {@inheritDoc} */
  203. public PDFICCStream getICCStream() {
  204. return null;
  205. }
  206. /** {@inheritDoc} */
  207. public boolean isPS() {
  208. return false;
  209. }
  210. /** {@inheritDoc} */
  211. public String getFilterHint() {
  212. return PDFFilterList.IMAGE_FILTER;
  213. }
  214. /** {@inheritDoc} */
  215. public PDFFilter getPDFFilter() {
  216. return null;
  217. }
  218. /** {@inheritDoc} */
  219. public boolean multipleFiltersAllowed() {
  220. return true;
  221. }
  222. }