Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何从二维阵列创建和写入图像?_C#_.net - Fatal编程技术网

C# 如何从二维阵列创建和写入图像?

C# 如何从二维阵列创建和写入图像?,c#,.net,C#,.net,我有一个C#中的Color[,]数组(2d数组的Drawing.Color)。如何在本地将其保存为PNG 只使用构建中提供的.Net官方软件包,不使用其他库或Nuget软件包。简单的方法 首先创建一个具有所需尺寸的空白位图实例: Bitmap bmp = new Bitmap(100, 100); 在颜色数组中循环并打印像素: for (int i = 0; i < 100; i++) { for (int j = 0; j < 100; j++) { bmp.Se

我有一个C#中的
Color[,]
数组(2d数组的
Drawing.Color
)。如何在本地将其保存为PNG


只使用构建中提供的.Net官方软件包,不使用其他库或Nuget软件包。

简单的方法

首先创建一个具有所需尺寸的空白
位图
实例:

Bitmap bmp = new Bitmap(100, 100);
在颜色数组中循环并打印像素:

for (int i = 0; i < 100; i++)
{
  for (int j = 0; j < 100; j++)
  {
    bmp.SetPixel(i, j, colors[i,j]);
  }
}
更快的方法

Bitmap.SetPixel
方法速度较慢。访问位图像素的一种更快的方法是直接写入32位值的数组(假设您拍摄的是32位PNG),并让
bitmap
类使用该数组作为支持

一种方法是创建所述数组,并在其上获取
GCHandle
,以防止其被垃圾收集。
Bitmap
类提供了一个构造函数,允许您从数组指针、像素格式和跨距(构成像素数据单行的字节数)创建实例:

公共位图(整数宽度、整数高度、整数步幅、,
System.Drawing.Imaging.PixelFormat格式,IntPtr scan0);
这是创建备份数组、句柄和
位图
实例的方法:

Int32[]位=新的Int32[width*height];
GCHandle handle=GCHandle.Alloc(位,GCHandleType.pinted);
位图bmp=新位图(宽度、高度、宽度*4,
PixelFormat.Format32bppPArgb,handle.AddrOfPinnedObject());
请注意:

  • 因为我们使用的是32位像素格式,所以支持数组有32位条目
  • 位图
    跨距是
    宽度*4
    ,它是一行像素占用的字节数(每像素4字节)
这样,您就可以将像素值直接写入支持数组,它们将反映在
位图中。这比使用位图.SetPixel要快得多。下面是一个代码示例,它假设您已将所有内容封装在一个类中,该类知道位图的宽度和高度:

public void SetPixelValue(int x,int y,int color)
{
//出界?
如果(x<0 | | x>=宽度| | y<0 | | y>=高度)返回;
int index=x+(y*宽度);
位[索引]=颜色;
}
请注意,
color
是一个
int
值,而不是
color
值。如果您有一个
Color
值数组,则必须首先将每个值转换为
int
,例如

public void SetPixelColor(int x,int y,Color-Color)
{
设置像素值(x,y,color.ToArgb());
}
这种转换需要时间,因此最好始终使用
int
值。如果您确定从未使用过越界坐标,则可以通过放弃x/y边界检查来加快速度:

public void SetPixelValueUnchecked(int x, int y, int color)
{
  // No out of bounds checking.
  int index = x + (y * Width);
  Bits[index] = color;
}
这里有一个警告。如果您以这种方式包装
位图
,您仍然可以使用
图形
通过直接访问
位图
实例来绘制直线、矩形、圆等,但不需要通过固定阵列获得速度增益。如果您想更快地绘制这些基本体,则必须提供自己的直线/圆实现。请注意,根据我的经验,您自己的Bresenham line例程很难超越GDI的内置例程,因此它可能不值得

更快的方法

如果您能够一次性设置多个像素,事情可能会更快。如果具有具有相同颜色值的像素的水平序列,则这将适用。我发现在数组中设置序列的最快方法是使用
Buffer.BlockCopy
。(有关讨论,请参阅)。下面是一个实现:

