如何在C#中对字节数组执行RLE(行程长度编码)?

3
我正在尝试对两个位图文件(它们的字节数组)进行异或运算,以生成一个字节数组,该数组可用于将图像A更改为图像B或反之亦然。由于我要通过网络发送此数据,因此在此之前我希望进行一些基本的压缩处理。
是否有办法在C#中对字节数组执行RLE(行程长度编码)(使用内置的或快速可靠的第三方库)以实现此目的?
注: 如果您要建议替代我的方法,请记住远程计算机上的解压缩和转换必须尽可能快速和高效。
3个回答

3

我通常使用 GZipStream。它足够快,而且运行良好。

class Compressor
{
    public static byte[] compress(byte[] buffer)
    {
        MemoryStream ms = new MemoryStream();
        GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true);
        zip.Write(buffer, 0, buffer.Length);
        zip.Close();
        ms.Position = 0;

        byte[] compressed = new byte[ms.Length];
        ms.Read(compressed, 0, compressed.Length);

        byte[] gzBuffer = new byte[compressed.Length + 4];
        Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
        Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
        return gzBuffer;
    }
    public static byte[] decompress(byte[] gzBuffer)
    {
        MemoryStream ms = new MemoryStream();
        int msgLength = BitConverter.ToInt32(gzBuffer, 0);
        ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

        byte[] buffer = new byte[msgLength];

        ms.Position = 0;
        GZipStream zip = new GZipStream(ms, CompressionMode.Decompress);
        zip.Read(buffer, 0, buffer.Length);

        return buffer;
    }
}

1
在Compress方法中,“outStream”有什么用途? - JYelton
实际上,“outStream”是相当无用的。我一段时间前只是将代码复制了下来,没有详细检查。当然你可以删除包含“outStream”定义的那一行。感谢你的提醒。 - Simon Ottenhaus

3
以下是 RLE 字符串打包/解包的两种方法。在大文本上使用将得到最佳效果。
    public string PackText()
    {
        try
        {
            StringBuilder str1 = new StringBuilder(Text);
            StringBuilder str = new StringBuilder();
            char ch;
            int i, k, j;
            for (i = 0; i < str1.Length; ) // from 0 to length of unpackedtext
            {
                ch = str1[i]; // get current char from str1
                k = 0; //count the number of repeated characters
                if (i == str1.Length - 1) // If this is the last character
                {
                    str.Append(ch);
                    break; //exit the loop
                }

                if (str1[i + 1] == ch) //if current symbol is next
                {
                    for (j = i; j < str1.Length; j++) //packing the characters
                    {
                        if (str1[j] == ch) //if current symbol is next
                        {
                            if (k == 9) break; //the maximum number of characters packed 9, 
                            //or there might be problems with unpacking is not packed numeric characters
                            k++;

                        }
                        else break;
                    }
                    i = j;
                }
                else if ("0123456789".Contains(ch)) //if this digit and it is not repeated, then it must be escaped,
                    //so when unpacking to understand that this is not the number of repeated characters
                {
                    k = 1;
                    i++;
                }
                else i++;


                if (k != 0)
                    str.AppendFormat("{0}{1}", k, ch); //forming packed string
                else
                    str.Append(ch);

            }
            return str.ToString();
        }
        catch
        {
            return null;
        }
    }

    public string UnpackText()
    {
        try
        {

            StringBuilder str1 = new StringBuilder(Text);
            StringBuilder str = new StringBuilder();

            char ch;
            char symb = 'a';
            int s = 0;
            int i, j;
            for (i = 0; i < str1.Length; ) // from 0 to length of packedtext
            {
                ch = str1[i]; // get current char from str1
                s = 0;
                if ("123456789".Contains(ch)) //if this digit
                {
                    if (i == str1.Length - 1) // If this is the last character
                    {
                        symb = ch;
                        s = 1;
                        i++;
                    }
                    else
                    {
                        symb = str1[i + 1]; // get packed symbol
                        i += 2;
                        s = Convert.ToInt32(ch) - 48; //get the number of repetitions
                    }
                }
                else
                {
                    s = 0;
                    i++;
                }
                if (s > 0)
                {
                    for (j = 0; j < s; j++) // write the decompressed symbol
                        str.Append(symb);
                }
                else
                    str.Append(ch);
            }
          return  str.ToString();
        }
        catch
        {
            return null;
        }

    }

问题是关于压缩一个 byte 数组,而不是字符串。 - Nyerguds

0

您可以使用来自 CodePlex 的 RLE 编码/解码工具:http://rle.codeplex.com/(C#)

您可以将其构建为 .net dll 和其 lib。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接