How can I tell if a file is an image of some type?


A customer wanted to know if there is some standard way of determining from the full path to a file whether it is a photo or image. They are writing a program that transfers a bunch of files to a back-end server, and they want to treat photos differently from other files.

You can use the Assoc­Get­Perceived­Type function to classify a file into one of a variety of categories. You can consult the document to see the full list, but it's things like "image", "audio", "video", "document". This information is obtained by studying the file extension and looking up the registered perceived type.

Let's take the function out for a spin:

#define UNICODE
#define _UNICODE
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h> // horrors! mixing C and C++!

int __cdecl wmain(int argc, wchar_t **argv)
{
 PERCEIVED perceived;
 PERCEIVEDFLAG flag;
 PWSTR pszType;
 if (argc > 1 && SUCCEEDED(AssocGetPerceivedType(
    PathFindExtensionW(argv[1]),
    &perceived, &flag, &pszType)))
 {
  wprintf(L"Type is %ls\n", pszType);
  if (perceived == PERCEIVED_TYPE_IMAGE) {
   wprintf(L"Hey, that's an image!\n");
  }
  CoTaskMemFree(pszType);
 }
 return 0;
}

Run this program and give a file name, or just an extension (with the dot) as the command line parameter. It will tell you the perceived type and include a special message if the type is an image.

But let's look at the customer's question again. It's not clear whether they are trying to identify files by file format or by classification. For example, suppose the file in question is a TIFF image. The Assoc­Get­Perceived­Type function will report this as an image, because, well, it's an image. But that may not be a file format that their back-end server supports.

  • If they wanted to know whether the file is a PNG, GIF, or JPG because those are the image formats supported by their back-end server, then they need to check for those specific extensions (and possibly even sniff file contents if they are paranoid).

  • If they care only that the file represents some sort of image (possibly in a format their program does not know how to parse), because they want to, say, upload all images into a Pictures folder regardless of the image format, then they should use the Perceived Type.

The customer thanked us for the pointer to the Assoc­Get­Perceived­Type function and especially for the clarifying remarks. "It turns out that the feature specification was not clear on the definition of 'image file', so that's something we will need to resolve ourselves. But the information you provided will definitely solve our problem, once we figure out what our problem is!"

Comments (20)
  1. Mason Wheeler says:

    "But the information you provided will definitely solve our problem, once we figure out what our problem is!"

    Wow.  Not often you see a client that honest about not truly knowing what they want...

  2. David-T says:

    I'd read the question as wanting a way to distinguish between files containing "photos" and files containing "images", which sounds like an unpleasant task.

  3. Ravu al Hemio says:

    > #include <stdio.h> // horrors! mixing C and C++!

    Out of curiosity, doesn't C++ strongly recommend including <cstdio> instead of <stdio.h>?

    [Horrors! -Raymond]
  4. CarlD says:

    > you provided will definitely solve our problem, once we figure out what our problem is!

    I would love to hear that from a customer once in a while!  I'm sure that half the time I spend with customers trying to solve their problem is in fact simply figuring out what their problem really is.

  5. dirk.gently says:

    >I'd read the question as wanting a way to distinguish between files containing "photos" and files containing "images"

    Me too. Don't you just love english?

  6. Mark says:

    David-T: simples. If it gets smaller when you turn it into a .png, it's an image. If it gets smaller when you turn it into a .jpg, it's a photo. If it doesn't get smaller for either, it's random noise.

  7. Sven2 says:

    "Photo" versus "Other image" is something that machine learning on an appropriate feature vector should be able to do with a pretty high accuracy though. Nothing you couldn't hack in OpenCV in a few hours.

    There could be a gray area such as advertisement images that contain both photographic and text/design elements. But then, such images couldn't be classified clearly by a human either.

  8. Adam Rosenfield says:

    And in the *nix world, you'd just run the file(1) command on the file and see if the output contains "image" in it.  Downside is that if you want to do this in code, you're shelling out to a separate process, but you could probably hack something together to compile it into a library and use it in-process.

  9. Kaso says:

    Adam R: Or you could use libmagic directly.

  10. Alex says:

    You've been writing too much assembler Raymond; your fingers are on autopilot! (eaxmple)

  11. SMW says:

    @Ravu: Raymond doesn't want to type 'std::' in front of his wprintf() (and other similar) instances, so that's why he's including <stdio.h> instead of <cstdio>.

  12. Cesar says:

    @SMW: that's what "using namespace std;" is for.

    But he is already including other C APIs (windows.h and friends), so including stdio "C style" is consistent with that and doesn't make much difference; the includes are already crapping all over the global namespace (windows.h is infamous for doing that).

  13. What C++ says:

    Actually, where is the C++ in that snippet?  It looks to me like the entire thing should compile successfully in plain C.

  14. dave says:

    Well, to a first approximation, it's an image file if it's got a PE header after a DOS "MZ" header.

    What?  Oh.  Not that sort.

  15. AnonyMark says:

    Even with cstdio, there's no need for std::

  16. Wear says:

    @dave In C#

    Try and reference the file as an assembly. If you get an ImageNotFoundException then it must be a photo.  

  17. > For eaxmple

    Is that an example stored in the eax register?

  18. Anon says:

    @Maurits [MSFT]

    Great, now Raymond can't fix this blog post for compatibility reasons. He'll have to make a new one:

    "How can I tell if a file is an image of some type?Ex"

    :D

  19. Shura Luberetsky says:

    > I'd read the question as wanting a way to distinguish between files containing "photos" and files containing "images", which sounds like an unpleasant task.

    And don't forget "disk images" :)

  20. Jon says:

    Useful function, but one oddity: I'm getting the correct result but for images like .jpg or .bmp, the PERCEIVEDFLAG is 0x16. MSDN says it's "one of" the flags- should that be "one or more of"? Because I'd lean towards thinking that means PERCEIVEDFLAG_HARDCODED||PERCEIVEDFLAG_WMSDK.

    [Should be "One or more of". I will submit a doc fix request. -Raymond]

Comments are closed.

Skip to main content