winamp/Src/jpeg/loader_jpg.cpp

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