捕获一块屏幕并放入 PictureBox
Capture piece of screen and put into PictureBox
我正在使用 C# 开发一个工具来捕获一块屏幕并将其放入 PicBox 中,我已经能够获取屏幕截图,但我在一点上遇到了问题。我拍摄的镜头是从屏幕的开始拍摄的,我想给出镜头应该开始的坐标(X,Y)。
这是我的代码,有什么建议吗?
#region DLLIMPORTS
enum RasterOperation : uint { SRC_COPY = 0x00CC0020 }
[DllImport("coredll.dll")]
static extern int BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, RasterOperation rasterOperation);
[DllImport("coredll.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("coredll.dll")]
private static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
#endregion
public PrtScreenFrm()
{
InitializeComponent();
}
private void MakeLayout()
{
this.imageOriginalPicBox.Image = PrtScreenProjectCF.Properties.Resources.testImage;
this.imageOriginalPicBox.SizeMode = PictureBoxSizeMode.StretchImage;
}
private void PrtScreenFrm_Load(object sender, EventArgs e)
{
this.MakeLayout();
}
private void TakeScreenShot(Point _start, Point _end)
{
Rectangle boundsOfShot = new Rectangle((int)_start.X, (int)_start.Y, (int)(_end.X - _start.X), (int)(_end.Y - _start.Y));
IntPtr hdc = GetDC(IntPtr.Zero);
Bitmap shotTook = new Bitmap(boundsOfShot.Width, boundsOfShot.Height, PixelFormat.Format16bppRgb565);
using (Graphics draw = Graphics.FromImage(shotTook))
{
IntPtr dstHdc = draw.GetHdc();
BitBlt(dstHdc, 0, 0, boundsOfShot.Width, boundsOfShot.Height, hdc, 0, 0,
RasterOperation.SRC_COPY);
draw.ReleaseHdc(dstHdc);
}
imagePrintedPicBox.Image = shotTook;
imagePrintedPicBox.SizeMode = PictureBoxSizeMode.StretchImage;
ReleaseDC(IntPtr.Zero, hdc);
}
private void takeShotMenuItem_Click(object sender, EventArgs e)
{
Point start = new Point(3, 3); //here I am forcing the rectangle
Point end = new Point(237, 133); //to start where the picBox starts
TakeScreenShot(start, end); //but it doesn't work
}
非常感谢,我可能遗漏了一些愚蠢的东西,请给我点灯。
问题是您的 BitBlt
将 (0,0) 指定为源 X-Y 位置。更改此行:
BitBlt(dstHdc, 0, 0, boundsOfShot.Width, boundsOfShot.Height, hdc,
0, 0, RasterOperation.SRC_COPY);
至
BitBlt(dstHdc, 0, 0, boundsOfShot.Width, boundsOfShot.Height, hdc,
_start.X, _start.Y, RasterOperation.SRC_COPY);
修复了代码问题。
如果您需要其中一个控件的屏幕位置与 Location
属性 不同,您可以使用:
Point _start = this.imageOriginalPicBox.PointToScreen(this.imageOriginalPicBox.Location);
上面的解决方案适用于紧凑型框架,但如果您使用完整框架,它会有点过于复杂。为了完整起见,这里有两种更好的方法。
正如Yorye Nathan在评论中指出的,更简单的方法是使用Graphics
class的CopyFromScreen
方法。这将删除所有 p/Invokes,并将捕获代码减少为:
Rectangle boundsOfShot = new Rectangle(_start.X, _start.Y,
_end.X - _start.X, _end.Y - _start.Y);
Bitmap shotTook = new Bitmap(boundsOfShot.Width, boundsOfShot.Height,
PixelFormat.Format16bppRgb565);
using (Graphics draw = Graphics.FromImage(shotTook))
{
draw.CopyFromScreen(_start, new Point(0, 0), boundsOfShot.Size);
}
或者,如果您尝试捕获您自己的控件之一的位图:
Bitmap b = new Bitmap(this.imageOriginalPicBox.Width, this.imageOriginalPicBox.Height);
this.imageOriginalPicBox.DrawToBitmap(b,
new Rectangle(new Point(0, 0), this.imageOriginalPicBox.Size));
我明白了,B 的回答几乎是正确的,问题是我必须使用他所说的加上使用 .PointToScreen(Point.Empty) 将点传递给构造函数。
所以,而不是:
private void takeShotMenuItem_Click(object sender, EventArgs e)
{
Point start = new Point(3, 3);
Point end = new Point(237, 133);
TakeScreenShot(start, end);
}
我需要将方法调用为:
private void takeShotMenuItem_Click(object sender, EventArgs e)
{
Point start = imageOriginalPicBox.PointToScreen(Point.Empty);
Point end = new Point(imageOriginalPicBox.PointToScreen(Point.Empty).X + imageOriginalPicBox.Width, imageOriginalPicBox.PointToScreen(Point.Empty).Y + imageOriginalPicBox.Height);
TakeScreenShot(start, end);
}
现在可以正常使用了。感谢您的帮助。你让编码变得如此简单。
我正在使用 C# 开发一个工具来捕获一块屏幕并将其放入 PicBox 中,我已经能够获取屏幕截图,但我在一点上遇到了问题。我拍摄的镜头是从屏幕的开始拍摄的,我想给出镜头应该开始的坐标(X,Y)。 这是我的代码,有什么建议吗?
#region DLLIMPORTS
enum RasterOperation : uint { SRC_COPY = 0x00CC0020 }
[DllImport("coredll.dll")]
static extern int BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, RasterOperation rasterOperation);
[DllImport("coredll.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("coredll.dll")]
private static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
#endregion
public PrtScreenFrm()
{
InitializeComponent();
}
private void MakeLayout()
{
this.imageOriginalPicBox.Image = PrtScreenProjectCF.Properties.Resources.testImage;
this.imageOriginalPicBox.SizeMode = PictureBoxSizeMode.StretchImage;
}
private void PrtScreenFrm_Load(object sender, EventArgs e)
{
this.MakeLayout();
}
private void TakeScreenShot(Point _start, Point _end)
{
Rectangle boundsOfShot = new Rectangle((int)_start.X, (int)_start.Y, (int)(_end.X - _start.X), (int)(_end.Y - _start.Y));
IntPtr hdc = GetDC(IntPtr.Zero);
Bitmap shotTook = new Bitmap(boundsOfShot.Width, boundsOfShot.Height, PixelFormat.Format16bppRgb565);
using (Graphics draw = Graphics.FromImage(shotTook))
{
IntPtr dstHdc = draw.GetHdc();
BitBlt(dstHdc, 0, 0, boundsOfShot.Width, boundsOfShot.Height, hdc, 0, 0,
RasterOperation.SRC_COPY);
draw.ReleaseHdc(dstHdc);
}
imagePrintedPicBox.Image = shotTook;
imagePrintedPicBox.SizeMode = PictureBoxSizeMode.StretchImage;
ReleaseDC(IntPtr.Zero, hdc);
}
private void takeShotMenuItem_Click(object sender, EventArgs e)
{
Point start = new Point(3, 3); //here I am forcing the rectangle
Point end = new Point(237, 133); //to start where the picBox starts
TakeScreenShot(start, end); //but it doesn't work
}
非常感谢,我可能遗漏了一些愚蠢的东西,请给我点灯。
问题是您的 BitBlt
将 (0,0) 指定为源 X-Y 位置。更改此行:
BitBlt(dstHdc, 0, 0, boundsOfShot.Width, boundsOfShot.Height, hdc,
0, 0, RasterOperation.SRC_COPY);
至
BitBlt(dstHdc, 0, 0, boundsOfShot.Width, boundsOfShot.Height, hdc,
_start.X, _start.Y, RasterOperation.SRC_COPY);
修复了代码问题。
如果您需要其中一个控件的屏幕位置与 Location
属性 不同,您可以使用:
Point _start = this.imageOriginalPicBox.PointToScreen(this.imageOriginalPicBox.Location);
上面的解决方案适用于紧凑型框架,但如果您使用完整框架,它会有点过于复杂。为了完整起见,这里有两种更好的方法。
正如Yorye Nathan在评论中指出的,更简单的方法是使用Graphics
class的CopyFromScreen
方法。这将删除所有 p/Invokes,并将捕获代码减少为:
Rectangle boundsOfShot = new Rectangle(_start.X, _start.Y,
_end.X - _start.X, _end.Y - _start.Y);
Bitmap shotTook = new Bitmap(boundsOfShot.Width, boundsOfShot.Height,
PixelFormat.Format16bppRgb565);
using (Graphics draw = Graphics.FromImage(shotTook))
{
draw.CopyFromScreen(_start, new Point(0, 0), boundsOfShot.Size);
}
或者,如果您尝试捕获您自己的控件之一的位图:
Bitmap b = new Bitmap(this.imageOriginalPicBox.Width, this.imageOriginalPicBox.Height);
this.imageOriginalPicBox.DrawToBitmap(b,
new Rectangle(new Point(0, 0), this.imageOriginalPicBox.Size));
我明白了,B 的回答几乎是正确的,问题是我必须使用他所说的加上使用 .PointToScreen(Point.Empty) 将点传递给构造函数。 所以,而不是:
private void takeShotMenuItem_Click(object sender, EventArgs e)
{
Point start = new Point(3, 3);
Point end = new Point(237, 133);
TakeScreenShot(start, end);
}
我需要将方法调用为:
private void takeShotMenuItem_Click(object sender, EventArgs e)
{
Point start = imageOriginalPicBox.PointToScreen(Point.Empty);
Point end = new Point(imageOriginalPicBox.PointToScreen(Point.Empty).X + imageOriginalPicBox.Width, imageOriginalPicBox.PointToScreen(Point.Empty).Y + imageOriginalPicBox.Height);
TakeScreenShot(start, end);
}
现在可以正常使用了。感谢您的帮助。你让编码变得如此简单。