Stream Images With Spring
In lot of social and other sites we see images don’t load at once, they are incrementally loaded and rendered. This is done by streaming the image contents, in this post I will write a small api to demonstrate how that can be achived.
At the end of this post we will see image is loaded incrementally like this -
I will use Spring boot for quick set up, we will read image as byte array then will write to output stream.
1. Read the image in byte array, using Files.readAllBytes from java.nio.file.Files
File fi = new File("/Users/Pratik/Desktop/me.jpg");
byte[] fileContent = Files.readAllBytes(fi.toPath());
2. Set the Content Type Header in Response
Setting this header is important as browser will understand the content type as image only from this. Here I am setting it as image/jpeg, set this according to used image type.
response.setContentType("image/jpeg");
3. We will Use StreamingResponseBody to stream the body content
Using StreamingResponseBody we have to override writeTo method which gets OutputStream, in which we can write image byte data and stream. This by default sets Transfer-Encoding:chunked, so we don’t need to set this header.
return new StreamingResponseBody() {
@Override
public void writeTo (OutputStream out) throws IOException {
File fi = new File("/Users/Pratik/Desktop/me.jpg");
try {
byte[] fileContent = Files.readAllBytes(fi.toPath());
int offset = 0,
chunkLength = 10000,
fileContentLength = fileContent.length;
while (offset+ chunkLength < fileContentLength) {
out.write(fileContent,offset, chunkLength );
out.flush();
offset = offset + chunkLength;
if(fileContentLength < offset + chunkLength){
chunkLength = fileContentLength - offset;
}
//Deliberately adding sleep to emulate buffering image
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
out.close();
} catch (IOException e) {
System.out.println(e);
}
}
};
Here we use OutputStream’s write(byte[] b, int off, int len) method, to write chunk of data in each iteration.
Above I am setting chunk length as 10000, which can be set according to your need. Also I have added a delay of 500 mili seconds to emulate delay in reading, which can be case where you are large reading file from input stream.
Run the Spring app and hit the url http://localhost:8080/streamImage to see the result.
Complete code can be found here