lancegerday
lancegerday

Reputation: 762

Test if a file is an image file

I am using some file IO and want to know if there is a method to check if a file is an image?

Upvotes: 41

Views: 84833

Answers (8)

Stephen C
Stephen C

Reputation: 719386

There are a variety of ways to do this; see other answers and the links to related questions. (The Java 7 approach seems the most attractive to me, because it uses platform specific conventions by default, and you can supply your own scheme for file type determination.)

However, I'd just like to point out that no mechanism is infallible:

  • Methods that rely on the file suffix will be tricked if the suffix is non-standard or wrong.

  • Methods that rely on file attributes (e.g. in the file system) will be tricked if the file has an incorrect content type attribute or none at all.

  • Methods that rely on looking at the file signature can be tricked by binary files which just happen to have the same signature bytes.

  • Even simply attempting to read the file as an image can be tricked if you are unlucky ... depending on the image format(s) that you try.

Upvotes: 4

Bertie
Bertie

Reputation: 17697

Here's my code based on the answer using tika.

private static final Tika TIKA = new Tika();
public boolean isImageMimeType(File src) {
    try (FileInputStream fis = new FileInputStream(src)) {
        String mime = TIKA.detect(fis, src.getName());
        return mime.contains("/") 
                && mime.split("/")[0].equalsIgnoreCase("image");
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Upvotes: 2

Ruslan Stelmachenko
Ruslan Stelmachenko

Reputation: 5429

Other answers suggest to load full image into memory (ImageIO.read) or to use standard JDK methods (MimetypesFileTypeMap and Files.probeContentType).

First way is not efficient if read image is not required and all you really want is to test if it is an image or not (and maybe to save it's content type to set it in Content-Type response header when this image will be read in the future).

Inbound JDK ways usually just test file extension and not really give you result that you can trust.

The way that works for me is to use Apache Tika library.

private final Tika tika = new Tika();

private MimeType detectImageContentType(InputStream inputStream, String fileExtension) {
    Assert.notNull(inputStream, "InputStream must not be null");

    String fileName = fileExtension != null ? "image." + fileExtension : "image";
    MimeType detectedContentType = MimeType.valueOf(tika.detect(inputStream, fileName));
    log.trace("Detected image content type: {}", detectedContentType);

    if (!validMimeTypes.contains(detectedContentType)) {
        throw new InvalidImageContentTypeException(detectedContentType);
    }

    return detectedContentType;
}

The type detection is based on the content of the given document stream and the name of the document. Only a limited number of bytes are read from the stream.

I pass fileExtension just as a hint for the Tika. It works without it. But according to documentation it helps to detect better in some cases.

  • The main advantage of this method compared to ImageIO.read is that Tika doesn't read full file into memory - only first bytes.

  • The main advantage compared to JDK's MimetypesFileTypeMap and Files.probeContentType is that Tika really reads first bytes of the file while JDK only checks file extension in current implementation.

TLDR

  • If you plan to do something with read image (like resize/crop/rotate it), then use ImageIO.read from Krystian's answer.

  • If you just want to check (and maybe store) real Content-Type, then use Tika (this answer).

  • If you work in the trusted environment and you are 100% sure that file extension is correct, then use Files.probeContentType from prunge's Answer.

Upvotes: 6

Biagio Cannistraro
Biagio Cannistraro

Reputation: 506

You may try something like this:

String pathname="abc\xyz.png"
File file=new File(pathname);


String mimetype = Files.probeContentType(file.toPath());
//mimetype should be something like "image/png"

if (mimetype != null && mimetype.split("/")[0].equals("image")) {
    System.out.println("it is an image");
}

Upvotes: 13

Krystian
Krystian

Reputation: 2290

if( ImageIO.read(*here your input stream*) == null)
    *IS NOT IMAGE*    

And also there is an answer: How to check a uploaded file whether it is a image or other file?

Upvotes: 37

Ismael
Ismael

Reputation: 16730

This works pretty well for me. Hope I could help

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
class Untitled {
    public static void main(String[] args) {
        String filepath = "/the/file/path/image.jpg";
        File f = new File(filepath);
        String mimetype= new MimetypesFileTypeMap().getContentType(f);
        String type = mimetype.split("/")[0];
        if(type.equals("image"))
            System.out.println("It's an image");
        else 
            System.out.println("It's NOT an image");
    }
}

Upvotes: 62

prunge
prunge

Reputation: 23268

In Java 7, there is the java.nio.file.Files.probeContentType() method. On Windows, this uses the file extension and the registry (it does not probe the file content). You can then check the second part of the MIME type and check whether it is in the form <X>/image.

Upvotes: 18

GameDroids
GameDroids

Reputation: 5662

You may try something like this:

   import javax.activation.MimetypesFileTypeMap;

   File myFile;

   String mimeType = new MimetypesFileTypeMap().getContentType( myFile ));
   // mimeType should now be something like "image/png"

   if(mimeType.substring(0,5).equalsIgnoreCase("image")){
         // its an image
   }

this should work, although it doesn't seem to be the most elegant version.

Upvotes: 4

Related Questions