1   /**
2    * Copyright (c) 2000-2007 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.util;
24  
25  import com.sun.imageio.plugins.gif.GIFImageReader;
26  import com.sun.imageio.plugins.jpeg.JPEGImageReader;
27  import com.sun.imageio.plugins.png.PNGImageReader;
28  import com.sun.media.jai.codec.ImageCodec;
29  import com.sun.media.jai.codec.ImageDecoder;
30  
31  import java.awt.geom.AffineTransform;
32  import java.awt.image.AffineTransformOp;
33  import java.awt.image.BufferedImage;
34  import java.awt.image.DataBuffer;
35  import java.awt.image.RenderedImage;
36  import java.awt.image.SampleModel;
37  
38  import java.io.ByteArrayInputStream;
39  import java.io.File;
40  import java.io.IOException;
41  import java.io.InputStream;
42  import java.io.OutputStream;
43  
44  import java.util.Iterator;
45  
46  import javax.imageio.ImageIO;
47  import javax.imageio.ImageReader;
48  import javax.imageio.stream.FileCacheImageInputStream;
49  
50  import javax.media.jai.RenderedImageAdapter;
51  
52  import net.jmge.gif.Gif89Encoder;
53  
54  import org.apache.commons.logging.Log;
55  import org.apache.commons.logging.LogFactory;
56  
57  /**
58   * <a href="ImageUtil.java.html"><b><i>View Source</i></b></a>
59   *
60   * @author Brian Wing Shun Chan
61   *
62   */
63  public class ImageUtil {
64  
65      public static final String TYPE_BMP = "bmp";
66  
67      public static final String TYPE_GIF = "gif";
68  
69      public static final String TYPE_JPEG = "jpeg";
70  
71      public static final String TYPE_PNG = "png";
72  
73      public static final String TYPE_TIFF = "tiff";
74  
75      public static final String TYPE_NOT_AVAILABLE = "na";
76  
77      public static void encodeGIF(RenderedImage renderedImage, OutputStream out)
78          throws IOException {
79  
80          Gif89Encoder encoder = new Gif89Encoder(
81              getBufferedImage(renderedImage));
82  
83          encoder.encode(out);
84      }
85  
86      public static void encodeWBMP(RenderedImage renderedImage, OutputStream out)
87          throws InterruptedException, IOException {
88  
89          BufferedImage bufferedImage = getBufferedImage(renderedImage);
90  
91          SampleModel sampleModel = bufferedImage.getSampleModel();
92  
93          int type = sampleModel.getDataType();
94  
95          if ((bufferedImage.getType() != BufferedImage.TYPE_BYTE_BINARY) ||
96              (type < DataBuffer.TYPE_BYTE) || (type > DataBuffer.TYPE_INT) ||
97              (sampleModel.getNumBands() != 1) ||
98              (sampleModel.getSampleSize(0) != 1)) {
99  
100             BufferedImage binaryImage = new BufferedImage(
101                 bufferedImage.getWidth(), bufferedImage.getHeight(),
102                 BufferedImage.TYPE_BYTE_BINARY);
103 
104             binaryImage.getGraphics().drawImage(bufferedImage, 0, 0, null);
105 
106             renderedImage = binaryImage;
107         }
108 
109         if (!ImageIO.write(renderedImage, "wbmp", out)) {
110 
111             // See http://www.jguru.com/faq/view.jsp?EID=127723
112 
113             out.write(0);
114             out.write(0);
115             out.write(_toMultiByte(bufferedImage.getWidth()));
116             out.write(_toMultiByte(bufferedImage.getHeight()));
117 
118             DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();
119 
120             int size = dataBuffer.getSize();
121 
122             for (int i = 0; i < size; i++) {
123                 out.write((byte)dataBuffer.getElem(i));
124             }
125         }
126     }
127 
128     public static BufferedImage getBufferedImage(RenderedImage renderedImage) {
129         if (renderedImage instanceof BufferedImage) {
130             return (BufferedImage)renderedImage;
131         }
132         else {
133             RenderedImageAdapter adapter = new RenderedImageAdapter(
134                 renderedImage);
135 
136             return adapter.getAsBufferedImage();
137         }
138     }
139 
140     public static ImageBag read(File file) throws IOException {
141         return read(FileUtil.getBytes(file));
142     }
143 
144     public static ImageBag read(byte[] bytes) throws IOException {
145         RenderedImage renderedImage = null;
146         String type = TYPE_NOT_AVAILABLE;
147 
148         InputStream is = null;
149         FileCacheImageInputStream fcis = null;
150 
151         try {
152             is = new ByteArrayInputStream(bytes);
153             fcis = new FileCacheImageInputStream(is, null);
154 
155             Iterator itr = ImageIO.getImageReaders(fcis);
156 
157             while (itr.hasNext()) {
158                 ImageReader reader = (ImageReader)itr.next();
159 
160                 if (reader instanceof GIFImageReader) {
161                     type = TYPE_GIF;
162                 }
163                 else if (reader instanceof JPEGImageReader) {
164                     type = TYPE_JPEG;
165                 }
166                 else if (reader instanceof PNGImageReader) {
167                     type = TYPE_PNG;
168                 }
169 
170                 reader.dispose();
171             }
172 
173             if (!type.equals(TYPE_NOT_AVAILABLE)) {
174                 renderedImage = ImageIO.read(fcis);
175             }
176 
177             if (renderedImage == null) {
178                 renderedImage = _getRenderedImage("BMP", bytes);
179 
180                 if (renderedImage != null) {
181                     type = TYPE_BMP;
182                 }
183             }
184 
185             if (renderedImage == null) {
186                 renderedImage = _getRenderedImage("TIFF", bytes);
187 
188                 if (renderedImage != null) {
189                     type = TYPE_TIFF;
190                 }
191             }
192 
193             if (renderedImage == null) {
194                 renderedImage = _getRenderedImage("GIF", bytes);
195 
196                 if (renderedImage != null) {
197                     type = TYPE_GIF;
198                 }
199             }
200 
201             if (renderedImage == null) {
202                 renderedImage = _getRenderedImage("JPEG", bytes);
203 
204                 if (renderedImage != null) {
205                     type = TYPE_JPEG;
206                 }
207             }
208 
209             if (renderedImage == null) {
210                 renderedImage = _getRenderedImage("PNG", bytes);
211 
212                 if (renderedImage != null) {
213                     type = TYPE_PNG;
214                 }
215             }
216         }
217         finally {
218             if (is != null) {
219                 try {
220                     is.close();
221                 }
222                 catch (IOException ioe) {
223                     if (_log.isWarnEnabled()) {
224                         _log.warn(ioe);
225                     }
226                 }
227             }
228 
229             if (fcis != null) {
230                 try {
231                     fcis.close();
232                 }
233                 catch (IOException ioe) {
234                     if (_log.isDebugEnabled()) {
235                         _log.debug(ioe);
236                     }
237                 }
238             }
239         }
240 
241         return new ImageBag(renderedImage, type);
242     }
243 
244     public static RenderedImage scale(
245         RenderedImage renderedImage, double factor) {
246 
247         AffineTransformOp op = new AffineTransformOp(
248             AffineTransform.getScaleInstance(factor, factor), null);
249 
250         BufferedImage bufferedImage = getBufferedImage(renderedImage);
251 
252         return op.filter(bufferedImage, null);
253     }
254 
255     public static RenderedImage scale(
256         RenderedImage renderedImage, int maxHeight, int maxWidth) {
257 
258         int imageHeight = renderedImage.getHeight();
259         int imageWidth = renderedImage.getWidth();
260 
261         if (maxHeight == 0) {
262             maxHeight = imageHeight;
263         }
264 
265         if (maxWidth == 0) {
266             maxWidth = imageWidth;
267         }
268 
269         if ((imageHeight <= maxHeight) && (imageWidth <= maxWidth)) {
270             return renderedImage;
271         }
272 
273         double factor = 0.1;
274 
275         int heightDelta = imageHeight - maxHeight;
276         int widthDelta = imageWidth - maxWidth;
277 
278         if (heightDelta > widthDelta) {
279             factor = (double)maxHeight / imageHeight;
280         }
281         else {
282             factor = (double)maxWidth / imageWidth;
283         }
284 
285         return scale(renderedImage, factor);
286     }
287 
288     private static RenderedImage _getRenderedImage(String name, byte[] bytes) {
289         RenderedImage renderedImage = null;
290 
291         InputStream is = null;
292 
293         try {
294             is = new ByteArrayInputStream(bytes);
295 
296             ImageDecoder decoder = ImageCodec.createImageDecoder(
297                 name, is, null);
298 
299             renderedImage = decoder.decodeAsRenderedImage();
300         }
301         catch (Exception e) {
302             if (_log.isDebugEnabled()) {
303                 _log.debug(name + ": " + e.getMessage());
304             }
305         }
306         finally {
307             if (is != null) {
308                 try {
309                     is.close();
310                 }
311                 catch (IOException ioe) {
312                     if (_log.isWarnEnabled()) {
313                         _log.warn(ioe);
314                     }
315                 }
316             }
317         }
318 
319         return renderedImage;
320     }
321 
322     private static byte[] _toMultiByte(int intValue) {
323         int numBits = 32;
324         int mask = 0x80000000;
325 
326         while (mask != 0 && (intValue & mask) == 0) {
327             numBits--;
328             mask >>>= 1;
329         }
330 
331         int numBitsLeft = numBits;
332         byte[] multiBytes = new byte[(numBitsLeft + 6) / 7];
333 
334         int maxIndex = multiBytes.length - 1;
335 
336         for (int b = 0; b <= maxIndex; b++) {
337             multiBytes[b] = (byte)((intValue >>> ((maxIndex - b) * 7)) & 0x7f);
338 
339             if (b != maxIndex) {
340                 multiBytes[b] |= (byte)0x80;
341             }
342         }
343 
344         return multiBytes;
345     }
346 
347     private static Log _log = LogFactory.getLog(ImageUtil.class);
348 
349 }