【问题标题】:Editing 8bpp indexed Bitmaps编辑 8bpp 索引位图
【发布时间】:2011-02-05 07:09:49
【问题描述】:

我正在尝试编辑 8bpp 的像素。由于此 PixelFormat 已编入索引,因此我知道它使用颜色表来映射像素值。尽管我可以通过将位图转换为 24bpp 来编辑位图,但 8bpp 的编辑速度要快得多(13 毫秒对 3 毫秒)。但是,在访问 8bpp 位图时更改每个值会导致一些随机的 rgb 颜色,即使 PixelFormat 仍然是 8bpp。

我目前在c#开发,算法如下:

(C#)

1- 以 8bpp 加载原始位图

2- 创建与原始大小相同的 8bpp 空临时位图

两个位图的 3-LockBits,并使用 P/Invoke 调用 c++ 方法,其中我传递每个 BitmapData 对象的 Scan0。 (我使用了 c++ 方法,因为它在遍历位图的像素时提供了更好的性能)

(C++)

4- 根据一些参数创建一个 int[256] 调色板,并通过调色板传递原始像素值来编辑临时位图字节。

(C#)

5- 解锁位。

我的问题是如何在没有奇怪的 rgb 颜色的情况下编辑像素值,或者更好的是,编辑 8bpp 位图的颜色表?

【问题讨论】:

    标签: c# gdi+ bitmap indexed


    【解决方案1】:

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

    颜色可能来自默认调色板。您会发现更改 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
    

    【讨论】:

    • 如何将新调色板应用于旧图像?是否也更改旧图像的大小?
    • 只需将Palette 属性设置回来。调整图像大小是不同的,在正确尺寸的新图像上使用Graphics.DrawImage。
    • Graphics.DrawImage 在索引像素格式上不受支持,并且转换为非索引会抵消使用索引格式的速度优势。
    • 如果你想在 c# 中调整索引图像的大小,你只需要自己编写基于处理原始字节数组的算法,然后使用 LockBits 将结果导入新的位图。或者以高颜色调整大小,然后将像素匹配回最接近的调色板匹配。
    • @nyerguds oh hai 来自 C&C :3
    【解决方案2】:

    假设您的索引 8ppp graysacle 存储在线性数组 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);
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 感谢您的回答。我知道我可以通过更改位图的调色板属性来修改位图的调色板。但是这样做太慢了。我希望有人能告诉我如何访问颜色表指针,以便我可以直接修改它。 SetPixel 不起作用,而且非常缓慢。我不明白为什么当我将像素的值从 0(黑色)更改为 100(应该是灰色但是红色)时,为什么会为像素分配 rgb 颜色。
      • 嗯。 Bitmap 继承自 Image...,因此具有相同的调色板。并且您可以简单地使用bm2.Palette = bm1.Palette 复制调色板。
      猜你喜欢
      • 2019-02-10
      • 1970-01-01
      • 2018-12-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 2015-09-24
      相关资源
      最近更新 更多