C语言实现RLE(游程编码)压缩算法(粘贴就能用)

RLE算法是最简单的压缩算法,作为学生党做作业不可避免的要去网上找RLE算法的代码,然而网上所有RLE压缩算法的代码都不好使,笔者在网上代码的基础上略加修改,使之粘贴即可使用。

源码来自:http://blog.csdn.net/calcular/article/details/46804919
算法思想来自:http://blog.csdn.net/orbit/article/details/7062218
感谢原作者。

原代码的问题在于,当一个字符超过127次重复之后,编码会出现错误。原作者可能并没有用足够的样本去测试,导致这个bug的出现。

废话不多说,先上代码。

bool IsRepeat3(unsigned char *in, int rest)
{
    if (rest<2) return false;
    else {
        if (*in == *(in + 1) && *in == *(in + 2)) return true;
        else return false;
    }
}

int GetNoRepeat3(unsigned char *in, int rest)
{
    if (rest <= 2)
        return rest + 1;
    else {
        int c = 0,
            restc = rest;
        unsigned char *g = in;
        while (!IsRepeat3(g, restc))
        {
            g++;
            restc--;
            c++;
            if (c >= 128)
                return c;
            if (restc == 0)
                return c + 1;

        }
        return c;
    }
}



int Rle_Encode(unsigned char *inbuf, int insize, unsigned char *outbuf1, int outsize)
{
    unsigned char *src = inbuf;
    unsigned char *outbuf = outbuf1;
    int rest = insize - 1;
    int outrest = outsize;
    int count = -1;
    int flag = 0;
    while (rest >= 0)
    {
        flag = 0;
        count = -1;
        if (IsRepeat3(src, rest))
        {
            while (rest >= 0)
            {
                if (count == 127) break;
                if (*src == *(src + 1)) {
                    rest--;
                    count++;
                    src++;
                }
                else {
                    count++;
                    if (count == 127) {
                        flag = 1;
                    }
                    break;
                }
            }
            if (outrest<2)
                return -1;
            *outbuf = count | 128;
            outbuf++;
            *outbuf = *src;
            outbuf++;
            outrest -= 2;

            if (count != 127||flag==1) {
                src++;
                rest--;
            }

        }
        else
        {
            if (IsRepeat3(src, rest))
                continue;
            int num = GetNoRepeat3(src, rest);
            int i;
            if (outrest<(num + 1))
                return -1;
            *outbuf = num-1;
            outbuf++;
            for (i = 0; i<num; i++) {
                *outbuf = *(src + i);
                outbuf++;
            }
            src += num;
            rest -= num;
            outrest -= num + 1;
        }
    }
    return outsize - outrest;
}

int Rle_Decode(unsigned char *inbuf, int insize, unsigned char *outbuf, int outsize)
{
    int inrest = insize;
    int outrest = outsize;
    int i;
    unsigned char *in = inbuf;
    unsigned char *out = outbuf;
    int  ns;
    unsigned char tmp;
    while (inrest >= 0)
    {
        ns = *in+1;
        if (ns>129) {
            if ((outrest - ns + 128)<0)
                return -1;
            tmp = *(in + 1);
            for (i = 0; i<ns - 128; i++) {
                *out = tmp;
                out++;
            }
            in += 2;
            inrest -= 2;
            outrest -= ns - 128;

        }
        else {
            if ((outrest - ns)<0)
                return -1;
            in++;
            for (i = 0; i<ns; i++) {
                *out = *in;
                out++;
                in++;
            }
            inrest -= 1 + ns;
            outrest -= ns;
        }
    }
    return outsize - outrest;
}

简单说下算法的原理。普通的RLE是把aabbccdd变成2a2b2c2d,这样当压缩abcd这样的数据时,不但压缩不了,还会产生冗余,所以我们需要高级点的RLE来解决这个问题。

我们知道,RLE编码是由一个个length-code字节对组成的,我们这个算法,将length字节的最高位置为标志位,如标志位为1,说明后面的一个byte连续重复X次(aaaaa这样),反之标志位为0,说明后面的X个bytes中,相邻byte互不相同(abcd这种)。标志位的后7位,表示一个X-1的整数(显然,X最大为128),当标志位为1时,X的意义和普通的RLE是一样的,当标志位为0时,X表示接下来X个bytes中相邻byte互不相同。

举例:aaaabcdefg
首先是四个连续的a,所以X=4,X-1=3,标志位为1,故length字节应为1000 0011=0x83,code字节为a,至此我们有0x83 a。
然后是6个相邻byte互不相同的字节,所以X=6,X-1=5,标志位为0,length字节为0x05,后面跟着6个bytes,bcdefg。至此,编码结束,结果为0x83 a 0x05 b c d e f g

最坏的情况,此算法会带来1/128的冗余,即使如此,比普通RLE 100%的冗余还是好上不少的。

    原文作者:游程编码问题
    原文地址: https://blog.csdn.net/bingma1995/article/details/78829301
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