How to check a uploaded file whether it is an image or other file?
Asked Answered
W

4

38

In my web application I have an image uploading module. I want to check the uploaded file whether it's an image file or any other file. I am using Java in server side.

The image is read as BufferedImage in java and then I am writing it to disk with ImageIO.write()

How shall I check the BufferedImage, whether it's really an image or something else?

Any suggestions or links would be appreciated.

Warner answered 12/11, 2010 at 22:39 Comment(1)
Your best bet is to look at the file extension, there is no 100% method to determine whether a file is an image or not.Terza
A
113

I'm assuming that you're running this in a servlet context. If it's affordable to check the content type based on just the file extension, then use ServletContext#getMimeType() to get the mime type (content type). Just check if it starts with image/.

String fileName = uploadedFile.getFileName();
String mimeType = getServletContext().getMimeType(fileName);
if (mimeType.startsWith("image/")) {
    // It's an image.
} else {
    // It's not an image.
}

The default mime types are definied in the web.xml of the servletcontainer in question. In for example Tomcat, it's located in /conf/web.xml. You can extend/override it in the /WEB-INF/web.xml of your webapp as follows:

<mime-mapping>
    <extension>svg</extension>
    <mime-type>image/svg+xml</mime-type>
</mime-mapping>

But this doesn't prevent you from users who are fooling you by changing the file extension. If you'd like to cover this as well, then you can also determine the mime type based on the actual file content. If it's affordable to check for only BMP, GIF, JPEG, PNG, TIFF or WBMP types (but not PSD, SVG, etc), then you can just feed it directly to ImageIO#read() and check if it doesn't throw an exception.

try (InputStream input = uploadedFile.getInputStream()) {
    try {
        ImageIO.read(input).toString();
        // It's an image (only BMP, GIF, JPEG, PNG, TIFF and WBMP are recognized).
    } catch (Exception e) {
        // It's not an image.
    }
}

But if you'd like to cover more image types as well, then consider using a 3rd party library which does all the work by sniffing the file signatures. For example Apache Tika which recognizes on top of ImageIO formats also PSD, BPG, WEBP, ICNS and SVG as well:

Tika tika = new Tika();
try (InputStream input = uploadedFile.getInputStream()) {
    String mimeType = tika.detect(input);
    if (mimeType.startsWith("image/")) {
        // It's an image.
    } else {
        // It's not an image.
    }
}

You could if necessary use combinations and outweigh the one and other.

That said, you don't necessarily need ImageIO#write() to save the uploaded image to disk. Just writing the obtained InputStream directly to a Path or any OutputStream like FileOutputStream the usual Java IO way is more than sufficient (see also Recommended way to save uploaded files in a servlet application):

try (InputStream input = uploadedFile.getInputStream()) {
    Files.copy(input, new File(uploadFolder, fileName).toPath());
}

Unless you'd like to gather some image information like its dimensions and/or want to manipulate it (crop/resize/rotate/convert/etc) of course.

Adult answered 12/11, 2010 at 22:52 Comment(9)
I tried ImageIO.read(input); but it doesn't throw any exception when the file is not an image.Osteoclast
ImageIO.read(input); doesn't throw any exception if the file is not an image, instead it just returns null.Osteoclast
Salih is right. If ImageIO.read(input) == null then it is not image file. else it is image file.Tumpline
@KyungMin: Non-images will indeed return null (and the toString() will then throw NPE). Images in unsupported formats like CMYK JPEGs will actually throw IOException.Adult
i have the same issue, but i need to validate the uploaded file for xlsx format, can you please help me?Subservience
@Masoud: just do the same way, logically only don't try to parse it as an image file, but as a XLSX file (with e.g. Apache POI or whatever XLSX parser you like).Adult
i tried that but doesn't work, instead i tried this mimeType.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") now it worksSubservience
This is not working. This is so dangerously. This is looking only extension of file. I can upload a shell file which extension is png or jpg. You have to check content of uploaded file.Regelation
Perhaps you forgot to read past first part of the answer?Adult
D
8

I used org.apache.commons.imaging.Imaging in my case. Below is a sample piece of code to check if an image is a jpeg image or not. It throws ImageReadException if uploaded file is not an image.

    try {
        //image is InputStream
        byte[] byteArray = IOUtils.toByteArray(image);
        ImageFormat mimeType = Imaging.guessFormat(byteArray);
        if (mimeType == ImageFormats.JPEG) {
            return;
        } else {
            // handle image of different format. Ex: PNG
        }
    } catch (ImageReadException e) {
        //not an image
    }
Denmark answered 17/2, 2016 at 15:23 Comment(2)
Still - as of June 2017, the lib has no stable version and just snapshots. Could be risky to use in prodCant
I can also read at commons.apache.org/proper/commons-imaging: <<Imaging was working and was used by a number of projects in production even before reaching its initial release as an Apache Commons component.>> I decided to go with it...Schreiber
D
5

This is built into the JDK and simply requires a stream with support for

byte[] data = ;
InputStream is = new BufferedInputStream(new ByteArrayInputStream(data));
String mimeType = URLConnection.guessContentTypeFromStream(is);
//...close stream

Since Java SE 6 https://docs.oracle.com/javase/6/docs/api/java/net/URLConnection.html

Detinue answered 29/2, 2016 at 20:19 Comment(0)
L
2

Try using multipart file instead of BufferedImage

import org.apache.http.entity.ContentType;
...

    public void processImage(MultipartFile file) {

       if(!Arrays.asList(ContentType.IMAGE_JPEG.getMimeType(), ContentType.IMAGE_PNG.getMimeType(), ContentType.IMAGE_GIF.getMimeType()).contains(file.getContentType())) {
            throw new IllegalStateException("File must be an Image");
                 }
      }
Leisurely answered 12/4, 2020 at 15:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.