001package com.hfg.image;
002
003import java.awt.Dimension;
004import java.awt.Image;
005import java.awt.image.BufferedImage;
006import java.io.File;
007import java.io.FileInputStream;
008import java.io.FileOutputStream;
009import java.io.IOException;
010import java.io.InputStream;
011import java.io.OutputStream;
012import java.util.Iterator;
013import java.util.Locale;
014import javax.imageio.IIOImage;
015import javax.imageio.ImageIO;
016import javax.imageio.ImageReader;
017import javax.imageio.ImageTypeSpecifier;
018import javax.imageio.ImageWriteParam;
019import javax.imageio.ImageWriter;
020import javax.imageio.metadata.IIOMetadata;
021import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
022import javax.imageio.stream.FileImageOutputStream;
023import javax.imageio.stream.ImageOutputStream;
024
025import com.hfg.util.StringUtil;
026
027//------------------------------------------------------------------------------
028/**
029 * General Image IO functions using ImageIO.
030 *
031 * @author J. Alex Taylor, hairyfatguy.com
032 */
033//------------------------------------------------------------------------------
034// com.hfg XML/HTML Coding Library
035//
036// This library is free software; you can redistribute it and/or
037// modify it under the terms of the GNU Lesser General Public
038// License as published by the Free Software Foundation; either
039// version 2.1 of the License, or (at your option) any later version.
040//
041// This library is distributed in the hope that it will be useful,
042// but WITHOUT ANY WARRANTY; without even the implied warranty of
043// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
044// Lesser General Public License for more details.
045//
046// You should have received a copy of the GNU Lesser General Public
047// License along with this library; if not, write to the Free Software
048// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
049//
050// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
051// jataylor@hairyfatguy.com
052//------------------------------------------------------------------------------
053
054public class ImageIO_Util
055{
056   public static float DEFAULT_JPG_QUALITY = 0.85f;
057
058   static
059   {
060      ImageIO.scanForPlugins();
061   }
062
063   //--------------------------------------------------------------------------
064   public static void writeBufferedImageAsJpeg(BufferedImage inImage, OutputStream inStream)
065   throws IOException
066   {
067      writeBufferedImageAsJpeg(inImage, inStream, DEFAULT_JPG_QUALITY);
068   }
069
070   //--------------------------------------------------------------------------
071   public static void writeBufferedImageAsJpeg(BufferedImage inBufferedImage, OutputStream inStream, float inJpgQuality)
072         throws IOException
073   {
074      ImageWriter jpegWriter = ImageIO.getImageWritersByFormatName("JPEG").next();
075
076      ImageWriteParam params = jpegWriter.getDefaultWriteParam();
077      params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
078      params.setCompressionQuality(inJpgQuality);
079
080      ImageOutputStream out = ImageIO.createImageOutputStream(inStream);
081      jpegWriter.setOutput(out);
082      jpegWriter.write(null, new IIOImage(inBufferedImage,null,null),params);
083      jpegWriter.dispose();
084   }
085
086   //---------------------------------------------------------------------------
087   public static Dimension getDimension(File inImgFile)
088   {
089      Dimension dimension;
090      try
091      {
092         BufferedImage image = ImageIO.read(inImgFile);
093         dimension = new Dimension(image.getWidth(), image.getHeight());
094      }
095      catch (IOException e)
096      {
097         throw new RuntimeException(e);
098      }
099
100      return dimension;
101   }
102
103   //---------------------------------------------------------------------------
104   public static Dimension getDimension(InputStream inImgStream)
105   {
106      Dimension dimension;
107      try
108      {
109         BufferedImage image = ImageIO.read(inImgStream);
110         dimension = new Dimension(image.getWidth(), image.getHeight());
111      }
112      catch (IOException e)
113      {
114         throw new RuntimeException(e);
115      }
116
117      return dimension;
118   }
119
120   //---------------------------------------------------------------------------
121   public static Dimension getDimension(InputStream inImgStream, ImageFormat inFormat)
122   {
123      Dimension dimension;
124      try
125      {
126         Iterator<ImageReader> readerIterator = ImageIO.getImageReadersBySuffix(inFormat.getFileExtension());
127         ImageReader imgReader = null;
128         if (readerIterator.hasNext())
129         {
130            imgReader = readerIterator.next();
131         }
132
133         if (imgReader == null) 
134         {
135            throw new RuntimeException("Reader for " + inFormat.name() + " not found.");
136         }
137
138         imgReader.setInput(ImageIO.createImageInputStream(inImgStream), true);
139
140         BufferedImage image = imgReader.read(0);
141         
142         dimension = new Dimension(image.getWidth(), image.getHeight());
143      }
144      catch (IOException e)
145      {
146         throw new RuntimeException(e);
147      }
148
149      return dimension;
150   }
151
152   //--------------------------------------------------------------------------
153   public static void convertImage(File inOrigImg, File inDestImg, float inCompressionQuality)
154   {
155      ImageFormat destFormat = ImageFormat.guessFormatFromName(inDestImg.getName());
156
157      try
158      {
159         // Read input image from file
160         BufferedImage srcImage = readImageFile(inOrigImg);
161
162         if (destFormat == ImageFormat.JPEG)
163         {
164            Iterator<ImageWriter> writerIter = ImageIO.getImageWritersBySuffix(destFormat.getFileExtension());
165            ImageWriteParam param = new JPEGImageWriteParam(Locale.getDefault());
166            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
167            param.setCompressionQuality(inCompressionQuality);
168            ImageWriter writer =writerIter.next();
169            IIOMetadata metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(srcImage), param);
170            ImageOutputStream outputStream = new FileImageOutputStream(inDestImg);
171            writer.setOutput(outputStream);
172            writer.write(metadata, new IIOImage(srcImage, null, metadata), param);
173            writer.dispose();
174            outputStream.close();
175         }
176         else
177         {
178            FileOutputStream outputStream = null;
179            try
180            {
181               outputStream = new FileOutputStream(inDestImg);
182               // Format to be converted to can be one of: jpeg, png, bmp, wbmp, and gif
183               ImageIO.write(srcImage, destFormat.getFileExtension(), outputStream);
184            }
185            finally
186            {
187               if (outputStream != null) outputStream.close();
188            }
189         }
190      }
191      catch (IOException e)
192      {
193         throw new RuntimeException(e);
194      }
195   }
196   /*
197   BufferedImage sourceImage = ImageIO.read(inputStream);
198   Image thumbnail = sourceImage.getScaledInstance(width, -1, Image.SCALE_SMOOTH);
199   BufferedImage bufferedThumbnail = new BufferedImage(thumbnail.getWidth(null),
200                                                       thumbnail.getHeight(null),
201                                                       BufferedImage.TYPE_INT_RGB);
202   bufferedThumbnail.getGraphics().drawImage(thumbnail, 0, 0, null);
203   ImageIO.write(bufferedThumbnail, "jpeg", outputStream);
204    */
205
206
207   //--------------------------------------------------------------------------
208
209   /**
210    If the destination format is JPG, a default compression quality of 0.7 is used.
211    */
212   public static void scaleDownImage(File inImgFile, int inMaxDimension, File inDestFile)
213   {
214      scaleDownImage(inImgFile, inMaxDimension, inDestFile, 0.7f);
215   }
216
217   //---------------------------------------------------------------------------
218   public static void scaleDownImage(File inOrigImgFile, int inMaxDimension, File inDestImgFile, float inCompressionQuality)
219   {
220      if (null == inOrigImgFile)
221      {
222         throw new RuntimeException("No source image was specified!");
223      }
224
225      ImageFormat destFormat = ImageFormat.guessFormatFromName(inDestImgFile.getName());
226
227      try
228      {
229         // Read input image from file
230         BufferedImage sourceImage = readImageFile(inOrigImgFile);
231
232         int width = -1;
233         int height = -1;
234         if (sourceImage.getWidth() > sourceImage.getHeight())
235         {
236            width = inMaxDimension;
237         }
238         else
239         {
240            height = inMaxDimension;
241         }
242
243         Image resizedImage = sourceImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
244         // Allocate a new BufferedImage
245         BufferedImage bufferedResizedImage = new BufferedImage(resizedImage.getWidth(null),
246               resizedImage.getHeight(null),
247               BufferedImage.TYPE_INT_RGB);
248         // Draw the resized image onto the new BufferedImage
249         bufferedResizedImage.getGraphics().drawImage(resizedImage, 0, 0, null);
250
251         if (destFormat == ImageFormat.JPEG)
252         {
253            Iterator<ImageWriter> writerIter = ImageIO.getImageWritersBySuffix(destFormat.getFileExtension());
254            ImageWriteParam param = new JPEGImageWriteParam(Locale.getDefault());
255            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
256            param.setCompressionQuality(inCompressionQuality);
257            ImageWriter writer =writerIter.next();
258            IIOMetadata metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(bufferedResizedImage), param);
259            ImageOutputStream outputStream = new FileImageOutputStream(inDestImgFile);
260            writer.setOutput(outputStream);
261            writer.write(metadata, new IIOImage(bufferedResizedImage, null, metadata), param);
262            writer.dispose();
263            outputStream.close();
264         }
265         else
266         {
267            FileOutputStream outputStream = null;
268            try
269            {
270               outputStream = new FileOutputStream(inDestImgFile);
271               // Format to be converted to can be one of: jpeg, png, bmp, wbmp, and gif
272               if (! ImageIO.write(bufferedResizedImage, destFormat.getFileExtension(), outputStream))
273               {
274                  String msg = "The destination image " + StringUtil.singleQuote(inDestImgFile) + " couldn't be written!";
275                  if (destFormat.equals(ImageFormat.TIFF))
276                  {
277                     msg += " The jai-imageio-core jar is needed to read/write TIFF format.";
278                  }
279
280                  throw new RuntimeException(msg);
281               }
282            }
283            finally
284            {
285               if (outputStream != null) outputStream.close();
286            }
287         }
288      }
289      catch (IOException e)
290      {
291         throw new RuntimeException(e);
292      }
293   }
294
295
296   //--------------------------------------------------------------------------
297   private static BufferedImage readImageFile(File inSrcImg)
298         throws IOException
299   {
300      BufferedImage srcImage = null;
301
302      ImageFormat srcFormat = ImageFormat.guessFormatFromName(inSrcImg.getName());
303
304      FileInputStream inputStream = null;
305      try
306      {
307         inputStream = new FileInputStream(inSrcImg);
308
309         // Read input image from file
310         srcImage = ImageIO.read(inputStream);
311         if (null == srcImage)
312         {
313            String msg = "The input image " + StringUtil.singleQuote(inSrcImg) + " couldn't be read!";
314            if (srcFormat != null
315                && srcFormat.equals(ImageFormat.TIFF))
316            {
317               msg += " The jai-imageio-core jar is needed to read/write TIFF format.";
318            }
319
320            throw new RuntimeException(msg);
321         }
322      }
323      finally
324      {
325         if (inputStream != null) inputStream.close();
326      }
327
328      return srcImage;
329   }
330
331}