Using ImageIO.read with a redirecting URL

5.7k views Asked by At

I'm trying to read an image from the net using ImageIO:

URL url = new URL(location);
bi = ImageIO.read(url);

When location is a URL that ends with the actual image (e.g. http://www.lol.net/1.jpg), the code above works. However, when the URL is a redirection (e.g. http://www.lol.net/redirection, leading to http://www.lol.net/1.jpg), the code above returns null in bi.

Two questions. One, why is this happening? Is it because the ImageIO library tries to find a suitable ImageReader based on the URL string? And two, what will be the cleanest solution to this limitation? Note that I require a BufferedImage output and not an Image output.

EDIT: For whomever wants to test it, the URL I'm trying to read is http://graph.facebook.com/804672289/picture, which is converted into http://profile.ak.fbcdn.net/hprofile-ak-snc4/hs351.snc4/41632_804672289_6662_q.jpg.

EDIT 2: I was incorrect in the last edit. the URL is https://graph.facebook.com/804672289/picture. If I replace the https with http, the code above works fine. So my new question is how to make it work with HTTPS so I won't need to do the replacement.

4

There are 4 answers

1
aioobe On BEST ANSWER

To me it doesn't seem like http://www.lol.net/1.jpg points directly to an image.

As @Bozho points out, the ImageIO uses the default URL.openConnection which (since the address starts with "http") returns a HttpURLConnection which, per default has setFollowRedirects(true).

Regarding your edit, this code seems to work just fine to me:

URL url = new URL("http://graph.facebook.com/804672289/picture");
BufferedImage bi = ImageIO.read(url);

System.out.println(bi);
// Prints: BufferedImage@43b09468: type = 5 ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@7ddf5a8f transparency = 1 has alpha = false isAlphaPre = false ByteInterleavedRaster: width = 50 height = 50 #numDataElements 3 dataOff[0] = 2

I suspect your error is somewhere else.

0
Syed On

Regarding your EDIT 2:

ImageIo.read(url), does not bother about the url type. i.e., http or https.

You can simply pass the url to this method but if you are passing https url then need to perform certain steps to validate the SSL certificate. Please find the below example.

1) For http & https:

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.cert.X509Certificate;
import javax.imageio.ImageIO;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;


/**
 * @author Syed CBE
 *
 */
public class Main {


    public static void main(String[] args) {

                int height = 0,width = 0;
                String imagePath="https://www.sampledomain.com/sampleimage.jpg";
                System.out.println("URL=="+imagePath);
                InputStream connection;
                try {
                    URL url = new URL(imagePath);  
                    if(imagePath.indexOf("https://")!=-1){
                        final SSLContext sc = SSLContext.getInstance("SSL");
                        sc.init(null, getTrustingManager(), new java.security.SecureRandom());                                 
                        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
                        connection = url.openStream();
                     }
                    else{
                        connection = url.openStream();
                    }
                    BufferedImage bufferedimage = ImageIO.read(connection);
                    width          = bufferedimage.getWidth();
                    height         = bufferedimage.getHeight();
                    System.out.println("width="+width);
                    System.out.println("height="+height);
                } catch (MalformedURLException e) {

                    System.out.println("URL is not correct : " + imagePath);
                } catch (IOException e) {

                    System.out.println("IOException Occurred : "+e);
                }
                catch (Exception e) {

                    System.out.println("Exception Occurred  : "+e);
                }


    }

     private static TrustManager[] getTrustingManager() {
            TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

                   @Override
                   public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                         return null;
                   }

                   @Override
                   public void checkClientTrusted(X509Certificate[] certs, String authType) {
                   }

                   @Override
                   public void checkServerTrusted(X509Certificate[] certs, String authType) {
                   }
            } };
            return trustAllCerts;
     }

}

2) For http alone:

// This Code will work only for http, you can make it work for https but you need additional code to add SSL certificate using keystore
    public static void getImage(String testUrl) {

            String testUrl="https://sampleurl.com/image.jpg";

        HttpGet httpGet = new HttpGet(testUrl);
                 System.out.println("HttpGet is  ---->"+httpGet.getURI());
                HttpResponse httpResponse = null;
                HttpClient httpClient=new DefaultHttpClient();

                try {

                    httpResponse = httpClient.execute(httpGet);
                    InputStream stream=httpResponse.getEntity().getContent();
                     BufferedImage sourceImg = ImageIO.read(stream);
                    System.out.println("------ source -----"+sourceImg.getHeight());
                     sourceImg.getWidth();
                        System.out.println(sourceImg);
                }catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    System.out.println("------ MalformedURLException -----"+e);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                System.out.println("------  IOEXCEPTION -----"+e);
                }
    }
0
Miguel Reyes On

I was having the same problem with https image links. The problem was that when I read the https link, in the code, it would return a 200. But in reality it was a 301. To go around this problem, I used the "curl" user-agent so that I would get the 301 and iterate until finding the final link. See the code below:

Hope this helps @Eldad-Mor.

private InputStream getInputStream(String url) throws IOException {
        InputStream stream = null;
        try {
            stream = handleRedirects(url);
            byte[] bytes = IOUtils.toByteArray(stream);
            return new ByteArrayInputStream(bytes);
        } finally {
            if (stream != null)
                stream.close();
        }
    }

    /**
     * Handle redirects in the URL Manually. Method calls itself if redirects are found until there re no more redirects.
     * 
     * @param url URL
     * @return input stream
     * @throws IOException
     */
    private InputStream handleRedirects(String url) throws IOException {
        HttpURLConnection.setFollowRedirects(false);
        URL obj = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) obj.openConnection();
        conn.setRequestProperty("User-Agent", "curl/7.30.0");
        conn.connect();
        boolean redirect = false;
        LOG.info(conn.getURL().toString());

        int status = conn.getResponseCode();
        if (status != HttpURLConnection.HTTP_OK) {
            if (status == HttpURLConnection.HTTP_MOVED_TEMP
                    || status == HttpURLConnection.HTTP_MOVED_PERM
                    || status == HttpURLConnection.HTTP_SEE_OTHER)
                redirect = true;
        }
        if (redirect) {
            String newUrl =conn.getHeaderField("Location");
            conn.getInputStream().close();
            conn.disconnect();
            return handleRedirects(newUrl);
        }
        return conn.getInputStream();
    }
0
user2046212 On

At the momemnt Apache HttpClient could be used, for me it works fine.

http://hc.apache.org/

    public static void main(String args[]) throws Exception{
    String url = "http://graph.facebook.com/804672289/picture?width=800";

    HttpClient client = HttpClients.createDefault();
    HttpResponse response = client.execute(new HttpGet(url));
    BufferedImage image = ImageIO.read(input);

    if(image == null){
        throw new RuntimeException("Ooops");
    } else{
        System.out.println(image.getHeight());
    }
}