RLE压缩算法

作者:追风剑情 发布于:2016-4-16 15:11 分类:C#

       RLE(Run Length Encoding)压缩算法即行程长度压缩算法,也称游程长度压缩算法,是最早出现、也是最简单的无损数据压缩算法。RLE压缩算法对黑白图像和基于调色板的单调图像有很高的压缩效率,不仅常用于处理图像数据,在传真机上也得到了广泛的应用。

压缩格式

[长度标识位] [数据块]

长度标识位通常用一个字节标识,字节最高位为1表示后面的数据块是连续重复数据。字节最高位为0表示后面的数据块是非连续数据。把最高位除开,只有剩下的7位用来表示数据长度(即最大值是127)。

重复数据: 连续出现次数2次以上。(例如:  65, 65, 65, ...)

以下是RLE算法实现代码

  1. using System;
  2.  
  3. /// <summary>
  4. /// 行程长度压缩算法 RLE(Run Length Encoding)
  5. /// 最简单的无损数据压缩算法
  6. /// </summary>
  7. public class RLE
  8. {
  9. /// <summary>
  10. /// 压缩
  11. /// </summary>
  12. /// <param name="inbuf">原始数据</param>
  13. /// <returns>压缩后的数据</returns>
  14. public static byte[] Encode(byte[] inbuf)
  15. {
  16. int encSize = 0;
  17. int inbufPos = 0;
  18. int inBuffSize = inbuf.Length;
  19. byte[] buff = new byte[inBuffSize];
  20.  
  21. while (inbufPos < inBuffSize)
  22. {
  23. byte count = 0;
  24. if (IsRepetitionStart(inbuf, inbufPos))
  25. {
  26. count = GetRepetitionCount(inbuf, inbufPos);
  27. //长度字节最高位设置为1
  28. buff[encSize++] = (byte)(count | 0x80);
  29. buff[encSize++] = inbuf[inbufPos];
  30. inbufPos += count;
  31. }
  32. else
  33. {
  34. count = GetNonRepetitionCount(inbuf, inbufPos);
  35. buff[encSize++] = count;
  36. //逐个复制这些数据
  37. for (int i = 0; i < count; i++)
  38. {
  39. buff[encSize++] = inbuf[inbufPos++];
  40. }
  41. }
  42. }
  43.  
  44. byte[] outbuf = new byte[encSize];
  45. Array.Copy(buff, 0, outbuf, 0, encSize);
  46.  
  47. return outbuf;
  48. }
  49.  
  50. /// <summary>
  51. /// 解压
  52. /// </summary>
  53. /// <param name="inbuf">压缩数据</param>
  54. /// <param name="outBuffSize">输出缓冲区大小</param>
  55. /// <returns>解压后的数据</returns>
  56. public static byte[] Decode(byte[] inbuf, int outBuffSize = -1)
  57. {
  58. int i;
  59. int decSize = 0;
  60. int count = 0;
  61. int inbufPos = 0;
  62. int inbufSize = inbuf.Length;
  63. if (-1 == outBuffSize)
  64. outBuffSize = inbufSize * 5;
  65. byte[] buff = new byte[outBuffSize];
  66.  
  67. while (inbufPos < inbufSize)
  68. {
  69. byte sign = inbuf[inbufPos++];
  70. count = sign & 0x3F;
  71. //输出缓冲区空间不够了
  72. if (decSize + count > outBuffSize)
  73. {
  74. Console.WriteLine("错误: 输出缓冲区空间不够");
  75. return null;
  76. }
  77.  
  78. if ((sign & 0x80) == 0x80)//连续重复数据标志
  79. {
  80. for (i = 0; i < count; i++)
  81. {
  82. buff[decSize++] = inbuf[inbufPos];
  83. }
  84. inbufPos++;
  85. }
  86. else
  87. {
  88. for (i = 0; i < count; i++)
  89. {
  90. buff[decSize++] = inbuf[inbufPos++];
  91. }
  92. }
  93. }
  94.  
  95. byte[] outbuf = new byte[decSize];
  96. Array.Copy(buff, 0, outbuf, 0, decSize);
  97.  
  98. return outbuf;
  99. }
  100.  
  101. /// <summary>
  102. /// 是否连续三个字节数据相同
  103. /// </summary>
  104. /// <returns></returns>
  105. static bool IsRepetitionStart(byte[] src, int srcLeft)
  106. {
  107. if (srcLeft + 3 >= src.Length)
  108. return false;
  109.  
  110. int byte1 = src[srcLeft];
  111. int byte2 = src[srcLeft + 1];
  112. int byte3 = src[srcLeft + 2];
  113.  
  114. return (byte1 == byte2 && byte1 == byte3);
  115. }
  116.  
  117. static byte GetRepetitionCount(byte[] src, int srcPos)
  118. {
  119. int endLeft = srcPos + 127;
  120. if (endLeft >= src.Length)
  121. endLeft = src.Length - 1;
  122.  
  123. byte count = 1;
  124. for (int i = srcPos; i < endLeft; i++)
  125. {
  126. if (src[i] != src[i + 1])
  127. break;
  128. count++;
  129. }
  130. return count;
  131. }
  132.  
  133. static byte GetNonRepetitionCount(byte[] src, int srcPos)
  134. {
  135. //只剩最后两字节数据了
  136. if (src.Length - srcPos <= 3)
  137. return 2;
  138.  
  139. int endLeft = srcPos + 127;
  140. if (endLeft >= src.Length)
  141. endLeft = src.Length - 1;
  142.  
  143.  
  144. byte count = 0;
  145. for (int i = srcPos; i <= endLeft; i++)
  146. {
  147. if (IsRepetitionStart(src, i))
  148. break;
  149. count++;
  150. }
  151. return count;
  152. }
  153. }

测试

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. class Program
  7. {
  8. static void Main(string[] args)
  9. {
  10. //测试数据
  11. byte[] data = new byte[] {
  12. 10,
  13. 20, 20,
  14. 30, 30, 30,
  15. 40, 40, 40, 40,
  16. 50, 50, 50, 50, 50,
  17. 60, 60, 60, 60, 60, 60,
  18. 70, 70, 80, 80, 90
  19. };
  20.  
  21. Console.WriteLine("原始数据");
  22. for (int i = 0; i < data.Length; i++)
  23. Console.Write(data[i]+", ");
  24.  
  25. Console.WriteLine();
  26. Console.WriteLine("RLE压缩数据");
  27.  
  28. byte[] en_data = RLE.Encode(data);
  29. for (int i = 0; i < en_data.Length; i++)
  30. Console.Write(en_data[i] + ", ");
  31.  
  32. Console.WriteLine();
  33. Console.WriteLine("RLE解压数据");
  34.  
  35. byte[] de_data = RLE.Decode(en_data);
  36. for (int i = 0; i < de_data.Length; i++)
  37. Console.Write(de_data[i] + ", ");
  38.  
  39. Console.Read();
  40. }
  41. }

运行效果

1111111111111111111.png

标签: C#

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号