Search code examples
javafaviconeofico

Saving internet icon then re-opening causes EOF with image4j


I'm currently working on a project where I'm attempting to download a .ico file, but for some strange reason, I can't seem to open it programmatically once downloaded. I can however, open the image saved using any image editor or viewer. My code:

public static BufferedImage parseImageLocal(String url) throws IOException {
        if (url.endsWith(".ico")) {
            return ICODecoder.read(new File(url)).get(0);
        } else if (url.endsWith(".bmp")) {
            return BMPDecoder.read(new File(url));

        } else {
            return ImageIO.read(new File(url));
        }
    }

    public static void saveImage(BufferedImage img, String path)
            throws IOException {

        File outputfile = new File(path.replace("http://", ""));
        File parent = outputfile.getParentFile();
        parent.mkdir();
        if (!outputfile.exists()) {
            outputfile.createNewFile();
        }
        if (path.endsWith(".ico")) {
            ICOEncoder.write(img, outputfile);
        } else if (path.endsWith(".bmp")) {
            BMPEncoder.write(img, outputfile);
        } else {
            ImageIO.write(img, "png", outputfile);
        }
    }

And this is how i download images from the internet:

public static BufferedImage parseImage(String url) throws IOException {
        URL dest = new URL(url);
        if (url.endsWith(".ico")) {
            return ICODecoder.read(dest.openStream()).get(0);
        } else if (url.endsWith(".bmp")) {
            return BMPDecoder.read(dest.openStream());

        } else {
            return ImageIO.read(dest);
        }
    }

The error is on this line:

return ICODecoder.read(new File(url)).get(0);

Solution

  • It "seems" that you are trying to download the icon from the internet, but you are trying to treat the URL as a File.

    Basically, this isn't going to be possible, File won't be able to resolve to an actual physical file.

    Instead, you should be using ICODecoder#read(InputStream) and URL#openStream

    Something more like...

    BufferedImage img = null;
    InputStream is = null;
    try {
        // url begin an instance of java.net.URL
        is = url.openStream();
        img = ICODecoder.read(is);
    } finally {
       try {
           is.close();
       } catch (Exception exp) {
       }
    }
    return img;
    

    Updated with example

    A web resource is not a File, you can not access it as if they were, instead, you need to use the classes designed for interacting with the internet/network.

    For example...

    enter image description here

    import java.awt.EventQueue;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.URL;
    import java.util.List;
    import javax.swing.ImageIcon;
    import javax.swing.JOptionPane;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import net.sf.image4j.codec.ico.ICODecoder;
    
    public class ReadFavicon {
    
        public static void main(String[] args) {
            new ReadFavicon();
        }
    
        public ReadFavicon() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    try {
                        BufferedImage img = readIcon(new URL("https://secure.gravatar.com/favicon.ico"));
                        JOptionPane.showMessageDialog(null, "My FAVICON", "Icon", JOptionPane.PLAIN_MESSAGE, new ImageIcon(img));
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
        }
    
        public BufferedImage readIcon(URL url) throws IOException {
            BufferedImage img = null;
            InputStream is = null;
            try {
                // url begin an instance of java.net.URL
                is = url.openStream();
                List<BufferedImage> imgs = ICODecoder.read(is);
                img = imgs != null ? imgs.size() > 0 ? imgs.get(0) : null : null;
            } finally {
                try {
                    is.close();
                } catch (Exception exp) {
                }
            }
            return img;
        }
    
    }
    

    Update with some more ideas

    Now. I could be wrong, but when I ran your code, I ran into a serious of problems with the paths...

    Let's assume the original url/path is https://secure.gravatar.com/favicon.ico, when you save the image, you do something like...

    File outputfile = new File(path.replace("http://", ""));
    File parent = outputfile.getParentFile();
    parent.mkdir();
    

    With our original path, this would result in a outputfile of https://secure.gravatar.com/favicon.ico, which is obviously wrong...

    We can correct for this by using path.replace("https://", "") as well...

    path = path.replace("http://", "");
    path = path.replace("https://", "");
    
    File outputfile = new File(path);
    File parent = outputfile.getParentFile();
    parent.mkdir();
    

    Now, this results in a outputfile of secure.gravatar.com/favicon.ico. I become a little unstuck, as I'm not sure if this is what you want...but it does work for me...

    Now, when you read the file, you do something like this...

    public static BufferedImage parseImage(String url) throws IOException {
        URL dest = new URL(url);
        if (url.endsWith(".ico")) {
            return ICODecoder.read(dest.openStream()).get(0);
        } else if (url.endsWith(".bmp")) {
            return BMPDecoder.read(dest.openStream());
    
        } else {
            return ImageIO.read(dest);
        }
    }
    

    Now, with no evidence to the contray, I have to assume the url has not changed and is still https://secure.gravatar.com/favicon.ico...this means that new File("https://secure.gravatar.com/favicon.ico") will produce an invalid file reference

    So, again, I parsed the input...

    url = url.replace("https://", "");
    url = url.replace("http://", "");
    File outputfile = new File(url);
    String parentPath = outputfile.getParent();
    String name = outputfile.getName();
    
    url = parentPath + File.separator + name;
    

    Which produces secure.gravatar.com\favicon.ico

    This all downloaded, wrote and read without error.