/**************************************************************************** * 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 */ }