#c# #graphics #bitmap #gdi #bitblt
#c# #графика #растровое изображение #gdi #bitblt
Вопрос:
Я пытаюсь скопировать содержимое графического объекта в bitmap. Я использую этот код
public static class GraphicsBitmapConverter
{
[DllImport("gdi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
public static Bitmap GraphicsToBitmap(Graphics g, Rectangle bounds)
{
Bitmap bmp = new Bitmap(bounds.Width, bounds.Height);
using (Graphics bmpGrf = Graphics.FromImage(bmp))
{
IntPtr hdc1 = g.GetHdc();
IntPtr hdc2 = bmpGrf.GetHdc();
BitBlt(hdc2, 0, 0, bmp.Width, bmp.Height, hdc1, 0, 0, TernaryRasterOperations.SRCCOPY);
g.ReleaseHdc(hdc1);
bmpGrf.ReleaseHdc(hdc2);
}
return bmp;
}
}
Если я использую метод, подобный этому
Graphics g = button1.CreateGraphics();
var bmp = GraphicsBitmapConverter.GraphicsToBitmap(g, Rectangle.Truncate(g.VisibleClipBounds));
растровое изображение содержит содержимое. Но если я рисую графический объект перед вызовом методов, bitmap будет пустым:
using (Bitmap bmp = new Bitmap(100, 100))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillRectangle(Brushes.Red, 10, 10, 50, 50);
g.FillRectangle(Brushes.Blue, 20, 20, 50, 50);
g.FillRectangle(Brushes.Green, 0, 0, bmp.Width, bmp.Height);
var bmp2 = GraphicsBitmapConverter.GraphicsToBitmap(g, Rectangle.Truncate(g.VisibleClipBounds));
}
}
Почему это работает в первом случае, а не во втором?
Комментарии:
1. Вы проверяете возвращаемое значение BitBlt()? Возможно, это сбой и может привести к подсказкам.
2. код неполный
Ответ №1:
Насколько я понимаю
Graphics g = Graphics.FromImage(bmp)
создает графический контекст для рисования в изображении, тогда как
Graphics g = button1.CreateGraphics();
создает изображение для элемента управления, который уже был выведен на экран. Вы могли бы нарисовать динамически созданное растровое изображение в PictureBox, а затем сделать то же самое, что и для вашей кнопки, что-то вроде
using (Bitmap bmp = new Bitmap(100, 100))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillRectangle(Brushes.Green, 0, 0, bmp.Width, bmp.Height);
g.FillRectangle(Brushes.Red, 10, 10, 50, 50);
g.FillRectangle(Brushes.Blue, 20, 20, 50, 50);
pictureBox1.Image = bmp;
pictureBox1.Update(); // force an update before doing anything with it
Graphics g2 = pictureBox1.CreateGraphics();
var bmp2 = GraphicsBitmapConverter.GraphicsToBitmap(g2, Rectangle.Truncate(g.VisibleClipBounds));
// bmp2 now has the same contents as bmp1
pictureBox1.Image = null; // bmp is about to be Disposed so remove the reference to it
}
}
Конечно, это просто воссоздает Bitmap, который у вас уже есть, поэтому я предполагаю, что вы имеете в виду какое-то другое использование.
Ответ №2:
Вы пытались удалить свою графику?
using (Bitmap bmp = new Bitmap(100, 100))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillRectangle(Brushes.Red, 10, 10, 50, 50);
g.FillRectangle(Brushes.Blue, 20, 20, 50, 50);
g.FillRectangle(Brushes.Green, 0, 0, bmp.Width, bmp.Height);
g.Flush(); // !!
var bmp2 = GraphicsBitmapConverter.GraphicsToBitmap(g, Rectangle.Truncate(g.VisibleClipBounds));
}
}
Ответ №3:
Вы делаете это сложным способом. Очевидно, что, поскольку один и тот же код выполняется успешно и завершается неудачей при разных вызовах, графика использует разное временное пространство для хранения информации до тех пор, пока не будет запрошено завершение с помощью create graphics — иначе оно должно быть прочитано в обоих случаях.
Попробуйте использовать
gr.Save();
для графики, возможно, это сработает перед созданием.
Однако, когда я хочу приступить к рисованию, я просто клонирую графическое изображение, используя:
public void CopyBackgroundLayer(ref Bitmap bitmap)
{
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
bitmap = new Bitmap(buffer.Clone(rect, Primary.BackGround.PixelFormat));
}
Итак, тем временем я добавляю материал в графический объект, который я называю этим, где клонирует изображение, которое рисует графический объект (буфер в примере), чтобы увеличить растровое изображение до любой точки, прежде чем добавлять больше материала.