223 lines
5.1 KiB
C++
223 lines
5.1 KiB
C++
#include "main.h"
|
|
|
|
#include "loader_jpg.h"
|
|
|
|
#include "api__jpeg.h"
|
|
#include "../xml/ifc_xmlreaderparams.h"
|
|
#include <api/memmgr/api_memmgr.h>
|
|
#include <shlwapi.h>
|
|
#include <setjmp.h>
|
|
|
|
#include <wingdi.h>
|
|
#include <intsafe.h>
|
|
|
|
/*BIG BIG THING TO NOTE
|
|
I have modified jmorecfg.h line 319 to specify 4 bytes per pixel with RGB. it is normally three.
|
|
*/
|
|
extern "C"
|
|
{
|
|
#undef FAR
|
|
#include "jpeglib.h"
|
|
};
|
|
|
|
int JpgLoad::isMine( const wchar_t *filename )
|
|
{
|
|
if ( !filename )
|
|
return 0;
|
|
|
|
const wchar_t *ext = PathFindExtensionW( filename );
|
|
|
|
if ( !ext )
|
|
return 0;
|
|
|
|
if ( !_wcsicmp( ext, L".jpg" ) )
|
|
return 1;
|
|
|
|
if ( !_wcsicmp( ext, L".jpeg" ) )
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
const wchar_t *JpgLoad::mimeType()
|
|
{
|
|
return L"image/jpeg";
|
|
}
|
|
|
|
int JpgLoad::getHeaderSize()
|
|
{
|
|
return 3;
|
|
}
|
|
|
|
int JpgLoad::testData( const void *data, int datalen )
|
|
{
|
|
if ( datalen < 3 )
|
|
return 0;
|
|
|
|
const unsigned __int8 *text = static_cast<const unsigned __int8 *>( data );
|
|
if ( text[ 0 ] == 0xFF && text[ 1 ] == 0xD8 && text[ 2 ] == 0xFF )
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
struct jpeg_source_mgr {
|
|
const JOCTET * next_input_byte; // => next byte to read from buffer
|
|
size_t bytes_in_buffer; // # of bytes remaining in buffer
|
|
|
|
JMETHOD(void, init_source, (j_decompress_ptr cinfo));
|
|
JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));
|
|
JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));
|
|
JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired));
|
|
JMETHOD(void, term_source, (j_decompress_ptr cinfo));
|
|
};
|
|
*/
|
|
|
|
// our reader...
|
|
extern "C"
|
|
{
|
|
static void init_source( j_decompress_ptr cinfo )
|
|
{}
|
|
static const JOCTET jpeg_eof[] = { (JOCTET)0xFF, (JOCTET)JPEG_EOI };
|
|
static boolean fill_input_buffer( j_decompress_ptr cinfo )
|
|
{
|
|
cinfo->src->next_input_byte = jpeg_eof;
|
|
cinfo->src->bytes_in_buffer = 2;
|
|
return TRUE;
|
|
}
|
|
static void skip_input_data( j_decompress_ptr cinfo, long num_bytes )
|
|
{
|
|
//my_src_ptr src = (my_src_ptr) cinfo->src;
|
|
if ( num_bytes > 0 )
|
|
{
|
|
if ( num_bytes > (long)cinfo->src->bytes_in_buffer )
|
|
{
|
|
fill_input_buffer( cinfo );
|
|
}
|
|
else
|
|
{
|
|
cinfo->src->next_input_byte += (size_t)num_bytes;
|
|
cinfo->src->bytes_in_buffer -= (size_t)num_bytes;
|
|
}
|
|
}
|
|
}
|
|
static void term_source( j_decompress_ptr cinfo )
|
|
{}
|
|
};
|
|
|
|
static void wasabi_jpgload_error_exit( j_common_ptr cinfo )
|
|
{
|
|
jmp_buf *stack_env = (jmp_buf *)cinfo->client_data;
|
|
longjmp( *stack_env, 1 );
|
|
}
|
|
|
|
static bool IsAMG( jpeg_saved_marker_ptr marker_list )
|
|
{
|
|
while ( marker_list )
|
|
{
|
|
if ( marker_list->marker == JPEG_COM && marker_list->data_length == 7 && memcmp( (const char *)marker_list->data, "AMG/AOL", 7 ) == 0 )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
marker_list = marker_list->next;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ARGB32 *JpgLoad::loadImage( const void *data, int datalen, int *w, int *h, ifc_xmlreaderparams *params )
|
|
{
|
|
int fail_on_amg = 0;
|
|
|
|
if ( params ) // epic failness
|
|
fail_on_amg = params->getItemValueInt( L"AMG", 0 );
|
|
|
|
ARGB32 *buf = 0;
|
|
jpeg_error_mgr jerr;
|
|
jpeg_decompress_struct cinfo;
|
|
jpeg_source_mgr src = { (const JOCTET *)data,(size_t)datalen,init_source,fill_input_buffer,skip_input_data,jpeg_resync_to_restart,term_source };
|
|
|
|
cinfo.err = jpeg_std_error( &jerr );
|
|
|
|
jpeg_create_decompress( &cinfo );
|
|
cinfo.src = &src;
|
|
|
|
/* set up error handling. basically C style exceptions :) */
|
|
jmp_buf stack_env;
|
|
cinfo.client_data = &stack_env;
|
|
cinfo.err->error_exit = wasabi_jpgload_error_exit;
|
|
if ( setjmp( stack_env ) )
|
|
{
|
|
// longjmp will goto here
|
|
jpeg_destroy_decompress( &cinfo );
|
|
if ( buf )
|
|
WASABI_API_MEMMGR->sysFree( buf );
|
|
|
|
return 0;
|
|
}
|
|
|
|
if ( fail_on_amg )
|
|
jpeg_save_markers( &cinfo, JPEG_COM, 10 );
|
|
|
|
if ( jpeg_read_header( &cinfo, TRUE ) == JPEG_HEADER_OK )
|
|
{
|
|
cinfo.out_color_space = JCS_RGB;
|
|
/*int ret = */jpeg_start_decompress( &cinfo );
|
|
if ( !fail_on_amg || !IsAMG( cinfo.marker_list ) )
|
|
{
|
|
size_t image_size = 0;
|
|
if ( SizeTMult( cinfo.output_width, cinfo.output_height, &image_size ) == S_OK && SizeTMult( image_size, 4, &image_size ) == S_OK )
|
|
{
|
|
buf = (ARGB32 *)WASABI_API_MEMMGR->sysMalloc( image_size );
|
|
int row_stride = cinfo.output_width * cinfo.output_components;
|
|
|
|
ARGB32 *p = buf;// + (cinfo.output_width * cinfo.output_height);
|
|
|
|
void* line = malloc(row_stride);
|
|
|
|
while ( cinfo.output_scanline < cinfo.output_height )
|
|
{
|
|
//p -= cinfo.output_width;
|
|
jpeg_read_scanlines( &cinfo, (JSAMPARRAY)&line, 1 );
|
|
|
|
unsigned char* rgb = (unsigned char*)line;
|
|
unsigned char* argb = (unsigned char*)p;
|
|
for (size_t i = 0; i < cinfo.output_width; i++)
|
|
{
|
|
argb[4 * i] = rgb[3 * i + 2];
|
|
argb[4 * i + 1] = rgb[3 * i + 1];
|
|
argb[4 * i + 2] = rgb[3 * i];
|
|
argb[4 * i + 3] = 0xff;
|
|
}
|
|
|
|
|
|
p += cinfo.output_width;
|
|
}
|
|
free(line);
|
|
|
|
if ( w )
|
|
*w = cinfo.output_width;
|
|
|
|
if ( h )
|
|
*h = cinfo.output_height;
|
|
|
|
jpeg_finish_decompress( &cinfo );
|
|
}
|
|
}
|
|
}
|
|
|
|
jpeg_destroy_decompress( &cinfo );
|
|
|
|
return buf;
|
|
}
|
|
|
|
#define CBCLASS JpgLoad
|
|
START_DISPATCH;
|
|
CB( ISMINE, isMine );
|
|
CB( MIMETYPE, mimeType );
|
|
CB( TESTDATA, testData );
|
|
CB( GETHEADERSIZE, getHeaderSize );
|
|
CB( LOADIMAGE, loadImage );
|
|
END_DISPATCH;
|
|
#undef CBCLASS |