how to draw constantly changing graphics
Have not done this before (except in java, look how Steve McLeod fixed it), so obviously I suck at it. Here 64 pixels around current mouse position get drawn little bigger on a form. Problem is, that it's 'kind of' to slow, and I have no idea where to start fixing.
Besides that, I made a timer thread, that constantly calls update graphics when it's finished and a little fps like text, to show really how fast things are drawn.
Image example: (Image is from letter 'a' in "IntelliTrace" in Microsoft VS2010)
Source example:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Zoom
{
public partial class Form1 : Form
{
static class dllRef
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out Point lpPoint);
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
// from http://www.pinvoke.net/default.aspx/gdi32/GetPixel.html
static public System.Drawing.Color getPixelColor(int x, int y) {
IntPtr hdc = GetDC(IntPtr.Zero);
uint pixel = GetPixel(hdc, x, y);
ReleaseDC(IntPtr.Zero, hdc);
Color color = Color.FromArgb((int)(pixel & 0x000000FF),
(int)(pixel & 0x0000FF00) >> 8,
(int)(pixel & 0x00FF0000) >> 16);
return color;
}
static public System.Drawing.Point getMousePosition() {
Point p = new Point();
GetCursorPos(out p);
return p;
}
}
public Form1() {
InitializeComponent();
this.Size = new Size(400,400);
this.Text="Image zoom";
this.Location = new Point(640, 0);
this.image = new Bitmap(320, 320);
this.timeRef = DateTime.Now;
this.BackColor = Color.White;
Timer t = new Timer();
t.Interval = 25;
t.Tick += new EventHandler(Timer_Tick);
t.Start();
}
public void Timer_Tick(object sender, EventArgs eArgs) {
this.Form1_Paint(this, new PaintEventArgs(this.CreateGraphics(), new Rectangle(0, 0, this.Width, this.Height)));
}
private bool isdone = true;
private int iter = 0;
private Bitmap image;
private DateTime timeRef;
private void Form1_Paint(object sender, PaintEventArgs e) {
if (isdone) {
isdone = false;
int step = 40;
Point p = dllRef.getMousePosition();
Pen myPen = new Pen(Color.Gray, 1);
SolidBrush myBrush = null;
Bitmap image2 = new Bitmap(320, 340);
Graphics gc = Graphics.FromImage(image2);
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
myBrush = new SolidBrush(dllRef.getPixelColor(p.X - 4 + x, p.Y - 4 + y));
gc.FillEllipse(myBrush, x * step, y * step, step - 3, step - 3);
gc.DrawEllipse(myPen, x * step, y * step, step - 3, step - 3);
}
}
StringBuilder sb = new StringBuilder();
sb.Append(iter)
.Append(" frames in ")
.Append(String.Format("{0:0.###}", ((DateTime.Now-this.timeRef).TotalMilliseconds)/1000))
.Append("s.");
gc.FillRectangle(new SolidBrush(this.BackColor), new Rectangle( 0, 320, 320, 40));
gc.DrawString(sb.ToString(),new Font("Arial", 12),new SolidBrush(Color.Black), 10, 320);
gc.Dispose();
isdone = true;
iter++;
image = image2;
}
e.Graphics.DrawImage(image, 35f, 15f);
}
}
}
After changes i made, this one is ~98% faster:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Zoom
{
public partial class Form1 : Form
{
static class dllRef
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out Point lpPoint);
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
// from http://www.pinvoke.net/default.aspx/gdi32/GetPix开发者_开发百科el.html
static public System.Drawing.Color getPixelColor(int x, int y) {
IntPtr hdc = GetDC(IntPtr.Zero);
uint pixel = GetPixel(hdc, x, y);
ReleaseDC(IntPtr.Zero, hdc);
Color color = Color.FromArgb((int)(pixel & 0x000000FF),
(int)(pixel & 0x0000FF00) >> 8,
(int)(pixel & 0x00FF0000) >> 16);
return color;
}
static public System.Drawing.Point getMousePosition() {
Point p = new Point();
GetCursorPos(out p);
return p;
}
}
public Form1() {
InitializeComponent();
this.Size = new Size(400,400);
this.Text="Image zoom";
this.Location = new Point(640, 0);
this.image = new Bitmap(320, 340);
this.timeRef = DateTime.Now;
this.BackColor = Color.White;
Timer t = new Timer();
t.Interval = 25;
t.Tick += new EventHandler(Timer_Tick);
t.Start();
}
public void Timer_Tick(object sender, EventArgs eArgs) {
this.Form1_Paint(this, new PaintEventArgs(this.CreateGraphics(), new Rectangle(0, 0, this.Width, this.Height)));
}
private bool isdone = true;
private int iter = 0;
private Bitmap image;
private DateTime timeRef;
private void Form1_Paint(object sender, PaintEventArgs e) {
if (isdone) {
isdone = false;
int step = 40;
Point p = dllRef.getMousePosition();
SolidBrush myBrush = null;
Bitmap hc = new Bitmap(8, 8);
using (Pen myPen = new Pen(Color.Gray, 1))
using (Graphics gc = Graphics.FromImage(image))
using (Graphics gf = Graphics.FromImage(hc))
{
gf.CopyFromScreen(p.X - 4, p.Y - 4, 0, 0, new Size(8, 8),
CopyPixelOperation.SourceCopy);
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 8; y++)
{
myBrush = new SolidBrush(hc.GetPixel(x, y));
gc.FillEllipse(myBrush, x * step, y * step, step - 3, step - 3);
gc.DrawEllipse(myPen, x * step, y * step, step - 3, step - 3);
}
}
double ts = ((DateTime.Now - this.timeRef).TotalMilliseconds) / 1000;
StringBuilder sb = new StringBuilder();
sb.Append(++iter).Append(" frames in ").Append(String.Format("{0:0.###}", ts)).Append("s.");
gc.FillRectangle(new SolidBrush(this.BackColor), new Rectangle(0, 320, 320, 40));
gc.DrawString(sb.ToString(), new Font("Arial", 12), new SolidBrush(Color.Black), 10, 320);
}
isdone = true;
}
e.Graphics.DrawImage(image, 35f, 15f);
}
}
}
One thing that should speed things up is if you do the GetDC
just once and get all of the pixels you need, then call ReleaseDC
. So rather than:
for each pixel
GetDC
Read Pixel
ReleaseDC
You have:
GetDC
for each pixel
read pixel and store value
ReleaseDC
Then process the stored pixels.
That said, you're probably better off not using GetPixel
at all, as I seem to remember it being terribly inefficient. I suspect you'd have better performance just grabbing the entire screen into a bitmap and getting the pixels from there. Perhaps the answer to this question will help you: Capture the Screen into a Bitmap
精彩评论