Spring RestTemplate - I/O error reading PNG header

2019-09-08 05:32发布

问题:

I am making an API call to an external app (this app converts all images originally loaded into it to PNG). If the image was originally loaded into that app as a PNG then RestTemplate can get it fine. If it was originally loaded as something else then converted to PNG the below code throws an error when trying to get it using RestTemplate in Spring 4.1.1. The image displays fine on the external app.

Caused by: javax.imageio.IIOException: I/O error reading PNG header! at com.sun.imageio.plugins.png.PNGImageReader.readHeader(PNGImageReader.java:315) ~[na:1.8.0_20] at com.sun.imageio.plugins.png.PNGImageReader.readMetadata(PNGImageReader.java:654) ~[na:1.8.0_20] at com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1248) ~[na:1.8.0_20] at com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1606) ~[na:1.8.0_20] at org.springframework.http.converter.BufferedImageHttpMessageConverter.read(BufferedImageHttpMessageConverter.java:174) ~[BufferedImageHttpMessageConverter.class:4.1.1.RELEASE] at org.springframework.http.converter.BufferedImageHttpMessageConverter.read(BufferedImageHttpMessageConverter.java:67) ~[BufferedImageHttpMessageConverter.class:4.1.1.RELEASE] at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:104) ~[HttpMessageConverterExtractor.class:4.1.1.RELEASE] at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:576) ~[RestTemplate.class:4.1.1.RELEASE] ... 74 common frames omitted Caused by: javax.imageio.IIOException: Bad PNG signature! at com.sun.imageio.plugins.png.PNGImageReader.readHeader(PNGImageReader.java:242) ~[na:1.8.0_20]

BufferedImage image = restTemplate.getForObject(getPhotoUrl(), BufferedImage.class, Collections.EMPTY_MAP);

回答1:

Instead of using getForObject method to get BufferedImage, using exchange method to get byte array back. Images that have bad PNG headers now display in the browser.

//Set HttpHeaders object
List<MediaType> acceptableMediaTypes = new ArrayList<>();
acceptableMediaTypes.add(MediaType.IMAGE_PNG);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);

//Get image from external app with API call
ResponseEntity<byte[]> responseEntity = restTemplate.exchange(getPhotoUrl(), HttpMethod.GET, new HttpEntity<byte[]>(headers), byte[].class);
byte[] image = responseEntity.getBody();

//Display image in browser
if(image != null) {
    InputStream in = new ByteArrayInputStream(image);
    BufferedImage bImageFromConvert = ImageIO.read(in);

    if(bImageFromConvert != null) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(bImageFromConvert, "png", baos);
        byte[] data = baos.toByteArray();
        response.setContentType(MediaType.IMAGE_PNG_VALUE);
        response.getOutputStream().write(data);
    }
}