coobird / thumbnailator

Thumbnailator - a thumbnail generation library for Java
MIT License
5.08k stars 780 forks source link

No suitable ImageReader found for source data errors #204

Closed goodale closed 1 year ago

goodale commented 1 year ago

Expected behavior

resize a png and save to a temp file. The image is provided as an inputstream via Servlet 3.1 multi-part web form

Actual behavior

net.coobird.thumbnailator.tasks.UnsupportedFormatException: No suitable ImageReader found for source data. at net.coobird.thumbnailator.tasks.io.InputStreamImageSource.read(Unknown Source) at net.coobird.thumbnailator.tasks.SourceSinkThumbnailTask.read(Unknown Source) at net.coobird.thumbnailator.Thumbnailator.createThumbnail(Unknown Source) at net.coobird.thumbnailator.Thumbnails$Builder.toFile(Unknown Source)

Steps to reproduce the behavior

The following method throws the above exception, regardless of whether the .of method is passed the input stream received via the form submission or the input stream is first saved to a temp file and explicitly given a suffix of .png

Note: the first portion of the method works as expected (saving the input stream to a CDN via SFTP and the image has been confirmed to be saved properly and renders properly confirming the input stream is indeed valid.

    private void resizeAndUploadToCDN(InputStream is, String fileName) throws Exception {

        _log.info("Uploading original {} to CDN..",fileName);
        uploadToCDN(is,fileName+".png");
        _log.info("original file uploaded");

        _log.info("Creating temp file for resized image");
        File tmpFile = File.createTempFile (fileName, ".png");
        tmpFile.deleteOnExit();
        _log.info("Temp file path {}",tmpFile.getAbsolutePath());

        //     Note:  I've attempt to pass both the Inputstream 'is' as well as a tmp file to .of.  Both fail
    //  File tmpFile2 = File.createTempFile (fileName, ".png");
    //  Files.copy(is, tmpFile2.toPath(), StandardCopyOption.REPLACE_EXISTING);

        //     The following line throws the exception
        Thumbnails.of(is).size(327, 36).addFilter(new Canvas(66, 36, Positions.TOP_RIGHT, true)).toFile(tmpFile);
        _log.info("Uploading resized image to CDN");
        uploadToCDN("66x36",new FileInputStream(tmpFile),fileName+".png");
        _log.info("Resized 66x36 uploaded");
    }

Additional notes: This code is a refactor to remove reliance on commons:fileupload in prep for migrating to jakarta. So FileItem is no longer available. Oddly, the following old code works fine. the only difference is whether i'm providing the input stream directly from the MultiPart (Servlet 3.1) or from FileItem

    private void resizeAndUploadToCDN(FileItem fi, String fileName) throws Exception {
         .....
       Thumbnails.of(fi.getInputStream()).size(327, 36).addFilter(new Canvas(66, 36, Positions.TOP_RIGHT, true)).toFile(tmpFile);

Environment

goodale commented 1 year ago

disregard - root issue was that i was incorrectly using the inputstream twice and it had a file length of zero the second time when calling Thumbnails.

Issue was solved by copying the inputstream using the following (credit to https://stackoverflow.com/questions/5923817/how-to-clone-an-inputstream)

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) > -1 ) {
            baos.write(buffer, 0, len);
}
baos.flush();
InputStream is1 = new ByteArrayInputStream(baos.toByteArray()); 
InputStream is2 = new ByteArrayInputStream(baos.toByteArray());     

Possible bug/enhancement suggestion: throw a different exception when the inputstream has zero bytes rather than net.coobird.thumbnailator.tasks.UnsupportedFormatException