#include "CImageLoaderJPG.h"
#ifdef _IRR_COMPILE_WITH_JPG_LOADER_
#include "IReadFile.h"
#include "CImage.h"
#include "os.h"
#include "irrString.h"
namespace irr
{
namespace video
{
CImageLoaderJPG::CImageLoaderJPG()
{
#ifdef _DEBUG
setDebugName("CImageLoaderJPG");
#endif
}
CImageLoaderJPG::~CImageLoaderJPG()
{
}
bool CImageLoaderJPG::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "jpg", "jpeg" );
}
#ifdef _IRR_COMPILE_WITH_LIBJPEG_
struct irr_jpeg_error_mgr
{
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
void CImageLoaderJPG::init_source (j_decompress_ptr cinfo)
{
}
boolean CImageLoaderJPG::fill_input_buffer (j_decompress_ptr cinfo)
{
return 1;
}
void CImageLoaderJPG::skip_input_data (j_decompress_ptr cinfo, long count)
{
jpeg_source_mgr * src = cinfo->src;
if(count > 0)
{
src->bytes_in_buffer -= count;
src->next_input_byte += count;
}
}
void CImageLoaderJPG::term_source (j_decompress_ptr cinfo)
{
}
void CImageLoaderJPG::error_exit (j_common_ptr cinfo)
{
(*cinfo->err->output_message) (cinfo);
irr_jpeg_error_mgr *myerr = (irr_jpeg_error_mgr*) cinfo->err;
longjmp(myerr->setjmp_buffer, 1);
}
void CImageLoaderJPG::output_message(j_common_ptr cinfo)
{
c8 temp1[JMSG_LENGTH_MAX];
(*cinfo->err->format_message)(cinfo, temp1);
os::Printer::log("JPEG FATAL ERROR",temp1, ELL_ERROR);
}
#endif
bool CImageLoaderJPG::isALoadableFileFormat(io::IReadFile* file) const
{
#ifndef _IRR_COMPILE_WITH_LIBJPEG_
return false;
#else
if (!file)
return false;
s32 jfif = 0;
file->seek(6);
file->read(&jfif, sizeof(s32));
return (jfif == 0x4a464946 || jfif == 0x4649464a);
#endif
}
IImage* CImageLoaderJPG::loadImage(io::IReadFile* file) const
{
#ifndef _IRR_COMPILE_WITH_LIBJPEG_
return 0;
#else
u8 **rowPtr=0;
u8* input = new u8[file->getSize()];
file->read(input, file->getSize());
struct jpeg_decompress_struct cinfo;
struct irr_jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr.pub);
cinfo.err->error_exit = error_exit;
cinfo.err->output_message = output_message;
if (setjmp(jerr.setjmp_buffer))
{
jpeg_destroy_decompress(&cinfo);
delete [] input;
if (rowPtr)
delete [] rowPtr;
return 0;
}
jpeg_create_decompress(&cinfo);
jpeg_source_mgr jsrc;
jsrc.bytes_in_buffer = file->getSize();
jsrc.next_input_byte = (JOCTET*)input;
cinfo.src = &jsrc;
jsrc.init_source = init_source;
jsrc.fill_input_buffer = fill_input_buffer;
jsrc.skip_input_data = skip_input_data;
jsrc.resync_to_restart = jpeg_resync_to_restart;
jsrc.term_source = term_source;
jpeg_read_header(&cinfo, TRUE);
bool useCMYK=false;
if (cinfo.jpeg_color_space==JCS_CMYK)
{
cinfo.out_color_space=JCS_CMYK;
cinfo.out_color_components=4;
useCMYK=true;
}
else
{
cinfo.out_color_space=JCS_RGB;
cinfo.out_color_components=3;
}
cinfo.do_fancy_upsampling=FALSE;
jpeg_start_decompress(&cinfo);
u16 rowspan = cinfo.image_width * cinfo.out_color_components;
u32 width = cinfo.image_width;
u32 height = cinfo.image_height;
u8* output = new u8[rowspan * height];
rowPtr = new u8* [height];
for( u32 i = 0; i < height; i++ )
rowPtr[i] = &output[ i * rowspan ];
u32 rowsRead = 0;
while( cinfo.output_scanline < cinfo.output_height )
rowsRead += jpeg_read_scanlines( &cinfo, &rowPtr[rowsRead], cinfo.output_height - rowsRead );
delete [] rowPtr;
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
IImage* image = 0;
if (useCMYK)
{
image = new CImage(ECF_R8G8B8,
core::dimension2d<u32>(width, height));
const u32 size = 3*width*height;
u8* data = (u8*)image->lock();
if (data)
{
for (u32 i=0,j=0; i<size; i+=3, j+=4)
{
data[i+0] = (char)(output[j+2]*(output[j+3]/255.f));
data[i+1] = (char)(output[j+1]*(output[j+3]/255.f));
data[i+2] = (char)(output[j+0]*(output[j+3]/255.f));
}
}
image->unlock();
delete [] output;
}
else
image = new CImage(ECF_R8G8B8,
core::dimension2d<u32>(width, height), output);
delete [] input;
return image;
#endif
}
IImageLoader* createImageLoaderJPG()
{
return new CImageLoaderJPG();
}
}
}
#endif