Это самый эффективный способ создания BuffreredImage из данных изображения в Java - PullRequest
0 голосов
/ 20 мая 2019

Я пересматриваю какой-то старый код, он загружает изображение с URL-адреса, а затем создает BufferedImage с помощью ридера. Поскольку мое приложение теперь загружает больше изображений, этот код становится все более значимым, и мне интересно, можно ли это сделать более эффективным способом?

public static byte[] convertUrlToByteArray(URL url) throws IOException
    {
        //Get imagedata, we want to ensure we just write the data as is as long as in a supported format
        URLConnection connection = url.openConnection();
        connection.setConnectTimeout(URL_TIMEOUT);
        connection.setReadTimeout(URL_TIMEOUT);

        //Do this because some services like Discogs reject calls if not from known user-agent, we pretend we are using
        //firefox,
        //TODO perhaps should be more sophisticated and select from a random list of browser user agents
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");

        // Since you get a URLConnection, use it to get the InputStream
        InputStream in = connection.getInputStream();
        // Now that the InputStream is open, get the content length
        int contentLength = connection.getContentLength();
        // To avoid having to resize the array over and over and over as
        // bytes are written to the array, provide an accurate estimate of
        // the ultimate size of the byte array
        ByteArrayOutputStream tmpOut;
        if (contentLength != -1)
        {
            tmpOut = new ByteArrayOutputStream(contentLength);
        }
        else
        {
            tmpOut = new ByteArrayOutputStream(16384); // Pick some appropriate size
        }

        byte[] buf = new byte[1024];
        while (true)
        {
            int len = in.read(buf);
            if (len == -1)
            {
                break;
            }
            tmpOut.write(buf, 0, len);
        }
        in.close();
        tmpOut.close(); // No effect, but good to do anyway to keep the metaphor alive
        return tmpOut.toByteArray();
    }

    public static BufferedImage createBufferedImageFromRawData(byte[] imageData, String logDescriptor)
        {
            if (imageData.length > MAX_IMAGE_SIZE)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").severe("ImageSizeTooLargeToProcess:"+logDescriptor);
                return null;
            }

            BufferedImage bi = null;
            ImageInputStream stream = null;
            ByteArrayInputStream bais = null;
            try
            {
                ImageReader ir;
                bais = new ByteArrayInputStream(imageData);
                stream = ImageIO.createImageInputStream(bais);
                Iterator<ImageReader> i = ImageIO.getImageReaders(stream);

                //Try each reader until we get one that could create an Image
                while (i.hasNext())
                {
                    ir = i.next();
                    bi = createBufferedImageUsingReader(stream, logDescriptor, ir);
                    if (bi != null)
                    {
                        break;
                    }

                    //Close the old Stream
                    try
                    {
                        stream.close();
                        bais.close();
                    }
                    catch (IOException ioe)
                    {
                        ioe.printStackTrace();
                    }

                    //Recreate stream to avoid flushing problem
                    bais = new ByteArrayInputStream(imageData);
                    stream = ImageIO.createImageInputStream(bais);
                }
            }
            catch (IOException ex)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"IOException reading image:"+logDescriptor+":"+ex.getMessage(),ex);
            }
            catch (OutOfMemoryError ome)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"OutOfMemoryException reading image:"+logDescriptor+":"+ome.getMessage(),ome);
                System.runFinalization();
            }
            catch (RuntimeException re)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"RuntimeException reading image:"+logDescriptor, re);
            }
            catch(Exception exe)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"Exception reading image:"+logDescriptor+":"+exe.getMessage(),exe);
                System.runFinalization();
            }
            finally
            {
                try
                {
                    stream.close();
                    bais.close();
                }
                catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }
            }
            return bi;
        }

        public static BufferedImage createBufferedImageUsingReader(ImageInputStream stream, String logDescriptor, ImageReader ir)
        {
            BufferedImage bi = null;
            try
            {
                ir.setInput(stream);
                ImageReadParam param = ir.getDefaultReadParam();

                Iterator<ImageTypeSpecifier> it;

                // Synchronized because ImageReader seems to come from a singleton and the call to ir.getImageTypes()
                // can throw ConcurrentModificationException because could have two threads both accessing the same image readers
                // image types
                synchronized(CoverImage.class)
                {
                    it = ir.getImageTypes(0);
                }
                //Used to loop round all ImageTypeSpecifier but to set Color Space as RGB
                //But set destination type to RGB this only works before Java 6 build 15
                //if the first colour space is RGB, it fails if have gray space image which supports both colour and gray
                //But has gray as the first colour space.
                //So for now only check the first one as this seems to be the one that gets used.
                if (it.hasNext())
                {
                    ImageTypeSpecifier type = it.next();
                    ColorSpace cs = type.getColorModel().getColorSpace();

                    if (cs.isCS_sRGB())
                    {
                        param.setDestinationType(type);
                    }
                }
                bi = ir.read(0, param);
                ir.dispose();
            }
            catch (IOException ex)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"IOException reading image:"+logDescriptor,ex);

            }
            catch (IllegalArgumentException iae)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"IllegalArgumentException reading image:"+logDescriptor, iae);
            }
            catch (OutOfMemoryError ome)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"OutOfMemoryException reading image:"+logDescriptor+":"+ome.getMessage(),ome);
                System.runFinalization();
            }
            catch (RuntimeException re)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"RuntimeException reading image:"+logDescriptor, re);
            }
            catch (Exception exe)
            {
                Logger.getLogger("com.jthink.songlayer.CoverImage").log(Level.SEVERE,"Exception reading image:"+logDescriptor, exe);
            }
            finally
            {
                //See http://bugs.sun.com/view_bug.do?bug_id=6687968 & http://bugs.sun.com/view_bug.do?bug_id=4797189
                //TODO RunFinalization has to create a thread, massively increasing thread count so although the above SUN
                //bugs are still open we don't really want to call this every time we create a BufferedImage from Reader
                System.runFinalization();
            }
            return bi;

}

...