2012-10-10 62 views
0

如何使用C#压缩具有运行长度编码的图像?有没有可用的库来支持它?如何使用C#压缩具有运行长度编码的图像?

运行长度编码仅适用于位图图像吗?如果是这样,我将如何使用C#将图像类型转换为位图?

我也想问一下他们的文件类型是什么,之后他们会保留文件类型还是会有新文件?

+0

有人可以向我解释为什么这个问题被拒绝吗?在什么条件下? – user919789

+0

我会猜测缺乏研究。 –

+0

你的问题已被回答? –

回答

0

如果你看看周围,你会发现相当多的资源...

Run length encoding作品在一个字符串的形式几乎任何类型的数据。

但这里是Rosetta Code一个例子:

public static void Main(string[] args) 
    { 
     string input = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW"; 
     Console.WriteLine(Encode(input));//Outputs: 12W1B12W3B24W1B14W 
     Console.WriteLine(Decode(Encode(input)));//Outputs: WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW 
     Console.ReadLine(); 
    } 
    public static string Encode(string s) 
    { 
     StringBuilder sb = new StringBuilder(); 
     int count = 1; 
     char current =s[0]; 
     for(int i = 1; i < s.Length;i++) 
     { 
      if (current == s[i]) 
      { 
       count++; 
      } 
      else 
      { 
       sb.AppendFormat("{0}{1}", count, current); 
       count = 1; 
       current = s[i]; 
      } 
     } 
     sb.AppendFormat("{0}{1}", count, current); 
     return sb.ToString(); 
    } 
    public static string Decode(string s) 
    { 
     string a = ""; 
     int count = 0; 
     StringBuilder sb = new StringBuilder(); 
     char current = char.MinValue; 
     for(int i = 0; i < s.Length; i++) 
     { 
      current = s[i]; 
      if (char.IsDigit(current)) 
       a += current; 
      else 
      { 
       count = int.Parse(a); 
       a = ""; 
       for (int j = 0; j < count; j++) 
        sb.Append(current); 
      } 
     } 
     return sb.ToString(); 
    } 

你必须适应这个您的需求,但它应该让你开始。

+0

RLE并不局限于字符串,问题是二进制情​​况,因为它是关于位图数据的...... – Nyerguds

-2

压缩图像我已经写了一些功能: 这将调整宽度和确定纵横比的高度。请注意,如果图像的原始宽度小于新宽度,那么图像的大小不确定(您可以在代码中更改该宽度)。

