像素数据到图像

时间:2013-04-21 10:35:01

标签: c#

我有这种格式的列表像素

ArrayList list = new ArrayList();
list.add(Red);
list.add(Blue);
list.add(Green);

我有很多像这样的价值观。我想将数组列表转换为图像..尝试了很多,但没有找到任何合适的材料。

编辑:这可能会有所帮助:

List<byte> pic = new List<byte>(); 
for (int j = 0; j < headdata.Count; j++)
{ 
    if(headdata.ElementAt(j).getHead() == i) 
    { 
        pic.Add((byte)headdata.ElementAt(j).getRed());
        pic.Add((byte)headdata.ElementAt(j).getGreen());
        pic.Add((byte)headdata.ElementAt(j).getBlue()); 
    }
} 

2 个答案:

答案 0 :(得分:9)

<强>更新

以为我会改进这篇文章以供将来参考。

如果将像素数据存储为32位整数数组(理想情况下为无符号),则要容易得多。每个整数的4个字节应分别对应于alpha,red,green和blue通道。如果您没有使用Alpha通道,请将其保持为空。

// If your image is always going to be the same size, make these constant -
// it speeds things up tremendously.
var width = 640;
var height = 480;

// Create the array to contain bitmap's pixel data.
// Making the pixels unsigned *can* speed up certain arithmetic operations,
// so use them if you're going to be manipulating colours as integers in the array.
// Note that array size is width * height only.
var pixels = new uint[width * height];

/* <Perform array operations here> */

// Create a handle to the object on the heap.
// Making it 'Pinned' prevents the GC from moving it around in memory.
var gchPixels = GCHandle.Alloc(pixels, GCHandleType.Pinned);

// Create the bitmap itself.
// Note: if you plan on making use of the alpha channel, make sure you use 
// Format32bppArgb instead (no P).
// Format32bppPArgb means that the alpha channel is present but should be ignored.
var bitmap = new Bitmap(width, height, width * sizeof(uint), 
                        PixelFormat.Format32bppPArgb,
                        gchPixels.AddrOfPinnedObject());

/* <Perform bitmap operations here> */

// Free the handle to stop the GC from pinning the array.
// This is important if you were dealing with a large array.
gchPixels.Free();

您可以创建自己的方法来设置某个坐标的像素:

public void SetPixel(int x, int y, uint colour) => pixels[x + y * width] = colour;

正如starbeamrainbowlabs所指出的那样:

GCHandleBitmapPixelFormat分别位于System.Runtime.InteropServicesSystem.DrawingSystem.Drawing.Imaging

下面的原始答案

有很好的方法可以做到这一点,但它要求你使用数组或字节而不是列表。

考虑一下:

// Define the width and the height of the image
int width = 100,
    height = 100;
/* Create an array of bytes consisting of the area's worth of pixels
 * with 3 bytes of data each.
 */
byte[] pixels = new byte[width * height * 3];

/* > Code for making the image etc. here < */

// Create our bitmap.
/* GCHandle requires System.Runtime.InteropServices
 * PixelFormat requires System.Drawing.Imaging.
 */
Bitmap bmp = new Bitmap(width, height, width * 3, PixelFormat.Format24bppRgb,
                        GCHandle.Alloc(pixels, GCHandleType.Pinned).AddrOfPinnedObject());

如果你想把它改成ARGB,只需用'4'改变'3'的所有实例, 并使用PixelFormat.Format32bppArgb。

正如我所说,这要求您使用数组而不是列表,但这需要 只要你知道图像的宽度和高度,就不应该太难。 在阵列中设置单个像素的好方法是(也许是一种方法 为此):

pixels[x + y * width]     = R;
pixels[x + y * width + 1] = G;
pixels[x + y * width + 2] = B;

这种方法通常也很快,如果这对你所做的一切都是必要的 做。

来源:经验。

答案 1 :(得分:5)

首先,正如我在评论中所说,最好使用 List 而不是 ArrayList 来避免装箱/拆箱。

然后,您需要 bpp (每像素位数)和宽度高度来创建图像。

如果您拥有所有这些值,那么您可以获得起始像素索引:

int i = ((y * Width) + x) * (depth / 8);

例如:

    List<byte> bytes = new List<byte>(); // this list should be filled with values
    int width = 100;
    int height = 100;
    int bpp = 24;

    Bitmap bmp = new Bitmap(width, height);

    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {   
            int i = ((y * width) + x) * (bpp / 8);
            if(bpp == 24) // in this case you have 3 color values (red, green, blue)
            {
                 // first byte will be red, because you are writing it as first value
                 byte r = bytes[i]; 
                 byte g = bytes[i + 1]; 
                 byte b = bytes[i + 2]; 
                 Color color = Color.FromArgb(r, g, b);
                 bmp.SetPixel(x, y, color); 
            }

        }
    }

您可以使用其他库来更快地创建位图和写入值。 ( SetPixel()非常慢。See