Я пересматриваю какой-то старый код, он загружает изображение с 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;
}