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?
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: