1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.image;
16  
17  import com.liferay.portal.kernel.image.ImageBag;
18  import com.liferay.portal.kernel.image.ImageProcessor;
19  import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
20  import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
21  import com.liferay.portal.kernel.log.Log;
22  import com.liferay.portal.kernel.log.LogFactoryUtil;
23  import com.liferay.portal.kernel.util.JavaProps;
24  import com.liferay.portal.util.FileImpl;
25  
26  import com.sun.media.jai.codec.ImageCodec;
27  import com.sun.media.jai.codec.ImageDecoder;
28  import com.sun.media.jai.codec.ImageEncoder;
29  
30  import java.awt.Graphics2D;
31  import java.awt.Graphics;
32  import java.awt.Image;
33  import java.awt.image.BufferedImage;
34  import java.awt.image.DataBuffer;
35  import java.awt.image.IndexColorModel;
36  import java.awt.image.RenderedImage;
37  import java.awt.image.SampleModel;
38  
39  import java.io.File;
40  import java.io.IOException;
41  import java.io.OutputStream;
42  
43  import java.util.Enumeration;
44  
45  import javax.imageio.ImageIO;
46  
47  import javax.media.jai.RenderedImageAdapter;
48  
49  import net.jmge.gif.Gif89Encoder;
50  
51  /**
52   * <a href="ImageProcessorImpl.java.html"><b><i>View Source</i></b></a>
53   *
54   * @author Brian Wing Shun Chan
55   */
56  public class ImageProcessorImpl implements ImageProcessor {
57  
58      public static ImageProcessorImpl getInstance() {
59          return _instance;
60      }
61  
62      public BufferedImage convertImageType(BufferedImage sourceImage, int type) {
63          BufferedImage targetImage = new BufferedImage(
64              sourceImage.getWidth(), sourceImage.getHeight(), type);
65  
66          Graphics2D graphics = targetImage.createGraphics();
67  
68          graphics.drawRenderedImage(sourceImage, null);
69  
70          graphics.dispose();
71  
72          return targetImage;
73      }
74  
75      public void encodeGIF(RenderedImage renderedImage, OutputStream os)
76          throws IOException {
77  
78          if (JavaProps.isJDK6()) {
79              ImageIO.write(renderedImage, TYPE_GIF, os);
80          }
81          else {
82              BufferedImage bufferedImage = getBufferedImage(renderedImage);
83  
84              if (!(bufferedImage.getColorModel() instanceof IndexColorModel)) {
85                  bufferedImage = convertImageType(
86                      bufferedImage, BufferedImage.TYPE_BYTE_INDEXED);
87              }
88  
89              Gif89Encoder encoder = new Gif89Encoder(bufferedImage);
90  
91              encoder.encode(os);
92          }
93      }
94  
95      public void encodeWBMP(RenderedImage renderedImage, OutputStream os)
96          throws IOException {
97  
98          BufferedImage bufferedImage = getBufferedImage(renderedImage);
99  
100         SampleModel sampleModel = bufferedImage.getSampleModel();
101 
102         int type = sampleModel.getDataType();
103 
104         if ((bufferedImage.getType() != BufferedImage.TYPE_BYTE_BINARY) ||
105             (type < DataBuffer.TYPE_BYTE) || (type > DataBuffer.TYPE_INT) ||
106             (sampleModel.getNumBands() != 1) ||
107             (sampleModel.getSampleSize(0) != 1)) {
108 
109             BufferedImage binaryImage = new BufferedImage(
110                 bufferedImage.getWidth(), bufferedImage.getHeight(),
111                 BufferedImage.TYPE_BYTE_BINARY);
112 
113             Graphics graphics = binaryImage.getGraphics();
114 
115             graphics.drawImage(bufferedImage, 0, 0, null);
116 
117             renderedImage = binaryImage;
118         }
119 
120         if (!ImageIO.write(renderedImage, "wbmp", os)) {
121 
122             // See http://www.jguru.com/faq/view.jsp?EID=127723
123 
124             os.write(0);
125             os.write(0);
126             os.write(_toMultiByte(bufferedImage.getWidth()));
127             os.write(_toMultiByte(bufferedImage.getHeight()));
128 
129             DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();
130 
131             int size = dataBuffer.getSize();
132 
133             for (int i = 0; i < size; i++) {
134                 os.write((byte)dataBuffer.getElem(i));
135             }
136         }
137     }
138 
139     public BufferedImage getBufferedImage(RenderedImage renderedImage) {
140         if (renderedImage instanceof BufferedImage) {
141             return (BufferedImage)renderedImage;
142         }
143         else {
144             RenderedImageAdapter adapter = new RenderedImageAdapter(
145                 renderedImage);
146 
147             return adapter.getAsBufferedImage();
148         }
149     }
150 
151     public byte[] getBytes(RenderedImage renderedImage, String contentType)
152         throws IOException {
153 
154         UnsyncByteArrayOutputStream baos = new UnsyncByteArrayOutputStream();
155 
156         if (contentType.indexOf(TYPE_BMP) != -1) {
157             ImageEncoder encoder = ImageCodec.createImageEncoder(
158                 TYPE_BMP, baos, null);
159 
160             encoder.encode(renderedImage);
161         }
162         else if (contentType.indexOf(TYPE_GIF) != -1) {
163             encodeGIF(renderedImage, baos);
164         }
165         else if ((contentType.indexOf(TYPE_JPEG) != -1) ||
166                  (contentType.indexOf("jpeg") != -1)) {
167 
168             ImageIO.write(renderedImage, "jpeg", baos);
169         }
170         else if (contentType.indexOf(TYPE_PNG) != -1) {
171             ImageIO.write(renderedImage, TYPE_PNG, baos);
172         }
173         else if (contentType.indexOf("tif") != -1) {
174             ImageEncoder encoder = ImageCodec.createImageEncoder(
175                 TYPE_TIFF, baos, null);
176 
177             encoder.encode(renderedImage);
178         }
179 
180         return baos.toByteArray();
181     }
182 
183     public ImageBag read(File file) throws IOException {
184         return read(_fileUtil.getBytes(file));
185     }
186 
187     public ImageBag read(byte[] bytes) {
188         RenderedImage renderedImage = null;
189         String type = TYPE_NOT_AVAILABLE;
190 
191         Enumeration<ImageCodec> enu = ImageCodec.getCodecs();
192 
193         while (enu.hasMoreElements()) {
194             ImageCodec codec = enu.nextElement();
195 
196             if (codec.isFormatRecognized(bytes)) {
197                 type = codec.getFormatName();
198 
199                 ImageDecoder decoder = ImageCodec.createImageDecoder(
200                     type, new UnsyncByteArrayInputStream(bytes), null);
201 
202                 try {
203                     renderedImage = decoder.decodeAsRenderedImage();
204                 }
205                 catch (IOException ioe) {
206                     if (_log.isDebugEnabled()) {
207                         _log.debug(type + ": " + ioe.getMessage());
208                     }
209                 }
210 
211                 break;
212             }
213         }
214 
215         if (type.equals("jpeg")) {
216             type = TYPE_JPEG;
217         }
218 
219         return new ImageBag(renderedImage, type);
220     }
221 
222     public RenderedImage scale(
223         RenderedImage renderedImage, int maxHeight, int maxWidth) {
224 
225         int imageHeight = renderedImage.getHeight();
226         int imageWidth = renderedImage.getWidth();
227 
228         if (maxHeight == 0) {
229             maxHeight = imageHeight;
230         }
231 
232         if (maxWidth == 0) {
233             maxWidth = imageWidth;
234         }
235 
236         if ((imageHeight <= maxHeight) && (imageWidth <= maxWidth)) {
237             return renderedImage;
238         }
239 
240         double factor = Math.min(
241             (double)maxHeight / imageHeight, (double)maxWidth / imageWidth);
242 
243         int scaledHeight = Math.max(1, (int)(factor * imageHeight));
244         int scaledWidth = Math.max(1, (int)(factor * imageWidth));
245 
246         BufferedImage bufferedImage = getBufferedImage(renderedImage);
247 
248         Image scaledImage = bufferedImage.getScaledInstance(
249             scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
250 
251         BufferedImage scaledBufferedImage = new BufferedImage(
252             scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);
253 
254         scaledBufferedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
255 
256         return scaledBufferedImage;
257     }
258 
259     private byte[] _toMultiByte(int intValue) {
260         int numBits = 32;
261         int mask = 0x80000000;
262 
263         while (mask != 0 && (intValue & mask) == 0) {
264             numBits--;
265             mask >>>= 1;
266         }
267 
268         int numBitsLeft = numBits;
269         byte[] multiBytes = new byte[(numBitsLeft + 6) / 7];
270 
271         int maxIndex = multiBytes.length - 1;
272 
273         for (int b = 0; b <= maxIndex; b++) {
274             multiBytes[b] = (byte)((intValue >>> ((maxIndex - b) * 7)) & 0x7f);
275 
276             if (b != maxIndex) {
277                 multiBytes[b] |= (byte)0x80;
278             }
279         }
280 
281         return multiBytes;
282     }
283 
284     private static Log _log = LogFactoryUtil.getLog(ImageProcessorImpl.class);
285 
286     private static ImageProcessorImpl _instance = new ImageProcessorImpl();
287 
288     private static FileImpl _fileUtil = FileImpl.getInstance();
289 
290 }