// Copyright (C) 2011 Davis E. King (davis@dlib.net), Nils Labugt, Changjiang Yang (yangcha@leidos.com)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_LOAd_IMAGE_Hh_
#define DLIB_LOAd_IMAGE_Hh_
#include "load_image_abstract.h"
#include "../string.h"
#include "png_loader.h"
#include "jpeg_loader.h"
#include "image_loader.h"
#include <fstream>
#include <sstream>
#ifdef DLIB_GIF_SUPPORT
#include <gif_lib.h>
#endif
namespace dlib
{
namespace image_file_type
{
enum type
{
BMP,
JPG,
PNG,
DNG,
GIF,
UNKNOWN
};
inline type read_type(const std::string& file_name)
{
std::ifstream file(file_name.c_str(), std::ios::in|std::ios::binary);
if (!file)
throw image_load_error("Unable to open file: " + file_name);
char buffer[9];
file.read((char*)buffer, 8);
buffer[8] = 0;
// Determine the true image type using link:
// http://en.wikipedia.org/wiki/List_of_file_signatures
if (strcmp(buffer, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") == 0)
return PNG;
else if(buffer[0]=='\xff' && buffer[1]=='\xd8' && buffer[2]=='\xff')
return JPG;
else if(buffer[0]=='B' && buffer[1]=='M')
return BMP;
else if(buffer[0]=='D' && buffer[1]=='N' && buffer[2] == 'G')
return DNG;
else if(buffer[0]=='G' && buffer[1]=='I' && buffer[2] == 'F')
return GIF;
return UNKNOWN;
}
}
// ----------------------------------------------------------------------------------------
// handle the differences in API between libgif v5 and older.
#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
#define DLIB_GIFLIB_HANDLE_DIFF_VERSIONS ,0
#else
#define DLIB_GIFLIB_HANDLE_DIFF_VERSIONS
#endif
template <typename image_type>
void load_image (
image_type& image,
const std::string& file_name
)
{
const image_file_type::type im_type = image_file_type::read_type(file_name);
switch (im_type)
{
case image_file_type::BMP: load_bmp(image, file_name); return;
case image_file_type::DNG: load_dng(image, file_name); return;
#ifdef DLIB_PNG_SUPPORT
case image_file_type::PNG: load_png(image, file_name); return;
#endif
#ifdef DLIB_JPEG_SUPPORT
case image_file_type::JPG: load_jpeg(image, file_name); return;
#endif
#ifdef DLIB_GIF_SUPPORT
case image_file_type::GIF:
{
image_view<image_type> img(image);
GifFileType* gif = DGifOpenFileName(file_name.c_str() DLIB_GIFLIB_HANDLE_DIFF_VERSIONS);
try
{
if (gif == 0) throw image_load_error("Couldn't open file " + file_name);
if (DGifSlurp(gif) != GIF_OK)
throw image_load_error("Error reading from " + file_name);
if (gif->ImageCount != 1) throw image_load_error("Dlib only supports reading GIF files containing one image.");
if (gif->SavedImages == 0) throw image_load_error("Unsupported GIF format 1.");
ColorMapObject* cmo=gif->SColorMap?gif->SColorMap:gif->SavedImages->ImageDesc.ColorMap;
if (cmo==0) throw image_load_error("Unsupported GIF format 2.");
if (cmo->Colors == 0) throw image_load_error("Unsupported GIF format 3.");
if (gif->SavedImages->ImageDesc.Width != gif->SWidth) throw image_load_error("Unsupported GIF format 4.");
if (gif->SavedImages->ImageDesc.Height != gif->SHeight) throw image_load_error("Unsupported GIF format 5.");
if (gif->SavedImages->RasterBits == 0) throw image_load_error("Unsupported GIF format 6.");
if (gif->Image.Top != 0) throw image_load_error("Unsupported GIF format 7.");
if (gif->Image.Left != 0) throw image_load_error("Unsupported GIF format 8.");
img.set_size(gif->SHeight, gif->SWidth);
unsigned char* raster = gif->SavedImages->RasterBits;
GifColorType* colormap = cmo->Colors;
if (gif->Image.Interlace)
{
const long interlaced_offset[] = { 0, 4, 2, 1 };
const long interlaced_jumps[] = { 8, 8, 4, 2 };
for (int i = 0; i < 4; ++i)
{
for (long r = interlaced_offset[i]; r < img.nr(); r += interlaced_jumps[i])
{
for (long c = 0; c < img.nc(); ++c)
{
if (*raster >= cmo->ColorCount)
throw image_load_error("Invalid GIF color value");
rgb_pixel p;
p.red = colormap[*raster].Red;
p.green = colormap[*raster].Green;
p.blue = colormap[*raster].Blue;
assign_pixel(img[r][c], p);
++raster;
}
}
}
}
else
{
for (long r = 0; r < img.nr(); ++r)
{
for (long c = 0; c < img.nc(); ++c)
{
if (*raster >= cmo->ColorCount)
throw image_load_error("Invalid GIF color value");
rgb_pixel p;
p.red = colormap[*raster].Red;
p.green = colormap[*raster].Green;
p.blue = colormap[*raster].Blue;
assign_pixel(img[r][c], p);
++raster;
}
}
}
DGifCloseFile(gif DLIB_GIFLIB_HANDLE_DIFF_VERSIONS);
}
catch(...)
{
if (gif)
DGifCloseFile(gif DLIB_GIFLIB_HANDLE_DIFF_VERSIONS);
throw;
}
return;
}
#endif
default: ;
}
if (im_type == image_file_type::JPG)
{
std::ostringstream sout;
sout << "Unable to load image in file " + file_name + ".\n" +
"You must #define DLIB_JPEG_SUPPORT and link to libjpeg to read JPEG files.\n" +
"Do this by following the instructions at http://dlib.net/compile.html.\n\n";
#ifdef _MSC_VER
sout << "Note that you must cause DLIB_JPEG_SUPPORT to be defined for your entire project.\n";
sout << "So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\n";
sout << "field in Visual Studio's Property Pages window so it takes effect for your entire application.";
#else
sout << "Note that you must cause DLIB_JPEG_SUPPORT to be defined for your entire project.\n";
sout << "So don't #define it in one file. Instead, use a compiler switch like -DDLIB_JPEG_SUPPORT\n";
sout << "so it takes effect for your entire application.";
#endif
throw image_load_error(sout.str());
}
else if (im_type == image_file_type::PNG)
{
std::ostringstream sout;
sout << "Unable to load image in file " + file_name + ".\n" +
"You must #define DLIB_PNG_SUPPORT and link to libpng to read PNG files.\n" +
"Do this by following the instructions at http://dlib.net/compile.html.\n\n";
#ifdef _MSC_VER
sout << "Note that you must cause DLIB_PNG_SUPPORT to be defined for your entire project.\n";
sout << "So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\n";
sout << "field in Visual Studio's Property Pages window so it takes effect for your entire application.\n";
#else
sout << "Note that you must cause DLIB_PNG_SUPPORT to be defined for your entire project.\n";
sout << "So don't #define it in one file. Instead, use a compiler switch like -DDLIB_PNG_SUPPORT\n";
sout << "so it takes effect for your entire application.";
#endif
throw image_load_error(sout.str());
}
else if (im_type == image_file_type::GIF)
{
std::ostringstream sout;
sout << "Unable to load image in file " + file_name + ".\n" +
"You must #define DLIB_GIF_SUPPORT and link to libgif to read GIF files.\n\n";
#ifdef _MSC_VER
sout << "Note that you must cause DLIB_GIF_SUPPORT to be defined for your entire project.\n";
sout << "So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\n";
sout << "field in Visual Studio's Property Pages window so it takes effect for your entire application.\n";
#else
sout << "Note that you must cause DLIB_GIF_SUPPORT to be defined for your entire project.\n";
sout << "So don't #define it in one file. Instead, use a compiler switch like -DDLIB_GIF_SUPPORT\n";
sout << "so it takes effect for your entire application.";
#endif
throw image_load_error(sout.str());
}
else
{
throw image_load_error("Unknown image file format: Unable to load image in file " + file_name);
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_LOAd_IMAGE_Hh_