38

我收到错误:

“不能从具有索引像素格式的图像创建图形对象。”

在功能上:

public static void AdjustImage(ImageAttributes imageAttributes, Image image)
{
        Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);

        Graphics g = Graphics.FromImage(image);       
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imageAttributes);
        g.Dispose();
}

我想问你,我该如何解决?

4

4 回答 4

45

参考这个,可以通过创建一个具有相同尺寸和正确 PixelFormat 的空白位图以及在该位图上绘制来解决。

// The original bitmap with the wrong pixel format. 
// You can check the pixel format with originalBmp.PixelFormat
Bitmap originalBmp = new (Bitmap)Image.FromFile("YourFileName.gif");

// Create a blank bitmap with the same dimensions
Bitmap tempBitmap = new Bitmap(originalBmp.Width, originalBmp.Height);

// From this bitmap, the graphics can be obtained, because it has the right PixelFormat
using(Graphics g = Graphics.FromImage(tempBitmap))
{
    // Draw the original bitmap onto the graphics of the new bitmap
    g.DrawImage(originalBmp, 0, 0);
    // Use g to do whatever you like
    g.DrawLine(...);
}

// Use tempBitmap as you would have used originalBmp
return tempBitmap;
于 2013-06-26T07:13:43.123 回答
14

最简单的方法是像这样创建一个新图像:

Bitmap EditableImg = new Bitmap(IndexedImg);

它会创建一个与原始图像完全相同的新图像及其所有内容。

于 2017-04-30T10:48:15.580 回答
2

总体而言,如果您想使用索引图像并实际保留它们的颜色深度和调色板,这将始终意味着为它们编写明确的检查和特殊代码。Graphics根本无法使用它们,因为它操纵颜色,索引图像的实际像素不包含颜色,只是索引。

对于这些年后仍然看到这一点的任何人......将图像绘制到现有(8位)索引图像上的有效方法是:

  • 查看您要粘贴的图像的所有像素,对于每种颜色,在目标图像的调色板中找到最接近的匹配,并将其索引保存到字节数组中。
  • 使用 打开索引图像的后备字节数组LockBits,并通过使用高度和图像步幅循环相关索引,将匹配的字节粘贴到所需位置。

这不是一件容易的事,但肯定是有可能的。如果粘贴的图像也被索引,并且包含超过 256 个像素,您可以通过在调色板上而不是在实际图像数据上进行颜色匹配来加快该过程,然后从另一个索引图像中获取支持字节,并重新映射他们使用创建的映射。

请注意,所有这些仅适用于八位。如果您的图像是 4 位或 1 位,处理它的最简单方法是先将其转换为 8 位,这样您就可以将其处理为每个像素一个字节,然后再将其转换回来。

有关这方面的更多信息,请参阅如何使用 1 位和 4 位图像?

于 2018-08-08T19:22:10.183 回答
0

尽管接受的答案有效,但它会从索引位图创建一个新的 32bpp ARGB 图像。

要直接操作索引位图,您可以使用这个库(警告:无耻的自我提升)。它的GetReadWriteBitmapData扩展允许为索引像素格式创建一个可写的托管访问器。

然后您可以使用与DrawInto类似的方法之一Graphics.DrawImage。当然,当目标位图被索引时,绘图操作必须使用目标调色板颜色量化像素,但是有一种重载可以使用抖动来保留更多图像细节。

用法示例(请参阅上面链接中的更多示例):

using (IReadWriteBitmapData indexedTarget = myIndexedBitmap.GetReadWriteBitmapData())
using (IReadableBitmapData source = someTrueColorBitmap.GetReadableBitmapData())
{
    // or DrawIntoAsync if you want to use async-await
    source.DrawInto(indexedTarget, targetRect, OrderedDitherer.Bayer8x8);
}

图片示例:

下面的所有图像都是PixelFormat.Format8bppIndexed使用默认调色板的格式创建的,并且一个 256x256 的图标和一个 alpha 渐变彩虹被绘制在彼此的顶部。请注意,尽可能多地使用可用调色板进行混合。

图片 描述
在图标上绘制的 8bpp alpha 渐变,没有抖动 无抖动
在带有有序抖动的图标上绘制的 8bpp alpha 渐变 有序Bayer8x8抖动
在带有误差扩散抖动的图标上绘制的 8bpp alpha 渐变 Floyd-Steinberg误差扩散抖动

免责声明:当然,与 相比,该库也有一些限制Graphics,例如没有绘制形状的方法。但在最坏的情况下,您仍然可以使用已接受的答案,然后ConvertPixelFormat在需要生成索引结果时最后调用该方法。

于 2022-01-25T14:31:15.957 回答