C# 从位图数组快速创建大位图的方法?
我有这个密码 复制/粘贴到新的winform应用程序中,如果您运行它,它将在您的桌面上写入一个文件:C# 从位图数组快速创建大位图的方法?,c#,vb.net,bitmap,gdi+,unsafe,C#,Vb.net,Bitmap,Gdi+,Unsafe,我有这个密码 复制/粘贴到新的winform应用程序中,如果您运行它,它将在您的桌面上写入一个文件:test123abcd.png Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load Dim SquareSize = 5 Dim GridX = 2500 Dim GridY = 2500 Dim SquareCount = GridX
test123abcd.png
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim SquareSize = 5
Dim GridX = 2500
Dim GridY = 2500
Dim SquareCount = GridX * GridY - 1
Dim sw As New Stopwatch
Dim Rect(4) As Rectangle
Rect(0) = New Rectangle(0, 3, 3, 1)
Rect(1) = New Rectangle(3, 0, 1, 3)
Rect(2) = New Rectangle(3, 3, 3, 1)
Rect(3) = New Rectangle(0, 0, 1, 3)
Dim fullsw = Stopwatch.StartNew
Using board = New Bitmap(SquareSize * (GridX + 1), SquareSize * (GridY + 1), Imaging.PixelFormat.Format32bppPArgb)
Using graph = Graphics.FromImage(board)
Using _board = New Bitmap(SquareSize, SquareSize, Imaging.PixelFormat.Format32bppPArgb)
Using g As Graphics = Graphics.FromImage(_board)
For i = 0 To SquareCount
g.Clear(If((i And 1) = 1, Color.Red, Color.Blue))
g.FillRectangles(Brushes.White, Rect)
sw.Start()
graph.DrawImageUnscaled(_board, ((i Mod GridX) * SquareSize), ((i \ GridY) * SquareSize))
sw.Stop()
Next
End Using
End Using
End Using
fullsw.Stop()
board.Save(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) & "\test123abcd.png", Imaging.ImageFormat.Png)
End Using
MessageBox.Show("Full SW: " & fullsw.ElapsedMilliseconds & Environment.NewLine &
"DrawImageUnscaled SW: " & sw.ElapsedMilliseconds)
End Sub
大约40%到45%的时间花在DrawImageUnscaled
上,在我当前的计算机上大约23秒,而整个过程大约需要50秒
有没有办法加速DrawImageUnscaled
?(也许是整个事情?)
编辑-vb.net中的问题,用c#回答,假设无法避免生成部分(
g.FillRectangles(Brush.White,Rect)
,也相当耗时),最好的办法是避免第二次图形生成过程(也适用于电路板
)只需从\u板
复制信息。复制比新一代(如下所示)要快得多,但您有一个问题,即源信息(\u board
)与目标格式(board
)不匹配,依赖于.SetPixel
),因此您必须创建一个函数,根据提供的信息确定当前像素(X/Y点)(当前矩形)
下面您可以看到一个简单的代码,显示两种方法之间的时间要求差异:
Dim SquareSize As Integer = 5
Dim _board As Bitmap = Bitmap.FromFile("in.png")
Dim board As Bitmap = New Bitmap(_board.Width * SquareSize, _board.Height * SquareSize)
For x As Integer = 0 To _board.Width - 1
For y As Integer = 0 To _board.Height - 1
board.SetPixel(x * SquareSize, y * SquareSize, _board.GetPixel(x, y))
Next
Next
board.Save("out1.png", Imaging.ImageFormat.Png)
board = New Bitmap(_board.Width, _board.Height)
Using board
Using graph = Graphics.FromImage(board)
Using _board
Using g As Graphics = Graphics.FromImage(_board)
For x As Integer = 0 To _board.Width - 1
For y As Integer = 0 To _board.Height - 1
graph.DrawImageUnscaled(_board, x, y)
Next
Next
End Using
End Using
End Using
board.Save("out2.png", Imaging.ImageFormat.Png)
End Using
请记住,它不是一个“正常工作的代码”。它的全部要点是显示如何在位图之间复制像素(通过乘以一个因子,只是为了得到不同于输入的输出);并将DrawImageUnscaled
方法置于同等条件下(尽管输出图片在逻辑上不同)了解两种方法在时间要求方面的差异
正如我在评论中所说,在目前的条件下,这就是我所能做的。我希望这将足以帮助您找到最佳解决方案。哇,我喜欢不安全的代码,因为它是值得的,最终用c解决了我的问题 这是代码,比我问题中的代码快70倍
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace BmpFile
{
public class BmpTest
{
private const int PixelSize = 4;
public static long Test(int GridX, int GridY, int SquareSize, Rectangle[][] Rect)
{
Bitmap bmp = new Bitmap(GridX * SquareSize, GridY * SquareSize, PixelFormat.Format32bppArgb);
BitmapData bmd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
int Stride = bmd.Stride;
int Height = bmd.Height;
int Width = bmd.Width;
int RectFirst = Rect.GetUpperBound(0);
int RectSecond;
int Offset1, Offset2, Offset3;
int i, j, k, l, w, h;
int FullRow = SquareSize * Stride;
int FullSquare = SquareSize * PixelSize;
var sw = System.Diagnostics.Stopwatch.StartNew();
unsafe
{
byte* row = (byte*)bmd.Scan0;
//draw all rectangles
for (i = 0; i <= RectFirst; ++i)
{
Offset1 = ((i / GridX) * FullRow) + ((i % GridX) * FullSquare) + 3;
RectSecond = Rect[i].GetUpperBound(0);
for (j = 0; j <= RectSecond; ++j)
{
Offset2 = Rect[i][j].X * PixelSize + Rect[i][j].Y * Stride;
w=Rect[i][j].Width;
h=Rect[i][j].Height;
for (k = 0; k <= w; ++k)
{
Offset3 = k * PixelSize;
for (l = 0; l <= h; ++l)
{
row[Offset1 + Offset2 + Offset3 + (l * Stride)] = 255;
}
}
}
}
//invert color
for (int y = 0; y < Height; y++)
{
Offset1 = (y * Stride) + 3;
for (int x = 0; x < Width; x++)
{
if (row[Offset1 + x * PixelSize] == 255)
{
row[Offset1 + x * PixelSize] = 0;
}
else
{
row[Offset1 + x * PixelSize] = 255;
}
}
}
}
sw.Stop();
bmp.UnlockBits(bmd);
bmp.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\test.png", ImageFormat.Png);
bmp.Dispose();
return sw.ElapsedMilliseconds;
}
}
}
使用系统;
使用系统图;
使用系统、绘图、成像;
命名空间BmpFile
{
公共类BmpTest
{
private const int PixelSize=4;
公共静态长测试(intgridx、intgridy、intsquaresize、Rectangle[]]Rect)
{
位图bmp=新位图(GridX*SquareSize、GridY*SquareSize、PixelFormat.Format32bppArgb);
BitmapData bmd=bmp.LockBits(新矩形(0,0,bmp.Width,bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
像素格式);
内跨步=骨密度跨步;
内部高度=骨密度高度;
内部宽度=骨密度宽度;
int RectFirst=Rect.GetUpperBound(0);
整数秒;
国际抵销1、抵销2、抵销3;
inti,j,k,l,w,h;
int FullRow=平方码*步幅;
int FullSquare=SquareSize*PixelSize;
var sw=System.Diagnostics.Stopwatch.StartNew();
不安全的
{
字节*行=(字节*)bmd.Scan0;
//绘制所有矩形
对于(i=0;i)您希望实现的具体目标是什么?(输入/输出)@varocarbas,我想保存分割成片段的完整位图,但我看不到任何输入图像或任何颜色数组。您基本上影响了空白位图中像素的位置/大小。这就是为什么我要问输入/输出问题的原因;例如,如果将image1.png和image2.png作为输入并希望将它们合并在一起你不需要做所有这些。如果你想重新缩放图像,你也不需要做所有这些,等等。最好的方法是(明显地)加速此循环正在采取另一种可能的方法,具体取决于具体情况。@varocarbas,输入是未知数量的小型\u板
,它们是在内存中创建的位图
,通过调用refreshSquare
,输出是板
,这是一个巨大的位图
c我正在做一些测试,DrawImageUnscaled显然花费了太长的时间。不幸的是,我不能完全确定它的功能;我使用的是从一个阵列到另一个阵列的简单逐像素复制(速度更快、更快)但我无法得到与DrawImageUnscale相同的结果。实际上,它提供了一种奇怪的行为(在代码中使用它):它不会精确复制所有像素(最终位于不同的位置),但还包括进一步的信息(在我的例子中是蓝色背景)…我接受了你对每个像素的想法,并创建了一个解决方案,请看我的代码答案。谢谢+1@Fredou我很高兴你能够解决你的问题。+1为你。我还没有测试你的代码,但我想它工作得很好。一个小问题是:你的代码是C#,问题标记为VB.NET。我用一个小问题更新了标记编辑并解释为什么同时使用vb.net和c#的原因。@Fredou好的,谢谢你让我知道。你应该继续并奖励你的答案为正确的答案;通常,我不太喜欢人们问自己和回答自己,但在这种情况下,这显然是正确的答案(尽管如此,我还没有测试你的代码:)。代码(c#)确实重现了我以前(vb.net)所做的相同输出,速度快了70倍(有时甚至更多)。在我的问题中,我说它需要50秒,现在同样的事情需要不到0.7秒。这是我意想不到的惊喜因素。