Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Features
uPNG supports loading and decoding PNG images into a simple byte buffer, suitable
for passing directly to OpenGL as texture data.

uPNG does NOT support interlaced images, paletted images, and fixed-transparency.
uPNG does NOT support interlaced images, and fixed-transparency.
Checksums are NOT verified and corrupt image data may be undetected.

It DOES support RGB, RGBA, greyscale, and greyscale-with-alpha images. RGB and
Expand Down Expand Up @@ -106,8 +106,16 @@ The formats supported are:
UPNG_RGB16 48-bit RGB
UPNG_RGBA8 32-bit RGBA
UPNG_RGBA16 64-bit RGBA
UPNG_LUMINANCE1 1-bit Greyscale
UPNG_LUMINANCE2 2-bit Greyscale
UPNG_LUMINANCE4 4-bit Greyscale
UPNG_LUMINANCE8 8-bit Greyscale
UPNG_LUMINANCEA8 8-bit Greyscale w/ 8-bit Alpha
UPNG_INDEX1 1-bit 2 Color RGB INDEX Color Palette
UPNG_INDEX2 2-bit 4 Color RGB INDEX Color Palette
UPNG_INDEX4 4-bit 16 Color RGB INDEX Color Palette
UPNG_INDEX8 8-bit 256 Color RGB INDEX Color Palette
(Now uPNG support paletted images !)

Possible error states are:

Expand Down
61 changes: 56 additions & 5 deletions upng.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ freely, subject to the following restrictions:
#define CHUNK_IHDR MAKE_DWORD('I','H','D','R')
#define CHUNK_IDAT MAKE_DWORD('I','D','A','T')
#define CHUNK_IEND MAKE_DWORD('I','E','N','D')
#define CHUNK_PLTE MAKE_DWORD('P','L','T','E')

#define FIRST_LENGTH_CODE_INDEX 257
#define LAST_LENGTH_CODE_INDEX 285
Expand Down Expand Up @@ -72,6 +73,7 @@ typedef enum upng_state {
typedef enum upng_color {
UPNG_LUM = 0,
UPNG_RGB = 2,
UPNG_INDX = 3,
UPNG_LUMA = 4,
UPNG_RGBA = 6
} upng_color;
Expand All @@ -93,6 +95,8 @@ struct upng_t {
unsigned char* buffer;
unsigned long size;

unsigned char* palette;

upng_error error;
unsigned error_line;

Expand Down Expand Up @@ -876,6 +880,19 @@ static upng_format determine_format(upng_t* upng) {
default:
return UPNG_BADFORMAT;
}
case UPNG_INDX:
switch (upng->color_depth) {
case 1:
return UPNG_INDEX1;
case 2:
return UPNG_INDEX2;
case 4:
return UPNG_INDEX4;
case 8:
return UPNG_INDEX8;
default:
return UPNG_BADFORMAT;
}
default:
return UPNG_BADFORMAT;
}
Expand Down Expand Up @@ -966,7 +983,9 @@ upng_error upng_decode(upng_t* upng)
const unsigned char *chunk;
unsigned char* compressed;
unsigned char* inflated;
unsigned char* palette = NULL;
unsigned long compressed_size = 0, compressed_index = 0;
unsigned long palette_size = 0;
unsigned long inflated_size;
upng_error error;

Expand Down Expand Up @@ -1000,7 +1019,7 @@ upng_error upng_decode(upng_t* upng)
* verify general well-formed-ness */
while (chunk < upng->source.buffer + upng->source.size) {
unsigned long length;
const unsigned char *data; /*the data in the chunk */
// const unsigned char *data; /*the data in the chunk */

/* make sure chunk header is not larger than the total compressed */
if ((unsigned long)(chunk - upng->source.buffer + 12) > upng->source.size) {
Expand All @@ -1022,19 +1041,21 @@ upng_error upng_decode(upng_t* upng)
}

/* get pointer to payload */
data = chunk + 8;
// data = chunk + 8;

/* parse chunks */
if (upng_chunk_type(chunk) == CHUNK_IDAT) {
compressed_size += length;
} else if (upng_chunk_type(chunk) == CHUNK_PLTE) {
palette_size = length;
} else if (upng_chunk_type(chunk) == CHUNK_IEND) {
break;
} else if (upng_chunk_critical(chunk)) {
SET_ERROR(upng, UPNG_EUNSUPPORTED);
return upng->error;
}

chunk += upng_chunk_length(chunk) + 12;
chunk += length + 12;
}

/* allocate enough space for the (compressed and filtered) image data */
Expand All @@ -1044,6 +1065,15 @@ upng_error upng_decode(upng_t* upng)
return upng->error;
}

