2013-03-26 90 views
2

我试图用纯色背景色创建一个8位图像。它看起来应该是非常直接的,但文件中的细节列出它为32位颜色深度。我错过了什么?创建8位图像

public void CreateImage() 
    { 
     var bmpOut = new Bitmap(300, 300); 
     var g = Graphics.FromImage(bmpOut); 
     g.FillRectangle(new SolidBrush(Color.Gray), 0, 0, 300, 300); 

     var stream = new MemoryStream(); 
     bmpOut.Save(stream, GetPngCodecInfo(), GetEncoderParameters()); 

     bmpOut.Save(@"C:\image.png", GetPngCodecInfo(), GetEncoderParameters()); 
    } 

    public EncoderParameters GetEncoderParameters() 
    { 
     var parameters = new EncoderParameters(); 
     parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8); 

     return parameters; 
    } 

    public ImageCodecInfo GetPngCodecInfo() 
    { 
     var encoders = ImageCodecInfo.GetImageEncoders(); 

     ImageCodecInfo codecInfo = null; 

     foreach (var imageCodecInfo in encoders) 
     { 
      if (imageCodecInfo.FormatID != ImageFormat.Png.Guid) 
       continue; 

      codecInfo = imageCodecInfo; 
      break; 
     } 

     return codecInfo; 
    } 
+0

'“C:\ image.png”'是可能无效的路径...假设你有前面的@(或只是随机的字符串样品)。 – 2013-03-26 03:08:09

+0

从我所看到的,你缺少的东西是一个调色板... – Nyerguds 2017-04-11 14:21:45

回答

1

使用此构造指定的像素格式:http://msdn.microsoft.com/en-us/library/3z132tat.aspx

因为你不能在创建索引像素格式的图形,你可以只写原始像素的8位图像。

Bitmap bitmap = new Bitmap(32, 32, PixelFormat.Format8bppIndexed); 
var bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.ReadWrite, bitmap.PixelFormat); 
Random random=new Random(); 
byte[] buffer=new byte[bitmap.Width*bitmap.Height]; 
random.NextBytes(buffer); 
Marshal.Copy(buffer,0,bitmapData.Scan0,buffer.Length); 
bitmap.UnlockBits(bitmapData); 
bitmap.Save("test.bmp",ImageFormat.Bmp); 

您可以使用上的WinForms这样的代码:http://www.codeproject.com/Articles/17162/Fast-Color-Depth-Change-for-Bitmaps

或者,如果你可以从WPF引用此类就会容易得多: http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.formatconvertedbitmap(v=vs.85).aspx

+2

但要小心。仅仅指定像素格式是不够的,因为创建8位索引图像将在下一行失败 - 从图像创建一个“图形”。 – DocMax 2013-03-26 06:21:44

+0

从索引格式创建图形将引发异常:无法从具有索引像素格式的图像创建Graphics对象。 – Aybe 2013-03-26 13:55:42

+1

究竟是在那里做“Random”? – Nyerguds 2017-03-31 18:01:17

0
  • ImageExtensions.cs

    using System.Runtime.InteropServices; 
    using System.Linq; 
    
    using System.Drawing.Imaging; 
    using System.Drawing; 
    using System; 
    
    public static partial class ImageExtensions { 
        public static ColorPalette ToGrayScale(this ColorPalette palette) { 
         var entries=palette.Entries; 
    
         for(var i=entries.Length; i-->0; entries[i]=entries[i].ToGrayScale()) 
          ; 
    
         return palette; 
        } 
    
        public static Color ToGrayScale(this Color color, double[] luminance=null) { 
         var list=(luminance??new[] { 0.2989, 0.5870, 0.1140 }).ToList(); 
         var channel=new[] { color.R, color.G, color.B }; 
         var c=(byte)Math.Round(list.Sum(x => x*channel[list.IndexOf(x)])); 
         return Color.FromArgb(c, c, c); 
        } 
    
        public static Bitmap To8bppIndexed(this Bitmap original) { 
         var rect=new Rectangle(Point.Empty, original.Size); 
         var pixelFormat=PixelFormat.Format8bppIndexed; 
         var destination=new Bitmap(rect.Width, rect.Height, pixelFormat); 
    
         using(var source=original.Clone(rect, PixelFormat.Format32bppArgb)) { 
          var destinationData=destination.LockBits(rect, ImageLockMode.WriteOnly, pixelFormat); 
          var sourceData=source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat); 
    
          var destinationSize=destinationData.Stride*destinationData.Height; 
          var destinationBuffer=new byte[destinationSize]; 
    
          var sourceSize=sourceData.Stride*sourceData.Height; 
          var sourceBuffer=new byte[sourceSize]; 
    
          Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, sourceSize); 
          source.UnlockBits(sourceData); 
    
          destination.Palette=destination.Palette.ToGrayScale(); 
          var list=destination.Palette.Entries.ToList(); 
    
          for(var y=destination.Height; y-->0;) { 
           for(var x=destination.Width; x-->0;) { 
            var pixelIndex=y*destination.Width+x; 
            var sourceIndex=4*pixelIndex; 
    
            var color= 
             Color.FromArgb(
              sourceBuffer[0+sourceIndex], 
              sourceBuffer[1+sourceIndex], 
              sourceBuffer[2+sourceIndex], 
              sourceBuffer[3+sourceIndex] 
              ).ToGrayScale(); 
    
            destinationBuffer[pixelIndex]=(byte)list.IndexOf(color); 
           } 
          } 
    
          Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, destinationSize); 
          destination.UnlockBits(destinationData); 
         } 
    
         return destination; 
        } 
    } 
    

呼叫bmpOut=bmpOut.To8bppIndexed();你之前将其保存到文件中。

+0

有_no sense_在转换调色板为灰度为新的图像。只需使用颜色值从00,00,00到FF,FF,FF填充调色板。使用这样的调色板,您可以100%确定具有所有灰度值,并且放置在最终像素上的8位值仅等于实际灰度像素颜色的三个颜色分量中的任何一个。没有更多的查找需要。 – Nyerguds 2017-04-11 14:32:45