【问题标题】:Easiest way to combine several PNG8 images in .NET在 .NET 中组合多个 PNG8 图像的最简单方法
【发布时间】:2010-12-05 02:02:46
【问题描述】:

我正在尝试在 C# 中将一堆 8 位 PNG 图像组合成一个更大的 PNG 图像。奇怪的是,这似乎特别困难。

由于 Graphics 不支持索引颜色,因此您不能使用它,所以我尝试构建一个非索引位图(使用 Graphics)并将其转换为索引颜色位图。转换很好,但我不知道如何设置输出图像的调色板。它默认为一些与我要查找的内容无关的预定义调色板。

所以:

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

Re:WriteableBitmap:我似乎无法在网上找到任何关于如何在这种情况下组合 PNG 的示例,或者即使尝试它是否有意义。

【问题讨论】:

  • 虽然专门指的是 GIF,但可能适用相同的颜色表原则...support.microsoft.com/kb/319061 只是在做非常相似的事情时对代码进行了一点试验。

标签: c# .net graphics gdi+


【解决方案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 位的。到目前为止看起来像一个功能......虽然如果我能明确控制它会很好。

【讨论】:

    【解决方案2】:

    免责声明,我为 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);
    

    如果您需要帮助,请对此答案发表评论或进入论坛。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-05
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 2018-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多