if (palette_size) {
palette = (unsigned char*)malloc(palette_size);
if (palette == NULL) {
free(compressed);
SET_ERROR(upng, UPNG_ENOMEM);
return upng->error;
}
}

/* scan through the chunks again, this time copying the values into
* our compressed buffer. there's no reason to validate anything a second time. */
chunk = upng->source.buffer + 33;
Expand All @@ -1052,23 +1082,27 @@ upng_error upng_decode(upng_t* upng)
const unsigned char *data; /*the data in the chunk */

length = upng_chunk_length(chunk);
data = chunk + 8;

/* parse chunks */
if (upng_chunk_type(chunk) == CHUNK_IDAT) {
data = chunk + 8;
memcpy(compressed + compressed_index, data, length);
compressed_index += length;
} else if (upng_chunk_type(chunk) == CHUNK_PLTE) {
data = chunk + 8;
memcpy(palette, data, palette_size);
} else if (upng_chunk_type(chunk) == CHUNK_IEND) {
break;
}

chunk += upng_chunk_length(chunk) + 12;
chunk += length + 12;
}

/* allocate space to store inflated (but still filtered) data */
inflated_size = ((upng->width * (upng->height * upng_get_bpp(upng) + 7)) / 8) + upng->height;
inflated = (unsigned char*)malloc(inflated_size);
if (inflated == NULL) {
free(palette);
free(compressed);
SET_ERROR(upng, UPNG_ENOMEM);
return upng->error;
Expand All @@ -1077,6 +1111,7 @@ upng_error upng_decode(upng_t* upng)
/* decompress image data */
error = uz_inflate(upng, inflated, inflated_size, compressed, compressed_size);
if (error != UPNG_EOK) {
free(palette);
free(compressed);
free(inflated);
return upng->error;
Expand All @@ -1089,6 +1124,7 @@ upng_error upng_decode(upng_t* upng)
upng->size = (upng->height * upng->width * upng_get_bpp(upng) + 7) / 8;
upng->buffer = (unsigned char*)malloc(upng->size);
if (upng->buffer == NULL) {
free(palette);
free(inflated);
upng->size = 0;
SET_ERROR(upng, UPNG_ENOMEM);
Expand All @@ -1100,10 +1136,13 @@ upng_error upng_decode(upng_t* upng)
free(inflated);

if (upng->error != UPNG_EOK) {
free(palette);
free(upng->buffer);
upng->buffer = NULL;
upng->size = 0;
} else {
/* palette */
upng->palette = palette;
upng->state = UPNG_DECODED;
}

Expand Down Expand Up @@ -1200,6 +1239,11 @@ upng_t* upng_new_from_file(const char *filename)

void upng_free(upng_t* upng)
{
/* deallocate palette */
if (upng->palette != NULL) {
free(upng->palette);
}

/* deallocate image buffer */
if (upng->buffer != NULL) {
free(upng->buffer);
Expand Down Expand Up @@ -1248,6 +1292,8 @@ unsigned upng_get_components(const upng_t* upng)
return 2;
case UPNG_RGBA:
return 4;
case UPNG_INDX:
return 1;
default:
return 0;
}
Expand Down Expand Up @@ -1279,3 +1325,8 @@ unsigned upng_get_size(const upng_t* upng)
{
return upng->size;
}

const unsigned char* upng_get_palette(const upng_t* upng)
{
return upng->palette;
}
7 changes: 6 additions & 1 deletion upng.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ typedef enum upng_format {
UPNG_LUMINANCE_ALPHA1,
UPNG_LUMINANCE_ALPHA2,
UPNG_LUMINANCE_ALPHA4,
UPNG_LUMINANCE_ALPHA8
UPNG_LUMINANCE_ALPHA8,
UPNG_INDEX1,
UPNG_INDEX2,
UPNG_INDEX4,
UPNG_INDEX8
} upng_format;

typedef struct upng_t upng_t;
Expand All @@ -77,5 +81,6 @@ upng_format upng_get_format (const upng_t* upng);

const unsigned char* upng_get_buffer (const upng_t* upng);
unsigned upng_get_size (const upng_t* upng);
const unsigned char* upng_get_palette (const upng_t* upng);

#endif /*defined(UPNG_H)*/