View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.util.image;
35  
36  
37  import java.awt.Color;
38  import java.awt.Graphics2D;
39  import java.awt.geom.AffineTransform;
40  import java.awt.image.BufferedImage;
41  import java.io.ByteArrayInputStream;
42  import java.io.ByteArrayOutputStream;
43  import java.io.IOException;
44  import java.math.BigDecimal;
45  
46  import javax.imageio.IIOImage;
47  import javax.imageio.ImageIO;
48  import javax.imageio.ImageWriteParam;
49  import javax.imageio.ImageWriter;
50  import javax.imageio.stream.MemoryCacheImageOutputStream;
51  
52  import org.apache.log4j.Logger;
53  
54  /**
55   * Utils for image processing
56   */
57  public class ImageUtil
58  {
59  
60      /** Parameter JPG */
61      private static final String PARAMETER_JPG = "jpg";
62  
63      private static final Logger _logger = Logger.getLogger( ImageUtil.class );
64  
65      /**
66       * Resize an image to a given size with a given quality using a JPEG output format
67       * @param blobImage The image as a BLOB
68       * @param strWidth The new width
69       * @param strHeight The new Height
70       * @param fQuality The quality as a float between 0.0 (lower) and 1.0 (higher)
71       * @return bytes
72       */
73      public static byte[] resizeImage( Object blobImage, String strWidth, String strHeight, float fQuality )
74      {
75  
76          byte[] newBlobImage = ( byte[] ) blobImage;
77          if ( blobImage != null )
78          {
79              ByteArrayInputStream bais = new ByteArrayInputStream( newBlobImage );
80              BufferedImage image = null;
81              try
82              {
83                  image = ImageIO.read( bais );
84  
85                  // Parameters
86                  double nParamWidth = Double.valueOf( strWidth );
87                  double nParamHeight = Double.valueOf( strHeight );
88                  double nParamRatio = BigDecimal.valueOf( nParamWidth ).divide( BigDecimal.valueOf( nParamHeight ), 6 ).doubleValue();
89  
90                  // Image attributes
91                  double nImageWidth = Double.valueOf( image.getWidth() );
92                  double nImageHeight = Double.valueOf( image.getHeight() );
93                  double nImageRatio = BigDecimal.valueOf( nImageWidth ).divide( BigDecimal.valueOf( nImageHeight ), 6 ).doubleValue();
94  
95                  if ( nImageWidth > nParamWidth || nImageHeight > nParamHeight )
96                  {
97                      double nTargetWidth = 0;
98                      double nTargetHeight = 0;
99                      // The width is larger than the height (landscape)
100                     if ( nParamRatio > nImageRatio )
101                     {
102                         // Set the Height target to min ( Image Height , Param Height )
103                         nTargetHeight = ( nImageHeight > nParamHeight ) ? nParamHeight : nImageHeight;
104                         nTargetWidth = BigDecimal.valueOf( nTargetHeight ).multiply( BigDecimal.valueOf( nImageRatio ) ).doubleValue();
105                     }
106                     // The Height is larger than the width (portrait)
107                     else
108                     {
109                         // Set the Width target to min ( Image Width , Param Width )
110                         nTargetWidth = ( nImageWidth > nParamWidth ) ? nParamWidth : nImageWidth;
111                         nTargetHeight = BigDecimal.valueOf( nTargetWidth ).divide( BigDecimal.valueOf( nImageRatio ), 6 ).doubleValue();
112                     }
113                     BufferedImage bdest = new BufferedImage( ( ( Double ) nTargetWidth ).intValue(), ( ( Double ) nTargetHeight ).intValue(), BufferedImage.TYPE_INT_RGB );
114                     Graphics2D g = bdest.createGraphics();
115                     AffineTransform at = AffineTransform.getScaleInstance( Double.valueOf( nTargetWidth ) / image.getWidth(), Double.valueOf( nTargetHeight ) / image.getHeight() );
116                     g.drawRenderedImage( image, at );
117 
118                     return getJPEGImageAsByteTab( bdest , fQuality ).toByteArray();
119                 }
120             }
121             catch ( IOException e )
122             {
123                 _logger.error( "Error ImageUtil : " + e.getMessage(), e );
124             }
125         }
126         return newBlobImage;
127     }
128 
129     /**
130      * Convert the buffered image as an array of bytes in a JPEG format
131      * @param image The image
132      * @param fQuality The quality
133      * @return The image as a Byte array
134      */
135     private static ByteArrayOutputStream getJPEGImageAsByteTab( BufferedImage image, float fQuality )
136     {
137         ByteArrayOutputStream outBuffered = null;
138         try
139         {
140             outBuffered = new ByteArrayOutputStream();
141 
142             // Boilerplate to be able to set the quality
143             ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName( PARAMETER_JPG ).next( );
144             ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam( );
145             jpgWriteParam.setCompressionMode( ImageWriteParam.MODE_EXPLICIT );
146             jpgWriteParam.setCompressionQuality( fQuality );
147             jpgWriter.setOutput( new MemoryCacheImageOutputStream( outBuffered ) );
148             IIOImage outputImage = new IIOImage( image, null, null );
149             jpgWriter.write( null, outputImage, jpgWriteParam );
150             jpgWriter.dispose( );
151             outBuffered.flush( );
152         }
153         catch ( IOException e2 )
154         {
155             return null;
156         }
157         return outBuffered;
158     }
159 }