位图/光栅软件使用两个内存缓冲区:一个是当前“持久”画布,其中包含用户已明确修改的像素,第二个是图形卡上的帧缓冲区,用于在屏幕上显示画布。
只需将内存中位图文档的原始字节复制到帧缓冲区即可使位图文档显示在屏幕上(如果帧缓冲区的字节格式或颜色深度与内存中位图不同,则您需要执行转换。如有必要,GDI 可以为您执行此操作,但我们假设一切都是 32 位 ARGB)。
在 WinForms 中,帧缓冲区由Graphics
传递给您的Control.OnPaint
覆盖的参数公开。
您可以使用以下两种方法之一来实现这些“预览”效果:
现代的
今天使用第一种方法,并且已经使用了 17 年左右(从 Windows 95 开始)。每当屏幕需要更新时,内存中的位图就会被复制到帧缓冲区,例如单个鼠标移动(甚至 1px)。然后在顶部绘制预览效果(例如用户释放鼠标按钮后将绘制的线条)。一旦用户的鼠标再次移动,该过程就会重复,以便更新预览。
你会有这样的事情:
public class PaintingCanvas : Control {
private Bitmap _canvas = new Bitmap();
private Boolean _inOp; // are we in a mouse operation?
private Point _opStart; // where the current mouse operation started
private Point _opEnd; // where it ends
public override void OnPaint(PaintEventArgs e) {
Graphics g = e.Graphics;
g.DrawImage( _canvas ); // draw the current state
if( _inOp ) {
// assuming the only operation is to draw a line
g.DrawLine( _opStart, _opEnd );
}
}
protected override OnMouseDown(Point p) {
_inOp = true;
_opStart = _opEnd = p;
}
protected override OnMouseMove(Point p) {
_opEnd = p;
this.Invalidate(); // trigger repainting
}
protected override OnMouseUp(Point p) {
using( Graphics g = Graphics.FromImage( _bitmap ) ) {
g.DrawLine( _opStart, _opEnd ); // a permanent line
}
_inOp = false;
}
}
1980 年代闪光黑
在过去(想想:1980 年代),将位图从内存复制到帧缓冲区很慢,所以一个非常好的 hack 是使用 XOR 绘画。该程序假定帧缓冲区的所有权(因此没有重叠的窗口会导致它需要从内存中复制)。预览线是通过对线将覆盖的所有像素执行异或来绘制的。这很快,因为对像素进行异或意味着可以恢复它们的原始颜色,而无需从内存中重新复制像素。直到最近,此技巧在计算机中用于多种选择、突出显示或预览效果。
highlightOrPreviewColor = originalPixelColor XOR (2^bpp - 1)
originalPixelColor = highlightOrPreviewColor XOR (2^bpp - 1)