Mercurial > hg > dmlib
changeset 1650:9233da9de92c
Refactor RLE encoding a bit, and add support for 16bit run counts and make things more configurable.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 30 May 2018 03:25:34 +0300 |
parents | dbdff3d50a4e |
children | 6dd191d04ea8 |
files | tools/lib64fmts.c tools/lib64gfx.c tools/lib64gfx.h |
diffstat | 3 files changed, 148 insertions(+), 92 deletions(-) [+] |
line wrap: on
line diff
--- a/tools/lib64fmts.c Wed May 30 01:29:09 2018 +0300 +++ b/tools/lib64fmts.c Wed May 30 03:25:34 2018 +0300 @@ -51,8 +51,9 @@ DMGrowBuf mem; DMCompParams cfg; - cfg.type = DM_COMP_RLE_MARKER2; - cfg.rleMarker = 0xfe; + cfg.type = DM_COMP_RLE_MARKER; + cfg.flags = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_2; + cfg.rleMarker1 = 0xfe; if ((res = dmDecodeGenericRLEAlloc(&mem, buf, buf + len, &cfg)) != DMERR_OK) goto out; @@ -75,8 +76,9 @@ goto out; // And now RLE compress the data to the existing buffer - cfg.type = DM_COMP_RLE_MARKER2; - cfg.rleMarker = 0xfe; + cfg.type = DM_COMP_RLE_MARKER; + cfg.flags = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_2; + cfg.rleMarker1 = 0xfe; cfg.rleMinCount = 3; cfg.rleMaxCount = 255; res = dmEncodeGenericRLE(buf, tmp.data, tmp.data + tmp.len, &cfg); @@ -110,8 +112,9 @@ DMGrowBuf mem; DMCompParams cfg; - cfg.type = DM_COMP_RLE_MARKER1; - cfg.rleMarker = buf[0x0d]; + cfg.type = DM_COMP_RLE_MARKER; + cfg.flags = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1; + cfg.rleMarker1 = buf[0x0d]; if ((res = dmDecodeGenericRLEAlloc(&mem, buf + 0x0e, buf + len, &cfg)) != DMERR_OK) goto out; @@ -135,21 +138,22 @@ if ((res = dmC64EncodeGenericBMP(TRUE, &tmp, img, fmt)) != DMERR_OK) goto out; - // Analyze the data .. - dmGenericRLEAnalyze(&tmp, &cfg.rleMarker, DM_COMP_RLE_MARKER1); + // Analyze and setup RLE + dmGenericRLEAnalyze(tmp.data, tmp.len, &cfg); + cfg.type = DM_COMP_RLE_MARKER; + cfg.flags = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1; + cfg.rleMinCount = 3; + cfg.rleMaxCount = 255; // Add the header bits if (!dmGrowBufPut(buf, magicID, strlen(magicID)) || - !dmGrowBufPutU8(buf, cfg.rleMarker)) + !dmGrowBufPutU8(buf, cfg.rleMarker1)) { res = DMERR_MALLOC; goto out; } // And now RLE compress the data to the existing buffer - cfg.type = DM_COMP_RLE_MARKER1; - cfg.rleMinCount = 3; - cfg.rleMaxCount = 255; res = dmEncodeGenericRLE(buf, tmp.data, tmp.data + tmp.len, &cfg); out: @@ -240,8 +244,10 @@ tmp.len = len + 1; // Now do an RLE decode on the enlarged buffer - cfg.type = DM_COMP_RLE_MARKER1; - cfg.rleMarker = 0xC2; + cfg.type = DM_COMP_RLE_MARKER; + cfg.flags = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1; + cfg.rleMarker1 = 0xC2; + if ((res = dmDecodeGenericRLEAlloc(&mem, tmp.data, tmp.data + tmp.len, &cfg)) != DMERR_OK) goto out; @@ -266,10 +272,12 @@ goto out; // And now RLE compress the data to the existing buffer - cfg.type = DM_COMP_RLE_MARKER1; - cfg.rleMarker = 0xC2; + cfg.type = DM_COMP_RLE_MARKER; + cfg.flags = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1; + cfg.rleMarker1 = 0xC2; cfg.rleMinCount = 3; cfg.rleMaxCount = 255; + res = dmEncodeGenericRLE(buf, tmp.data, tmp.data + tmp.len, &cfg); out: @@ -504,8 +512,9 @@ DMGrowBuf mem; DMCompParams cfg; - cfg.type = DM_COMP_RLE_MARKER1; - cfg.rleMarker = buf[15]; + cfg.type = DM_COMP_RLE_MARKER; + cfg.flags = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1; + cfg.rleMarker1 = buf[15]; if ((res = dmDecodeGenericRLEAlloc( &mem, buf + FUNPAINT2_HEADER_SIZE, buf + len, &cfg)) == DMERR_OK) @@ -543,21 +552,22 @@ if ((res = dmC64EncodeGenericBMP(TRUE, &tmp, img, fmt)) != DMERR_OK) goto out; - // Analyze the data .. - dmGenericRLEAnalyze(&tmp, &cfg.rleMarker, DM_COMP_RLE_MARKER1); + // Analyze and setup RLE + dmGenericRLEAnalyze(tmp.data, tmp.len, &cfg); + cfg.type = DM_COMP_RLE_MARKER; + cfg.flags = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1; + cfg.rleMinCount = 3; + cfg.rleMaxCount = 255; // Add the header bits if (!dmGrowBufPut(buf, fmtFunPaint2MagicID, strlen(fmtFunPaint2MagicID)) || - !dmGrowBufPutU8(buf, cfg.rleMarker)) + !dmGrowBufPutU8(buf, cfg.rleMarker1)) { res = DMERR_MALLOC; goto out; } // And now RLE compress the data to the existing buffer - cfg.type = DM_COMP_RLE_MARKER1; - cfg.rleMinCount = 3; - cfg.rleMaxCount = 255; res = dmEncodeGenericRLE(buf, tmp.data, tmp.data + tmp.len, &cfg); out:
--- a/tools/lib64gfx.c Wed May 30 01:29:09 2018 +0300 +++ b/tools/lib64gfx.c Wed May 30 03:25:34 2018 +0300 @@ -282,7 +282,7 @@ } -void dmGenericRLEAnalyze(const DMGrowBuf *buf, Uint8 *rleMarker, const int rleType) +void dmGenericRLEAnalyze(const Uint8 *buf, const size_t len, DMCompParams *cfg) { #define DM_STAT_MAX 256 size_t *stats; @@ -292,29 +292,37 @@ return; // Get statistics on the data - for (size_t offs = 0; offs < buf->len; offs++) - stats[buf->data[offs]]++; + for (size_t offs = 0; offs < len; offs++) + stats[buf[offs]]++; // According to compression type .. - if (rleType == DM_COMP_RLE_MARKER1 || rleType == DM_COMP_RLE_MARKER2) + switch (cfg->type) { - size_t selected = 0, - smallest = buf->len; - - // Find least used byte value - for (size_t n = 0; n < DM_STAT_MAX; n++) - { - if (stats[n] < smallest) + case DM_COMP_RLE_MARKER: { - selected = n; - smallest = stats[n]; - } - } + size_t selected = 0, + smallest = len; - *rleMarker = selected; + // Find least used byte value + for (size_t n = 0; n < DM_STAT_MAX; n++) + { + if (stats[n] < smallest) + { + selected = n; + smallest = stats[n]; + } + } + + cfg->rleMarker1 = selected; + } + break; + + case DM_COMP_RLE_MASK: + cfg->rleMarker1 = 0xC0; + cfg->rleMask1 = 0xC0; + cfg->rleMask2 = 0x3f; + break; } - else - *rleMarker = 0xC0; dmFree(stats); } @@ -330,49 +338,71 @@ Uint8 data = *src++; int count = 1; - switch (cfg->type) + if (cfg->type == DM_COMP_RLE_MARKER) { - case DM_COMP_RLE_MARKER1: - case DM_COMP_RLE_MARKER2: - // A simple marker byte RLE variant: [Marker] [count] [data] - if (data == cfg->rleMarker) + // A simple marker byte RLE variant: [Marker] [count] [data] + if (data == cfg->rleMarker1 && (cfg->flags & DM_RLE_8BIT_RUNS)) + { + if (srcEnd - src + 1 < 2) { - if (srcEnd - src + 1 < 2) - { - res = DMERR_INVALID_DATA; - goto err; - } + res = DMERR_INVALID_DATA; + goto err; + } - switch (cfg->type) - { - case DM_COMP_RLE_MARKER1: - count = *src++; - data = *src++; - break; + switch (cfg->flags & DM_RLE_ORDER_MASK) + { + case DM_RLE_ORDER_1: + count = src[0]; + data = src[1]; + break; - case DM_COMP_RLE_MARKER2: - data = *src++; - count = *src++; - break; - } + case DM_RLE_ORDER_2: + data = src[0]; + count = src[1]; + break; } - break; + src += 2; + } + else + if (data == cfg->rleMarker2 && (cfg->flags & DM_RLE_16BIT_RUNS)) + { + if (srcEnd - src + 1 < 3) + { + res = DMERR_INVALID_DATA; + goto err; + } + + switch (cfg->flags & DM_RLE_ORDER_MASK) + { + case DM_RLE_ORDER_1: + count = (src[1] << 8) | src[0]; + data = src[2]; + break; - case DM_COMP_RLE_MASK: - // Mask marker RLE: usually high bit(s) of byte mark RLE sequence - // and the lower bits contain the count: [Mask + count] [data] - if ((data & cfg->rleMask1) == cfg->rleMarker) + case DM_RLE_ORDER_2: + data = src[0]; + count = (src[2] << 8) | src[1]; + break; + } + src += 3; + } + } + else + if (cfg->type == DM_COMP_RLE_MASK) + { + // Mask marker RLE: usually high bit(s) of byte mark RLE sequence + // and the lower bits contain the count: [Mask + count] [data] + if ((data & cfg->rleMask1) == cfg->rleMarker1) + { + if (srcEnd - src + 1 < 1) { - if (srcEnd - src + 1 < 1) - { - res = DMERR_INVALID_DATA; - goto err; - } + res = DMERR_INVALID_DATA; + goto err; + } - count = data & cfg->rleMask2; - data = *src++; - } - break; + count = data & cfg->rleMask2; + data = *src++; + } } while (count--) @@ -408,23 +438,22 @@ switch (cfg->type) { - case DM_COMP_RLE_MARKER1: - case DM_COMP_RLE_MARKER2: - if (count >= cfg->rleMinCount || data == cfg->rleMarker) + case DM_COMP_RLE_MARKER: + if (count >= cfg->rleMinCount || data == cfg->rleMarker1) { // A simple marker byte RLE variant: [Marker] [count] [data] - if (!dmGrowBufPutU8(dst, cfg->rleMarker)) + if (!dmGrowBufPutU8(dst, cfg->rleMarker1)) return FALSE; - switch (cfg->type) + switch (cfg->flags & DM_RLE_ORDER_MASK) { - case DM_COMP_RLE_MARKER1: + case DM_RLE_ORDER_1: if (!dmGrowBufPutU8(dst, count) || !dmGrowBufPutU8(dst, data)) return FALSE; break; - case DM_COMP_RLE_MARKER2: + case DM_RLE_ORDER_2: if (!dmGrowBufPutU8(dst, data) || !dmGrowBufPutU8(dst, count)) return FALSE; @@ -436,11 +465,11 @@ break; case DM_COMP_RLE_MASK: - if (count >= cfg->rleMinCount || (data & cfg->rleMarker) == cfg->rleMarker) + if (count >= cfg->rleMinCount || (data & cfg->rleMask1) == cfg->rleMarker1) { // Mask marker RLE: usually high bit(s) of byte mark RLE sequence // and the lower bits contain the count: [Mask + count] [data] - if (!dmGrowBufPutU8(dst, cfg->rleMarker | count) || + if (!dmGrowBufPutU8(dst, cfg->rleMarker1 | count) || !dmGrowBufPutU8(dst, data)) return FALSE; }
--- a/tools/lib64gfx.h Wed May 30 01:29:09 2018 +0300 +++ b/tools/lib64gfx.h Wed May 30 03:25:34 2018 +0300 @@ -204,17 +204,34 @@ // -// Compression types +// Compression types and flags // -#define DM_COMP_RLE_MARKER1 1 -#define DM_COMP_RLE_MARKER2 2 -#define DM_COMP_RLE_MASK 3 +enum +{ + DM_COMP_RLE_MARKER = 1, // RLE with a separate marker byte + DM_COMP_RLE_MASK = 2, // RLE that has marker bits and lower part acts as run length +}; + +enum +{ + DM_RLE_8BIT_RUNS = 0x0001, // Uses one-byte runs + DM_RLE_16BIT_RUNS = 0x0002, // Uses two-byte runs + DM_RLE_RUNS_MASK = 0x000f, + + DM_RLE_ORDER_1 = 0x0000, // Order: <marker>, <count/run length>, <data> + DM_RLE_ORDER_2 = 0x0010, // Order: <marker>, <data>, <count/run length> + DM_RLE_ORDER_MASK = 0x00f0, +}; typedef struct { int type; - Uint8 rleMarker, rleMask1, rleMask2, rleMinCount, rleMaxCount; + int flags; + Uint8 + rleMarker1, rleMarker2, + rleMask1, rleMask2, + rleMinCount, rleMaxCount; } DMCompParams; @@ -267,7 +284,7 @@ int dmC64ConvertGenericBMP2Image(DMImage *dst, const DMC64Image *src, const DMC64ImageFormat *fmt); int dmC64ConvertGenericImage2BMP(DMC64Image *dst, const DMImage *src, const DMC64ImageFormat *fmt); -void dmGenericRLEAnalyze(const DMGrowBuf *buf, Uint8 *rleMarker, const int rleType); +void dmGenericRLEAnalyze(const Uint8 *buf, const size_t len, DMCompParams *cfg); int dmDecodeGenericRLE(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg); int dmDecodeGenericRLEAlloc(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg);