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

2024-03-17

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

由于图形不支持索引颜色,因此您不能使用它,因此我尝试构建非索引位图(使用图形)并将其转换为索引颜色位图。转换很好,但我不知道如何设置输出图像的调色板。它默认为一些预定义的调色板,与我正在寻找的内容几乎没有关系。

So:

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

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


事实证明,我能够构建一个非索引位图并使用 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 位的。到目前为止看起来像是一个功能......不过如果我能明确地控制它那就太好了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • clang 格式换行符在错误的位置

    给出以下代码行 get abc manager get platform status abc platform status sw update status fill update status actions allowed stat
  • 内联函数/方法

    声明 内联函数必须在调用之前定义 这个说法正确吗 EDIT 该问题最初是德语 内联功能穆森 弗 伊赫雷姆 奥夫鲁夫定义 sein 也许它对任何人都有帮助 是的 它是正确的 但只是部分正确 它可能正确地重新构建如下 内联函数必须在每个翻译单位
  • 从多线程程序中调用 system()

    我们正在开发一个用 C 编写的多线程内存消耗应用程序 我们必须执行大量的 shellscript linux 命令 并获取返回码 读完之后article http www linuxprogrammingblog com threads a
  • 在 C# 中生成 HMAC-SHA1

    我正在尝试使用 C 来使用 REST API API 创建者提供了以下用于 hmac 创建的伪代码 var key1 sha1 body var key2 key1 SECRET KEY var key3 sha1 key2 var sig
  • 在 C++ 中将成对向量转换为两个独立向量的最快方法

    假设我有一个vector of pair
  • 从 C 结构生成 C# 结构

    我有几十个 C 结构 我需要在 C 中使用它们 典型的 C 结构如下所示 typedef struct UM EVENT ULONG32 Id ULONG32 Orgin ULONG32 OperationType ULONG32 Size
  • 获取尚未实例化的类的函数句柄

    我对 C 相当陌生 我想做的事情可能看起来很复杂 首先 我想获取一些函数的句柄以便稍后执行它们 我知道我可以通过以下方式实现这一目标 List
  • 预处理后解析 C++ 源文件

    我正在尝试分析c 使用我定制的解析器的文件 写在c 在开始解析之前 我想摆脱所有 define 我希望源文件在预处理后可以编译 所以最好的方法是运行C Preprocessor在文件上 cpp myfile cpp temp cpp or
  • 为什么具有相同名称但不同签名的多个继承函数不会被视为重载函数?

    以下代码片段在编译期间产生 对 foo 的调用不明确 错误 我想知道是否有任何方法可以解决此问题而不完全限定对 foo 的调用 include
  • 分配器感知容器和propagate_on_container_swap

    The std allocator traits模板定义了一些常量 例如propagate on container copy move assign让其他容器知道它们是否应该在复制或移动操作期间复制第二个容器的分配器 我们还有propag
  • tabcontrol selectedindex 更改事件未被触发 C#

    嘿伙计们 我有一个很小的问题 请参阅下面的代码 this is main load private void Form1 Load object sender EventArgs e tabAddRemoveOperator Selecte
  • 从 R 到 C 处理列表并访问它

    我想使用从 R 获得的 C 列表 我意识到这个问题与此非常相似 使用 call 在 R 和 C 之间传递数据帧 https stackoverflow com questions 6658168 passing a data frame f
  • WPF。如何从另一个窗口隐藏/显示主窗口

    我有两个窗口 MainWindow 和 Login 显示登录的按钮位于主窗口 this Hide Login li new Login li Show 登录窗口上有一个检查密码的按钮 如果密码正确 我如何显示主窗口 将参数传递给 MainW
  • 从 Delphi 调用 C# dll

    我用单一方法编写了 Net 3 5 dll 由Delphi exe调用 不幸的是它不起作用 步骤 1 使用以下代码创建 C 3 5 dll public class MyDllClass public static int MyDllMet
  • 使用 HTMLAgilityPack 从节点的子节点中选择所有

    我有以下代码用于获取 html 页面 将网址设置为绝对 然后将链接设置为 rel nofollow 并在新窗口 选项卡中打开 我的问题是关于将属性添加到 a s string url http www mysite com string s
  • C 中带有指针的结构的内存开销[重复]

    这个问题在这里已经有答案了 我意识到当我的结构包含指针时 它们会产生内存开销 这里有一个例子 typedef struct int num1 int num2 myStruct1 typedef struct int p int num2
  • 在 C++17 中使用 成员的链接错误

    我在 Ubuntu 16 04 上使用 gcc 7 2 并且需要使用 C 17 中的新文件系统库 尽管确实有一个名为experimental filesystem的库 但我无法使用它的任何成员 例如 当我尝试编译此文件时 include
  • C语言声明数组没有初始大小

    编写一个程序来操纵温度详细信息 如下所示 输入要计算的天数 主功能 输入摄氏度温度 输入功能 将温度从摄氏度转换为华氏度 独立功能 查找华氏度的平均温度 我怎样才能在没有数组初始大小的情况下制作这个程序 include
  • 带有私有设置器的 EFCore Base 实体模型属性 - 迁移奇怪的行为

    实体模型继承的类内的私有设置器似乎会导致 EFCore 迁移出现奇怪的问题 考虑以下示例 其中有多个类 Bar and Baz 继承自Foo 跑步时Add Migration多次命令 添加 删除private修饰符 生成的模式在多个方面都是
  • 如何使用 C# 以低分辨率形式提供高分辨率图像

    尝试使用 300dpi tif 图像在网络上显示 目前 当用户上传图像时 我正在动态创建缩略图 如果创建的页面引用宽度为 500x500px 的高分辨率图像 我可以使用相同的功能即时转换为 gif jpg 吗 将创建的 jpg 的即将分辨率

随机推荐