/// <summary>
/// Set a sequential stretch of integers in the bitmap to a specified value.
/// This is done using a Buffer.BlockCopy that duplicates its size on each
/// pass for speed.
/// </summary>
/// <param name="value">Fill value</param>
/// <param name="startIndex">Fill start index</param>
/// <param name="count">Number of ints to fill</param>
private void FillUsingBlockCopy(Int32 value, int startIndex, int count)
{
  int numBytesInItem = 4;

  int block = 32, index = startIndex;
  int endIndex = startIndex + Math.Min(block, count);

  while (index < endIndex)          // Fill the initial block
    Bits[index++] = value;

  endIndex = startIndex + count;
  for (; index < endIndex; index += block, block *= 2)
  {
    int actualBlockSize = Math.Min(block, endIndex - index);
    Buffer.BlockCopy(Bits, startIndex * numBytesInItem, Bits, index * numBytesInItem, actualBlockSize * numBytesInItem);
  }
}
//
///将位图中整数的顺序拉伸设置为指定值。
///这是使用Buffer.BlockCopy完成的,该Buffer.BlockCopy在每个
///传速度。
/// 
///填充值
///填充起始索引
///要填充的整数数
使用BlockCopy(Int32值、int startIndex、int计数)填充私有无效
{
int numBytesInItem=4;
int block=32,index=startIndex;
int endIndex=startIndex+Math.Min(块,计数);
while(index
当您需要快速清除位图、使用水平线填充矩形或三角形(例如在之后)时,这将特别有用。

//Color 2D Array
var imgColors=新颜色[128128];
//从颜色数组中获取图像宽度和高度
int imageH=imgColors.GetLength(0);
int imageW=imgColors.GetLength(1);
//创建映像实例
位图img=新位图(imageW,imageH);
//在我们的图像上填充颜色
对于(整数x=0;x
您必须使用位图,然后调用。位图对象本身是一个三维数组(X、Y、RGB),因此您应该可以通过使用位图而不是颜色数组来完全绕过二维颜色数组。位图对象包含在特定坐标处设置/获取像素颜色的函数。要绘制某些东西,需要颜色和形状。你不能只用颜色来画画。OP和up的投票人也许应该复习一下这是WinForms吗?WPF?有没有更快的方法,比如不迭代所有行、列、按行/数组设置?@Daniel我更新了我的答案,观察了如何加快设置
位图中的像素。
/// <summary>
/// Set a sequential stretch of integers in the bitmap to a specified value.
/// This is done using a Buffer.BlockCopy that duplicates its size on each
/// pass for speed.
/// </summary>
/// <param name="value">Fill value</param>
/// <param name="startIndex">Fill start index</param>
/// <param name="count">Number of ints to fill</param>
private void FillUsingBlockCopy(Int32 value, int startIndex, int count)
{
  int numBytesInItem = 4;

  int block = 32, index = startIndex;
  int endIndex = startIndex + Math.Min(block, count);

  while (index < endIndex)          // Fill the initial block
    Bits[index++] = value;

  endIndex = startIndex + count;
  for (; index < endIndex; index += block, block *= 2)
  {
    int actualBlockSize = Math.Min(block, endIndex - index);
    Buffer.BlockCopy(Bits, startIndex * numBytesInItem, Bits, index * numBytesInItem, actualBlockSize * numBytesInItem);
  }
}
// Color 2D Array
var imgColors = new Color[128, 128];

// Get Image Width And Height Form Color Array
int imageH = imgColors.GetLength(0);
int imageW = imgColors.GetLength(1);

// Create Image Instance
Bitmap img = new Bitmap(imageW, imageH);

// Fill Colors on Our Image
for (int x = 0; x < img.Width; ++x)
{
    for (int y = 0; y < img.Height; ++y)
    {
        img.SetPixel(x, y, imgColors[x, y]);
    }
}

// Just Save it
img.Save("image.png", ImageFormat.Png);