Skip to content

Instantly share code, notes, and snippets.

@martincohen
Created November 20, 2015 23:44
Show Gist options
  • Save martincohen/62e23219a5940d812112 to your computer and use it in GitHub Desktop.
Save martincohen/62e23219a5940d812112 to your computer and use it in GitHub Desktop.
Tiny PCX reader
#ifndef PCX_H
#define PCX_H
#include <assert.h>
#include "common.h"
typedef struct PCXHeader
{
u8 id;
u8 version;
u8 encoding;
u8 bits_per_px;
s16 x_min;
s16 y_min;
s16 x_max;
s16 y_max;
s16 x_res;
s16 y_res;
u8 pal[48];
u8 __reserved_1;
u8 planes;
s16 bytes_per_line;
s16 palette_type;
s16 x_screen_size;
s16 y_screen_size;
u8 __reserved_2[54]; /* Reserved (Always 0) */
} PCXHeader;
typedef struct PCXColor
{
u8 r;
u8 g;
u8 b;
} PCXColor;
typedef PCXColor PCXPalette[256];
typedef struct PCX
{
PCXHeader *header;
u8 *data_begin;
PCXPalette *palette;
u32 size;
u16 w;
u16 pitch;
u16 h;
u16 bpp;
} PCX;
PCX
pcx_open(u8 *buffer, u32 size)
{
assert(size >= sizeof(PCXHeader));
PCX pcx = {0};
pcx.header = (PCXHeader*)buffer;
// PCX header control byte 0x0a.
assert(pcx.header->id == 0x0a);
// Encoding must be RLE.
assert(pcx.header->encoding == 1);
// Only 8-bit format is supported.
assert(pcx.header->bits_per_px == 8);
assert(pcx.header->x_max > pcx.header->x_min);
assert(pcx.header->y_max > pcx.header->y_min);
pcx.w = pcx.header->x_max - pcx.header->x_min + 1;
pcx.h = pcx.header->y_max - pcx.header->y_min + 1;
pcx.bpp = 8 / pcx.header->bits_per_px;
pcx.pitch = pcx.header->bytes_per_line * pcx.header->planes * pcx.bpp;
// No padding allowed.
assert((pcx.pitch - pcx.w) == 0);
pcx.size = pcx.w * pcx.h * pcx.bpp;
pcx.data_begin = (u8*)(pcx.header + 1);
u8 *palette = buffer + size - sizeof(PCXPalette) - 1;
// Control byte 0xC before the palette.
assert(*palette == 0xC);
pcx.palette = (PCXPalette*)(palette + 1);
return pcx;
}
void
pcx_decode(PCX *pcx, u8 *buffer)
{
u8 *wit = buffer;
u8 *rit = pcx->data_begin;
u8 rc;
while ((wit - buffer) < (s32)pcx->size)
{
if ((*rit & 0xC0) == 0xC0)
{
rc = *rit & 0x3F;
rit++;
assert(rit != (u8*)pcx->palette);
do {
*wit++ = *rit;
} while (--rc);
rit++;
}
else
{
*wit++ = *rit++;
}
}
assert((wit - buffer) == (s32)pcx->size);
}
#endif // PCX_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment