如何在 Magick.NET 中创建 8 bpp BMP?

How to create 8 bpp BMP in Magick.NET?

使用Magick.NET-Q8-AnyCPU。我想将现有的 TIFF 图像转换为灰度 8 bpp BMP 图像。我试过这个:

byte[] input = <existing TIFF image>;
using (var image = new MagickImage(input))
{
    image.Grayscale();
    image.ColorType = ColorType.Palette;
    image.Depth = 8;
    image.Quantize(new QuantizeSettings() { Colors = 256,  DitherMethod = DitherMethod.No });

    byte[] result = image.ToByteArray(MagickFormat.Bmp);

    return result;
}

在 FastStone Viewer 中,图像被报告为 8 位,但是在文件属性 > 详细信息中,图像被报告为位深度:32。我在这里需要它是 8。我可以在 Paint.NET 中转换此图像,当我在那里选择位深度:8 位时,新图像将在文件属性中正确显示 8 位深度。

因此,Paint.NET 创建了正确的 8 位位图。如何使用 Magick.NET?

看来这不可能。 image.Depth = 8image.BitDepth(8) 都不起作用。 可能是根在:

// ImageMagick.MagickImage.NativeMethods.X{ver.}
[DllImport("Magick.Native-Q8-x{ver.}.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MagickImage_SetBitDepth(IntPtr Instance, UIntPtr channels, UIntPtr value);

// ImageMagick.MagickImage.NativeMethods.X{ver.}
[DllImport("Magick.Native-Q8-x{ver.}.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MagickImage_WriteStream(IntPtr Instance, IntPtr settings, ReadWriteStreamDelegate writer, SeekStreamDelegate seeker, TellStreamDelegate teller, ReadWriteStreamDelegate reader, out IntPtr exception);

看起来它不能创建 8 位 .bmp,虽然 .png 没有问题。

var original = @"D:\tmp[=12=].tif";
var copy = @"D:\tmp[=12=].bmp";

using (var image = new MagickImage(original))
{
    image.Grayscale();
    image.ColorType = ColorType.Palette;
    image.Quantize(new QuantizeSettings() { Colors = 256, DitherMethod = DitherMethod.No });
    byte[] result = image.ToByteArray(MagickFormat.Png8);
    File.WriteAllBytes(copy, result);
}
Console.WriteLine("Press 'Enter'..."); // one have 8 bits .png here
Console.ReadLine();
using (var image = new MagickImage(copy))
{
    byte[] result = image.ToByteArray(MagickFormat.Bmp3);
    File.WriteAllBytes(copy, result);
} // but ends up with 32 bits .bmp again here

我也注意到

image.Quantize(new QuantizeSettings() { Colors = 16, DitherMethod = DitherMethod.No });

产生 4 位结果。逐渐增加给出 32 位,但永远不会是 8 位。

Windows 资源管理器将所有 压缩的 BMP 文件显示为 32 位,这与其实际位深度相反。

我不知道这是不是错误,但我更接近于将其称为错误。

因为;用你的代码创建一个 8bpp BMP 文件后,当我用二进制编辑器打开文件时,在位图头结构中我看到每像素字段值的位数(块 28-29)是 8 因为它必须是.此外,下一个字节 01(偏移量 30)表示使用 Run-length encoding 压缩的数据,这是一种直接的无损数据压缩算法。

因此,我可以说你用Magick.NET制作的图像没有问题,它肯定是一个8bpp的BMP图像文件,但是压缩了。

与 Magick.NET 的默认设置不同,似乎 Paint.NET 生成未压缩的 BMP 文件,这就是为什么您会因为 Windows Explorer 的怪异而看到不同的位深度。

要解决此问题,您可以禁用压缩,这样属性对话框中显示的位深度值将是您期望的值。

image.Settings.Compression = CompressionMethod.NoCompression;
byte[] result = image.ToByteArray(MagickFormat.Bmp);