mirror of
https://gitlab.com/Nanolx/homebrewfilter.git
synced 2024-12-26 17:41:48 +01:00
updated PNGu
This commit is contained in:
parent
d31f2d5c88
commit
a024b3c93f
629
source/pngu.c
629
source/pngu.c
@ -6,23 +6,28 @@ Coder : frontier
|
||||
|
||||
More info : http://frontier-dev.net
|
||||
|
||||
Modified by Tantric, 2009
|
||||
|
||||
********************************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include "pngu.h"
|
||||
#include <stdlib.h>
|
||||
#include "png.h"
|
||||
#include "pngu.h"
|
||||
#include "pngu_impl.h"
|
||||
|
||||
#ifndef SAFE_FREE
|
||||
#define SAFE_FREE(p) if(p){free(p);p=NULL;}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// moved to pngu_impl.h
|
||||
// Constants
|
||||
#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);
|
||||
int pngu_decode_add_alpha (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha, int force32bit);
|
||||
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);
|
||||
@ -37,6 +42,7 @@ struct _IMGCTX
|
||||
void *buffer;
|
||||
char *filename;
|
||||
PNGU_u32 cursor;
|
||||
PNGU_u32 buf_size; // buffer size
|
||||
|
||||
PNGU_u32 propRead;
|
||||
PNGUPROP prop;
|
||||
@ -49,18 +55,19 @@ struct _IMGCTX
|
||||
png_bytep *row_pointers;
|
||||
png_bytep img_data;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// PNGU Implementation //
|
||||
|
||||
IMGCTX PNGU_SelectImageFromBuffer (const void *buffer)
|
||||
IMGCTX PNGU_SelectImageFromBufferX (const void *buffer, int size)
|
||||
{
|
||||
IMGCTX ctx = NULL;
|
||||
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
ctx = malloc (sizeof (struct _IMGCTX));
|
||||
ctx = calloc (sizeof (struct _IMGCTX), 1);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
@ -70,10 +77,16 @@ IMGCTX PNGU_SelectImageFromBuffer (const void *buffer)
|
||||
ctx->filename = NULL;
|
||||
ctx->propRead = 0;
|
||||
ctx->infoRead = 0;
|
||||
ctx->buf_size = size;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
IMGCTX PNGU_SelectImageFromBuffer (const void *buffer)
|
||||
{
|
||||
return PNGU_SelectImageFromBufferX(buffer, 0);
|
||||
}
|
||||
|
||||
|
||||
IMGCTX PNGU_SelectImageFromDevice (const char *filename)
|
||||
{
|
||||
@ -82,7 +95,7 @@ IMGCTX PNGU_SelectImageFromDevice (const char *filename)
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
ctx = malloc (sizeof (struct _IMGCTX));
|
||||
ctx = calloc (sizeof (struct _IMGCTX), 1);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
@ -685,6 +698,361 @@ int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *bu
|
||||
}
|
||||
|
||||
|
||||
//########################################################################################
|
||||
//---------- Start CMPR added section ---------------------------------------------------
|
||||
//########################################################################################
|
||||
|
||||
static inline PNGU_u16 rgb8ToRGB565(PNGU_u8 *color)
|
||||
{
|
||||
return ((color[0] >> 3) << 11) | ((color[1] >> 2) << 5) | (color[2] >> 3);
|
||||
}
|
||||
|
||||
static int colorDistance(const PNGU_u8 *c0, const PNGU_u8 *c1)
|
||||
{
|
||||
return (c1[0] - c0[0]) * (c1[0] - c0[0]) + (c1[1] - c0[1]) * (c1[1] - c0[1]) + (c1[2] - c0[2]) * (c1[2] - c0[2]);
|
||||
}
|
||||
|
||||
static void getBaseColors(PNGU_u8 *color0, PNGU_u8 *color1, const PNGU_u8 *srcBlock)
|
||||
{
|
||||
int maxDistance = -1;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < 15; ++i)
|
||||
for (j = i + 1; j < 16; ++j)
|
||||
{
|
||||
int distance = colorDistance(srcBlock + i * 4, srcBlock + j * 4);
|
||||
if (distance > maxDistance)
|
||||
{
|
||||
maxDistance = distance;
|
||||
*(PNGU_u32 *)color0 = ((PNGU_u32 *)srcBlock)[i];
|
||||
*(PNGU_u32 *)color1 = ((PNGU_u32 *)srcBlock)[j];
|
||||
}
|
||||
}
|
||||
if (rgb8ToRGB565(color0) < rgb8ToRGB565(color1))
|
||||
{
|
||||
PNGU_u32 tmp;
|
||||
tmp = *(PNGU_u32 *)color0;
|
||||
*(PNGU_u32 *)color0 = *(PNGU_u32 *)color1;
|
||||
*(PNGU_u32 *)color1 = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static PNGU_u32 colorIndices(const PNGU_u8 *color0, const PNGU_u8 *color1, const PNGU_u8 *srcBlock)
|
||||
{
|
||||
PNGU_u16 colors[4][4];
|
||||
PNGU_u32 res = 0;
|
||||
int i;
|
||||
|
||||
// Make the 4 colors available in the block
|
||||
colors[0][0] = (color0[0] & 0xF8) | (color0[0] >> 5);
|
||||
colors[0][1] = (color0[1] & 0xFC) | (color0[1] >> 6);
|
||||
colors[0][2] = (color0[2] & 0xF8) | (color0[2] >> 5);
|
||||
colors[1][0] = (color1[0] & 0xF8) | (color1[0] >> 5);
|
||||
colors[1][1] = (color1[1] & 0xFC) | (color1[1] >> 6);
|
||||
colors[1][2] = (color1[2] & 0xF8) | (color1[2] >> 5);
|
||||
colors[2][0] = (2 * colors[0][0] + 1 * colors[1][0]) / 3;
|
||||
colors[2][1] = (2 * colors[0][1] + 1 * colors[1][1]) / 3;
|
||||
colors[2][2] = (2 * colors[0][2] + 1 * colors[1][2]) / 3;
|
||||
colors[3][0] = (1 * colors[0][0] + 2 * colors[1][0]) / 3;
|
||||
colors[3][1] = (1 * colors[0][1] + 2 * colors[1][1]) / 3;
|
||||
colors[3][2] = (1 * colors[0][2] + 2 * colors[1][2]) / 3;
|
||||
for (i = 15; i >= 0; --i)
|
||||
{
|
||||
int c0 = srcBlock[i * 4 + 0];
|
||||
int c1 = srcBlock[i * 4 + 1];
|
||||
int c2 = srcBlock[i * 4 + 2];
|
||||
int d0 = abs(colors[0][0] - c0) + abs(colors[0][1] - c1) + abs(colors[0][2] - c2);
|
||||
int d1 = abs(colors[1][0] - c0) + abs(colors[1][1] - c1) + abs(colors[1][2] - c2);
|
||||
int d2 = abs(colors[2][0] - c0) + abs(colors[2][1] - c1) + abs(colors[2][2] - c2);
|
||||
int d3 = abs(colors[3][0] - c0) + abs(colors[3][1] - c1) + abs(colors[3][2] - c2);
|
||||
int b0 = d0 > d3;
|
||||
int b1 = d1 > d2;
|
||||
int b2 = d0 > d2;
|
||||
int b3 = d1 > d3;
|
||||
int b4 = d2 > d3;
|
||||
int x0 = b1 & b2;
|
||||
int x1 = b0 & b3;
|
||||
int x2 = b0 & b4;
|
||||
res |= (x2 | ((x0 | x1) << 1)) << ((15 - i) << 1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int PNGU_DecodeToCMPR_Trim(IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer)
|
||||
{
|
||||
int result;
|
||||
PNGU_u8 srcBlock[16 * 4];
|
||||
PNGU_u8 color0[4];
|
||||
PNGU_u8 color1[4];
|
||||
PNGU_u8 *outBuf = (PNGU_u8 *)buffer;
|
||||
int ii;
|
||||
int jj;
|
||||
int k;
|
||||
|
||||
//check for alpha channel
|
||||
result = pngu_decode_add_alpha (ctx, width, height, 0, 1);
|
||||
if (result != PNGU_OK)
|
||||
return result;
|
||||
|
||||
// trim down
|
||||
width = width & ~7u;
|
||||
height = height & ~7u;
|
||||
|
||||
// Alpha channel present, copy image to the output buffer
|
||||
for (jj = 0; jj < height; jj += 8)
|
||||
for (ii = 0; ii < width; ii += 8)
|
||||
for (k = 0; k < 4; ++k)
|
||||
{
|
||||
int j = jj + ((k >> 1) << 2); // jj + 0, jj + 0, jj + 4, jj + 4
|
||||
int i = ii + ((k & 1) << 2); // ii + 0, ii + 4, ii + 0, ii + 4
|
||||
memcpy(srcBlock, ctx->row_pointers[j] + i * 4, 16);
|
||||
memcpy(srcBlock + 4 * 4, ctx->row_pointers[j + 1] + i * 4, 16);
|
||||
memcpy(srcBlock + 8 * 4, ctx->row_pointers[j + 2] + i * 4, 16);
|
||||
memcpy(srcBlock + 12 * 4, ctx->row_pointers[j + 3] + i * 4, 16);
|
||||
getBaseColors(color0, color1, srcBlock);
|
||||
*(PNGU_u16 *)outBuf = rgb8ToRGB565(color0);
|
||||
outBuf += 2;
|
||||
*(PNGU_u16 *)outBuf = rgb8ToRGB565(color1);
|
||||
outBuf += 2;
|
||||
*(PNGU_u32 *)outBuf = colorIndices(color0, color1, srcBlock);
|
||||
outBuf += 4;
|
||||
}
|
||||
// Free resources
|
||||
free (ctx->img_data);
|
||||
free (ctx->row_pointers);
|
||||
|
||||
// Success
|
||||
return PNGU_OK;
|
||||
}
|
||||
|
||||
|
||||
// if width or height is not divisible by 8
|
||||
// then the remaining will be padded with last row/column
|
||||
// buffer must be allocated with width and height rounded up
|
||||
|
||||
int PNGU_DecodeToCMPR_Pad(IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer)
|
||||
{
|
||||
int result;
|
||||
PNGU_u8 srcBlock[16 * 4];
|
||||
PNGU_u8 color0[4];
|
||||
PNGU_u8 color1[4];
|
||||
PNGU_u8 *outBuf = (PNGU_u8 *)buffer;
|
||||
int ii;
|
||||
int jj;
|
||||
int k;
|
||||
|
||||
//check for alpha channel
|
||||
result = pngu_decode_add_alpha (ctx, width, height, 0, 1);
|
||||
if (result != PNGU_OK)
|
||||
return result;
|
||||
|
||||
// Alpha channel present, copy image to the output buffer
|
||||
for (jj = 0; jj < height; jj += 8) {
|
||||
for (ii = 0; ii < width; ii += 8) {
|
||||
for (k = 0; k < 4; ++k) {
|
||||
// k(i,j)
|
||||
// 0(0,0) 1(4,0)
|
||||
// 2(4,0) 3(4,4)
|
||||
int i = ii + ((k & 1) << 2); // ii + 0, ii + 4, ii + 0, ii + 4
|
||||
int j = jj + ((k >> 1) << 2); // jj + 0, jj + 0, jj + 4, jj + 4
|
||||
int ny; // 4 lines
|
||||
int px = 4; // num columns to copy
|
||||
if (i >= width) i = width - 1;
|
||||
if (i + px > width) px = width - i;
|
||||
for (ny=0; ny<4; ny++) {
|
||||
if (j >= height) j = height - 1;
|
||||
memcpy(srcBlock + ny * 4 * 4,
|
||||
ctx->row_pointers[j] + i * 4, px * 4);
|
||||
if (px < 4) {
|
||||
// repeat last column (4-px) times
|
||||
int x = width - 1;
|
||||
int nx;
|
||||
for (nx = px; nx < 4; nx++) {
|
||||
memcpy(srcBlock + ny * 4 * 4 + nx * 4,
|
||||
ctx->row_pointers[j] + x * 4, 4);
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
getBaseColors(color0, color1, srcBlock);
|
||||
*(PNGU_u16 *)outBuf = rgb8ToRGB565(color0);
|
||||
outBuf += 2;
|
||||
*(PNGU_u16 *)outBuf = rgb8ToRGB565(color1);
|
||||
outBuf += 2;
|
||||
*(PNGU_u32 *)outBuf = colorIndices(color0, color1, srcBlock);
|
||||
outBuf += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Free resources
|
||||
free (ctx->img_data);
|
||||
free (ctx->row_pointers);
|
||||
|
||||
// Success
|
||||
return PNGU_OK;
|
||||
}
|
||||
|
||||
void ExtractBlock( PNGU_u8 *inPtr, int y, int x, PNGU_u32 width, int i, PNGU_u8 colorBlock[] ) {
|
||||
PNGU_u32 offset;
|
||||
PNGU_u8 r, g, b, a;
|
||||
|
||||
offset = (((y >> 2)<<4)*width) + ((x >> 2)<<6) + ((((y&3) << 2) + (x&3) ) << 1);
|
||||
//offset = (((y >> 2) << 4)*width) + ((x >> 2) << 6) + (((y % 4 << 2) + x % 4) << 1);
|
||||
//get rgba values based on the RGBA8 offsets
|
||||
a = *(inPtr+offset);
|
||||
r = *(inPtr+offset+1);
|
||||
g = *(inPtr+offset+32);
|
||||
b = *(inPtr+offset+33);
|
||||
colorBlock[i*4] = r;
|
||||
colorBlock[i*4+1] = g;
|
||||
colorBlock[i*4+2] = b;
|
||||
colorBlock[i*4+3] = a;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* by usptactical
|
||||
* Converts a 4x4 RGBA8 image to CMPR.
|
||||
*/
|
||||
int PNGU_4x4RGBA8_To_CMPR(void *buf_rgb, PNGU_u32 width, PNGU_u32 height, void *buf_cmpr)
|
||||
{
|
||||
PNGU_u8 srcBlock[16 * 4];
|
||||
PNGU_u8 color0[4];
|
||||
PNGU_u8 color1[4];
|
||||
PNGU_u8 *outBuf = (PNGU_u8 *)buf_cmpr;
|
||||
PNGU_u8 *rgba = (PNGU_u8 *)buf_rgb;
|
||||
int jj, ii, i, j, k;
|
||||
|
||||
width = width & ~7u;
|
||||
height = height & ~7u;
|
||||
|
||||
// loop over blocks
|
||||
//CMPR needs 4x4 block of pixels:
|
||||
//image row 0: 0, 1, 2, 3 (first 16 block)
|
||||
//image row 1: 0, 1, 2, 3 (second 16 block)
|
||||
//image row 2: 0, 1, 2, 3 (third 16 block)
|
||||
//image row 3: 0, 1, 2, 3 (last 16 block)
|
||||
|
||||
//image row 0: 4, 5, 6, 7 (first 16 block)
|
||||
//image row 1: 4, 5, 6, 7 (second 16 block)
|
||||
//image row 2: 4, 5, 6, 7 (third 16 block)
|
||||
//image row 3: 4, 5, 6, 7 (last 16 block)
|
||||
|
||||
//image row 4: 0, 1, 2, 3 (first 16 block)
|
||||
//image row 5: 0, 1, 2, 3 (second 16 block)
|
||||
//image row 6: 0, 1, 2, 3 (third 16 block)
|
||||
//image row 7: 0, 1, 2, 3 (last 16 block)
|
||||
|
||||
//image row 4: 4, 5, 6, 7 (first 16 block)
|
||||
//image row 5: 4, 5, 6, 7 (second 16 block)
|
||||
//image row 6: 4, 5, 6, 7 (third 16 block)
|
||||
//image row 7: 4, 5, 6, 7 (last 16 block)
|
||||
|
||||
for(jj = 0; jj < height; jj += 8)
|
||||
for(ii = 0; ii < width; ii += 8)
|
||||
for (k=0; k < 4; k++)
|
||||
{
|
||||
j = jj + ((k >> 1) << 2); // jj + 0, jj + 0, jj + 4, jj + 4
|
||||
i = ii + ((k & 1) << 2); // ii + 0, ii + 4, ii + 0, ii + 4
|
||||
|
||||
ExtractBlock(rgba, j, i, width, 0, srcBlock);
|
||||
ExtractBlock(rgba, j, i+1, width, 1, srcBlock);
|
||||
ExtractBlock(rgba, j, i+2, width, 2, srcBlock);
|
||||
ExtractBlock(rgba, j, i+3, width, 3, srcBlock);
|
||||
|
||||
ExtractBlock(rgba, j+1, i, width, 4, srcBlock);
|
||||
ExtractBlock(rgba, j+1, i+1, width, 5, srcBlock);
|
||||
ExtractBlock(rgba, j+1, i+2, width, 6, srcBlock);
|
||||
ExtractBlock(rgba, j+1, i+3, width, 7, srcBlock);
|
||||
|
||||
ExtractBlock(rgba, j+2, i, width, 8, srcBlock);
|
||||
ExtractBlock(rgba, j+2, i+1, width, 9, srcBlock);
|
||||
ExtractBlock(rgba, j+2, i+2, width, 10, srcBlock);
|
||||
ExtractBlock(rgba, j+2, i+3, width, 11, srcBlock);
|
||||
|
||||
ExtractBlock(rgba, j+3, i, width, 12, srcBlock);
|
||||
ExtractBlock(rgba, j+3, i+1, width, 13, srcBlock);
|
||||
ExtractBlock(rgba, j+3, i+2, width, 14, srcBlock);
|
||||
ExtractBlock(rgba, j+3, i+3, width, 15, srcBlock);
|
||||
|
||||
getBaseColors(color0, color1, srcBlock);
|
||||
*(PNGU_u16 *)outBuf = rgb8ToRGB565(color0);
|
||||
outBuf += 2;
|
||||
*(PNGU_u16 *)outBuf = rgb8ToRGB565(color1);
|
||||
outBuf += 2;
|
||||
*(PNGU_u32 *)outBuf = colorIndices(color0, color1, srcBlock);
|
||||
outBuf += 4;
|
||||
}
|
||||
// Success
|
||||
return PNGU_OK;
|
||||
}
|
||||
|
||||
// if width or height is not divisible by 8
|
||||
// then the remaining will be padded with last row/column
|
||||
// buffer must be allocated with width and height rounded up
|
||||
int PNGU_RGBA8_To_CMPR(void *buf_rgb, PNGU_u32 width, PNGU_u32 height, void *buf_cmpr)
|
||||
{
|
||||
PNGU_u8 srcBlock[16 * 4];
|
||||
PNGU_u8 color0[4];
|
||||
PNGU_u8 color1[4];
|
||||
PNGU_u8 *src, *block;
|
||||
PNGU_u8 *cmpr = (PNGU_u8 *)buf_cmpr;
|
||||
PNGU_u8 *rgba = (PNGU_u8 *)buf_rgb;
|
||||
int jj, ii, i, j, k;
|
||||
int x, y; // counter
|
||||
int px, py; // pixel coord
|
||||
|
||||
for(jj = 0; jj < height; jj += 8) {
|
||||
for(ii = 0; ii < width; ii += 8) {
|
||||
for (k=0; k < 4; k++) {
|
||||
i = ii + ((k & 1) << 2); // ii + 0, ii + 4, ii + 0, ii + 4
|
||||
j = jj + ((k >> 1) << 2); // jj + 0, jj + 0, jj + 4, jj + 4
|
||||
|
||||
block = srcBlock;
|
||||
for (y=0; y<4; y++) {
|
||||
py = j + y;
|
||||
if (py >= height) py = height - 1;
|
||||
src = rgba + py * width * 4;
|
||||
for (x=0; x<4; x++) {
|
||||
px = i + x;
|
||||
if (px >= width) px = width - 1;
|
||||
memcpy(block, src + px * 4, 4);
|
||||
block += 4;
|
||||
}
|
||||
}
|
||||
|
||||
getBaseColors(color0, color1, srcBlock);
|
||||
*(PNGU_u16 *)cmpr = rgb8ToRGB565(color0);
|
||||
cmpr += 2;
|
||||
*(PNGU_u16 *)cmpr = rgb8ToRGB565(color1);
|
||||
cmpr += 2;
|
||||
*(PNGU_u32 *)cmpr = colorIndices(color0, color1, srcBlock);
|
||||
cmpr += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Success
|
||||
return PNGU_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* added by usptactical
|
||||
* handles png error messages
|
||||
*/
|
||||
void user_error (png_structp png_ptr, png_const_charp c)
|
||||
{
|
||||
longjmp(png_jmpbuf(png_ptr), 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//########################################################################################
|
||||
//---------- End CMPR added section -----------------------------------------------------
|
||||
//########################################################################################
|
||||
|
||||
|
||||
int PNGU_EncodeFromYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride)
|
||||
{
|
||||
png_uint_32 rowbytes;
|
||||
@ -709,21 +1077,21 @@ int PNGU_EncodeFromYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *bu
|
||||
|
||||
// Allocation of libpng structs
|
||||
ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!(ctx->png_ptr))
|
||||
if (!(ctx->png_ptr))
|
||||
{
|
||||
if (ctx->source == PNGU_SOURCE_DEVICE)
|
||||
fclose (ctx->fd);
|
||||
return PNGU_LIB_ERROR;
|
||||
return PNGU_LIB_ERROR;
|
||||
}
|
||||
|
||||
ctx->info_ptr = png_create_info_struct (ctx->png_ptr);
|
||||
if (!(ctx->info_ptr))
|
||||
{
|
||||
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;
|
||||
}
|
||||
return PNGU_LIB_ERROR;
|
||||
}
|
||||
|
||||
if (ctx->source == PNGU_SOURCE_BUFFER)
|
||||
{
|
||||
@ -738,7 +1106,7 @@ int PNGU_EncodeFromYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *bu
|
||||
}
|
||||
|
||||
// Setup output file properties
|
||||
png_set_IHDR (ctx->png_ptr, ctx->info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
|
||||
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
|
||||
@ -797,138 +1165,6 @@ int PNGU_EncodeFromYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *bu
|
||||
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 / 4) + 1) * 4; // 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 x,y,res;
|
||||
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++)
|
||||
{
|
||||
for(x=0; x < width; x++)
|
||||
{
|
||||
offset = (((y >> 2)<<4)*width) + ((x >> 2)<<6) + (((y%4 << 2) + x%4 ) << 1);
|
||||
|
||||
tmpbuffer[y*640*3+x*3] = ptr[offset+1]; // R
|
||||
tmpbuffer[y*640*3+x*3+1] = ptr[offset+32]; // G
|
||||
tmpbuffer[y*640*3+x*3+2] = ptr[offset+33]; // B
|
||||
}
|
||||
}
|
||||
|
||||
res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride);
|
||||
free(tmpbuffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
// This function is taken from a libogc example
|
||||
PNGU_u32 PNGU_RGB8_TO_YCbYCr (PNGU_u8 r1, PNGU_u8 g1, PNGU_u8 b1, PNGU_u8 r2, PNGU_u8 g2, PNGU_u8 b2)
|
||||
@ -990,7 +1226,7 @@ int pngu_info (IMGCTX ctx)
|
||||
return PNGU_CANT_OPEN_FILE;
|
||||
|
||||
// Load first 8 bytes into magic buffer
|
||||
if (fread (magic, 1, 8, ctx->fd) != 8)
|
||||
if (fread (magic, 1, 8, ctx->fd) != 8)
|
||||
{
|
||||
fclose (ctx->fd);
|
||||
return PNGU_CANT_READ_FILE;
|
||||
@ -1009,21 +1245,21 @@ int pngu_info (IMGCTX ctx)
|
||||
|
||||
// Allocation of libpng structs
|
||||
ctx->png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!(ctx->png_ptr))
|
||||
if (!(ctx->png_ptr))
|
||||
{
|
||||
if (ctx->source == PNGU_SOURCE_DEVICE)
|
||||
fclose (ctx->fd);
|
||||
return PNGU_LIB_ERROR;
|
||||
return PNGU_LIB_ERROR;
|
||||
}
|
||||
|
||||
ctx->info_ptr = png_create_info_struct (ctx->png_ptr);
|
||||
if (!(ctx->info_ptr))
|
||||
{
|
||||
ctx->info_ptr = png_create_info_struct (ctx->png_ptr);
|
||||
if (!(ctx->info_ptr))
|
||||
{
|
||||
if (ctx->source == PNGU_SOURCE_DEVICE)
|
||||
fclose (ctx->fd);
|
||||
png_destroy_read_struct (&(ctx->png_ptr), (png_infopp)NULL, (png_infopp)NULL);
|
||||
return PNGU_LIB_ERROR;
|
||||
}
|
||||
png_destroy_read_struct (&(ctx->png_ptr), (png_infopp)NULL, (png_infopp)NULL);
|
||||
return PNGU_LIB_ERROR;
|
||||
}
|
||||
|
||||
if (ctx->source == PNGU_SOURCE_BUFFER)
|
||||
{
|
||||
@ -1140,10 +1376,15 @@ int pngu_info (IMGCTX ctx)
|
||||
}
|
||||
|
||||
|
||||
int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha)
|
||||
int pngu_decode_add_alpha (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha, int force32bit)
|
||||
{
|
||||
png_uint_32 rowbytes;
|
||||
int i;
|
||||
int chunk;
|
||||
int rowsLeft;
|
||||
png_bytep *curRow;
|
||||
int mem_err = 0;
|
||||
|
||||
|
||||
// Read info if it hasn't been read before
|
||||
if (!ctx->infoRead)
|
||||
@ -1161,22 +1402,43 @@ int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlph
|
||||
if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_PALETTE) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_UNKNOWN) )
|
||||
return PNGU_UNSUPPORTED_COLOR_TYPE;
|
||||
|
||||
//*************************************************
|
||||
//* added by usptactical to catch corrupted pngs *
|
||||
jmp_buf save_jmp;
|
||||
memcpy(save_jmp, png_jmpbuf(ctx->png_ptr), sizeof(save_jmp));
|
||||
if (setjmp(png_jmpbuf(ctx->png_ptr))) {
|
||||
error:
|
||||
memcpy(png_jmpbuf(ctx->png_ptr), save_jmp, sizeof(save_jmp));
|
||||
SAFE_FREE(ctx->row_pointers);
|
||||
SAFE_FREE(ctx->img_data);
|
||||
pngu_free_info (ctx);
|
||||
//printf("*** This is a corrupted image!!\n"); sleep(5);
|
||||
return (mem_err)?PNGU_LIB_ERROR:-666;
|
||||
}
|
||||
//override default error handler to suppress warning messages from libpng
|
||||
png_set_error_fn (ctx->png_ptr, NULL, user_error, user_error);
|
||||
//*************************************************
|
||||
|
||||
// Scale 16 bit samples to 8 bit
|
||||
if (ctx->prop.imgBitDepth == 16)
|
||||
png_set_strip_16 (ctx->png_ptr);
|
||||
png_set_strip_16 (ctx->png_ptr);
|
||||
|
||||
// Remove alpha channel if we don't need it
|
||||
if (stripAlpha && ((ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA)))
|
||||
png_set_strip_alpha (ctx->png_ptr);
|
||||
png_set_strip_alpha (ctx->png_ptr);
|
||||
|
||||
// Expand 1, 2 and 4 bit samples to 8 bit
|
||||
if (ctx->prop.imgBitDepth < 8)
|
||||
png_set_packing (ctx->png_ptr);
|
||||
png_set_packing (ctx->png_ptr);
|
||||
|
||||
// Transform grayscale images to RGB
|
||||
if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) )
|
||||
png_set_gray_to_rgb (ctx->png_ptr);
|
||||
|
||||
// Transform RBG images to RGBA
|
||||
if (force32bit && (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY || ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB))
|
||||
png_set_filler(ctx->png_ptr, 0xFF, PNG_FILLER_AFTER);
|
||||
|
||||
// Flush transformations
|
||||
png_read_update_info (ctx->png_ptr, ctx->info_ptr);
|
||||
|
||||
@ -1188,23 +1450,44 @@ int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlph
|
||||
ctx->img_data = malloc (rowbytes * ctx->prop.imgHeight);
|
||||
if (!ctx->img_data)
|
||||
{
|
||||
pngu_free_info (ctx);
|
||||
return PNGU_LIB_ERROR;
|
||||
//pngu_free_info (ctx);
|
||||
//return PNGU_LIB_ERROR;
|
||||
mem_err = 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ctx->row_pointers = malloc (sizeof (png_bytep) * ctx->prop.imgHeight);
|
||||
if (!ctx->row_pointers)
|
||||
{
|
||||
free (ctx->img_data);
|
||||
pngu_free_info (ctx);
|
||||
return PNGU_LIB_ERROR;
|
||||
//free (ctx->img_data);
|
||||
//pngu_free_info (ctx);
|
||||
//return PNGU_LIB_ERROR;
|
||||
mem_err = 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < ctx->prop.imgHeight; i++)
|
||||
for (i = 0; i < (int)ctx->prop.imgHeight; i++)
|
||||
ctx->row_pointers[i] = ctx->img_data + (i * rowbytes);
|
||||
|
||||
// Transform the image and copy it to our allocated memory
|
||||
png_read_image (ctx->png_ptr, ctx->row_pointers);
|
||||
if (png_get_interlace_type(ctx->png_ptr, ctx->info_ptr) != PNG_INTERLACE_NONE)
|
||||
png_read_image (ctx->png_ptr, ctx->row_pointers);
|
||||
else
|
||||
{
|
||||
rowsLeft = ctx->prop.imgHeight;
|
||||
curRow = ctx->row_pointers;
|
||||
while (rowsLeft > 0)
|
||||
{
|
||||
chunk = rowsLeft > 0x80 ? 0x80 : rowsLeft;
|
||||
png_read_rows(ctx->png_ptr, curRow, NULL, chunk);
|
||||
//usleep(1000);
|
||||
curRow += chunk;
|
||||
rowsLeft -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
// restore default error handling
|
||||
memcpy(png_jmpbuf(ctx->png_ptr), save_jmp, sizeof(save_jmp));
|
||||
|
||||
// Free resources
|
||||
pngu_free_info (ctx);
|
||||
@ -1213,6 +1496,11 @@ int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlph
|
||||
return PNGU_OK;
|
||||
}
|
||||
|
||||
int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha)
|
||||
{
|
||||
return pngu_decode_add_alpha(ctx, width, height, stripAlpha, 0);
|
||||
}
|
||||
|
||||
|
||||
void pngu_free_info (IMGCTX ctx)
|
||||
{
|
||||
@ -1232,6 +1520,13 @@ void pngu_free_info (IMGCTX ctx)
|
||||
void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr);
|
||||
if (ctx->buf_size && (ctx->cursor + length > ctx->buf_size))
|
||||
{
|
||||
static char err_str[40];
|
||||
snprintf(err_str, sizeof(err_str), "read error (%x/%x)",
|
||||
ctx->cursor + length, ctx->buf_size);
|
||||
png_error(png_ptr, err_str);
|
||||
}
|
||||
memcpy (data, ctx->buffer + ctx->cursor, length);
|
||||
ctx->cursor += length;
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ Coder : frontier
|
||||
|
||||
More info : http://frontier-dev.net
|
||||
|
||||
Modified by Tantric, 2009
|
||||
|
||||
********************************************************************************************/
|
||||
#ifndef __PNGU__
|
||||
#define __PNGU__
|
||||
@ -92,6 +90,7 @@ void PNGU_YCbYCr_TO_RGB8 (PNGU_u32 ycbycr, PNGU_u8 *r1, PNGU_u8 *g1, PNGU_u8 *b1
|
||||
|
||||
// Selects a PNG file, previosly loaded into a buffer, and creates an image context for subsequent procesing.
|
||||
IMGCTX PNGU_SelectImageFromBuffer (const void *buffer);
|
||||
IMGCTX PNGU_SelectImageFromBufferX (const void *buffer, int size);
|
||||
|
||||
// Selects a PNG file, from any devoptab device, and creates an image context for subsequent procesing.
|
||||
IMGCTX PNGU_SelectImageFromDevice (const char *filename);
|
||||
@ -140,12 +139,17 @@ int PNGU_DecodeToRGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffe
|
||||
// Macro for decoding an image inside a buffer at given coordinates.
|
||||
#define PNGU_DECODE_TO_COORDS_RGBA8(ctx,coordX,coordY,imgWidth,imgHeight,default_alpha,bufferWidth,bufferHeight,buffer) \
|
||||
\
|
||||
PNGU_DecodeToRGBA8 (ctx, imgWidth, imgHeight, ((void *) buffer) + (coordY) * (bufferWidth) * 2 + \
|
||||
(coordX) * 2, (bufferWidth) - (imgWidth), default_alpha)
|
||||
PNGU_DecodeToRGBA8 (ctx, imgWidth, imgHeight, ((void *) buffer) + (coordY) * (bufferWidth) * 4 + \
|
||||
(coordX) * 4, (bufferWidth) - (imgWidth), default_alpha)
|
||||
|
||||
// Expands selected image into a 4x4 tiled RGB565 buffer. You need to specify context, image dimensions
|
||||
// and destination address.
|
||||
int PNGU_DecodeTo4x4RGB565 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer);
|
||||
// Compressed version (DXT1/CMPR)
|
||||
int PNGU_DecodeToCMPR_Trim(IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer);
|
||||
int PNGU_DecodeToCMPR_Pad(IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer);
|
||||
int PNGU_4x4RGBA8_To_CMPR(void *buf_rgb, PNGU_u32 width, PNGU_u32 height, void *buf_cmpr);
|
||||
int PNGU_RGBA8_To_CMPR(void *buf_rgb, PNGU_u32 width, PNGU_u32 height, void *buf_cmpr);
|
||||
|
||||
// Expands selected image into a 4x4 tiled RGB5A3 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.
|
||||
@ -159,15 +163,16 @@ int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *bu
|
||||
// specify context, image dimensions, destination address and stride in pixels (stride = buffer width - image width).
|
||||
int PNGU_EncodeFromYCbYCr (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);
|
||||
|
||||
// Macro for encoding an image stored into an YCbYCr buffer at given coordinates.
|
||||
#define PNGU_ENCODE_TO_COORDS_YCbYCr(ctx,coordX,coordY,imgWidth,imgHeight,bufferWidth,bufferHeight,buffer) \
|
||||
\
|
||||
PNGU_EncodeFromYCbYCr (ctx, imgWidth, imgHeight, ((void *) buffer) + (coordY) * (bufferWidth) * 2 + \
|
||||
(coordX) * 2, (bufferWidth) - (imgWidth))
|
||||
|
||||
PNGU_u8 * PNGU_DecodeTo4x4RGBA8_EX (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, int * dstWidth, int * dstHeight, PNGU_u8 *dstPtr);
|
||||
|
||||
int PNGU_EncodeFromEFB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stride);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user