mirror of
https://github.com/dborth/vbagx.git
synced 2024-11-29 05:54:17 +01:00
new font, rewritten PNGU, menu tweaks, optimized text code
This commit is contained in:
parent
5166ca2b61
commit
c926152762
Binary file not shown.
@ -109,7 +109,7 @@ GuiFileBrowser::GuiFileBrowser(int w, int h)
|
|||||||
fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff});
|
fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff});
|
||||||
fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||||
fileListText[i]->SetPosition(5,0);
|
fileListText[i]->SetPosition(5,0);
|
||||||
fileListText[i]->SetMaxWidth(380);
|
fileListText[i]->SetMaxWidth(450);
|
||||||
|
|
||||||
fileListBg[i] = new GuiImage(bgFileSelectionEntry);
|
fileListBg[i] = new GuiImage(bgFileSelectionEntry);
|
||||||
fileListIcon[i] = NULL;
|
fileListIcon[i] = NULL;
|
||||||
|
@ -20,40 +20,7 @@ GuiImageData::GuiImageData(const u8 * i)
|
|||||||
height = 0;
|
height = 0;
|
||||||
|
|
||||||
if(i)
|
if(i)
|
||||||
{
|
data = DecodePNG(i, &width, &height);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -238,56 +238,17 @@ void GuiText::Draw()
|
|||||||
currentSize = newSize;
|
currentSize = newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(maxWidth > 0)
|
u8 maxChar;
|
||||||
{
|
|
||||||
char * tmpText = strdup(origText);
|
|
||||||
u8 maxChar = int((float((maxWidth<<1))) / (float(newSize)));
|
|
||||||
|
|
||||||
if(!textDyn)
|
if(maxWidth == 0)
|
||||||
{
|
{
|
||||||
if(strlen(tmpText) > maxChar)
|
fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), text, c, style);
|
||||||
tmpText[maxChar] = 0;
|
goto done;
|
||||||
textDyn = charToWideChar(tmpText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(textScroll == SCROLL_HORIZONTAL)
|
maxChar = int((float((maxWidth<<1))) / (float(newSize))); // approximate
|
||||||
{
|
|
||||||
int textlen = strlen(origText);
|
|
||||||
|
|
||||||
if(textlen > maxChar && (FrameTimer % textScrollDelay == 0))
|
if(wrap)
|
||||||
{
|
|
||||||
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 lineheight = newSize + 6;
|
||||||
int txtlen = wcslen(text);
|
int txtlen = wcslen(text);
|
||||||
@ -347,16 +308,59 @@ void GuiText::Draw()
|
|||||||
fontSystem[currentSize]->drawText(left, top+i*lineheight, textrow[i], c, style);
|
fontSystem[currentSize]->drawText(left, top+i*lineheight, textrow[i], c, style);
|
||||||
delete[] textrow[i];
|
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
|
else
|
||||||
{
|
{
|
||||||
fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style);
|
++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(tmpText);
|
||||||
|
free(tmpText2);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if(!textDyn)
|
||||||
{
|
{
|
||||||
fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), text, c, style);
|
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();
|
this->UpdateEffects();
|
||||||
}
|
}
|
||||||
|
@ -3472,7 +3472,7 @@ static int MenuSettingsNetwork()
|
|||||||
GuiOptionBrowser optionBrowser(552, 248, &options);
|
GuiOptionBrowser optionBrowser(552, 248, &options);
|
||||||
optionBrowser.SetPosition(0, 108);
|
optionBrowser.SetPosition(0, 108);
|
||||||
optionBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
optionBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||||
optionBrowser.SetCol2Position(275);
|
optionBrowser.SetCol2Position(290);
|
||||||
|
|
||||||
HaltGui();
|
HaltGui();
|
||||||
GuiWindow w(screenwidth, screenheight);
|
GuiWindow w(screenwidth, screenheight);
|
||||||
|
@ -1,31 +1,41 @@
|
|||||||
/********************************************************************************************
|
/********************************************************************************************
|
||||||
|
*
|
||||||
PNGU Version : 0.2a
|
* PNGU
|
||||||
|
*
|
||||||
Coder : frontier
|
* Original author: frontier (http://frontier-dev.net)
|
||||||
|
* Modified by Tantric, 2009-2010
|
||||||
More info : http://frontier-dev.net
|
*
|
||||||
|
|
||||||
Modified by Tantric, 2009
|
|
||||||
|
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <gccore.h>
|
||||||
#include "pngu.h"
|
#include "pngu.h"
|
||||||
#include "png.h"
|
#include <png.h>
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
#define PNGU_SOURCE_BUFFER 1
|
#define PNGU_SOURCE_BUFFER 1
|
||||||
#define PNGU_SOURCE_DEVICE 2
|
#define PNGU_SOURCE_DEVICE 2
|
||||||
|
|
||||||
// Prototypes of helper functions
|
// Return codes
|
||||||
int pngu_info (IMGCTX ctx);
|
#define PNGU_OK 0
|
||||||
int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha);
|
#define PNGU_ODD_WIDTH 1
|
||||||
void pngu_free_info (IMGCTX ctx);
|
#define PNGU_ODD_STRIDE 2
|
||||||
void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length);
|
#define PNGU_INVALID_WIDTH_OR_HEIGHT 3
|
||||||
void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length);
|
#define PNGU_FILE_IS_NOT_PNG 4
|
||||||
void pngu_flush_data_to_buffer (png_structp png_ptr);
|
#define PNGU_UNSUPPORTED_COLOR_TYPE 5
|
||||||
int pngu_clamp (int value, int min, int max);
|
#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
|
// PNGU Image context struct
|
||||||
struct _IMGCTX
|
struct _IMGCTX
|
||||||
@ -49,362 +59,42 @@ struct _IMGCTX
|
|||||||
|
|
||||||
// PNGU Implementation
|
// PNGU Implementation
|
||||||
|
|
||||||
IMGCTX PNGU_SelectImageFromBuffer (const void *buffer)
|
static void pngu_free_info (IMGCTX ctx)
|
||||||
{
|
{
|
||||||
IMGCTX ctx = NULL;
|
if (ctx->infoRead)
|
||||||
|
{
|
||||||
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
||||||
|
fclose (ctx->fd);
|
||||||
|
|
||||||
if (!buffer)
|
png_destroy_read_struct (&(ctx->png_ptr), &(ctx->info_ptr), (png_infopp)NULL);
|
||||||
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;
|
ctx->infoRead = 0;
|
||||||
|
}
|
||||||
return ctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IMGCTX PNGU_SelectImageFromDevice (const char *filename)
|
// 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)
|
||||||
{
|
{
|
||||||
IMGCTX ctx = NULL;
|
IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr);
|
||||||
|
memcpy (data, ctx->buffer + ctx->cursor, length);
|
||||||
|
ctx->cursor += length;
|
||||||
|
}
|
||||||
|
|
||||||
if (!filename)
|
// Custom data writer function used for writing to memory buffers.
|
||||||
return NULL;
|
static void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length)
|
||||||
|
|
||||||
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);
|
IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr);
|
||||||
return NULL;
|
memcpy (ctx->buffer + ctx->cursor, data, length);
|
||||||
}
|
ctx->cursor += length;
|
||||||
strcpy(ctx->filename, filename);
|
|
||||||
|
|
||||||
ctx->propRead = 0;
|
|
||||||
ctx->infoRead = 0;
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PNGU_ReleaseImageContext (IMGCTX ctx)
|
// Custom data flusher function used for writing to memory buffers.
|
||||||
|
static void pngu_flush_data_to_buffer (png_structp png_ptr)
|
||||||
{
|
{
|
||||||
if (!ctx)
|
// Nothing to do here
|
||||||
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)
|
static int pngu_info (IMGCTX ctx)
|
||||||
{
|
|
||||||
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->source == PNGU_SOURCE_DEVICE)
|
|
||||||
fclose (ctx->fd);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pngu_info (IMGCTX ctx)
|
|
||||||
{
|
{
|
||||||
png_byte magic[8];
|
png_byte magic[8];
|
||||||
png_uint_32 width;
|
png_uint_32 width;
|
||||||
@ -604,7 +294,7 @@ int pngu_info (IMGCTX ctx)
|
|||||||
return PNGU_OK;
|
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 rowbytes;
|
||||||
png_uint_32 i, propImgHeight;
|
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;
|
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)
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
||||||
fclose (ctx->fd);
|
fclose (ctx->fd);
|
||||||
|
return PNGU_LIB_ERROR;
|
||||||
png_destroy_read_struct (&(ctx->png_ptr), &(ctx->info_ptr), (png_infopp)NULL);
|
|
||||||
|
|
||||||
ctx->infoRead = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom data provider function used for reading from memory buffers.
|
ctx->info_ptr = png_create_info_struct (ctx->png_ptr);
|
||||||
void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length)
|
if (!(ctx->info_ptr))
|
||||||
{
|
{
|
||||||
IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr);
|
png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL);
|
||||||
memcpy (data, ctx->buffer + ctx->cursor, length);
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
||||||
ctx->cursor += length;
|
fclose (ctx->fd);
|
||||||
|
return PNGU_LIB_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom data writer function used for writing to memory buffers.
|
if (ctx->source == PNGU_SOURCE_BUFFER)
|
||||||
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);
|
// Installation of our custom data writer function
|
||||||
memcpy (ctx->buffer + ctx->cursor, data, length);
|
ctx->cursor = 0;
|
||||||
ctx->cursor += length;
|
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)
|
||||||
// Custom data flusher function used for writing to memory buffers.
|
|
||||||
void pngu_flush_data_to_buffer (png_structp png_ptr)
|
|
||||||
{
|
{
|
||||||
// Nothing to do here
|
// Default data writer uses function fwrite, so it needs to use our FILE*
|
||||||
|
png_init_io (ctx->png_ptr, ctx->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function used in YCbYCr to RGB decoding
|
// Setup output file properties
|
||||||
int pngu_clamp (int value, int min, int max)
|
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)
|
||||||
{
|
{
|
||||||
if (value < min)
|
png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL);
|
||||||
value = min;
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
||||||
else if (value > max)
|
fclose (ctx->fd);
|
||||||
value = max;
|
return PNGU_LIB_ERROR;
|
||||||
|
}
|
||||||
return value;
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,15 @@
|
|||||||
/********************************************************************************************
|
/********************************************************************************************
|
||||||
|
*
|
||||||
PNGU Version : 0.2a
|
* PNGU
|
||||||
|
*
|
||||||
Coder : frontier
|
* Original author: frontier (http://frontier-dev.net)
|
||||||
|
* Modified by Tantric, 2009-2010
|
||||||
More info : http://frontier-dev.net
|
*
|
||||||
|
|
||||||
Modified by Tantric, 2009
|
|
||||||
|
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
|
|
||||||
#ifndef __PNGU__
|
#ifndef __PNGU__
|
||||||
#define __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
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -79,9 +56,8 @@ IMGCTX PNGU_SelectImageFromDevice (const char *filename);
|
|||||||
// Frees resources associated with an image context. Always call this function when you no longer need the IMGCTX.
|
// Frees resources associated with an image context. Always call this function when you no longer need the IMGCTX.
|
||||||
void PNGU_ReleaseImageContext (IMGCTX ctx);
|
void PNGU_ReleaseImageContext (IMGCTX ctx);
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Miscelaneous *
|
* Miscellaneous *
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
// Retrieves info from selected PNG file, including image dimensions, color format, background and transparency colors.
|
// Retrieves info from selected PNG file, including image dimensions, color format, background and transparency colors.
|
||||||
@ -91,10 +67,7 @@ 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,
|
PNGU_u8 * DecodePNG(const PNGU_u8 *src, int *width, int *height);
|
||||||
// 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);
|
|
||||||
|
|
||||||
int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride);
|
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);
|
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
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user