编辑 8bpp 索引位图

发布于 2024-08-27 15:10:03 字数 585 浏览 8 评论 0原文

我正在尝试编辑 8bpp 的像素。由于此 PixelFormat索引,我知道它使用颜色表来映射像素值。

尽管我可以通过将位图转换为 24bpp 来编辑位图,但 8bpp 编辑要快得多(13 毫秒 vs 3 毫秒)。但是,在访问 8bpp 位图时更改每个值会导致一些随机的 RGB 颜色,即使 PixelFormat 仍为 8bpp。

我目前正在使用 C# 进行开发,算法如下:

  1. 以 8bpp 加载原始位图
  2. 使用 8bpp 创建空临时位图,其大小与
  3. 两个位图的原始 LockBits 相同,并使用 P/Invoke 调用 C++ 方法,其中我传递每个 BitmapData 对象的 Scan0。 (我使用了 C++ 方法,因为它在迭代位图像素时提供了更好的性能)
  4. 根据一些参数创建一个 int[256] 调色板,并通过将原始的像素值传递给调色板。
  5. 解锁位。

我的问题是如何在不使用奇怪的 RGB 颜色的情况下编辑像素值。或者,更好的是,如何编辑 8bpp 位图的颜色表?

i'm trying to edit the pixels of a 8bpp. Since this PixelFormat is indexed i'm aware that it uses a Color Table to map the pixel values.

Even though I can edit the bitmap by converting it to 24bpp, 8bpp editing is much faster (13ms vs 3ms). But, changing each value when accessing the 8bpp bitmap results in some random rgb colors even though the PixelFormat remains 8bpp.

I'm currently developing in C# and the algorithm is as follows:

  1. Load original Bitmap at 8bpp
  2. Create Empty temp Bitmap with 8bpp with the same size as the original
  3. LockBits of both bitmaps and, using P/Invoke, calling C++ method where I pass the Scan0 of each BitmapData object. (I used a C++ method as it offers better performance when iterating through the Bitmap's pixels)
  4. Create a int[256] palette according to some parameters and edit the temp bitmap bytes by passing the original's pixel values through the palette.
  5. UnlockBits.

My question is how can I edit the pixel values without having the strange rgb colors. Or, even better, how can I edit the 8bpp bitmap's Color Table?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

世界等同你 2024-09-03 15:10:03

根本不需要进入 C++ 领域或使用 P/Invoke; C# 完全支持指针和不安全代码;我什至可能会猜测这是导致您出现问题的原因。

颜色可能来自默认调色板。您会发现更改调色板一点也不慢。这就是我创建灰度调色板的方法:

image = new Bitmap( _size.Width, _size.Height, PixelFormat.Format8bppIndexed);
ColorPalette pal = image.Palette;
for(int i=0;i<=255;i++) {
    // create greyscale color table
    pal.Entries[i] = Color.FromArgb(i, i, i);
}
image.Palette = pal; // you need to re-set this property to force the new ColorPalette

There is no need to move into C++ land or use P/Invoke at all; C# supports pointers and unsafe code perfectly fine; I may even hazard a guess that this is causing your problems.

The colors are likely coming from the default Palette. You'll find that changing the Palette shouldn't be slow at all. This is what I do to create a greyscale palette:

image = new Bitmap( _size.Width, _size.Height, PixelFormat.Format8bppIndexed);
ColorPalette pal = image.Palette;
for(int i=0;i<=255;i++) {
    // create greyscale color table
    pal.Entries[i] = Color.FromArgb(i, i, i);
}
image.Palette = pal; // you need to re-set this property to force the new ColorPalette
执笏见 2024-09-03 15:10:03

想象一下,您的索引 8ppp 灰度存储在线性数组 dataB 中(为了速度)

尝试以下代码:

//Create 8bpp bitmap and look bitmap data
bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
bmp.SetResolution(horizontalResolution, verticalResolution);
bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

//Create grayscale color table
ColorPalette palette = bmp.Palette;
for (int i = 0; i < 256; i++)
    palette.Entries[i] = Color.FromArgb(i, i, i);
bmp.Palette = palette;

//write data to bitmap
int dataCount = 0;
int stride = bmpData.Stride < 0 ? -bmpData.Stride : bmpData.Stride;
unsafe
{
    byte* row = (byte*)bmpData.Scan0;
    for (int f = 0; f < height; f++)
    {
        for (int w = 0; w < width; w++)
        {
            row[w] = (byte)Math.Min(255, Math.Max(0, dataB[dataCount]));
            dataCount++;
        }
        row += stride;
    }
}

//Unlock bitmap data
bmp.UnlockBits(bmpData);

Imagine that your indexed 8ppp graysacle are stored in a linear array dataB (for speed)

Try this code:

//Create 8bpp bitmap and look bitmap data
bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
bmp.SetResolution(horizontalResolution, verticalResolution);
bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

//Create grayscale color table
ColorPalette palette = bmp.Palette;
for (int i = 0; i < 256; i++)
    palette.Entries[i] = Color.FromArgb(i, i, i);
bmp.Palette = palette;

//write data to bitmap
int dataCount = 0;
int stride = bmpData.Stride < 0 ? -bmpData.Stride : bmpData.Stride;
unsafe
{
    byte* row = (byte*)bmpData.Scan0;
    for (int f = 0; f < height; f++)
    {
        for (int w = 0; w < width; w++)
        {
            row[w] = (byte)Math.Min(255, Math.Max(0, dataB[dataCount]));
            dataCount++;
        }
        row += stride;
    }
}

//Unlock bitmap data
bmp.UnlockBits(bmpData);
久隐师 2024-09-03 15:10:03

您是否尝试过加载System.Drawing.Image?该类使您可以访问调色板。设置调色板后,您可以将 System.Drawing.Image 包装为 System.Drawing.Bitmap

我不确定 System.Drawing.BitMap.SetPixel() 如何处理索引彩色图像。它可能会尝试将其映射到调色板中最接近的颜色。

Have you tried loading a System.Drawing.Image instead? That class gives you access to the colour palette. You can then wrap the System.Drawing.Image up as a System.Drawing.Bitmap once the palette is set.

I'm not sure how System.Drawing.BitMap.SetPixel() works with indexed coloured images. It could be it tries to map it to the closest colour in the palette.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文