我正在制作一个小型油漆程序。我在位图上使用SetPixel来绘制线条。当画笔大小变大时,如同25个像素一样,会有明显的性能下降。我想知道是否有更快的方法来绘制位图。以下是该项目的背景知识:
我将包含我的绘图代码,以防万一这是缓慢而不是Set-Pixel位。
这是在绘画发生的窗口:
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
m_lastPosition = m_currentPosition;
m_currentPosition = e.Location;
if(m_penDown && m_pointInWindow)
m_currentTool.MouseMove(m_lastPosition, m_currentPosition, m_layer);
canvas.Invalidate();
}
MouseMove的实现:
public override void MouseMove(Point lastPos, Point currentPos, Layer currentLayer)
{
DrawLine(lastPos, currentPos, currentLayer);
}
DrawLine的实现:
// The primary drawing code for most tools. A line is drawn from the last position to the current position
public override void DrawLine(Point lastPos, Point currentPos, Layer currentLayer)
{
// Creat a line vector
Vector2D vector = new Vector2D(currentPos.X - lastPos.X, currentPos.Y - lastPos.Y);
// Create the point to draw at
PointF drawPoint = new Point(lastPos.X, lastPos.Y);
// Get the amount to step each time
PointF step = vector.GetNormalisedVector();
// Find the length of the line
double length = vector.GetMagnitude();
// For each step along the line...
for (int i = 0; i < length; i++)
{
// Draw a pixel
PaintPoint(currentLayer, new Point((int)drawPoint.X, (int)drawPoint.Y));
drawPoint.X += step.X;
drawPoint.Y += step.Y;
}
}
PaintPoint的实现:
public override void PaintPoint(Layer layer, Point position)
{
// Rasterise the pencil tool
// Assume it is square
// Check the pixel to be set is witin the bounds of the layer
// Set the tool size rect to the locate on of the point to be painted
m_toolArea.Location = position;
// Get the area to be painted
Rectangle areaToPaint = new Rectangle();
areaToPaint = Rectangle.Intersect(layer.GetRectangle(), m_toolArea);
// Check this is not a null area
if (!areaToPaint.IsEmpty)
{
// Go through the draw area and set the pixels as they should be
for (int y = areaToPaint.Top; y < areaToPaint.Bottom; y++)
{
for (int x = areaToPaint.Left; x < areaToPaint.Right; x++)
{
layer.GetBitmap().SetPixel(x, y, m_colour);
}
}
}
}
非常感谢您提供的任何帮助。
答案 0 :(得分:12)
您可以锁定位图数据并使用指针手动设置值。它快得多。虽然你必须使用不安全的代码。
public override void PaintPoint(Layer layer, Point position)
{
// Rasterise the pencil tool
// Assume it is square
// Check the pixel to be set is witin the bounds of the layer
// Set the tool size rect to the locate on of the point to be painted
m_toolArea.Location = position;
// Get the area to be painted
Rectangle areaToPaint = new Rectangle();
areaToPaint = Rectangle.Intersect(layer.GetRectangle(), m_toolArea);
Bitmap bmp;
BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = data.Stride;
unsafe
{
byte* ptr = (byte*)data.Scan0;
// Check this is not a null area
if (!areaToPaint.IsEmpty)
{
// Go through the draw area and set the pixels as they should be
for (int y = areaToPaint.Top; y < areaToPaint.Bottom; y++)
{
for (int x = areaToPaint.Left; x < areaToPaint.Right; x++)
{
// layer.GetBitmap().SetPixel(x, y, m_colour);
ptr[(x * 3) + y * stride] = m_colour.B;
ptr[(x * 3) + y * stride + 1] = m_colour.G;
ptr[(x * 3) + y * stride + 2] = m_colour.R;
}
}
}
}
bmp.UnlockBits(data);
}
答案 1 :(得分:5)
答案 2 :(得分:3)
我通常使用数组来表示原始像素数据。然后使用不安全的代码在该数组和位图之间进行复制。
制作Color
数组是一个坏主意,因为Color
结构相对较大(12字节+)。因此,您可以定义自己的4字节结构(这是我选择的结构),或者只使用int
或byte
的数组。
您还应该重复使用阵列,因为LOH上的GC往往很昂贵。
我的代码可以在以下网址找到:
https://github.com/CodesInChaos/ChaosUtil/blob/master/Chaos.Image/
另一种方法是直接使用指针将所有代码写入位图。这仍然有点快,但可能使代码更加丑陋,更容易出错。
答案 3 :(得分:1)
只是一个想法:使用画笔像素填充屏幕外的位图。只需更改画笔,大小或颜色时,您只需重新生成此位图。然后只需将此位图绘制到鼠标所在的现有位图上。 如果您可以使用颜色调制位图,则可以将像素设置为灰度并使用当前画笔颜色对其进行调制。
答案 4 :(得分:0)
您在嵌套for循环中调用GetBitmap。看起来没有必要,你应该在for循环之外使用GetBitmap,因为引用不会改变。
另请参阅@fantasticfix答案,Lockbits几乎总是通过获取/设置像素来排除性能问题