Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将8bpp图像转换为24bpp并保留颜色_C#_Bitmap_Gdi+ - Fatal编程技术网

C# 将8bpp图像转换为24bpp并保留颜色

C# 将8bpp图像转换为24bpp并保留颜色,c#,bitmap,gdi+,C#,Bitmap,Gdi+,我有一张8bpp的图片,上面有一张彩色图片 现在,我正在尝试将其转换为PixelFormat.Format24bppRgb格式图片。我正在使用直接像素访问,使用这里的代码 用法是 Bitmap bmp = (Bitmap) Image.FromFile("T:\\500-blue-orig.png"); LockBitmap lbmpSrc = new LockBitmap(bmp); Bitmap dst = new Bitmap(bmp.Width, bmp.Height, PixelFor

我有一张8bpp的图片,上面有一张彩色图片

现在,我正在尝试将其转换为
PixelFormat.Format24bppRgb
格式图片。我正在使用直接像素访问,使用这里的代码

用法是

Bitmap bmp = (Bitmap) Image.FromFile("T:\\500-blue-orig.png");
LockBitmap lbmpSrc = new LockBitmap(bmp);
Bitmap dst = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format24bppRgb);
LockBitmap lbmpDst = new LockBitmap(dst);

lbmpSrc.LockBits();
lbmpDst.LockBits();

dst.Palette = bmp.Palette;
for (int y = 0; y < lbmpSrc.Height; y++)
{
    for (int x = 0; x < lbmpSrc.Width; x++)
    {
        Color c = lbmpSrc.GetPixel(x, y);

        lbmpDst.SetPixel(x, y, c);
    }
}

lbmpDst.UnlockBits();
lbmpSrc.UnlockBits();

dst.Save("T:\\x.png", ImageFormat.Png);
Bitmap bmp=(Bitmap)Image.FromFile(“T:\\500 blue orig.png”);
LockBitmap lbmpSrc=新的锁位图(bmp);
位图dst=新位图(bmp.Width、bmp.Height、PixelFormat.Format24bppRgb);
LockBitmap lbmpDst=新的锁位图(dst);
lbmpSrc.LockBits();
lbmpDst.LockBits();
dst.palete=bmp.palete;
对于(int y=0;y
但是,即使我复制了原始调色板,最终的结果仍然是灰度图像


我做错了什么?如何从实际有颜色的
8bpp
图片中获取
24bpp
彩色图像?

您使用的
LockBitmap
类不关心调色板,它假定8bpp图像始终为灰度,只返回灰度

此外,该类还远远不够快,因为它将位图数据复制到另一个数组并返回,在不一定需要时创建
颜色
,等等。如果确实需要性能,您将自己处理

你有两个选择:

  • 直接使用
    Bitmap
    中的
    GetPixel
    SetPixel
    。它会正常工作

  • 首先将8bpp调色板图像复制到32/24bpp图像中,然后使用该类进行处理


我尝试了一种使用非托管代码的手动方法-本地基准测试显示它比无知(
Bitmap.GetPixel
Bitmap.SetPixel
)方法快99.7%

基本上,我们使用
LockBits
指针,并根据调色板逐个分配字节

static unsafe void To24Bpp(Bitmap source, Bitmap dest)
{
    var sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly,
        PixelFormat.Format8bppIndexed);
    var destData = dest.LockBits(new Rectangle(0, 0, dest.Width, dest.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
    var paletteBytes = source.Palette.Entries.Select(ColorToUintRgbLeftAligned).ToArray();
    var current = (byte*) sourceData.Scan0.ToPointer();
    var lastPtr = (byte*) (sourceData.Scan0 + sourceData.Width*sourceData.Height).ToPointer();
    var targetPtr = (byte*) destData.Scan0;
    while (current <= lastPtr)
    {
        var value = paletteBytes[*current++];
        targetPtr[0] = (byte) (value >> 24);
        targetPtr[1] = (byte) (value >> 16);
        targetPtr[2] = (byte) (value >> 8);
        targetPtr += 3;
    }

    source.UnlockBits(sourceData);
    dest.UnlockBits(destData);
}

static uint ColorToUintRgbLeftAligned(Color color)
{
    return ((uint) color.B << 24) + ((uint) color.G << 16) + ((uint) color.R << 8);
}
我在方法中创建位图不是为了进行基准测试,应该这样调用它:

static Bitmap To24Bpp(Bitmap source)
{
    var dest = new Bitmap(source.Width, source.Height, PixelFormat.Format24bppRgb);
    To24BppUintAssignment(source, dest);
    return dest;
}

这里的人似乎都可笑地把事情复杂化了。将8BPP映像转换为24BPP或32BPP不需要任何特殊代码

关于8BPP图像,唯一困难的是操作它们,而且,你根本不需要这样做;您的最终结果不是这些有问题的8BPP图像之一

您可以在不到五行的时间内完成:

public static Bitmap PaintOn32bpp(Image image)
{
    Bitmap bp = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);
    using (Graphics gr = Graphics.FromImage(bp))
        gr.DrawImage(image, new Rectangle(0, 0, bp.Width, bp.Height));
    return bp;
}

这将适用于任何图像,无论其颜色格式如何。

为什么不在旧位图的基础上使用新格式创建新位图,或者将位图绘制到新位图上?速度更快,代码更少。我确实使用了这些代码,仔细看,我使用的是LockBitmap中的GetPixel,而不是Bitmap。我不能复制位图,因为这是更复杂的图像处理方法的一部分。是的,对不起,注意到了。但是使用这个类并不是更好,因为仍然有颜色转换、方法调用和数据复制。可以做得更快。但是不能马上看出代码有什么问题。哦,等等。使用的代码假定8位图像始终为灰度。它不处理调色板。这就是原因。但是为什么原始图像有颜色呢?如何使用调色板获得实际颜色?好的,我可以尝试第二个选项。但出于好奇,我该如何实现一个关注调色板的GetPixel呢?8位图像根本不被认为是灰度图像。事实上,一旦进入字节级,它们就不会被“考虑”任何东西;它们只是字节。这些字节指的是图像调色板上的索引。@nyrguds如果您费心阅读正在使用的代码,它会特别假定8bpp值是灰度值,因为它返回的颜色将R、G和B设置为存储的值。正如我所说,它忽略了调色板,所以这只是将问题简化为“我使用的一些外部代码有缺陷”。我明白了。@nyrguds一点也没有bug,只是功能与假设的不同。正如我的回答所说。而不是“一些外部代码”,“这个外部代码”。出于好奇,如果我有一张24bpp的图片,我如何在调色板中找到正确的颜色?调色板每个条目都有一种颜色,如果你有颜色,你必须进行反向查找。
public static Bitmap PaintOn32bpp(Image image)
{
    Bitmap bp = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);
    using (Graphics gr = Graphics.FromImage(bp))
        gr.DrawImage(image, new Rectangle(0, 0, bp.Width, bp.Height));
    return bp;
}