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);