javaimageinputstreamjavax.imageiojava.nio.file

PNG file corrupted after calling ImageReader getHeigth


I got my png file corrupted after calling :

BufferedImage im = ImageIO.read(inputStream);

You will find the service life cycle below :

InputStream inputStream = multipartFile.getInputStream();
throwExceptionIfImageDimensionsNotValid(inputStream);
storeIntoFileSystem(inputStream);

implementation

private void throwExceptionIfImageDimensionsNotValid(InputStream inputStream) throws IOException, StoreFileException {
        
        BufferedImage im = ImageIO.read(inputStream);
        
        if(isImageWidthHeightRatioOk(im.getHeight(), im.getWidth())) {
            return;
        } else {
            throw new StoreFileException("Le rapport hauteur / largeur de limage doit etre compris entre 0.55 et 0.625");
        }
    }

Store file implementation :

void storeIntoFileSystem(InputStream inputStreamIn) throws IOException{
        try (InputStream inputStream = inputStreamIn) {
            Path targetDirectoryPath = Paths.get("Files-Upload/");
            Path filePath = Paths.get("Files-Upload/").resolve("pacman_preview.png");

            Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);

        } catch (IOException ioe) {
            throw new IOException("Could not save file: " , ioe);
        }
    }

The problem is : When I open the file in my OS image viewer, I've got this message :

Could not load image ... Fatal error reading PNG image file. Not a PNG file

NOTE : When the throwExceptionIfImageDimensionsNotValid(inputStream) is commented, the image open's correctly. enter image description here

At debug time I found that the inputStream object is modified when ImageIO.read(inputStream); is executed.

At this moment in variable eclipse view I can see bb and bs modified : enter image description here


Solution

  • InputStream is a stream - if you read it in first method (ImageIO.read(inputStream)), it's done, there is nothing left in the stream. You can't read it again. In that case you have to open the stream again, as below, or do some refactor to do both operations by reading InputStream only once.

    InputStream inputStream = multipartFile.getInputStream();
    throwExceptionIfImageDimensionsNotValid(inputStream);
    inputStream = multipartFile.getInputStream();
    storeIntoFileSystem(inputStream);
    

    I should mention as well, that when you read the first stream, you should close it, before opening the new one.

    As mentioned in comment, there are also streams that allow seeking or resetting. You can use such a stream here, so you don't need to create another one, but just call reset method after you read in the first method.