summaryrefslogtreecommitdiffstats
path: root/lisiblepng
diff options
context:
space:
mode:
Diffstat (limited to 'lisiblepng')
-rw-r--r--lisiblepng/src/lisiblepng.c105
1 files changed, 97 insertions, 8 deletions
diff --git a/lisiblepng/src/lisiblepng.c b/lisiblepng/src/lisiblepng.c
index beba003..34040b8 100644
--- a/lisiblepng/src/lisiblepng.c
+++ b/lisiblepng/src/lisiblepng.c
@@ -15,6 +15,7 @@ const uint8_t PNG_SIGNATURE[PNG_SIGNATURE_LENGTH] = {0x89, 0x50, 0x4E, 0x47,
#define IHDR_CHUNK_TYPE 0x49484452
#define IEND_CHUNK_TYPE 0x49454e44
#define IDAT_CHUNK_TYPE 0x49444154
+#define PLTE_CHUNK_TYPE 0x504C5445
const uint32_t CRC32_TABLE[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
@@ -61,8 +62,19 @@ const uint32_t CRC32_TABLE[256] = {
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
+typedef struct {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+} PaletteEntry;
+typedef struct {
+ PaletteEntry entries[256];
+ size_t entry_count;
+} Palette;
+
struct LisPng {
uint8_t *data;
+ Palette *palette;
size_t width;
size_t height;
LisPngColourType colour_type;
@@ -294,24 +306,59 @@ bool parse_IHDR_chunk(DeflateDecompressor *ctx, ImageHeader *image_header) {
return true;
}
-bool parse_IDAT_chunk(DeflateDecompressor *ctx, uint32_t data_length,
+bool parse_IDAT_chunk(DeflateDecompressor *decompressor, uint32_t data_length,
ImageData *image_data) {
- ASSERT(ctx != NULL);
+ ASSERT(decompressor != NULL);
ASSERT(image_data != NULL);
image_data->data =
realloc(image_data->data, image_data->length + data_length);
- ParsingContext_parse_bytes(ctx, data_length,
- &image_data->data[image_data->length]);
+ if (!ParsingContext_parse_bytes(decompressor, data_length,
+ &image_data->data[image_data->length])) {
+ return false;
+ }
image_data->length = image_data->length + data_length;
- if (!ParsingContext_validate_crc_if_required(ctx)) {
+ if (!ParsingContext_validate_crc_if_required(decompressor)) {
return false;
}
return true;
}
+Palette *parse_PLTE_chunk(DeflateDecompressor *decompressor,
+ uint32_t data_length) {
+ ASSERT(decompressor != NULL);
+ if (data_length % 3 != 0) {
+ return NULL;
+ }
+
+ Palette *palette = malloc(sizeof(Palette));
+ if (!palette) {
+ return NULL;
+ }
+
+ palette->entry_count = data_length / 3;
+ for (size_t entry_index = 0; entry_index < palette->entry_count;
+ entry_index++) {
+ if (!ParsingContext_parse_bytes(decompressor, 1,
+ &palette->entries[entry_index].r))
+ return false;
+ if (!ParsingContext_parse_bytes(decompressor, 1,
+ &palette->entries[entry_index].g))
+ return false;
+ if (!ParsingContext_parse_bytes(decompressor, 1,
+ &palette->entries[entry_index].b))
+ return false;
+ }
+
+ if (!ParsingContext_validate_crc_if_required(decompressor)) {
+ return false;
+ }
+
+ return palette;
+}
+
uint32_t uint32_t_to_le(uint32_t value) {
char *value_bytes = (char *)&value;
return (value_bytes[0] << 24) + (value_bytes[1] << 16) +
@@ -455,6 +502,8 @@ LisPng *LisPng_decode(FILE *stream) {
ImageHeader_print_image_header(&header);
ImageData image_data = {0};
+ Palette *palette = NULL;
+
size_t parsed_data_chunk_count = 0;
bool end_reached = false;
while (!end_reached) {
@@ -489,6 +538,13 @@ LisPng *LisPng_decode(FILE *stream) {
end_reached = true;
ParsingContext_skip_bytes(&ctx, sizeof(uint32_t));
break;
+ case PLTE_CHUNK_TYPE:
+ palette = parse_PLTE_chunk(&ctx, length);
+ if (!palette) {
+ LPNG_LOG_ERR0("Couldn't parse PLTE chunk");
+ goto cleanup_data;
+ }
+ break;
default:
LPNG_LOG_DBG0("Unknown chunk type, skipping chunk...");
ParsingContext_skip_bytes(&ctx, length + sizeof(uint32_t));
@@ -506,6 +562,7 @@ LisPng *LisPng_decode(FILE *stream) {
png->height = header.height;
png->colour_type = header.colour_type;
png->bits_per_sample = header.bit_depth;
+ png->palette = palette;
size_t output_length;
uint8_t *output_buffer =
zlib_decompress(image_data.data, image_data.length, &output_length);
@@ -519,6 +576,7 @@ LisPng *LisPng_decode(FILE *stream) {
cleanup_data:
free(image_data.data);
+ free(palette);
err:
return NULL;
}
@@ -540,7 +598,20 @@ void LisPng_write_RGBA8_data(const LisPng *png, uint8_t *output_data) {
size_t source_pixel_base = pixel_index * bytes_per_pixel;
size_t target_pixel_base = pixel_index * TARGET_BYTES_PER_PIXEL;
- if (png->colour_type == LisPngColourType_Greyscale) {
+ if (png->colour_type == LisPngColourType_IndexedColour) {
+ ASSERT(png->palette != NULL);
+ size_t absolute_bit_offset = pixel_index * bits_per_pixel;
+ size_t byte_offset = absolute_bit_offset / 8;
+ size_t relative_bit_offset = absolute_bit_offset % 8;
+ uint8_t index = (png->data[byte_offset] >>
+ (7 - relative_bit_offset - (bits_per_pixel - 1))) &
+ ((1 << bits_per_pixel) - 1);
+ PaletteEntry *entry = &png->palette->entries[index];
+ output_data[target_pixel_base] = entry->r;
+ output_data[target_pixel_base + 1] = entry->g;
+ output_data[target_pixel_base + 2] = entry->b;
+ output_data[target_pixel_base + 3] = 0xFF;
+ } else if (png->colour_type == LisPngColourType_Greyscale) {
if (bits_per_pixel == 16) {
uint16_t grey = (png->data[source_pixel_base] << 8) |
png->data[source_pixel_base + 1];
@@ -589,6 +660,10 @@ void LisPng_write_RGBA8_data(const LisPng *png, uint8_t *output_data) {
}
void LisPng_destroy(LisPng *png) {
+ if (png->colour_type == LisPngColourType_IndexedColour) {
+ free(png->palette);
+ }
+
free(png->data);
free(png);
}
@@ -596,7 +671,11 @@ void LisPng_dump_ppm(const LisPng *png) {
ASSERT(png != NULL);
printf("P3\n");
printf("%zu %zu\n", png->width, png->height);
- printf("%d\n", (1 << png->bits_per_sample) - 1);
+ if (png->colour_type == LisPngColourType_IndexedColour) {
+ printf("255\n");
+ } else {
+ printf("%d\n", (1 << png->bits_per_sample) - 1);
+ }
size_t sample_count = LisPngColourType_sample_count(png->colour_type);
size_t bits_per_pixel = png->bits_per_sample * sample_count;
size_t bytes_per_pixel = bits_per_pixel / 8;
@@ -606,7 +685,17 @@ void LisPng_dump_ppm(const LisPng *png) {
for (size_t pixel_index = 0; pixel_index < png->height * png->width;
pixel_index++) {
size_t pixel_base = pixel_index * bytes_per_pixel;
- if (png->colour_type == LisPngColourType_Greyscale) {
+ if (png->colour_type == LisPngColourType_IndexedColour) {
+ ASSERT(png->palette != NULL);
+ size_t absolute_bit_offset = pixel_index * bits_per_pixel;
+ size_t byte_offset = absolute_bit_offset / 8;
+ size_t relative_bit_offset = absolute_bit_offset % 8;
+ uint8_t index = (png->data[byte_offset] >>
+ (7 - relative_bit_offset - (bits_per_pixel - 1))) &
+ ((1 << bits_per_pixel) - 1);
+ PaletteEntry *entry = &png->palette->entries[index];
+ printf("%u %u %u\n", entry->r, entry->g, entry->b);
+ } else if (png->colour_type == LisPngColourType_Greyscale) {
if (bits_per_pixel == 16) {
uint16_t grey =
(png->data[pixel_base] << 8) | png->data[pixel_base + 1];
Go back to lisible.xyz