36

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

Gerhard
  • 18,114
  • 5
  • 20
  • 38
lancegerday
  • 701
  • 1
  • 7
  • 22
  • 1
    http://stackoverflow.com/questions/670546/determine-if-file-is-an-image (C#, but it's about checking headers, which is not language specific), or http://stackoverflow.com/questions/2192717/check-if-a-file-is-an-image, or http://stackoverflow.com/questions/9244710/know-if-a-file-is-a-image-in-java-android or – wkl Mar 10 '12 at 01:51

8 Answers8

57

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");
    }
}
Ismael
  • 15,815
  • 6
  • 55
  • 73
  • hi @dermoritz This seems to be a problem on your system. Check out this SO post http://stackoverflow.com/questions/4855627/java-mimetypesfiletypemap-always-returning-application-octet-stream-on-android-e – Ismael Nov 08 '13 at 10:08
  • How about if it is from URL? Before saving the URL to a file? I got "application/octet-stream" instead of image. Any idea ? – WowBow Feb 23 '15 at 20:50
  • @dermoritz,me too."new MimetypesFileTypeMap().getContentType(path)" returns "application/octet-stream",but "URLConnection.guessContentTypeFromName(path)" returns the right mime type. – wangqi060934 Jun 25 '15 at 01:08
  • Does it checks file content or just extension? – gstackoverflow Jun 29 '15 at 10:50
  • 9
    This only checks based on the extension of the file. Non-valid images (other binaries without image content and proper file headers) cannot be detected using this method. – Alex Fedulov Oct 06 '15 at 13:00
  • You are right @Alex Fedulov. Try prunge s answer if this is not enough to you – Ismael Oct 06 '15 at 13:20
  • 6
    This is a bad way to test if the file is an image. a better solution is: Files.probeContentType(path); – Biagio Cannistraro Feb 18 '16 at 11:10
  • @BiagioCannistraro You might want to add that as another answer – Ismael Feb 18 '16 at 13:21
28
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?

Community
  • 1
  • 1
Krystian
  • 1,961
  • 23
  • 36
16

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.

prunge
  • 20,579
  • 3
  • 71
  • 75
  • 3
    On Linux, it seems to only look at the extension on my machine. Changed a .jpeg file to .txt and it returned "text/plain". I like Krystian's answer below. – yngwietiger May 19 '16 at 21:49
11

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");
}
Kyrie
  • 53
  • 7
4

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.

GameDroids
  • 5,338
  • 6
  • 34
  • 54
  • 1
    sorry, when I wrote my answer yours wasn't there... maybe it took me too long to write it. But you are right, its completely the same :) – GameDroids Mar 10 '12 at 03:11
  • eheh, no problem. I think it happens to everyone all the time in here. :) – Ismael Mar 10 '12 at 03:13
  • 1
    @ismaelga - Indeed, it happens so often that most people wouldn't even bother to comment on it. – Stephen C Mar 10 '12 at 04:25
  • @StephenC - I am a bad person, I know. I just commented because of the gap of something like 30 minutes, but i know it's still a normal thing. :) and i'm not being sarcastic – Ismael Mar 10 '12 at 04:36
3

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 entirely 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.

Stephen C
  • 632,615
  • 86
  • 730
  • 1,096
2

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.

Ruslan Stelmachenko
  • 3,746
  • 28
  • 43
1

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);
    }
}
Albert Gan
  • 16,262
  • 44
  • 125
  • 177