usbloadergx/source/libwiigui/gui_imagedata.cpp

456 lines
12 KiB
C++
Raw Normal View History

/****************************************************************************
* 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 <jpeglib.h>
#ifdef __cplusplus
}
#endif
#define new_width 640
#define new_height 480
/**
* Constructor for the GuiImageData class.
*/
extern int idiotFlag;
extern char idiotChar[50];
2010-09-24 02:48:03 +02:00
GuiImageData::GuiImageData(const u8 * img)
{
data = NULL;
width = 0;
height = 0;
2010-09-24 02:48:03 +02:00
if (img)
{
PNGUPROP imgProp;
2010-09-24 02:48:03 +02:00
IMGCTX ctx = PNGU_SelectImageFromBuffer(img);
2010-09-24 02:48:03 +02:00
if (!ctx) return;
2010-09-24 02:48:03 +02:00
int res = PNGU_GetImageProperties(ctx, &imgProp);
//if (((4%imgProp.imgWidth)!=0)||((4%imgProp.imgHeight)!=0))idiotFlag=1;
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
int len = imgProp.imgWidth * imgProp.imgHeight * 4;
2010-09-24 02:48:03 +02:00
if (len % 32) len += (32 - len % 32);
data = (u8 *) memalign(32, len);
2010-09-24 02:48:03 +02:00
if (data)
{
2010-09-24 02:48:03 +02:00
res = PNGU_DecodeTo4x4RGBA8(ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
width = imgProp.imgWidth;
height = imgProp.imgHeight;
2010-09-24 02:48:03 +02:00
DCFlushRange(data, len);
}
else
{
2010-09-24 02:48:03 +02:00
free(data);
data = NULL;
idiotFlag = 1;
2010-09-24 02:48:03 +02:00
snprintf(idiotChar, sizeof(idiotChar), "%s", img);
}
}
}
2010-09-24 02:48:03 +02:00
PNGU_ReleaseImageContext(ctx);
}
}
2010-09-24 02:48:03 +02:00
GuiImageData::GuiImageData(const u8 * img, int imgSize)
{
data = NULL;
width = 0;
height = 0;
2010-09-24 02:48:03 +02:00
if (img)
{
2010-09-24 02:48:03 +02:00
if (img[0] == 0xFF && img[1] == 0xD8) // IMAGE_JPEG
{
2010-09-24 02:48:03 +02:00
LoadJpeg(img, imgSize);
}
}
}
/**
* Constructor for the GuiImageData class.
*/
2010-09-24 02:48:03 +02:00
GuiImageData::GuiImageData(const char * imgPath, const u8 * buffer)
{
data = NULL;
width = 0;
height = 0;
2010-09-24 02:48:03 +02:00
if (imgPath)
{
PNGUPROP imgProp;
2010-09-24 02:48:03 +02:00
IMGCTX ctx = PNGU_SelectImageFromDevice(imgPath);
//if (((4%imgProp.imgWidth)!=0)||((4%imgProp.imgHeight)!=0))idiotFlag=1;
2010-09-24 02:48:03 +02:00
if (ctx)
{
2010-09-24 02:48:03 +02:00
int res = PNGU_GetImageProperties(ctx, &imgProp);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
int len = imgProp.imgWidth * imgProp.imgHeight * 4;
2010-09-24 02:48:03 +02:00
if (len % 32) len += (32 - len % 32);
data = (u8 *) memalign(32, len);
2010-09-24 02:48:03 +02:00
if (data)
{
2010-09-24 02:48:03 +02:00
res = PNGU_DecodeTo4x4RGBA8(ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
width = imgProp.imgWidth;
height = imgProp.imgHeight;
2010-09-24 02:48:03 +02:00
DCFlushRange(data, len);
}
else
{
2010-09-24 02:48:03 +02:00
free(data);
data = NULL;
idiotFlag = 1;
2010-09-24 02:48:03 +02:00
snprintf(idiotChar, sizeof(idiotChar), "%s", imgPath);
}
}
}
2010-09-24 02:48:03 +02:00
PNGU_ReleaseImageContext(ctx);
}
}
2010-09-24 02:48:03 +02:00
if (!data) //use buffer data instead
{
width = 0;
height = 0;
2010-09-24 02:48:03 +02:00
if (buffer)
{
PNGUPROP imgProp;
2010-09-24 02:48:03 +02:00
IMGCTX ctx = PNGU_SelectImageFromBuffer(buffer);
2010-09-24 02:48:03 +02:00
if (!ctx) return;
2010-09-24 02:48:03 +02:00
int res = PNGU_GetImageProperties(ctx, &imgProp);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
int len = imgProp.imgWidth * imgProp.imgHeight * 4;
2010-09-24 02:48:03 +02:00
if (len % 32) len += (32 - len % 32);
data = (u8 *) memalign(32, len);
2010-09-24 02:48:03 +02:00
if (data)
{
2010-09-24 02:48:03 +02:00
res = PNGU_DecodeTo4x4RGBA8(ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
width = imgProp.imgWidth;
height = imgProp.imgHeight;
2010-09-24 02:48:03 +02:00
DCFlushRange(data, len);
}
else
{
2010-09-24 02:48:03 +02:00
free(data);
data = NULL;
}
}
}
2010-09-24 02:48:03 +02:00
PNGU_ReleaseImageContext(ctx);
}
}
}
/**
* Constructor for the GuiImageData class.
*/
2010-09-24 02:48:03 +02:00
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;
2010-09-24 02:48:03 +02:00
snprintf(path_4_3, sizeof(path_4_3), "%s%s", path, file);
if (force_widescreen)
{
2010-09-24 02:48:03 +02:00
snprintf(path_16_9, sizeof(path_16_9), "%sw%s", path, file);
imgPath = path_16_9;
2010-09-24 02:48:03 +02:00
if (wbuffer) buffer = wbuffer;
}
2010-09-24 02:48:03 +02:00
else imgPath = path_4_3;
2010-09-24 02:48:03 +02:00
for (;;)
{
2010-09-24 02:48:03 +02:00
if (imgPath)
{
PNGUPROP imgProp;
2010-09-24 02:48:03 +02:00
IMGCTX ctx = PNGU_SelectImageFromDevice(imgPath);
//if (((4%imgProp.imgWidth)!=0)||((4%imgProp.imgHeight)!=0))idiotFlag=1;
2010-09-24 02:48:03 +02:00
if (ctx)
{
2010-09-24 02:48:03 +02:00
int res = PNGU_GetImageProperties(ctx, &imgProp);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
int len = imgProp.imgWidth * imgProp.imgHeight * 4;
2010-09-24 02:48:03 +02:00
if (len % 32) len += (32 - len % 32);
data = (u8 *) memalign(32, len);
2010-09-24 02:48:03 +02:00
if (data)
{
2010-09-24 02:48:03 +02:00
res = PNGU_DecodeTo4x4RGBA8(ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
width = imgProp.imgWidth;
height = imgProp.imgHeight;
2010-09-24 02:48:03 +02:00
DCFlushRange(data, len);
}
else
{
2010-09-24 02:48:03 +02:00
free(data);
data = NULL;
idiotFlag = 1;
2010-09-24 02:48:03 +02:00
snprintf(idiotChar, sizeof(idiotChar), "%s", imgPath);
}
}
}
2010-09-24 02:48:03 +02:00
PNGU_ReleaseImageContext(ctx);
}
}
2010-09-24 02:48:03 +02:00
if (data || imgPath == path_4_3) break;
imgPath = path_4_3;
}
2010-09-24 02:48:03 +02:00
if (!data) //use buffer data instead
{
width = 0;
height = 0;
2010-09-24 02:48:03 +02:00
if (buffer)
{
PNGUPROP imgProp;
2010-09-24 02:48:03 +02:00
IMGCTX ctx = PNGU_SelectImageFromBuffer(buffer);
2010-09-24 02:48:03 +02:00
if (!ctx) return;
2010-09-24 02:48:03 +02:00
int res = PNGU_GetImageProperties(ctx, &imgProp);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
int len = imgProp.imgWidth * imgProp.imgHeight * 4;
2010-09-24 02:48:03 +02:00
if (len % 32) len += (32 - len % 32);
data = (u8 *) memalign(32, len);
2010-09-24 02:48:03 +02:00
if (data)
{
2010-09-24 02:48:03 +02:00
res = PNGU_DecodeTo4x4RGBA8(ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255);
2010-09-24 02:48:03 +02:00
if (res == PNGU_OK)
{
width = imgProp.imgWidth;
height = imgProp.imgHeight;
2010-09-24 02:48:03 +02:00
DCFlushRange(data, len);
}
else
{
2010-09-24 02:48:03 +02:00
free(data);
data = NULL;
}
}
}
2010-09-24 02:48:03 +02:00
PNGU_ReleaseImageContext(ctx);
}
}
}
/**
* Destructor for the GuiImageData class.
*/
GuiImageData::~GuiImageData()
{
2010-09-24 02:48:03 +02:00
if (data)
{
2010-09-24 02:48:03 +02:00
free(data);
data = NULL;
}
}
u8 * GuiImageData::GetImage()
{
return data;
}
int GuiImageData::GetWidth()
{
return width;
}
int GuiImageData::GetHeight()
{
return height;
}
2010-09-24 02:48:03 +02:00
void GuiImageData::SetGrayscale(void)
{
GXColor color;
u32 offset, gray;
2010-09-24 02:48:03 +02:00
for (int x = 0; x < width; x++)
{
2010-09-24 02:48:03 +02:00
for (int y = 0; y < height; y++)
{
2010-09-24 02:48:03 +02:00
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);
2010-09-24 02:48:03 +02:00
gray = (77 * color.r + 150 * color.g + 28 * color.b) / 255;
2010-09-24 02:48:03 +02:00
*(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/
2010-09-24 02:48:03 +02:00
void GuiImageData::LoadJpeg(const u8 *img, int imgSize)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
int n = imgSize;
2010-09-24 02:48:03 +02:00
while (n > 1)
{
2010-09-24 02:48:03 +02:00
if (img[n - 1] == 0xff && img[n] == 0xd9)
{
break;
}
n--;
}
jpeg_create_decompress( &cinfo );
2010-09-24 02:48:03 +02:00
cinfo.err = jpeg_std_error(&jerr);
cinfo.progress = NULL;
2010-09-24 02:48:03 +02:00
jpeg_mem_src(&cinfo, (u8 *) img, n);
jpeg_read_header(&cinfo, TRUE);
jpeg_calc_output_dimensions(&cinfo);
2010-09-24 02:48:03 +02:00
if (cinfo.output_width > new_width || cinfo.output_height > new_height)
{
2010-09-24 02:48:03 +02:00
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;
}
2010-09-24 02:48:03 +02:00
jpeg_start_decompress(&cinfo);
int rowsize = cinfo.output_width * cinfo.num_components;
2010-09-24 02:48:03 +02:00
unsigned char *tempBuffer = (unsigned char *) malloc(rowsize * cinfo.output_height);
JSAMPROW row_pointer[1];
2010-09-24 02:48:03 +02:00
row_pointer[0] = (unsigned char*) malloc(rowsize);
size_t location = 0;
2010-09-24 02:48:03 +02:00
while (cinfo.output_scanline < cinfo.output_height)
{
2010-09-24 02:48:03 +02:00
jpeg_read_scanlines(&cinfo, row_pointer, 1);
memcpy(tempBuffer + location, row_pointer[0], rowsize);
location += rowsize;
}
2010-09-24 02:48:03 +02:00
int len = ((cinfo.output_width + 3) >> 2) * ((cinfo.output_height + 3) >> 2) * 32 * 2;
2010-09-24 02:48:03 +02:00
data = (u8 *) memalign(32, len);
2010-09-24 02:48:03 +02:00
RawTo4x4RGBA(tempBuffer, data, cinfo.output_width, cinfo.output_height);
DCFlushRange(data, len);
width = cinfo.output_width;
height = cinfo.output_height;
2010-09-24 02:48:03 +02:00
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
2010-09-24 02:48:03 +02:00
*/
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;
2010-09-24 02:48:03 +02:00
unsigned char *p = (unsigned char*) dst;
2010-09-24 02:48:03 +02:00
for (block = 0; block < height; block += 4)
{
2010-09-24 02:48:03 +02:00
for (i = 0; i < width; i += 4)
{
/* Alpha and Red */
2010-09-24 02:48:03 +02:00
for (c = 0; c < 4; ++c)
{
2010-09-24 02:48:03 +02:00
for (ar = 0; ar < 4; ++ar)
{
/* Alpha pixels */
*p++ = 255;
/* Red pixels */
2010-09-24 02:48:03 +02:00
*p++ = src[((i + ar) + ((block + c) * width)) * 3];
}
}
/* Green and Blue */
2010-09-24 02:48:03 +02:00
for (c = 0; c < 4; ++c)
{
2010-09-24 02:48:03 +02:00
for (gb = 0; gb < 4; ++gb)
{
/* Green pixels */
2010-09-24 02:48:03 +02:00
*p++ = src[(((i + gb) + ((block + c) * width)) * 3) + 1];
/* Blue pixels */
2010-09-24 02:48:03 +02:00
*p++ = src[(((i + gb) + ((block + c) * width)) * 3) + 2];
}
}
} /* i */
} /* block */
}