Захват формы в растровое изображение после изменения размера формы
Работая в C# у меня есть проект с требованием захватить Control
или же Form
в растровое изображение. У меня есть класс, который занимает Control
параметр в конструкторе, а затем выполняет следующий код (упрощенный для этого примера), чтобы сохранить растровое изображение Control
,
public MyItem(Control control)
{
if (control != null)
{
Control rootParent = control;
while (rootParent.Parent != null)
rootParent = rootParent.Parent;
rootParent.BringToFront();
_bounds = control.Bounds;
Rectangle controlBounds;
if (control.Parent == null)
{
_bounds = new Rectangle(new Point(0, 0), control.Bounds.Size);
controlBounds = _bounds;
}
else
{
_bounds.Intersect(control.Parent.ClientRectangle);
_bounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(_bounds.Location)), _bounds.Size);
controlBounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(control.Location)), control.Size);
}
if (_bounds.Height > 0 && _bounds.Width > 0)
{
IntPtr hDC = IntPtr.Zero;
if (control.Parent == null && !Clarity.ClientAreaOnly)
// Used for capturing a form including non-client area
hDC = Win32.GetWindowDC(control.Handle);
else
// Used for capturing a form excluding non-client area or a control
hDC = control.CreateGraphics().GetHdc();
try
{
_controlBitmap = new Bitmap(_bounds.Width, _bounds.Height);
using (Graphics bitmapGraphics = Graphics.FromImage(_controlBitmap))
{
IntPtr bitmapHandle = bitmapGraphics.GetHdc();
Win32.BitBlt(bitmapHandle, 0, 0, _bounds.Width, _bounds.Height, hDC, _bounds.X - controlBounds.X, _bounds.Y - controlBounds.Y, 13369376);
bitmapGraphics.ReleaseHdc(bitmapHandle);
}
}
finally
{
if (hDC != IntPtr.Zero)
Win32.ReleaseDC(control.Handle, hDC);
}
}
}
}
Экземпляр этого класса создается для каждого элемента управления, который мне нужен для захвата, используется растровое изображение (в данном случае оно выводится на экран), и объект удаляется, когда он больше не нужен. Это прекрасно работает и дает мне растровое изображение указанного Control
или же Form
, включая не клиентскую область в случае последней, как показано ниже:
http://i.imgur.com/ZizXjNX.png
Однако, если я попытаюсь захватить Form
опять сталкиваюсь с проблемами. Если я изменил размер Form
перед повторным захватом второй захват покажет неверную область, не относящуюся к клиенту.
Ниже показано изображение, чтобы проиллюстрировать это - слева - то, как форма выглядит на экране (правильно), а справа - как этот код ее фиксирует (неправильно).
http://i.imgur.com/y46kFDj.png
Я не придумал ничего из моих собственных поисков и поэтому задавался вопросом, может ли кто-то указать на то, что я делаю неправильно / не делаю?
1 ответ
Я не смог решить эту проблему должным образом (сохранив существующий метод захвата), и, поскольку это касается прототипа приложения, у меня сейчас нет времени, чтобы углубляться в него. Если этот прототип будет поднят или у меня будет еще одна возможность изучить это снова, я обновлю этот ответ соответственно.
В то же время я использовал следующий подход в качестве альтернативы. Это производит вывод по желанию, хотя и использует другой механизм для захвата контента. Я не очень люблю это, так как это "портит" окна и формы больше, чем хотелось бы, но пока этого достаточно.
По сути, я просто перенес интересующее окно / форму на передний план, установил его на самый верхний, а затем сделал снимок экрана только на границах окна. Как я уже сказал, грязнее, чем хотелось бы, но на практике это работает достаточно хорошо!
public MyItem(Control control)
{
if (control != null)
{
Control rootParent = control;
while (rootParent.Parent != null)
rootParent = rootParent.Parent;
rootParent.BringToFront();
_bounds = control.Bounds;
Rectangle controlBounds;
if (control.Parent == null)
{
_bounds = new Rectangle(new Point(0, 0), control.Bounds.Size);
controlBounds = _bounds;
}
else
{
_bounds.Intersect(control.Parent.ClientRectangle);
_bounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(_bounds.Location)), _bounds.Size);
controlBounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(control.Location)), control.Size);
}
if (_bounds.Height > 0 && _bounds.Width > 0)
{
_controlBitmap = new Bitmap(_bounds.Width, _bounds.Height);
using (Graphics bitmapGraphics = Graphics.FromImage(_controlBitmap))
{
if (control.Parent == null)
{
Form form = control as Form;
Boolean currentTopMost = form.TopMost;
form.TopMost = true;
control.BringToFront();
bitmapGraphics.CopyFromScreen(control.Location, Point.Empty, _bounds.Size);
form.TopMost = currentTopMost;
}
else
{
IntPtr hDC = IntPtr.Zero;
try
{
hDC = control.CreateGraphics().GetHdc();
IntPtr bitmapHandle = bitmapGraphics.GetHdc();
Win32.BitBlt(bitmapHandle, 0, 0, _bounds.Width, _bounds.Height, hDC, _bounds.X - controlBounds.X, _bounds.Y - controlBounds.Y, 13369376);
bitmapGraphics.ReleaseHdc(bitmapHandle);
}
finally
{
if (hDC != IntPtr.Zero)
Win32.ReleaseDC(control.Handle, hDC);
}
}
}
}
}
}