c# - 减少 C# 中的位图位大小

标签 c# bitmap

我正在使用 C#,并将图像存储在对象位图中。

现在我想将此图像转换为 8 位灰度,然后再转换为 4 位灰度图像。

你有什么制作技巧吗?

最佳答案

在 .NET 位图格式中,没有 8 位或 4 位灰度图像这样的东西。 PixelFormat enumeration 列举了支持的格式.但是,您可以通过创建索引图像(8bppIndexed 或 4bppIndexed)来创建 4 或 8 位图像,其中调色板中的每个条目都是一个灰度值。

此代码获取位图并创建一个副本作为具有灰度值的 8bpp 索引图像:

    public static Bitmap BitmapToGrayscale(Bitmap source)
    {
        // Create target image.
        int width = source.Width;
        int height = source.Height;
        Bitmap target = new Bitmap(width,height,PixelFormat.Format8bppIndexed);
        // Set the palette to discrete shades of gray
        ColorPalette palette = target.Palette;            
        for(int i = 0 ; i < palette.Entries.Length ; i++)
        {                
            palette.Entries[i] = Color.FromArgb(0,i,i,i);
        }
        target.Palette = palette;

        // Lock bits so we have direct access to bitmap data
        BitmapData targetData = target.LockBits(new Rectangle(0, 0, width,height),
                                                ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
        BitmapData sourceData = source.LockBits(new Rectangle(0, 0, width,height),
                                                ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

        unsafe
        {
            for(int r = 0 ; r < height ; r++)
            {
                byte* pTarget = (byte*) (targetData.Scan0 + r*targetData.Stride);
                byte* pSource = (byte*) (sourceData.Scan0 + r*sourceData.Stride);
                for(int c = 0 ; c < width ; c++)
                {
                    byte colorIndex = (byte) (((*pSource)*0.3 + *(pSource + 1)*0.59 + *(pSource + 2)*0.11));
                    *pTarget = colorIndex;
                    pTarget++;
                    pSource += 3;
                }
            }
        }

        target.UnlockBits(targetData);
        source.UnlockBits(sourceData);
        return target;
    }

为了制作 4Bpp 图像,您需要使用 PixelFormat.Format4bppIndexed 创建目标,然后将调色板设置为 16 种离散的灰色阴影。最后,在循环中,您应该将值 2 归一化到 0-15 之间,并将每 2 个像素值打包到一个字节中。

这是制作 4bpp 灰度图像的修改代码:

    public static Bitmap BitmapToGrayscale4bpp(Bitmap source)
    {
        // Create target image.
        int width = source.Width;
        int height = source.Height;
        Bitmap target = new Bitmap(width,height,PixelFormat.Format4bppIndexed);
        // Set the palette to discrete shades of gray
        ColorPalette palette = target.Palette;            
        for(int i = 0 ; i < palette.Entries.Length ; i++)
        {
            int cval = 17*i;
            palette.Entries[i] = Color.FromArgb(0,cval,cval,cval);
        }
        target.Palette = palette;

        // Lock bits so we have direct access to bitmap data
        BitmapData targetData = target.LockBits(new Rectangle(0, 0, width,height),
                                                ImageLockMode.ReadWrite, PixelFormat.Format4bppIndexed);
        BitmapData sourceData = source.LockBits(new Rectangle(0, 0, width,height),
                                                ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

        unsafe
        {
            for(int r = 0 ; r < height ; r++)
            {
                byte* pTarget = (byte*) (targetData.Scan0 + r*targetData.Stride);
                byte* pSource = (byte*) (sourceData.Scan0 + r*sourceData.Stride);
                byte prevValue = 0;
                for(int c = 0 ; c < width ; c++)
                {
                    byte colorIndex = (byte) ((((*pSource)*0.3 + *(pSource + 1)*0.59 + *(pSource + 2)*0.11)) / 16);
                    if (c % 2 == 0)
                        prevValue = colorIndex;
                    else
                        *(pTarget++) = (byte)(prevValue | colorIndex << 4);

                    pSource += 3;
                }
            }
        }

        target.UnlockBits(targetData);
        source.UnlockBits(sourceData);
        return target;
    }

关于c# - 减少 C# 中的位图位大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2703947/

相关文章:

c# - 需要保护 WCF 数据,但只是一个部分

c# - 值更改时触发事件 C#

c# - Moq第一次和第二次返回不同的值

java - 为静态使用加载位图对垃圾收集不利吗?

android - 位图变大要用getPixels?

c# - 无法使用 TextRenderer 获得正确的 DrawnText 大小

C# 导入 C++ 非托管 dll 并从一个 dll 创建多个实例?

c# - 如何禁用所有 Roslyn 代码分析器?

c++ - 如何将屏幕截图写入 PNG?

android - 更改位图的一种特定颜色