aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/util/ImageUtils.java
blob: 9b7d7d09a41966bb44825464ab8b9095a5424e7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/*
 * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package net.java.sip.communicator.util;

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;

import javax.imageio.*;
import javax.swing.*;

import net.java.sip.communicator.util.swing.*;

/**
 * Utility methods for image manipulation.
 *
 * @author Sebastien Mazy
 * @author Yana Stamcheva
 * @author Lubomir Marinov
 */
public class ImageUtils
{
    private static final Logger logger = Logger.getLogger(ImageUtils.class);

    /**
     * Returns a scaled image fitting within the given bounds while keeping the
     * aspect ratio.
     *
     * @param image the image to scale
     * @param width maximum width of the scaled image
     * @param height maximum height of the scaled image
     * @return the scaled image
     */
    public static Image scaleImageWithinBounds( Image image,
                                                int width,
                                                int height)
    {
        int initialWidth = image.getWidth(null);
        int initialHeight = image.getHeight(null);

        Image scaledImage;
        int scaleHint = Image.SCALE_SMOOTH;
        double originalRatio =
            (double) initialWidth / initialHeight;
        double areaRatio = (double) width / height;

        if(originalRatio > areaRatio)
            scaledImage = image.getScaledInstance(width, -1, scaleHint);
        else
            scaledImage = image.getScaledInstance(-1, height, scaleHint);
        return scaledImage;
    }

    /**
     * Scales the given <tt>image</tt> to fit in the given <tt>width</tt> and
     * <tt>height</tt>.
     * @param image the image to scale
     * @param width the desired width
     * @param height the desired height
     * @return the scaled image
     */
    public static ImageIcon scaleIconWithinBounds(Image image, int width,
        int height)
    {
        return new ImageIcon(scaleImageWithinBounds(image, width, height));
    }

    /**
     * Creates a rounded avatar image.
     *
     * @param image image of the initial avatar image.
     * @param width the desired width
     * @param height the desired height
     * @return The rounded corner image.
     */
    public static Image getScaledRoundedImage(  Image image,
                                                int width,
                                                int height)
    {
        ImageIcon scaledImage =
            ImageUtils.scaleIconWithinBounds(image, width, height);
        int scaledImageWidth = scaledImage.getIconWidth();
        int scaledImageHeight = scaledImage.getIconHeight();

        if(scaledImageHeight <= 0 ||
           scaledImageWidth <= 0)
            return null;

        // Just clipping the image would cause jaggies on Windows and Linux.
        // The following is a soft clipping solution based on the solution
        // proposed by Chris Campbell:
        // http://java.sun.com/mailers/techtips/corejava/2006/tt0923.html
        BufferedImage destImage
            = new BufferedImage(scaledImageWidth, scaledImageHeight,
                BufferedImage.TYPE_INT_ARGB);

        Graphics2D g = destImage.createGraphics();

        try
        {
            // Render our clip shape into the image.  Note that we enable
            // antialiasing to achieve the soft clipping effect.
            g.setComposite(AlphaComposite.Src);
            AntialiasingManager.activateAntialiasing(g);
            g.setColor(Color.WHITE);
            g.fillRoundRect(0, 0, scaledImageWidth, scaledImageHeight, 15, 15);

            // We use SrcAtop, which effectively uses the
            // alpha value as a coverage value for each pixel stored in the
            // destination.  For the areas outside our clip shape, the
            // destination alpha will be zero, so nothing is rendered in those
            // areas. For the areas inside our clip shape, the destination alpha
            // will be fully opaque, so the full color is rendered. At the edges,
            // the original antialiasing is carried over to give us the desired
            // soft clipping effect.
            g.setComposite(AlphaComposite.SrcAtop);
            g.drawImage(scaledImage.getImage(), 0, 0, null);
        }
        finally
        {
            g.dispose();
        }
        return destImage;
    }

    /**
     * Returns a scaled instance of the given <tt>image</tt>.
     * @param image the image to scale
     * @param width the desired width
     * @param height the desired height
     * @return a byte array containing the scaled image
     */
    public static byte[] getScaledInstanceInBytes(
        Image image, int width, int height)
    {
        byte[] scaledBytes = null;

        BufferedImage scaledImage
            = (BufferedImage) getScaledRoundedImage(image, width, height);

        if (scaledImage != null)
        {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();

            try
            {
                ImageIO.write(scaledImage, "png", outStream);
                scaledBytes = outStream.toByteArray();
            }
            catch (IOException e)
            {
                if (logger.isDebugEnabled())
                    logger.debug("Could not scale image in bytes.", e);
            }

        }

        return scaledBytes;
    }

    /**
     * Returns a scaled rounded icon from the given <tt>image</tt>, scaled
     * within the given <tt>width</tt> and <tt>height</tt>.
     * @param image the image to scale
     * @param width the maximum width of the scaled icon
     * @param height the maximum height of the scaled icon
     * @return a scaled rounded icon
     */
    public static ImageIcon getScaledRoundedIcon(Image image, int width,
        int height)
    {
        Image scaledImage = getScaledRoundedImage(image, width, height);

        if (scaledImage != null)
            return new ImageIcon(scaledImage);

        return null;
    }

    /**
     * Creates a rounded corner scaled image.
     *
     * @param imageBytes The bytes of the image to be scaled.
     * @param width The maximum width of the scaled image.
     * @param height The maximum height of the scaled image.
     *
     * @return The rounded corner scaled image.
     */
    public static ImageIcon getScaledRoundedIcon(  byte[] imageBytes,
                                                    int width,
                                                    int height)
    {
        if (imageBytes == null || !(imageBytes.length > 0))
            return null;

        ImageIcon imageIcon = null;

        try
        {
            Image image = null;

            // sometimes ImageIO fails, will fall back to awt Toolkit
            try
            {
                image = ImageIO.read(new ByteArrayInputStream(imageBytes));
            } catch (Exception e)
            {
                try
                {
                    image = Toolkit.getDefaultToolkit().createImage(imageBytes);
                } catch (Exception e1)
                {
                    // if it fails throw the original exception
                    throw e;
                }
            }
            if(image != null)
                imageIcon = getScaledRoundedIcon(image, width, height);
            else
                if (logger.isTraceEnabled())
                    logger.trace("Unknown image format or error reading image");
        }
        catch (Exception e)
        {
            if (logger.isDebugEnabled())
                logger.debug("Could not create image.", e);
        }

        return imageIcon;
    }

    /**
     * Returns the buffered image corresponding to the given url image path.
     *
     * @param imagePath the path indicating, where we can find the image.
     *
     * @return the buffered image corresponding to the given url image path.
     */
    public static BufferedImage getBufferedImage(URL imagePath)
    {
        BufferedImage image = null;

        if (imagePath != null)
        {
            try
            {
                image = ImageIO.read(imagePath);
            }
            catch (IOException ex)
            {
                if (logger.isDebugEnabled())
                    logger.debug("Failed to load image:" + imagePath, ex);
            }
        }
        return image;
    }
}