【问题标题】:How to create a bitmap with 16 bits per pixel on MacOS?如何在 MacOS 上创建每像素 16 位的位图?
【发布时间】:2020-07-08 12:46:00
【问题描述】:

我想创建一个每像素 16 位的位图,但是当我指定任何像素格式时:

PixelFormat.Format16bppArgb1555, PixelFormat.Format16bppGrayScale, PixelFormat.Format16bppRgb555, PixelFormat.Format16bppRgb565

他们都抛出了一个System.NotImplementedException 并带有错误消息"Not Implemented"。我无法手动为每个像素分配 16 位,因为 Bitmap.SetPixel() 只允许您将一个字节设置为 alpha、red、green 或 blue(所以我需要使用需要特定像素格式的编组)。我没有为每个颜色值设置一个字节,而是尝试在红色、绿色和蓝色之间分配 16 位。例如红色 5 位,绿色 5 位,蓝色 5 位。

以下是每像素 16 位像素格式之一的示例,该格式会引发 System.NotImplementedException:

Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format16bppArgb1555);

我的系统是 MacOS。

【问题讨论】:

  • @mjwills 我有图像字节(即仅代表图像的字节,没有标头),我正在测试图像字节解码为的图像格式是否为每像素 16 位。
  • @harold 你在 MacOS 上吗?

标签: c# image-processing .net-core bitmap imaging


【解决方案1】:

System.Drawing 并不支持所有平台上的所有像素格式。一旦我collected 差异(请参阅不同平台上可能的像素格式的限制部分)。我认为 MacOS 使用与 Linux 版本相同的包。

由于Bitmap 编码器无论如何都无法保存保留Format16bppArgb1555 像素格式的图像,我建议您使用最接近的兼容格式(例如,Format32bppArgb 而不是Format16bppArgb1555)创建Bitmap 实例,如果您真的想将颜色转换为ARGB1555 颜色空间,您可以使用Quantize 方法和PredefinedColorsQuantizer.Argb1555,使用我链接的相同库进行比较。你可以从NuGet下载。

免责声明:我没有在 MacOS 上测试它,但它可以在 Linux (Ubuntu) 上运行。

我没有为每个颜色值设置一个字节,而是尝试在红色、绿色和蓝色之间分配 16 位。例如红色 5 位,绿色 5 位,蓝色 5 位。

编辑:我已经在开发下一个版本,它将允许在任何平台上使用带有任何PixelFormat 的托管位图数据。请参阅公开的BitmapDataFactory.CreateBitmapData 方法(尚未在公开版本中提供,但如果您查看Development 分支,您已经可以使用它了)。


更新:

我有图像字节(即只表示图像的字节,没有标题),我正在测试图像字节解码成的图像格式是否为每像素 16 位。

现在我明白为什么需要以 16 位原始格式设置像素了。就像在 Linux/MacOS 中一样,System.Drawing.Bitmap 对最简单的解决方案的支持有限,如果您如上所述创建托管位图数据。

注意:我发布了一个pre-release,它使BitmapDataFactory.CreateBitmapData 方法可用,而无需检查我的开发分支。现在您可以将任何PixelFormat 的原始字节转换为Bitmap,如下所示:

(当然,如果pfGuess 不是实际格式,结果可能会很混乱)

public Bitmap ToBitmap(byte[] rawData, PixelFormat pfGuess, Size size)
{
    // the result bitmap will be ARGB32, which works on every platform
    Bitmap result = new Bitmap(size.Width, size.Height);

    // we create an accessor for the result so we can quickly copy the translated pixels
    using var bitmapDataDst = result.GetWritableBitmapData();

    // For the managed source any pixel format will work.
    // Please note though that unlike System.Drawing.Bitmap images,
    // managed bitmap data never has padding bytes at the end of each line.
    // So if your rawData has padding (eg. when size has odd width and pf is 16bpp),
    // then maybe the best if you include the padding in width.
    // See https://docs.microsoft.com/en-us/windows/win32/medfound/image-stride for details
    using var bitmapDataSrc = BitmapDataFactory.CreateBitmapData(size, pfGuess);

    // Checking if rawData is long enough. RowSize is the width in bytes.
    if (rawData.Length < bitmapDataSrc.RowSize * size.Height)
        throw new ArgumentException("rawData is too short");

    int currentByte = 0;

    // iterating through rows
    for (int y = 0; y < size.Height; y++)
    {
        var rowSrc = bitmapDataSrc[y]; // has the specified pixel format
        var rowDst = bitmapDataDst[y]; // has ARGB32 pixel format

        // writing raw pixels
        for (int x = 0; x < bitmapDataSrc.RowSize; x++)
            rowSrc.WriteRaw<byte>(x, rawData[currentByte++]);

        // copying the pixels interpreted as pfGuess to result
        for (int x = 0; x < size.Width; x++)
            rowDst[x] = rowSrc[x];
    }

    // The result bitmap is now populated from the arbitrarily interpreted raw data.
    // As it has ARGB32 format you can save it on any platform without any issues.
    return result;
}

【讨论】:

  • Edit2:抱歉,第一个链接有误,现在用对照表指向正确的页面。
  • 没问题。这是我见过的最详细、最专业、最全面的非微软nuget包,干得好。我进行了第一次测试,但我不确定如何使用它。这就是我所做的:Bitmap bitmap = new Bitmap(width, height); BitmapExtensions.Quantize(bitmap, PredefinedColorsQuantizer.Argb1555()); Bitmap 对象的 pixelformat 属性在调试器中仍显示为 Format32bppArgb,我是否应该期望 pixelformat 属性显示 FormatArg1555?我错过了任何论点吗?
  • 就地量化不会改变像素格式,而是使用受限的色彩空间或调色板转换颜色。例如,如果您使用黑白或灰度量化器会更明显。
  • 那么上面的代码是使每个像素为 16bpp 的正确方法吗(也许您可以将您在 Ubuntu 上测试的代码添加到您的答案中)?在我执行量化位图像素尚未着色时,着色在我稍后运行Marshal.Copy() 时完成。由于量化会转换颜色,我应该在使用Marshal.Copy对像素着色后运行量化代码吗?
  • 在 Linux/MacOS 上,您无法创建具有 ARGB1555 像素格式的 Bitmap(尽管您将能够创建我提到的任何托管位图数据)。所以基本上你应该填充一个 32bpp 位图,最后你可以量化它,这样颜色就会被调整,就好像它是一个真正的 ARGB1555 位图一样。当然,实际像素格式不会改变。顺便说一句,即使在 Windows 中,一旦您通过任何编码器(例如 PNG)保存 16bpp 位图,重新加载的位图将具有 32bpp 格式,因此如果您想保留 16bpp 原始数据,则需要手动保存。这清楚还是我应该提供一个例子?
猜你喜欢
  • 2018-04-19
  • 1970-01-01
  • 1970-01-01
  • 2017-08-21
  • 2015-06-29
  • 2012-11-03
  • 2022-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多