在.NET中组合多个PNG8图像的最简单方法

问题描述:

我试图在C#中将一组8位PNG图像组合成更大的PNG图像。奇怪的是,这似乎特别困难。在.NET中组合多个PNG8图像的最简单方法

因为Graphics不支持索引颜色,所以我不能使用它,所以我尝试构建一个非索引位图(使用图形)并将其转换为索引颜色位图。转换很好,但我无法弄清楚如何设置输出图像的调色板。它默认使用一些预定义的调色板,这与我正在寻找的内容无关。

所以:

有没有办法来控制位图调色板?还是有另一种方法(例如System.Windows.Media.Imaging.WriteableBitmap)可以支持这个?

Re:WriteableBitmap:我似乎无法在网上找到任何关于如何将PNG合并到此上下文中的示例,或者即使它尝试使用它也没有任何意义。

+0

尽管专门提到GIF,但相同的颜色表主要可能适用于... http://support.microsoft.com/kb/319061只有在做一些非常相似的事情时才会尝试使用代码。 – 2010-12-05 03:08:05

事实证明,我能够打造出一个非索引位图和使用转换PngBitmapEncoder像这样:

byte[] ConvertTo8bpp(Bitmap sourceBitmap) 
    { 
     // generate a custom palette for the bitmap (I already had a list of colors 
     // from a previous operation 
     Dictionary<System.Drawing.Color, byte> colorDict = new Dictionary<System.Drawing.Color, byte>(); // lookup table for conversion to indexed color 
     List<System.Windows.Media.Color> colorList = new List<System.Windows.Media.Color>(); // list for palette creation 
     byte index = 0; 
     unchecked 
     { 
      foreach (var cc in ColorsFromPreviousOperation) 
      { 
       colorDict[cc] = index++; 
       colorList.Add(cc.ToMediaColor()); 
      } 
     } 
     System.Windows.Media.Imaging.BitmapPalette bmpPal = new System.Windows.Media.Imaging.BitmapPalette(colorList); 

     // create the byte array of raw image data 
     int width = sourceBitmap.Width; 
     int height = sourceBitmap.Height; 
     int stride = sourceBitmap.Width; 
     byte[] imageData = new byte[width * height]; 

     for (int x = 0; x < width; ++x) 
      for (int y = 0; y < height; ++y) 
      { 
       var pixelColor = sourceBitmap.GetPixel(x, y); 
       imageData[x + (stride * y)] = colorDict[pixelColor]; 
      } 

     // generate the image source 
     var bsource = BitmapSource.Create(width, height, 96, 96, PixelFormats.Indexed8, bmpPal, imageData, stride); 

     // encode the image 
     PngBitmapEncoder encoder = new PngBitmapEncoder(); 
     encoder.Interlace = PngInterlaceOption.Off; 
     encoder.Frames.Add(BitmapFrame.Create(bsource)); 

     MemoryStream outputStream = new MemoryStream(); 
     encoder.Save(outputStream); 

     return outputStream.ToArray(); 
    } 

加上辅助扩展方法:

public static System.Windows.Media.Color ToMediaColor(this System.Drawing.Color color) 
    { 
     return new System.Windows.Media.Color() 
     { 
      A = color.A, 
      R = color.R, 
      G = color.G, 
      B = color.B 
     }; 
    } 

注意的警惕:PngBitmapEncoder实际上似乎可以将bpp计数从8减少到4。例如,当我使用6种颜色进行测试时,输出PNG只有4位。当我使用更色彩丰富的图像时,它是8位的。看起来像一个功能到目前为止...虽然它会很好,如果我有明确的控制权。

声明,我为Atalasoft工作。

我们的产品DotImage Photo是免费的,可以做到这一点。

要读取PNG

AtalaImage img = new AtalaImage("image.png"); 

要转换为24 BPP

img = img.GetChangedPixelFormat(newPixelFormat); 

创建大小的图像,你要

AtalaImage img2 = new AtalaImage(width, height, color); 

使用OverlayCommand叠加的img到IMG2

OverlayCommand cmd = new OverlayCommand(img); 
cmd.Apply(img2, point); 

为了节省

img2.Save("new.png", new PngEncoder(), null); 

如果您需要帮助这个答案无论是评论还是一个论坛条目。