C#位图设置Format8Bppined的像素值

C#位图设置Format8Bppined的像素值,c#,bitmap,C#,Bitmap,我有一个位图。我想更改所有像素的像素值。这是我的代码: // I use this : // - int width = 300 // - int height = 400 // - Byte[] matrix = new Byte[width * height] Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); for (int y = 0; y <

我有一个位图。我想更改所有像素的像素值。这是我的代码:

// I use this :
// - int width = 300
// - int height = 400
// - Byte[] matrix = new Byte[width * height]

Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
for (int y = 0; y < height; y++)
{
    for (int x = 0; x < width; x++)
    {
        byte pixValue = matrix[y * width + x];
        Color c = Color.FromArgb(pixValue, pixValue, pixValue);
        bmp.SetPixel(x, y, c);
    }
}
//我使用这个:
//-整数宽度=300
//-内部高度=400
//-字节[]矩阵=新字节[宽度*高度]
位图bmp=新位图(宽度、高度、系统、绘图、成像、像素格式、Format8Bppined);
对于(int y=0;y
之前,我将这段代码与位图格式24bpprgb一起使用,效果很好。现在我将其与Format8Bppined一起使用,但出现错误:

具有索引像素格式的图像不支持SetPixel


如何修复此问题?

您不能使用
SetPixel
,您应该在嵌套的
循环中执行类似操作:

int width = 300;
int height = 400;
Byte[] matrix = new Byte[width * height];
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
for (int y = 0; y < height; y++)
{
    for (int x = 0; x < width; x++)
    { 
        Color colorBefore = bmp.GetPixel(x, y);
        BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); 
        byte[] bytes = new byte[data.Height * data.Stride];
        Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
        bytes[y * data.Stride + x] = 7; 
        Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
        bmp.UnlockBits(data); 
    }
}
bmp.Save("D:\\imageBimap1.jpg", ImageFormat.Jpeg);
int-width=300;
内部高度=400;
字节[]矩阵=新字节[宽度*高度];
位图bmp=新位图(宽度、高度、像素格式.Format8Bppined);
对于(int y=0;y
从我所看到的,你有一个字节数组,你想制作一个8位图像,其中包含这些字节作为灰度值。这实际上非常简单,因为8位图像中需要的图像数据正是该数组中已有的数据。一般程序是:

  • 创建具有所需尺寸的新8位位图
  • 使用
    LockBits
    Marshal.Copy
    ,将数组的内容逐行复制到图像数据中。请注意,
    位图数据
    内的行长度可能与实际图像宽度不同;它通常四舍五入到四个字节的下一个倍数。因此,使用其
    Stride
    属性从数组中每行的开始处复制到
    BitmapData
    中每行的开始处,以了解数据中的线宽
  • 索引图像中的像素值实际上不是颜色;它们指的是图像调色板上的索引。因此,为你的图像生成一个灰度调色板,从黑到白,这样图像上的每个值都指向一种亮度完全相同的颜色
代码:

public static Bitmap MatrixToGrayImage(Byte[] matrix, Int32 width, Int32 height)
{
    // Create a new 8bpp bitmap
    Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
    // Get the backing data
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
    Int64 scan0 = data.Scan0.ToInt64();
    // Copy the contents of your matrix into the image, line by line.
    for (Int32 y = 0; y < height; y++)
        Marshal.Copy(matrix, y * width, new IntPtr(scan0 + y * data.Stride), width);
    bmp.UnlockBits(data);
    // Get the original palette. Note that this makes a COPY of the ColorPalette object.
    ColorPalette pal = bmp.Palette;
    // Generate grayscale colours:
    for (Int32 i = 0; i < 256; i++)
        pal.Entries[i] = Color.FromArgb(i, i, i);
    // Assign the edited palette to the bitmap.
    bmp.Palette = pal;
    return bmp;
}
公共静态位图矩阵xTograyImage(字节[]矩阵,Int32宽度,Int32高度)
{
//创建新的8bpp位图
位图bmp=新位图(宽度、高度、像素格式.Format8Bppined);
//获取支持数据
BitmapData data=bmp.LockBits(新矩形(0,0,宽度,高度),ImageLockMode.WriteOnly,PixelFormat.Format8Bppined);
Int64 scan0=data.scan0.ToInt64();
//将矩阵的内容逐行复制到图像中。
对于(Int32 y=0;y<高度;y++)
Marshal.Copy(矩阵,y*宽度,新IntPtr(扫描0+y*数据跨距),宽度);
解锁位(数据);
//获取原始调色板。请注意,这将创建ColorPalette对象的副本。
调色板pal=bmp.palete;
//生成灰度颜色:
对于(Int32 i=0;i<256;i++)
pal.Entries[i]=Color.FromArgb(i,i,i);
//将编辑的调色板指定给位图。
bmp.palete=pal;
返回bmp;
}

是不是
字节[x+数据.Stride*y]
?我已经尝试过了,但是我的图像没有正确保存。它必须是包含
字节[y*data.Stride+x]
的部分,我的
字节
数组长度是53360,我的矩阵是52900。我错过了什么?我已经测试了上面的代码,并且成功创建了
imageBimap1.jpg
,如果你的
300*400
w*h
数组是如何
53360
它应该是
120000
。这个代码做了一些非常奇怪的事情。。。锁位不应该在覆盖所有像素的循环的最低级别内完成。而且矩阵甚至没有被使用……而且,colorBefore从来没有被使用过,这意味着你会无缘无故地调用一个昂贵的
GetPixel
,为你编辑的每个像素指定一个任意值“7”,整个位图被复制到一个数组中,并为你更改的每个像素返回到图像中,当问题代码生成灰度颜色时,您永远不会更改图像的默认调色板,并且您将最终结果保存为jpeg,这意味着它将转换回24bpp,甚至使用有损压缩。