Search code examples
c++boostdetectionimage-formatsboost-gil

Cannot use Boost GIL to detect image filetype (exception not caught)


I need to test if a file is a JPEG or PNG and I can not trust the file extension because it might be wrong. To accomplish this I decided to use GIL.

Here's the header file declaring (and defining) boost::gil::png_read_dimensions. It clearly states that boost::gil::png_read_dimensions "Throws std::ios_base::failure if the location does not correspond to a valid PNG file". And indeed, this seems to be on par with the functions actual behaviour.

The problem is with boost::gil::jpeg_read_dimensions which you can see here. It also clearly states that it "Throws std::ios_base::failure if the location does not correspond to a valid JPEG file". However, this does not seem to be the case! No exception is thrown and instead libjpeg prints to stdout or stderr and then exits the program.

See the following code:

#include <iostream>
#include <string>

#include <boost/gil/extension/io/jpeg_io.hpp>
#include <boost/gil/extension/io/png_io.hpp>

using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::ios_base;

namespace bg = boost::gil;

int main(int, char**) {
  const string not_jpeg_or_png ("image.gif");

  cout << "bg::png_read_dimensions:" << endl;
  try {
    bg::png_read_dimensions(not_jpeg_or_png);
  } catch(const ios_base::failure &ib_f) {
    cerr << "what: " << ib_f.what() << endl;
  }

  cout << "\nbg::jpeg_read_dimensions:" << endl;
  try {
    bg::jpeg_read_dimensions(not_jpeg_or_png);
  } catch(const ios_base::failure &ib_f) {
    cerr << "what: " << ib_f.what() << endl;
  }

  cout << "\nDone." << endl;

  return 0;
}

Program output:

bg::png_read_dimensions:
what: png_check_validity: invalid png file: unspecified iostream_category error

bg::jpeg_read_dimensions:
Not a JPEG file: starts with 0x62 0x6c

Note how what: ... yadiyadiyada ... and Done. isn't printed.

I've tried doing } catch(...) { instead of } catch(const ios_base::failure &ib_f) { to make sure that no exception passes unnoticed but without success. No exception gets thrown!

Am I missing something really obvious here...? Am I doing something wrong? Is there a workaround?


Solution

  • I don't understand why the exception as thrown apparently cannot be caught. It might be a bug.

    However, to accomplish the task I'd suggest

    • libmagic or
    • identify (from ImageMagick)

    which does what the other answer suggests.

    This answer contains an example of how to use libmagic (which is usually present on linux, but can be built and (statically) linked on any other platform: