/**************************************************************************** * libwiigui * * Tantric 2009 * * gui_imagedata.cpp * * LoadJpeg copyright by r-win for WiiXplorer * check WiiXplorer source for license conditions * * GUI class definitions ***************************************************************************/ #include "gui.h" #ifdef __cplusplus extern "C" { #endif #include #ifdef __cplusplus } #endif #define new_width 640 #define new_height 480 /** * Constructor for the GuiImageData class. */ extern int idiotFlag; extern char idiotChar[50]; GuiImageData::GuiImageData( const u8 * img ) { data = NULL; width = 0; height = 0; if ( img ) { PNGUPROP imgProp; IMGCTX ctx = PNGU_SelectImageFromBuffer( img ); if ( !ctx ) return; int res = PNGU_GetImageProperties( ctx, &imgProp ); //if (((4%imgProp.imgWidth)!=0)||((4%imgProp.imgHeight)!=0))idiotFlag=1; if ( res == PNGU_OK ) { int len = imgProp.imgWidth * imgProp.imgHeight * 4; if ( len % 32 ) len += ( 32 - len % 32 ); data = ( u8 * )memalign ( 32, len ); if ( data ) { res = PNGU_DecodeTo4x4RGBA8 ( ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255 ); if ( res == PNGU_OK ) { width = imgProp.imgWidth; height = imgProp.imgHeight; DCFlushRange( data, len ); } else { free( data ); data = NULL; idiotFlag = 1; snprintf( idiotChar, sizeof( idiotChar ), "%s", img ); } } } PNGU_ReleaseImageContext ( ctx ); } } GuiImageData::GuiImageData( const u8 * img, int imgSize ) { data = NULL; width = 0; height = 0; if ( img ) { if ( img[0] == 0xFF && img[1] == 0xD8 ) // IMAGE_JPEG { LoadJpeg( img, imgSize ); } } } /** * Constructor for the GuiImageData class. */ GuiImageData::GuiImageData( const char * imgPath, const u8 * buffer ) { data = NULL; width = 0; height = 0; if ( imgPath ) { PNGUPROP imgProp; IMGCTX ctx = PNGU_SelectImageFromDevice( imgPath ); //if (((4%imgProp.imgWidth)!=0)||((4%imgProp.imgHeight)!=0))idiotFlag=1; if ( ctx ) { int res = PNGU_GetImageProperties( ctx, &imgProp ); if ( res == PNGU_OK ) { int len = imgProp.imgWidth * imgProp.imgHeight * 4; if ( len % 32 ) len += ( 32 - len % 32 ); data = ( u8 * )memalign ( 32, len ); if ( data ) { res = PNGU_DecodeTo4x4RGBA8 ( ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255 ); if ( res == PNGU_OK ) { width = imgProp.imgWidth; height = imgProp.imgHeight; DCFlushRange( data, len ); } else { free( data ); data = NULL; idiotFlag = 1; snprintf( idiotChar, sizeof( idiotChar ), "%s", imgPath ); } } } PNGU_ReleaseImageContext ( ctx ); } } if ( !data ) //use buffer data instead { width = 0; height = 0; if ( buffer ) { PNGUPROP imgProp; IMGCTX ctx = PNGU_SelectImageFromBuffer( buffer ); if ( !ctx ) return; int res = PNGU_GetImageProperties( ctx, &imgProp ); if ( res == PNGU_OK ) { int len = imgProp.imgWidth * imgProp.imgHeight * 4; if ( len % 32 ) len += ( 32 - len % 32 ); data = ( u8 * )memalign ( 32, len ); if ( data ) { res = PNGU_DecodeTo4x4RGBA8 ( ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255 ); if ( res == PNGU_OK ) { width = imgProp.imgWidth; height = imgProp.imgHeight; DCFlushRange( data, len ); } else { free( data ); data = NULL; } } } PNGU_ReleaseImageContext ( ctx ); } } } /** * Constructor for the GuiImageData class. */ GuiImageData::GuiImageData( const char *path, const char *file, const u8 *buffer, bool force_widescreen/*=false*/, const u8 *wbuffer/*=NULL*/ ) { data = NULL; width = 0; height = 0; char path_4_3[100]; char path_16_9[100]; char *imgPath; snprintf( path_4_3, sizeof( path_4_3 ), "%s%s", path, file ); if ( force_widescreen ) { snprintf( path_16_9, sizeof( path_16_9 ), "%sw%s", path, file ); imgPath = path_16_9; if ( wbuffer ) buffer = wbuffer; } else imgPath = path_4_3; for ( ;; ) { if ( imgPath ) { PNGUPROP imgProp; IMGCTX ctx = PNGU_SelectImageFromDevice( imgPath ); //if (((4%imgProp.imgWidth)!=0)||((4%imgProp.imgHeight)!=0))idiotFlag=1; if ( ctx ) { int res = PNGU_GetImageProperties( ctx, &imgProp ); if ( res == PNGU_OK ) { int len = imgProp.imgWidth * imgProp.imgHeight * 4; if ( len % 32 ) len += ( 32 - len % 32 ); data = ( u8 * )memalign ( 32, len ); if ( data ) { res = PNGU_DecodeTo4x4RGBA8 ( ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255 ); if ( res == PNGU_OK ) { width = imgProp.imgWidth; height = imgProp.imgHeight; DCFlushRange( data, len ); } else { free( data ); data = NULL; idiotFlag = 1; snprintf( idiotChar, sizeof( idiotChar ), "%s", imgPath ); } } } PNGU_ReleaseImageContext ( ctx ); } } if ( data || imgPath == path_4_3 ) break; imgPath = path_4_3; } if ( !data ) //use buffer data instead { width = 0; height = 0; if ( buffer ) { PNGUPROP imgProp; IMGCTX ctx = PNGU_SelectImageFromBuffer( buffer ); if ( !ctx ) return; int res = PNGU_GetImageProperties( ctx, &imgProp ); if ( res == PNGU_OK ) { int len = imgProp.imgWidth * imgProp.imgHeight * 4; if ( len % 32 ) len += ( 32 - len % 32 ); data = ( u8 * )memalign ( 32, len ); if ( data ) { res = PNGU_DecodeTo4x4RGBA8 ( ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255 ); if ( res == PNGU_OK ) { width = imgProp.imgWidth; height = imgProp.imgHeight; DCFlushRange( data, len ); } else { free( data ); data = NULL; } } } PNGU_ReleaseImageContext ( ctx ); } } } /** * Destructor for the GuiImageData class. */ GuiImageData::~GuiImageData() { if ( data ) { free( data ); data = NULL; } } u8 * GuiImageData::GetImage() { return data; } int GuiImageData::GetWidth() { return width; } int GuiImageData::GetHeight() { return height; } void GuiImageData::SetGrayscale( void ) { GXColor color; u32 offset, gray; for ( int x = 0; x < width; x++ ) { for ( int y = 0; y < height; y++ ) { offset = ( ( ( y >> 2 ) << 4 ) * width ) + ( ( x >> 2 ) << 6 ) + ( ( ( y % 4 << 2 ) + x % 4 ) << 1 ); color.r = *( data + offset + 1 ); color.g = *( data + offset + 32 ); color.b = *( data + offset + 33 ); gray = ( 77 * color.r + 150 * color.g + 28 * color.b ) / 255; *( data + offset + 1 ) = gray; *( data + offset + 32 ) = gray; *( data + offset + 33 ) = gray; } } } // This function finds it's origin in GRRLIB, which can be found here: http://code.google.com/p/grrlib/ void GuiImageData::LoadJpeg( const u8 *img, int imgSize ) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; int n = imgSize; while ( n > 1 ) { if ( img[n - 1] == 0xff && img[n] == 0xd9 ) { break; } n--; } jpeg_create_decompress( &cinfo ); cinfo.err = jpeg_std_error( &jerr ); cinfo.progress = NULL; jpeg_mem_src( &cinfo, ( u8 * ) img, n ); jpeg_read_header( &cinfo, TRUE ); jpeg_calc_output_dimensions( &cinfo ); if ( cinfo.output_width > new_width || cinfo.output_height > new_height ) { float factor = ( cinfo.output_width > cinfo.output_height ) ? ( 1.0 * cinfo.output_width ) / new_width : ( 1.0 * cinfo.output_height ) / new_height; cinfo.scale_num = 1; cinfo.scale_denom = factor; cinfo.do_fancy_upsampling = true; cinfo.do_block_smoothing = false; cinfo.dct_method = JDCT_IFAST; } jpeg_start_decompress( &cinfo ); int rowsize = cinfo.output_width * cinfo.num_components; unsigned char *tempBuffer = ( unsigned char * ) malloc( rowsize * cinfo.output_height ); JSAMPROW row_pointer[1]; row_pointer[0] = ( unsigned char* ) malloc( rowsize ); size_t location = 0; while ( cinfo.output_scanline < cinfo.output_height ) { jpeg_read_scanlines( &cinfo, row_pointer, 1 ); memcpy( tempBuffer + location, row_pointer[0], rowsize ); location += rowsize; } int len = ( ( cinfo.output_width + 3 ) >> 2 ) * ( ( cinfo.output_height + 3 ) >> 2 ) * 32 * 2; data = ( u8 * ) memalign( 32, len ); RawTo4x4RGBA( tempBuffer, data, cinfo.output_width, cinfo.output_height ); DCFlushRange( data, len ); width = cinfo.output_width; height = cinfo.output_height; jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); free( row_pointer[0] ); free( tempBuffer ); } /** * Convert a raw bmp (RGB, no alpha) to 4x4RGBA. * @author DragonMinded * @param src * @param dst * @param width * @param height */ void GuiImageData::RawTo4x4RGBA( const unsigned char *src, void *dst, const unsigned int width, const unsigned int height ) { unsigned int block; unsigned int i; unsigned int c; unsigned int ar; unsigned int gb; unsigned char *p = ( unsigned char* )dst; for ( block = 0; block < height; block += 4 ) { for ( i = 0; i < width; i += 4 ) { /* Alpha and Red */ for ( c = 0; c < 4; ++c ) { for ( ar = 0; ar < 4; ++ar ) { /* Alpha pixels */ *p++ = 255; /* Red pixels */ *p++ = src[( ( i + ar ) + ( ( block + c ) * width ) ) * 3]; } } /* Green and Blue */ for ( c = 0; c < 4; ++c ) { for ( gb = 0; gb < 4; ++gb ) { /* Green pixels */ *p++ = src[( ( ( i + gb ) + ( ( block + c ) * width ) ) * 3 ) + 1]; /* Blue pixels */ *p++ = src[( ( ( i + gb ) + ( ( block + c ) * width ) ) * 3 ) + 2]; } } } /* i */ } /* block */ }