C# 对图片进行哈夫曼编码与解码
时间: 2023-07-19 08:05:24 浏览: 130
C# 中可以使用 System.Drawing 命名空间中的 Bitmap 类来处理图片的编码和解码。下面是使用哈夫曼编码对图片进行压缩和解压缩的示例代码:
```csharp
using System;
using System.Drawing;
using System.IO;
using System.Linq;
namespace HuffmanCompression
{
public class Huffman
{
private class HuffmanNode : IComparable<HuffmanNode>
{
public byte Value { get; set; }
public int Frequency { get; set; }
public HuffmanNode Left { get; set; }
public HuffmanNode Right { get; set; }
public int CompareTo(HuffmanNode other)
{
return Frequency.CompareTo(other.Frequency);
}
}
private static HuffmanNode BuildHuffmanTree(byte[] data)
{
var freq = new int[256];
foreach (var b in data)
{
freq[b]++;
}
var nodes = freq.Select((f, i) => new HuffmanNode { Value = (byte)i, Frequency = f })
.Where(n => n.Frequency > 0)
.ToList();
while (nodes.Count > 1)
{
nodes.Sort();
var left = nodes[0];
var right = nodes[1];
nodes.RemoveRange(0, 2);
var parent = new HuffmanNode { Value = 0, Frequency = left.Frequency + right.Frequency, Left = left, Right = right };
nodes.Add(parent);
}
return nodes.FirstOrDefault();
}
private static void BuildHuffmanTable(HuffmanNode node, string code, string[] table)
{
if (node.Left == null && node.Right == null)
{
table[node.Value] = code;
return;
}
if (node.Left != null)
{
BuildHuffmanTable(node.Left, code + "0", table);
}
if (node.Right != null)
{
BuildHuffmanTable(node.Right, code + "1", table);
}
}
public static byte[] Compress(byte[] data)
{
var root = BuildHuffmanTree(data);
var table = new string[256];
BuildHuffmanTable(root, "", table);
using (var ms = new MemoryStream())
using (var bw = new BinaryWriter(ms))
{
// Write the Huffman tree to the stream
WriteHuffmanTree(root, bw);
// Write the compressed data to the stream
var code = "";
foreach (var b in data)
{
code += table[b];
while (code.Length >= 8)
{
var c = Convert.ToByte(code.Substring(0, 8), 2);
bw.Write(c);
code = code.Substring(8);
}
}
if (code.Length > 0)
{
code = code.PadRight(8, '0');
var c = Convert.ToByte(code, 2);
bw.Write(c);
}
return ms.ToArray();
}
}
private static void WriteHuffmanTree(HuffmanNode node, BinaryWriter bw)
{
if (node.Left == null && node.Right == null)
{
bw.Write(true);
bw.Write(node.Value);
return;
}
bw.Write(false);
WriteHuffmanTree(node.Left, bw);
WriteHuffmanTree(node.Right, bw);
}
public static byte[] Decompress(byte[] data)
{
using (var ms = new MemoryStream(data))
using (var br = new BinaryReader(ms))
{
// Read the Huffman tree from the stream
var root = ReadHuffmanTree(br);
// Read the compressed data from the stream
var result = new byte[ms.Length - ms.Position];
var node = root;
var i = 0;
while (ms.Position < ms.Length)
{
var b = br.ReadByte();
for (var j = 0; j < 8; j++)
{
if (((b >> (7 - j)) & 1) == 1)
{
node = node.Right;
}
else
{
node = node.Left;
}
if (node.Left == null && node.Right == null)
{
result[i] = node.Value;
node = root;
i++;
}
}
}
return result.Take(i).ToArray();
}
}
private static HuffmanNode ReadHuffmanTree(BinaryReader br)
{
if (br.ReadBoolean())
{
return new HuffmanNode { Value = br.ReadByte(), Frequency = 1 };
}
var left = ReadHuffmanTree(br);
var right = ReadHuffmanTree(br);
return new HuffmanNode { Value = 0, Frequency = left.Frequency + right.Frequency, Left = left, Right = right };
}
}
class Program
{
static void Main(string[] args)
{
var inputFileName = "input.bmp";
var outputFileName = "output.bmp";
// Load the image
var bitmap = new Bitmap(inputFileName);
// Convert the image to a byte array
var data = new byte[bitmap.Width * bitmap.Height * 3];
for (var y = 0; y < bitmap.Height; y++)
{
for (var x = 0; x < bitmap.Width; x++)
{
var color = bitmap.GetPixel(x, y);
data[(y * bitmap.Width + x) * 3] = color.R;
data[(y * bitmap.Width + x) * 3 + 1] = color.G;
data[(y * bitmap.Width + x) * 3 + 2] = color.B;
}
}
// Compress the data
var compressedData = Huffman.Compress(data);
// Save the compressed data to a file
File.WriteAllBytes(outputFileName, compressedData);
// Read the compressed data from the file
var input = File.ReadAllBytes(outputFileName);
// Decompress the data
var decompressedData = Huffman.Decompress(input);
// Convert the byte array back to an image
for (var y = 0; y < bitmap.Height; y++)
{
for (var x = 0; x < bitmap.Width; x++)
{
var r = decompressedData[(y * bitmap.Width + x) * 3];
var g = decompressedData[(y * bitmap.Width + x) * 3 + 1];
var b = decompressedData[(y * bitmap.Width + x) * 3 + 2];
bitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
// Save the decompressed image to a file
bitmap.Save("output.bmp");
}
}
}
```
请注意,此示例代码仅支持 24 位 RGB 格式的位图。其他格式的图片需要进行相应的修改。
阅读全文