public Bitmap ResizedImage(Stream imageStream, int newWidth) 
    { 
     Image image = Image.FromStream(imageStream); 
     int newwidthimg = image.Size.Width; 
     int newheightimg = image.Size.Height; 
     if (newWidth <= image.Size.Width) 
     { 
      newwidthimg = newWidth; 
      float AspectRatio = (float)image.Size.Width/(float)image.Size.Height; 
      newheightimg = Convert.ToInt32(newwidthimg/AspectRatio); 
     } 
     Bitmap thumbnailBitmap = new Bitmap(newwidthimg, newheightimg); 
     using (Graphics thumbnailGraph = Graphics.FromImage(thumbnailBitmap)) 
     { 
      thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality; 
      thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality; 
      thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic; 
      var imageRectangle = new Rectangle(0, 0, newwidthimg, newheightimg); 
      thumbnailGraph.DrawImage(image, imageRectangle); 
     } 
     return thumbnailBitmap; 
+1

这不是行程编码。 –

+1

这是缩小图像,并不回答问题。 – PhonicUK

1

我知道这是一个古老的问题,但它是在Google搜索中用C#进行RLE压缩的少数几件事之一。对于像我这样根本没有图像处理经验的人来说,这是一个非常令人沮丧的经历,所以希望这个答案能够在将来为别人节省一些痛苦。

据我所知,RLE是一种过时的压缩形式,但我们中的一些人坚持要求我们使用它的限制(如将bmp导出到自定义设备)。以下需要8bpp索引位图才能工作。如果您需要将图像转换为该格式的帮助,则可以在线获取大量资源。

我把它放在一个名为BmpCompressor的类中。

private enum Compression 
    { 
     // others not necessary for the 8bpp compression, but left for reference 
     //BI_RGB = 0x0000, 
     BI_RLE8 = 0x0001, 
     //BI_RLE4 = 0x0002, 
     //BI_BITFIELDS = 0x0003, 
     //BI_JPEG = 0x0004, 
     //BI_PNG = 0x0005, 
     //BI_CMYK = 0x000B, 
     //BI_CMYKRLE8 = 0x000C, 
     //BI_CMYKRLE4 = 0x000D 
    } 

    private enum BitCount 
    { 
     // others not necessary for the 8bpp compression, but left for reference 
     //Undefined = (ushort)0x0000, 
     //TwoColors = (ushort)0x0001, 
     //Max16Colors = (ushort)0x0004, 
     Max256Colors = (ushort)0x0008, 
     //Max32KBColors = (ushort)0x0010, 
     //Max16MBColors = (ushort)0x0018, 
     //Max16MBColors_Compressed = (ushort)0x0020 
    } 

    private struct RleCompressedBmpHeader 
    { 
     // Everything before the HeaderSize is technically not part of the header (it's not included in the HeaderSize calculation) 

     /// <summary> 
     /// Size of the .bmp file. 
     /// Always header size (40), plus palette size, plus image size, plus pre-header size (14); 
     /// </summary> 
     public uint Size; 

     /// <summary> 
     /// Offset to start of image data in bytes from the start of the file 
     /// </summary> 
     public uint Offset; 

     /// <summary> 
     /// Size of this header in bytes. (Always 40) 
     /// </summary> 
     public uint HeaderSize; // 4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4 

     /// <summary> 
     /// Width of bitmap in pixels 
     /// </summary> 
     public int Width; 

     /// <summary> 
     /// Height of bitmap in pixels 
     /// </summary> 
     public int Height; 

     /// <summary> 
     /// Number of Planes (layers). Always 1. 
     /// </summary> 
     public ushort Planes; 
     /// <summary> 
     /// Number of bits that define each pixel and maximum number of colors 
     /// </summary> 
     public BitCount BitCount; 

     /// <summary> 
     /// Defines the compression mode of the bitmap. 
     /// </summary> 
     public Compression Compression; 

     /// <summary> 
     /// Size, in bytes, of image. 
     /// </summary> 
     public uint ImageSize; 

     // These shouldn't really be all that important 
     public uint XPixelsPerMeter; 
     public uint YPixelsPerMeter; 

     /// <summary> 
     /// The number of indexes in the color table used by this bitmap. 
     /// <para>0 - Use max available</para> 
     /// <para>If BitCount is less than 16, this is the number of colors used by the bitmap</para> 
     /// <para>If BitCount is 16 or greater, this specifies the size of the color table used to optimize performance of the system palette.</para> 
     /// </summary> 
     public uint ColorUsed; 

     /// <summary> 
     /// Number of color indexes that are required for displaying the bitmap. 0 means all color indexes are required. 
     /// </summary> 
     public uint ColorImportant; 

     public byte[] ToBytes() 
     { 
      var swap = BitConverter.IsLittleEndian; 
      var result = new List<byte>(); 

      result.AddRange(new byte[] { 0x42, 0x4d }); // signature (BM) 
      result.AddRange(BitConverter.GetBytes(Size)); 
      result.AddRange(new byte[4]); // reserved 
      result.AddRange(BitConverter.GetBytes(Offset)); 
      result.AddRange(BitConverter.GetBytes(HeaderSize)); 
      result.AddRange(BitConverter.GetBytes(Width)); 
      result.AddRange(BitConverter.GetBytes(Height)); 
      result.AddRange(BitConverter.GetBytes(Planes)); 
      result.AddRange(BitConverter.GetBytes((ushort)BitCount)); 
      result.AddRange(BitConverter.GetBytes((uint)Compression)); 
      result.AddRange(BitConverter.GetBytes(ImageSize)); 
      result.AddRange(BitConverter.GetBytes(XPixelsPerMeter)); 
      result.AddRange(BitConverter.GetBytes(YPixelsPerMeter)); 
      result.AddRange(BitConverter.GetBytes(ColorUsed)); 
      result.AddRange(BitConverter.GetBytes(ColorImportant)); 

      return result.ToArray(); 
     } 
    } 

    public unsafe byte[] RunLengthEncodeBitmap(Bitmap bmp) 
    { 
     if (bmp.PixelFormat != PixelFormat.Format8bppIndexed) { throw new ArgumentException("The image must be in 8bppIndexed PixelFormat", "bmp"); } 

     var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed); 
     List<byte> result = new List<byte>(); 

     // Actual RLE algorithm. Bottom of image is first stored row, so start from bottom. 
     for (var rowIndex = bmp.Height - 1; rowIndex >= 0; rowIndex--) 
     { 
      byte? storedPixel = null; 
      var curPixelRepititions = 0; 
      var imageRow = (byte*)data.Scan0.ToPointer() + (rowIndex * data.Stride); 
      for (var pixelIndex = 0; pixelIndex < bmp.Width; pixelIndex++) 
      { 
       var curPixel = imageRow[pixelIndex]; 
       if (!storedPixel.HasValue) 
       { 
        curPixelRepititions = 1; 
        storedPixel = curPixel; 
       } 
       else if (storedPixel.Value != curPixel || curPixelRepititions == 255) 
       { 
        result.Add(Convert.ToByte(curPixelRepititions)); 
        result.Add(storedPixel.Value); 
        curPixelRepititions = 1; 
        storedPixel = curPixel; 
       } 
       else 
       { 
        curPixelRepititions++; 
       } 
      } 

      if (curPixelRepititions > 0) 
      { 
       result.Add(Convert.ToByte(curPixelRepititions)); 
       result.Add(storedPixel.Value); 
      } 

      if (rowIndex == 0) 
      { 
       // EOF flag 
       result.Add(0x00); 
       result.Add(0x01); 
      } 
      else 
      { 
       // End of Line Flag 
       result.Add(0x00); 
       result.Add(0x00); 
      } 
     } 

     bmp.UnlockBits(data); 

     var paletteSize = (uint)bmp.Palette.Entries.Length * 4; 
     var header = new RleCompressedBmpHeader(); 
     header.HeaderSize = 40; 
     header.Size = header.HeaderSize + paletteSize + (uint)result.Count + 14; 
     header.Offset = header.HeaderSize + 14 + paletteSize; // total header size + palette size 
     header.Width = bmp.Width; 
     header.Height = bmp.Height; 
     header.Planes = 1; 
     header.BitCount = BitCount.Max256Colors; 
     // as far as I can tell, PixelsPerMeter are not terribly important 
     header.XPixelsPerMeter = 0x10000000; 
     header.YPixelsPerMeter = 0x10000000; 
     header.Compression = Compression.BI_RLE8; 
     header.ColorUsed = 256; 
     header.ColorImportant = 0; // use all available colors 
     header.ImageSize = header.HeaderSize + (uint)result.Count; 

     var headerBytes = header.ToBytes(); 
     var paletteBytes = ConvertPaletteToBytes(bmp.Palette); 

     return headerBytes.Concat(paletteBytes).Concat(result).ToArray(); 
    } 

    private byte[] ConvertPaletteToBytes(ColorPalette colorPalette) 
    { 
     return colorPalette.Entries.SelectMany(c => new byte[] 
      { 
       c.B, 
       c.G, 
       c.R, 
       0 
      }).ToArray(); 
    } 

希望这会有所帮助!