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

4
我正在尝试在C#中将一堆8位PNG图像合并成一个更大的PNG图像。奇怪的是,这似乎特别困难。
由于Graphics不支持索引颜色,因此您不能使用它,因此我尝试构建非索引位图(使用Graphics)并将其转换为索引颜色位图。转换很好,但我无法弄清如何设置输出图像的调色板。它默认为一些预定义的调色板,与我所寻找的有点不同。
所以:
有没有办法控制位图调色板?还是有另一种方法(例如System.Windows.Media.Imaging.WriteableBitmap)可以支持此操作?
关于WriteableBitmap:我似乎找不到任何在线示例来说明如何在此上下文中组合PNG,甚至是否尝试进行这样的操作都没有意义。

尽管特指GIF,但相同的颜色表原则可能适用...在执行非常类似的操作时,只对http://support.microsoft.com/kb/319061中的代码进行了少量实验。 - Chris Baxter
2个回答

1

事实证明,我能够构建一个非索引位图并使用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 位。目前看起来像是一项特性……虽然如果我能有明确的控制权会更好。

0

声明:我是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);

如果您需要帮助,请在此答案下评论或发布到论坛中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接