diff --git a/source/ngc/fonts/font.ttf b/source/ngc/fonts/font.ttf index 934f65e..01ce581 100644 Binary files a/source/ngc/fonts/font.ttf and b/source/ngc/fonts/font.ttf differ diff --git a/source/ngc/gui/gui_filebrowser.cpp b/source/ngc/gui/gui_filebrowser.cpp index 4caf25f..50f51fb 100644 --- a/source/ngc/gui/gui_filebrowser.cpp +++ b/source/ngc/gui/gui_filebrowser.cpp @@ -109,7 +109,7 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff}); fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); fileListText[i]->SetPosition(5,0); - fileListText[i]->SetMaxWidth(380); + fileListText[i]->SetMaxWidth(450); fileListBg[i] = new GuiImage(bgFileSelectionEntry); fileListIcon[i] = NULL; diff --git a/source/ngc/gui/gui_imagedata.cpp b/source/ngc/gui/gui_imagedata.cpp index b9fbf80..bc2f1e3 100644 --- a/source/ngc/gui/gui_imagedata.cpp +++ b/source/ngc/gui/gui_imagedata.cpp @@ -20,40 +20,7 @@ GuiImageData::GuiImageData(const u8 * i) height = 0; if(i) - { - PNGUPROP imgProp; - IMGCTX ctx = PNGU_SelectImageFromBuffer(i); - - if(!ctx) - return; - - int res = PNGU_GetImageProperties(ctx, &imgProp); - - if(res == PNGU_OK) - { - int len = (imgProp.imgWidth * imgProp.imgHeight) <<2; - 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); - } + data = DecodePNG(i, &width, &height); } /** diff --git a/source/ngc/gui/gui_text.cpp b/source/ngc/gui/gui_text.cpp index 11d431b..9d0c9f3 100644 --- a/source/ngc/gui/gui_text.cpp +++ b/source/ngc/gui/gui_text.cpp @@ -237,126 +237,130 @@ void GuiText::Draw() fontSystem[newSize] = new FreeTypeGX(newSize); currentSize = newSize; } + + u8 maxChar; - if(maxWidth > 0) - { - char * tmpText = strdup(origText); - u8 maxChar = int((float((maxWidth<<1))) / (float(newSize))); - - if(!textDyn) - { - if(strlen(tmpText) > maxChar) - tmpText[maxChar] = 0; - textDyn = charToWideChar(tmpText); - } - - if(textScroll == SCROLL_HORIZONTAL) - { - int textlen = strlen(origText); - - if(textlen > maxChar && (FrameTimer % textScrollDelay == 0)) - { - if(textScrollInitialDelay) - { - --textScrollInitialDelay; - } - else - { - ++textScrollPos; - if(textScrollPos > textlen-1) - { - textScrollPos = 0; - textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; - } - - strncpy(tmpText, &origText[textScrollPos], maxChar-1); - tmpText[maxChar-1] = 0; - - int dynlen = strlen(tmpText); - - if(dynlen+2 < maxChar) - { - tmpText[dynlen] = ' '; - tmpText[dynlen+1] = ' '; - strncat(&tmpText[dynlen+2], origText, maxChar - dynlen - 2); - } - if(textDyn) delete[] textDyn; - textDyn = charToWideChar(tmpText); - } - } - if(textDyn) - fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style); - } - else if(wrap) - { - int lineheight = newSize + 6; - int txtlen = wcslen(text); - int i = 0; - int ch = 0; - int linenum = 0; - int lastSpace = -1; - int lastSpaceIndex = -1; - wchar_t * textrow[20]; - - while(ch < txtlen) - { - if(i == 0) - textrow[linenum] = new wchar_t[txtlen + 1]; - - textrow[linenum][i] = text[ch]; - textrow[linenum][i+1] = 0; - - if(text[ch] == ' ' || ch == txtlen-1) - { - if(wcslen(textrow[linenum]) >= maxChar) - { - if(lastSpace >= 0) - { - textrow[linenum][lastSpaceIndex] = 0; // discard space, and everything after - ch = lastSpace; // go backwards to the last space - lastSpace = -1; // we have used this space - lastSpaceIndex = -1; - } - ++linenum; - i = -1; - } - else if(ch == txtlen-1) - { - ++linenum; - } - } - if(text[ch] == ' ' && i >= 0) - { - lastSpace = ch; - lastSpaceIndex = i; - } - ++ch; - ++i; - } - - int voffset = 0; - - if(alignmentVert == ALIGN_MIDDLE) - voffset = (lineheight >> 1) * (1-linenum); - - int left = this->GetLeft(); - int top = this->GetTop() + voffset; - - for(i=0; i < linenum; ++i) - { - fontSystem[currentSize]->drawText(left, top+i*lineheight, textrow[i], c, style); - delete[] textrow[i]; - } - } - else - { - fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style); - } - free(tmpText); - } - else + if(maxWidth == 0) { fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), text, c, style); + goto done; } + + maxChar = int((float((maxWidth<<1))) / (float(newSize))); // approximate + + if(wrap) + { + int lineheight = newSize + 6; + int txtlen = wcslen(text); + int i = 0; + int ch = 0; + int linenum = 0; + int lastSpace = -1; + int lastSpaceIndex = -1; + wchar_t * textrow[20]; + + while(ch < txtlen) + { + if(i == 0) + textrow[linenum] = new wchar_t[txtlen + 1]; + + textrow[linenum][i] = text[ch]; + textrow[linenum][i+1] = 0; + + if(text[ch] == ' ' || ch == txtlen-1) + { + if(wcslen(textrow[linenum]) >= maxChar) + { + if(lastSpace >= 0) + { + textrow[linenum][lastSpaceIndex] = 0; // discard space, and everything after + ch = lastSpace; // go backwards to the last space + lastSpace = -1; // we have used this space + lastSpaceIndex = -1; + } + ++linenum; + i = -1; + } + else if(ch == txtlen-1) + { + ++linenum; + } + } + if(text[ch] == ' ' && i >= 0) + { + lastSpace = ch; + lastSpaceIndex = i; + } + ++ch; + ++i; + } + + int voffset = 0; + + if(alignmentVert == ALIGN_MIDDLE) + voffset = (lineheight >> 1) * (1-linenum); + + int left = this->GetLeft(); + int top = this->GetTop() + voffset; + + for(i=0; i < linenum; ++i) + { + fontSystem[currentSize]->drawText(left, top+i*lineheight, textrow[i], c, style); + delete[] textrow[i]; + } + goto done; + } + + if(textScroll == SCROLL_HORIZONTAL) + { + char *tmpText = strdup(gettext(origText)); + char *tmpText2 = strdup(tmpText); + int textlen = strlen(tmpText); + + if(textlen > maxChar && (FrameTimer % textScrollDelay == 0)) + { + if(textScrollInitialDelay) + { + --textScrollInitialDelay; + } + else + { + ++textScrollPos; + if(textScrollPos > textlen-1) + { + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + } + + strncpy(tmpText, &tmpText2[textScrollPos], maxChar-1); + tmpText[maxChar-1] = 0; + + int dynlen = strlen(tmpText); + + if(dynlen+2 < maxChar) + { + tmpText[dynlen] = ' '; + tmpText[dynlen+1] = ' '; + strncat(&tmpText[dynlen+2], tmpText2, maxChar - dynlen - 2); + } + if(textDyn) delete[] textDyn; + textDyn = charToWideChar(tmpText); + } + } + free(tmpText); + free(tmpText2); + } + + if(!textDyn) + { + char *tmpText = strdup(gettext(origText)); + if(strlen(tmpText) > maxChar) + tmpText[maxChar] = 0; + textDyn = charToWideChar(tmpText); + free(tmpText); + } + + fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style); +done: this->UpdateEffects(); } diff --git a/source/ngc/menu.cpp b/source/ngc/menu.cpp index 7e87dbc..1ac2d1c 100644 --- a/source/ngc/menu.cpp +++ b/source/ngc/menu.cpp @@ -3758,7 +3758,7 @@ static int MenuSettingsNetwork() GuiOptionBrowser optionBrowser(552, 248, &options); optionBrowser.SetPosition(0, 108); optionBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - optionBrowser.SetCol2Position(275); + optionBrowser.SetCol2Position(290); HaltGui(); GuiWindow w(screenwidth, screenheight); diff --git a/source/ngc/pngu.c b/source/ngc/pngu.c index e3a0293..f621220 100644 --- a/source/ngc/pngu.c +++ b/source/ngc/pngu.c @@ -1,31 +1,41 @@ /******************************************************************************************** - -PNGU Version : 0.2a - -Coder : frontier - -More info : http://frontier-dev.net - -Modified by Tantric, 2009 - +* +* PNGU +* +* Original author: frontier (http://frontier-dev.net) +* Modified by Tantric, 2009-2010 +* ********************************************************************************************/ + #include #include +#include #include "pngu.h" -#include "png.h" +#include // Constants -#define PNGU_SOURCE_BUFFER 1 -#define PNGU_SOURCE_DEVICE 2 +#define PNGU_SOURCE_BUFFER 1 +#define PNGU_SOURCE_DEVICE 2 -// Prototypes of helper functions -int pngu_info (IMGCTX ctx); -int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha); -void pngu_free_info (IMGCTX ctx); -void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length); -void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length); -void pngu_flush_data_to_buffer (png_structp png_ptr); -int pngu_clamp (int value, int min, int max); +// Return codes +#define PNGU_OK 0 +#define PNGU_ODD_WIDTH 1 +#define PNGU_ODD_STRIDE 2 +#define PNGU_INVALID_WIDTH_OR_HEIGHT 3 +#define PNGU_FILE_IS_NOT_PNG 4 +#define PNGU_UNSUPPORTED_COLOR_TYPE 5 +#define PNGU_NO_FILE_SELECTED 6 +#define PNGU_CANT_OPEN_FILE 7 +#define PNGU_CANT_READ_FILE 8 +#define PNGU_LIB_ERROR 9 + +// Color types +#define PNGU_COLOR_TYPE_GRAY 1 +#define PNGU_COLOR_TYPE_GRAY_ALPHA 2 +#define PNGU_COLOR_TYPE_PALETTE 3 +#define PNGU_COLOR_TYPE_RGB 4 +#define PNGU_COLOR_TYPE_RGB_ALPHA 5 +#define PNGU_COLOR_TYPE_UNKNOWN 6 // PNGU Image context struct struct _IMGCTX @@ -49,362 +59,42 @@ struct _IMGCTX // PNGU Implementation -IMGCTX PNGU_SelectImageFromBuffer (const void *buffer) +static void pngu_free_info (IMGCTX ctx) { - IMGCTX ctx = NULL; - - if (!buffer) - return NULL; - - ctx = malloc (sizeof (struct _IMGCTX)); - if (!ctx) - return NULL; - - ctx->buffer = (void *) buffer; - ctx->source = PNGU_SOURCE_BUFFER; - ctx->cursor = 0; - ctx->filename = NULL; - ctx->propRead = 0; - ctx->infoRead = 0; - - return ctx; -} - -IMGCTX PNGU_SelectImageFromDevice (const char *filename) -{ - IMGCTX ctx = NULL; - - if (!filename) - return NULL; - - ctx = malloc (sizeof (struct _IMGCTX)); - if (!ctx) - return NULL; - - ctx->buffer = NULL; - ctx->source = PNGU_SOURCE_DEVICE; - ctx->cursor = 0; - - ctx->filename = malloc (strlen (filename) + 1); - if (!ctx->filename) - { - free (ctx); - return NULL; - } - strcpy(ctx->filename, filename); - - ctx->propRead = 0; - ctx->infoRead = 0; - - return ctx; -} - -void PNGU_ReleaseImageContext (IMGCTX ctx) -{ - if (!ctx) - return; - - if (ctx->filename) - free (ctx->filename); - - if ((ctx->propRead) && (ctx->prop.trans)) - free (ctx->prop.trans); - - pngu_free_info (ctx); - free (ctx); -} - -int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *imgprop) -{ - int res; - - if (!ctx->propRead) - { - res = pngu_info (ctx); - if (res != PNGU_OK) - return res; - } - - *imgprop = ctx->prop; - return PNGU_OK; -} - -int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha) -{ - int result; - PNGU_u32 x, y, qwidth, qheight; - PNGU_u64 alphaMask; - - // width and height need to be divisible by four - if ((width % 4) || (height % 4)) - return PNGU_INVALID_WIDTH_OR_HEIGHT; - - result = pngu_decode (ctx, width, height, 0); - if (result != PNGU_OK) - return result; - - // Init some variables - qwidth = width >> 2; - qheight = height >> 2; - - // Check is source image has an alpha channel - if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) ) - { - // Alpha channel present, copy image to the output buffer - for (y = 0; y < qheight; y++) - for (x = 0; x < qwidth; x++) - { - int blockbase = (y * qwidth + x) << 3; - - PNGU_u32 y4 = y << 2; - PNGU_u32 x16 = x << 4; - - PNGU_u64 fieldA = *((PNGU_u64 *)(ctx->row_pointers[y4]+x16)); - PNGU_u64 fieldB = *((PNGU_u64 *)(ctx->row_pointers[y4]+x16+8)); - ((PNGU_u64 *) buffer)[blockbase] = - ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | - ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | - ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | - ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); - ((PNGU_u64 *) buffer)[blockbase+4] = - ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | - ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); - - fieldA = *((PNGU_u64 *)(ctx->row_pointers[y4+1]+x16)); - fieldB = *((PNGU_u64 *)(ctx->row_pointers[y4+1]+x16+8)); - ((PNGU_u64 *) buffer)[blockbase+1] = - ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | - ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | - ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | - ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); - ((PNGU_u64 *) buffer)[blockbase+5] = - ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | - ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); - - fieldA = *((PNGU_u64 *)(ctx->row_pointers[y4+2]+x16)); - fieldB = *((PNGU_u64 *)(ctx->row_pointers[y4+2]+x16+8)); - ((PNGU_u64 *) buffer)[blockbase+2] = - ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | - ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | - ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | - ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); - ((PNGU_u64 *) buffer)[blockbase+6] = - ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | - ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); - - fieldA = *((PNGU_u64 *)(ctx->row_pointers[y4+3]+x16)); - fieldB = *((PNGU_u64 *)(ctx->row_pointers[y4+3]+x16+8)); - ((PNGU_u64 *) buffer)[blockbase+3] = - ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | - ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | - ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | - ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); - ((PNGU_u64 *) buffer)[blockbase+7] = - ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | - ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); - } - } - else - { - // No alpha channel present, copy image to the output buffer - alphaMask = (((PNGU_u64)default_alpha) << 56) | (((PNGU_u64)default_alpha) << 40) | - (((PNGU_u64)default_alpha) << 24) | (((PNGU_u64)default_alpha) << 8); - - for (y = 0; y < qheight; y++) - for (x = 0; x < qwidth; x++) - { - int blockbase = (y * qwidth + x) << 3; - - PNGU_u32 y4 = y << 2; - PNGU_u32 x12 = x * 12; - - PNGU_u64 field64 = *((PNGU_u64 *)(ctx->row_pointers[y4]+x12)); - PNGU_u64 field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y4]+x12+8)); - ((PNGU_u64 *) buffer)[blockbase] = - (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | - ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); - ((PNGU_u64 *) buffer)[blockbase+4] = - (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | - ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); - - field64 = *((PNGU_u64 *)(ctx->row_pointers[y4+1]+x12)); - field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y4+1]+x12+8)); - ((PNGU_u64 *) buffer)[blockbase+1] = - (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | - ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); - ((PNGU_u64 *) buffer)[blockbase+5] = - (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | - ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); - - field64 = *((PNGU_u64 *)(ctx->row_pointers[y4+2]+x12)); - field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y4+2]+x12+8)); - ((PNGU_u64 *) buffer)[blockbase+2] = - (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | - ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); - ((PNGU_u64 *) buffer)[blockbase+6] = - (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | - ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); - - field64 = *((PNGU_u64 *)(ctx->row_pointers[y4+3]+x12)); - field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y4+3]+x12+8)); - ((PNGU_u64 *) buffer)[blockbase+3] = - (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | - ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); - ((PNGU_u64 *) buffer)[blockbase+7] = - (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | - ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); - } - } - - // Free resources - free (ctx->img_data); - free (ctx->row_pointers); - - // Success - return PNGU_OK; -} - -int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) -{ - png_uint_32 rowbytes; - PNGU_u32 y; - - // Erase from the context any readed info - pngu_free_info (ctx); - ctx->propRead = 0; - - // Check if the user has selected a file to write the image - if (ctx->source == PNGU_SOURCE_BUFFER); - - else if (ctx->source == PNGU_SOURCE_DEVICE) - { - // Open file - if (!(ctx->fd = fopen (ctx->filename, "wb"))) - return PNGU_CANT_OPEN_FILE; - } - - else - return PNGU_NO_FILE_SELECTED; - - // Allocation of libpng structs - ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!(ctx->png_ptr)) + if (ctx->infoRead) { if (ctx->source == PNGU_SOURCE_DEVICE) fclose (ctx->fd); - return PNGU_LIB_ERROR; + + png_destroy_read_struct (&(ctx->png_ptr), &(ctx->info_ptr), (png_infopp)NULL); + + ctx->infoRead = 0; } - - ctx->info_ptr = png_create_info_struct (ctx->png_ptr); - if (!(ctx->info_ptr)) - { - png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); - if (ctx->source == PNGU_SOURCE_DEVICE) - fclose (ctx->fd); - return PNGU_LIB_ERROR; - } - - if (ctx->source == PNGU_SOURCE_BUFFER) - { - // Installation of our custom data writer function - ctx->cursor = 0; - png_set_write_fn (ctx->png_ptr, ctx, pngu_write_data_to_buffer, pngu_flush_data_to_buffer); - } - else if (ctx->source == PNGU_SOURCE_DEVICE) - { - // Default data writer uses function fwrite, so it needs to use our FILE* - png_init_io (ctx->png_ptr, ctx->fd); - } - - // Setup output file properties - png_set_IHDR (ctx->png_ptr, ctx->info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - // Allocate memory to store the image in RGB format - rowbytes = width * 3; - if (rowbytes % 4) - rowbytes = ((rowbytes >>2) + 1) <<2; // Add extra padding so each row starts in a 4 byte boundary - - ctx->img_data = malloc(rowbytes * height); - memset(ctx->img_data, 0, rowbytes * height); - - if (!ctx->img_data) - { - png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); - if (ctx->source == PNGU_SOURCE_DEVICE) - fclose (ctx->fd); - return PNGU_LIB_ERROR; - } - - ctx->row_pointers = malloc (sizeof (png_bytep) * height); - memset(ctx->row_pointers, 0, sizeof (png_bytep) * height); - - if (!ctx->row_pointers) - { - png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); - if (ctx->source == PNGU_SOURCE_DEVICE) - fclose (ctx->fd); - return PNGU_LIB_ERROR; - } - - for (y = 0; y < height; ++y) - { - ctx->row_pointers[y] = buffer + (y * rowbytes); - } - - // Tell libpng where is our image data - png_set_rows (ctx->png_ptr, ctx->info_ptr, ctx->row_pointers); - - // Write file header and image data - png_write_png (ctx->png_ptr, ctx->info_ptr, PNG_TRANSFORM_IDENTITY, NULL); - - // Tell libpng we have no more data to write - png_write_end (ctx->png_ptr, (png_infop) NULL); - - // Free resources - free (ctx->img_data); - free (ctx->row_pointers); - png_destroy_write_struct (&(ctx->png_ptr), &(ctx->info_ptr)); - if (ctx->source == PNGU_SOURCE_DEVICE) - fclose (ctx->fd); - - // Success - return ctx->cursor; } -int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +// Custom data provider function used for reading from memory buffers. +static void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length) { - int res; - PNGU_u32 x,y, tmpy1, tmpy2, tmpyWid, tmpxy; - - unsigned char * ptr = (unsigned char*)buffer; - unsigned char * tmpbuffer = (unsigned char *)malloc(width*height*3); - memset(tmpbuffer, 0, width*height*3); - png_uint_32 offset; - - for(y=0; y < height; y++) - { - tmpy1 = y * 640*3; - tmpy2 = y%4 << 2; - tmpyWid = (((y >> 2)<<4)*width); - - for(x=0; x < width; x++) - { - offset = tmpyWid + ((x >> 2)<<6) + ((tmpy2+ x%4 ) << 1); - tmpxy = x * 3 + tmpy1; - - tmpbuffer[tmpxy ] = ptr[offset+1]; // R - tmpbuffer[tmpxy+1] = ptr[offset+32]; // G - tmpbuffer[tmpxy+2] = ptr[offset+33]; // B - } - } - - res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride); - free(tmpbuffer); - return res; + IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); + memcpy (data, ctx->buffer + ctx->cursor, length); + ctx->cursor += length; } -int pngu_info (IMGCTX ctx) +// Custom data writer function used for writing to memory buffers. +static void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length) +{ + IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); + memcpy (ctx->buffer + ctx->cursor, data, length); + ctx->cursor += length; +} + +// Custom data flusher function used for writing to memory buffers. +static void pngu_flush_data_to_buffer (png_structp png_ptr) +{ + // Nothing to do here +} + +static int pngu_info (IMGCTX ctx) { png_byte magic[8]; png_uint_32 width; @@ -604,7 +294,7 @@ int pngu_info (IMGCTX ctx) return PNGU_OK; } -int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha) +static int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha) { png_uint_32 rowbytes; png_uint_32 i, propImgHeight; @@ -679,48 +369,313 @@ int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlph return PNGU_OK; } -void pngu_free_info (IMGCTX ctx) +static inline PNGU_u32 coordsRGBA8(PNGU_u32 x, PNGU_u32 y, PNGU_u32 w) { - if (ctx->infoRead) + return ((((y >> 2) * (w >> 2) + (x >> 2)) << 5) + ((y & 3) << 2) + (x & 3)) << 1; +} + +static PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u8 default_alpha) +{ + PNGU_u8 *dst; + PNGU_u32 x, y, offset; + png_byte *pixel; + + if (pngu_decode (ctx, width, height, 0) != PNGU_OK) + return NULL; + + PNGU_u32 newWidth = width; + if(newWidth%4) newWidth += (4-newWidth%4); + PNGU_u32 newHeight = height; + if(newHeight%4) newHeight += (4-newHeight%4); + + int len = (newWidth * newHeight) << 2; + if(len%32) len += (32-len%32); + dst = memalign (32, len); + + if(!dst) + return NULL; + + for (y = 0; y < newHeight; y++) + { + for (x = 0; x < newWidth; x++) + { + offset = coordsRGBA8(x, y, newWidth); + + if(y >= height || x >= width) + { + dst[offset] = 0; + dst[offset+1] = 255; + dst[offset+32] = 255; + dst[offset+33] = 255; + } + else + { + if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA || + ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) + { + pixel = &(ctx->row_pointers[y][x*4]); + dst[offset] = pixel[3]; // Alpha + dst[offset+1] = pixel[0]; // Red + dst[offset+32] = pixel[1]; // Green + dst[offset+33] = pixel[2]; // Blue + } + else + { + pixel = &(ctx->row_pointers[y][x*3]); + dst[offset] = default_alpha; // Alpha + dst[offset+1] = pixel[0]; // Red + dst[offset+32] = pixel[1]; // Green + dst[offset+33] = pixel[2]; // Blue + } + } + } + } + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + + DCFlushRange(dst, len); + return dst; +} + +IMGCTX PNGU_SelectImageFromBuffer (const void *buffer) +{ + IMGCTX ctx = NULL; + + if (!buffer) + return NULL; + + ctx = malloc (sizeof (struct _IMGCTX)); + if (!ctx) + return NULL; + + ctx->buffer = (void *) buffer; + ctx->source = PNGU_SOURCE_BUFFER; + ctx->cursor = 0; + ctx->filename = NULL; + ctx->propRead = 0; + ctx->infoRead = 0; + + return ctx; +} + +IMGCTX PNGU_SelectImageFromDevice (const char *filename) +{ + IMGCTX ctx = NULL; + + if (!filename) + return NULL; + + ctx = malloc (sizeof (struct _IMGCTX)); + if (!ctx) + return NULL; + + ctx->buffer = NULL; + ctx->source = PNGU_SOURCE_DEVICE; + ctx->cursor = 0; + + ctx->filename = malloc (strlen (filename) + 1); + if (!ctx->filename) + { + free (ctx); + return NULL; + } + strcpy(ctx->filename, filename); + + ctx->propRead = 0; + ctx->infoRead = 0; + + return ctx; +} + +void PNGU_ReleaseImageContext (IMGCTX ctx) +{ + if (!ctx) + return; + + if (ctx->filename) + free (ctx->filename); + + if ((ctx->propRead) && (ctx->prop.trans)) + free (ctx->prop.trans); + + pngu_free_info (ctx); + free (ctx); +} + +int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *imgprop) +{ + int res; + + if (!ctx->propRead) + { + res = pngu_info (ctx); + if (res != PNGU_OK) + return res; + } + + *imgprop = ctx->prop; + return PNGU_OK; +} + +PNGU_u8 * DecodePNG(const PNGU_u8 *src, int * width, int * height) +{ + PNGUPROP imgProp; + IMGCTX ctx = PNGU_SelectImageFromBuffer(src); + PNGU_u8 *dst = NULL; + + if(!ctx) + return NULL; + + if(PNGU_GetImageProperties(ctx, &imgProp) == PNGU_OK) + { + dst = PNGU_DecodeTo4x4RGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, 255); + + *width = imgProp.imgWidth; + *height = imgProp.imgHeight; + } + + PNGU_ReleaseImageContext (ctx); + return dst; +} + +int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +{ + png_uint_32 rowbytes; + PNGU_u32 y; + + // Erase from the context any readed info + pngu_free_info (ctx); + ctx->propRead = 0; + + // Check if the user has selected a file to write the image + if (ctx->source == PNGU_SOURCE_BUFFER); + + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Open file + if (!(ctx->fd = fopen (ctx->filename, "wb"))) + return PNGU_CANT_OPEN_FILE; + } + + else + return PNGU_NO_FILE_SELECTED; + + // Allocation of libpng structs + ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!(ctx->png_ptr)) { if (ctx->source == PNGU_SOURCE_DEVICE) fclose (ctx->fd); - - png_destroy_read_struct (&(ctx->png_ptr), &(ctx->info_ptr), (png_infopp)NULL); - - ctx->infoRead = 0; + return PNGU_LIB_ERROR; } + + ctx->info_ptr = png_create_info_struct (ctx->png_ptr); + if (!(ctx->info_ptr)) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + if (ctx->source == PNGU_SOURCE_BUFFER) + { + // Installation of our custom data writer function + ctx->cursor = 0; + png_set_write_fn (ctx->png_ptr, ctx, pngu_write_data_to_buffer, pngu_flush_data_to_buffer); + } + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Default data writer uses function fwrite, so it needs to use our FILE* + png_init_io (ctx->png_ptr, ctx->fd); + } + + // Setup output file properties + png_set_IHDR (ctx->png_ptr, ctx->info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + // Allocate memory to store the image in RGB format + rowbytes = width * 3; + if (rowbytes % 4) + rowbytes = ((rowbytes >>2) + 1) <<2; // Add extra padding so each row starts in a 4 byte boundary + + ctx->img_data = malloc(rowbytes * height); + memset(ctx->img_data, 0, rowbytes * height); + + if (!ctx->img_data) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + ctx->row_pointers = malloc (sizeof (png_bytep) * height); + memset(ctx->row_pointers, 0, sizeof (png_bytep) * height); + + if (!ctx->row_pointers) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + for (y = 0; y < height; ++y) + { + ctx->row_pointers[y] = buffer + (y * rowbytes); + } + + // Tell libpng where is our image data + png_set_rows (ctx->png_ptr, ctx->info_ptr, ctx->row_pointers); + + // Write file header and image data + png_write_png (ctx->png_ptr, ctx->info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + // Tell libpng we have no more data to write + png_write_end (ctx->png_ptr, (png_infop) NULL); + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + png_destroy_write_struct (&(ctx->png_ptr), &(ctx->info_ptr)); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + + // Success + return ctx->cursor; } -// Custom data provider function used for reading from memory buffers. -void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length) +int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) { - IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); - memcpy (data, ctx->buffer + ctx->cursor, length); - ctx->cursor += length; -} + int res; + PNGU_u32 x,y, tmpy1, tmpy2, tmpyWid, tmpxy; -// Custom data writer function used for writing to memory buffers. -void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length) -{ - IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); - memcpy (ctx->buffer + ctx->cursor, data, length); - ctx->cursor += length; -} + unsigned char * ptr = (unsigned char*)buffer; + unsigned char * tmpbuffer = (unsigned char *)malloc(width*height*3); + memset(tmpbuffer, 0, width*height*3); + png_uint_32 offset; + + for(y=0; y < height; y++) + { + tmpy1 = y * 640*3; + tmpy2 = y%4 << 2; + tmpyWid = (((y >> 2)<<4)*width); -// Custom data flusher function used for writing to memory buffers. -void pngu_flush_data_to_buffer (png_structp png_ptr) -{ - // Nothing to do here -} + for(x=0; x < width; x++) + { + offset = tmpyWid + ((x >> 2)<<6) + ((tmpy2+ x%4 ) << 1); + tmpxy = x * 3 + tmpy1; -// Function used in YCbYCr to RGB decoding -int pngu_clamp (int value, int min, int max) -{ - if (value < min) - value = min; - else if (value > max) - value = max; - - return value; + tmpbuffer[tmpxy ] = ptr[offset+1]; // R + tmpbuffer[tmpxy+1] = ptr[offset+32]; // G + tmpbuffer[tmpxy+2] = ptr[offset+33]; // B + } + } + + res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride); + free(tmpbuffer); + return res; } diff --git a/source/ngc/pngu.h b/source/ngc/pngu.h index 192506b..4819fbc 100644 --- a/source/ngc/pngu.h +++ b/source/ngc/pngu.h @@ -1,38 +1,15 @@ /******************************************************************************************** - -PNGU Version : 0.2a - -Coder : frontier - -More info : http://frontier-dev.net - -Modified by Tantric, 2009 - +* +* PNGU +* +* Original author: frontier (http://frontier-dev.net) +* Modified by Tantric, 2009-2010 +* ********************************************************************************************/ + #ifndef __PNGU__ #define __PNGU__ -// Return codes -#define PNGU_OK 0 -#define PNGU_ODD_WIDTH 1 -#define PNGU_ODD_STRIDE 2 -#define PNGU_INVALID_WIDTH_OR_HEIGHT 3 -#define PNGU_FILE_IS_NOT_PNG 4 -#define PNGU_UNSUPPORTED_COLOR_TYPE 5 -#define PNGU_NO_FILE_SELECTED 6 -#define PNGU_CANT_OPEN_FILE 7 -#define PNGU_CANT_READ_FILE 8 -#define PNGU_LIB_ERROR 9 - -// Color types -#define PNGU_COLOR_TYPE_GRAY 1 -#define PNGU_COLOR_TYPE_GRAY_ALPHA 2 -#define PNGU_COLOR_TYPE_PALETTE 3 -#define PNGU_COLOR_TYPE_RGB 4 -#define PNGU_COLOR_TYPE_RGB_ALPHA 5 -#define PNGU_COLOR_TYPE_UNKNOWN 6 - - #ifdef __cplusplus extern "C" { #endif @@ -67,7 +44,7 @@ struct _IMGCTX; typedef struct _IMGCTX *IMGCTX; /**************************************************************************** -* Image context handling * +* Image context handling * ****************************************************************************/ // Selects a PNG file, previosly loaded into a buffer, and creates an image context for subsequent procesing. @@ -79,22 +56,18 @@ IMGCTX PNGU_SelectImageFromDevice (const char *filename); // Frees resources associated with an image context. Always call this function when you no longer need the IMGCTX. void PNGU_ReleaseImageContext (IMGCTX ctx); - /**************************************************************************** -* Miscelaneous * +* Miscellaneous * ****************************************************************************/ // Retrieves info from selected PNG file, including image dimensions, color format, background and transparency colors. int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *fileproperties); /**************************************************************************** -* Image conversion * +* Image conversion * ****************************************************************************/ -// Expands selected image into a 4x4 tiled RGBA8 buffer. You need to specify context, image dimensions, -// destination address and default alpha value, which is used if the source image doesn't have an alpha channel. -int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha); - +PNGU_u8 * DecodePNG(const PNGU_u8 *src, int *width, int *height); int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); @@ -103,4 +76,3 @@ int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void #endif #endif -