com.sun.socialsite.util.ImageUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.sun.socialsite.util.ImageUtil.java

Source

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://socialsite.dev.java.net/legal/CDDL+GPL.html
 * or legal/LICENSE.txt.  See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at legal/LICENSE.txt.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided by Sun
 * in the GPL Version 2 section of the License file that accompanied this code.
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.socialsite.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import javax.imageio.ImageIO;
import javax.imageio.IIOException;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Image Utility.
 */
public class ImageUtil {

    private static Log log = LogFactory.getLog(ImageUtil.class);
    private static int maxWidth = 150;
    private static int maxHeight = 150;

    private HttpConnectionManager httpConnectionManager;
    private Protocol httpsProtocol;

    /**
     * Public constructor.
     */
    public ImageUtil(int timeout) {

        httpConnectionManager = new MultiThreadedHttpConnectionManager();
        httpConnectionManager.getParams().setConnectionTimeout(timeout);
        httpConnectionManager.getParams().setSoTimeout(timeout);

        // This allows us to accept self-signed certs
        // TODO: make this configurable, or at least stop setting default for all HttpClients
        ProtocolSocketFactory protocolSocketFactory = new LeniantSSLProtocolSocketFactory();
        httpsProtocol = new Protocol("https", protocolSocketFactory, 443);
        Protocol.registerProtocol("https", httpsProtocol);
    }

    /**
     * Grabs an image from a URI (and scales it to some reasonable size).
     *
     * @param uriString the URI from which to grab the image.
     */
    public BufferedImage getImage(final String uriString) {

        // TODO: better approach to Exceptions

        if ((uriString == null) || ("".equals(uriString))) {
            return null;
        }

        URI uri = null;
        GetMethod method = null;
        try {
            uri = new URI(uriString, false);
            HttpClient httpClient = new HttpClient(httpConnectionManager);
            method = new GetMethod(uri.getEscapedURI());
            httpClient.executeMethod(method);
            BufferedImage origImage = ImageIO.read(method.getResponseBodyAsStream());
            log.debug(String.format("Got origImage for %s", uriString));
            return getScaledImage(origImage, maxWidth, maxHeight);
        } catch (ConnectException e) {
            log.warn(String.format("Failed to retrieve image: %s [%s]", uriString, e.toString()));
            return null;
        } catch (ConnectTimeoutException e) {
            log.warn(String.format("Failed to retrieve image: %s [%s]", uriString, e.toString()));
            return null;
        } catch (SocketTimeoutException e) {
            log.warn(String.format("Failed to retrieve image: %s [%s]", uriString, e.toString()));
            return null;
        } catch (UnknownHostException e) {
            log.warn(String.format("Failed to retrieve image: %s [%s]", uriString, e.toString()));
            return null;
        } catch (IllegalArgumentException e) {
            log.warn(String.format("Failed to retrieve image: %s [%s]", uriString, e.toString()));
            return null;
        } catch (IllegalStateException e) {
            log.warn(String.format("Failed to retrieve image: %s [%s]", uriString, e.toString()));
            return null;
        } catch (IIOException e) {
            log.warn(String.format("Failed to process image: %s [%s]", uriString, e.toString()));
            return null;
        } catch (Throwable t) {
            log.error(String.format("Failed to retrieve image: %s", uriString), t);
            return null;
        } finally {
            if (method != null) {
                method.releaseConnection();
            }
        }
    }

    public static BufferedImage getScaledImage(BufferedImage origImage, Integer desiredWidth, Integer desiredHeight)
            throws IOException {

        if (origImage == null) {
            return null;
        }

        if (desiredWidth == null) {
            desiredWidth = origImage.getWidth();
        }

        if (desiredHeight == null) {
            desiredHeight = origImage.getHeight();
        }

        int origWidth = origImage.getWidth();
        int origHeight = origImage.getHeight();

        double ratio = Math.min((((double) desiredWidth) / origWidth), (((double) desiredHeight) / origHeight));

        int extraWidth = desiredWidth - ((int) (origWidth * ratio));
        int extraHeight = desiredHeight - ((int) (origHeight * ratio));

        int tmpWidth = (desiredWidth - extraWidth);
        int tmpHeight = (desiredHeight - extraHeight);
        BufferedImage tmpImage = getScaledInstance(origImage, tmpWidth, tmpHeight,
                RenderingHints.VALUE_INTERPOLATION_BICUBIC, true);

        log.debug(String.format("tmpImage[width=%d height=%d", tmpImage.getWidth(), tmpImage.getHeight()));

        if ((tmpImage.getWidth() == desiredWidth) && (tmpImage.getHeight() == desiredHeight)) {
            return tmpImage;
        } else {
            BufferedImage scaledImage = new BufferedImage(desiredWidth, desiredHeight, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = scaledImage.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

            // We recalculate these in case scaling didn't quite hit its targets
            extraWidth = desiredWidth - tmpImage.getWidth();
            extraHeight = desiredHeight - tmpImage.getHeight();

            int dx1 = extraWidth / 2;
            int dy1 = extraHeight / 2;
            int dx2 = desiredWidth - dx1;
            int dy2 = desiredWidth - dy1;

            // transparent background
            g2d.setColor(new Color(0, 0, 0, 0));
            g2d.fillRect(0, 0, desiredWidth, desiredHeight);

            g2d.drawImage(tmpImage, dx1, dy1, dx2, dy2, null);
            return scaledImage;
        }
    }

    /**
     * Convenience method that returns a scaled instance of the
     * provided {@code BufferedImage}.
     *
     * NOTE: Adapted from code at
     * {@link http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html}.
     *
     * @param img the original image to be scaled
     * @param targetWidth the desired width of the scaled instance,
     *    in pixels
     * @param targetHeight the desired height of the scaled instance,
     *    in pixels
     * @param hint one of the rendering hints that corresponds to
     *    {@code RenderingHints.KEY_INTERPOLATION} (e.g.
     *    {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
     *    {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
     *    {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
     * @param higherQuality if true, this method will use a multi-step
     *    scaling technique that provides higher quality than the usual
     *    one-step technique (only useful in downscaling cases, where
     *    {@code targetWidth} or {@code targetHeight} is
     *    smaller than the original dimensions, and generally only when
     *    the {@code BILINEAR} hint is specified)
     * @return a scaled version of the original {@code BufferedImage}
     */
    private static BufferedImage getScaledInstance(BufferedImage img, int targetWidth, int targetHeight,
            Object hint, boolean higherQuality) {
        int type = BufferedImage.TYPE_INT_ARGB;
        BufferedImage ret = (BufferedImage) img;
        int w, h;
        if (higherQuality) {
            // Use multi-step technique: start with original size, then
            // scale down in multiple passes with drawImage()
            // until the target size is reached
            w = img.getWidth();
            h = img.getHeight();
        } else {
            // Use one-step technique: scale directly from original
            // size to target size with a single drawImage() call
            w = targetWidth;
            h = targetHeight;
        }

        do {
            if (higherQuality && w > targetWidth) {
                w /= 2;
                if (w < targetWidth) {
                    w = targetWidth;
                }
            }

            if (higherQuality && h > targetHeight) {
                h /= 2;
                if (h < targetHeight) {
                    h = targetHeight;
                }
            }

            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();

            ret = tmp;
        } while (w > targetWidth || h > targetHeight);

        return ret;
    }

}