I want to capture the screen but without the current form, I tried to minimize -> capture -> maximize, but I'm looking for a better solution if exists. This was my code::
int w = this.Width;
int h = this.Height;
Size sz = this.Size;
Point loc = this.Location;
this.WindowState = FormWindowState.Minimized;
System.Threading.Thread.Sleep(500);
using (Bitmap b = new Bitmap(w, h))
{
using (Graphics g = Graphics.FromImage(b))
{
g.CopyFromScreen(loc, new Point(0, 0), sz);
}
b.Save(Environment.CurrentDirectory + "\\slides\\screen.jpeg");
this.BackgroundImage = System.Drawing.Image.FromFile(#"slides\screen.jpeg");
}
this.WindowState = FormWindowState.Maximized;
And I ask if there is a direct way to put the captured image as form background, without saving it.
Set the forms Opacity to 0.
This will make the form completely transparent and hence invisible.
Make the form invisible. Set the Visible property to `false.
This will hide the form without changing it's state, though on XP this won't make the window disappear straight away.
Try, although I did notice both yours and mine is marginally offset by the form border.
int w = this.Width;
int h = this.Height;
Size sz = this.Size;
Point loc = this.Location;
Hide();
System.Threading.Thread.Sleep(500);
using (Image b = new Bitmap(w, h))
{ using (Graphics g = Graphics.FromImage(b))
{
g.CopyFromScreen(loc, new Point(0, 0), sz); }
Image x = new Bitmap(b);
this.BackgroundImage = x;
}
Show();
Related
I am writing the app, and a part of it is open textbox. When the textbox is opening I want to dark background.
I have looked the solution and found it here:
Creating a dark background when a new form appears
But, it does not work for me correctly.
Here is my code:
private void App_Load(object sender, EventArgs e)
{
this.Text = "TestApp";
this.Size = new Size(350, 250);
this.BackColor = Color.DarkGray;
this.Location = new Point(50, 50);
this.MaximizeBox = false;
TextBox.BackColor = Color.WhiteSmoke;
TextBox.Multiline = true;
TextBox.Size = new Size(200, 90);
Button.Text = "Search";
Bitmap bmp = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
using (Graphics G = Graphics.FromImage(bmp))
{
G.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
G.CopyFromScreen(this.PointToScreen(new Point(0, 0)), new Point(0, 0), this.ClientRectangle.Size);
double percent = 0.60;
Color darken = Color.FromArgb((int)(255 * percent), Color.Black);
using (Brush brsh = new SolidBrush(darken))
{
G.FillRectangle(brsh, this.ClientRectangle);
}
}
using (Panel p = new Panel())
{
p.Location = new Point(0, 0);
p.Size = this.ClientRectangle.Size;
p.BackgroundImage = bmp;
this.Controls.Add(p);
p.BringToFront();
// display your dialog somehow:
Form frm = new Form();
frm.StartPosition = FormStartPosition.Manual;
frm.ShowDialog(this);
}
}
I receive this:
Maybe, someone can point me out where is my mistake?
EDIT: I have found the solution, the question was not clear enough.
When the textbox is opening I want to dark background.
So you want the textBox to be dark, not the complete form?
Almost always when you think you have to do some painting yourself, think again. It is seldom necessary do to paint. Only do this, if you don't have any standard options.
Just set Property BackGround of the text box. Use visual studio designer to do this.
If you don't want to do this using the designer, do this in the constructor after InitializeComponent:
public MyForm()
{
InitializeComponent();
// text box dark background:
this.textBox1.BackColor = Color.Black;
}
If you want the complete form to be black, again use visual studio designer, or add:
InitializeComponent();
this.BackColor = Color.Black;
I have successfully printed a windows form, but all the text is slightly blurry. I have concluded that this is a result of the resolution of the screen being much less than the resolution the printer uses. Is there a fundamental flaw in my approach or is there a way to reformat the text prior to printing so that it comes out crisp?
void PrintImage(object o, PrintPageEventArgs e)
{
int x = SystemInformation.WorkingArea.X;
int y = SystemInformation.WorkingArea.Y;
int width = panel1.Width;
int height = panel1.Height;
Rectangle bounds = new Rectangle(x, y, width, height);
Bitmap img = new Bitmap(width, height);
this.DrawToBitmap(img, bounds);
Point p = new Point(100, 100);
e.Graphics.DrawImage(img, p);
}
private void BtnPrint_Click(object sender, EventArgs e)
{
btnPrint.Visible = false;
btnCancel.Visible = false;
if(txtNotes.Text == "Notes:" || txtNotes.Text == "")
{
txtNotes.Visible = false;
}
PrintDocument pd = new PrintDocument();
pd.PrintPage += new PrintPageEventHandler(PrintImage);
pd.Print();
}
Is there a fundamental flaw in my approach [...] ?
Yes.
You take the size of panel1 to calculate the size of the image. Later, you let this draw to the image, but this is the form, not the panel.
What makes you think that SystemInformation.WorkingArea is related to the window you want to print?
You should take a bit more care of disposable objects.
[...] is there a way to reformat the text prior to printing so that it comes out crisp?
There's not a general way which would allow you to scale all other controls as well.
However, instead of blurry text, you can get crisp pixelated text by scaling the bitmap up by a certain factor using the NearestNeighbor mechanism.
Here's the difference in a PDF generated without scaling (left) and a factor of 3 scaling (right) at the same zoom level in Acrobat Reader (click to enlarge):
Here's the scaling code, also without fixing any disposable issues:
this.DrawToBitmap(img, bounds);
Point p = new Point(100, 100);
img = ResizeBitmap(img, 3);
e.Graphics.DrawImage(img, p);
}
private static Bitmap ResizeBitmap(Bitmap source, int factor)
{
Bitmap result = new Bitmap(source.Width*factor, source.Height*factor);
result.SetResolution(source.HorizontalResolution*factor, source.VerticalResolution*factor);
using (Graphics g = Graphics.FromImage(result))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(source, 0, 0, source.Width*factor, source.Height*factor);
}
return result;
}
This behavior in C# is bizarre. I have the following class to allow me to effectively 'draw' on the desktop:
class drawOnDesktop {
public static Form dodF = new Form();
public static Graphics formGraphics;
public drawOnDesktop() {
formGraphics = dodF.CreateGraphics();
dodF.BackColor = Color.LightGreen;
dodF.TransparencyKey = Color.LightGreen;
dodF.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
dodF.Location = new Point(0,0);
dodF.StartPosition = FormStartPosition.Manual;
//dodF.FormBorderStyle = FormBorderStyle.None;
dodF.WindowState = FormWindowState.Maximized;
dodF.MinimizeBox = false;
dodF.MaximizeBox = false;
dodF.ControlBox = false;
//dodF.TopMost = true; //For development in case something goes wrong
dodF.BringToFront();
dodF.Show();
}
public static void drawCircle(Point location) {
formGraphics.FillEllipse(Brushes.Black, location.X, location.Y, 10, 10);
}
}
And I call it like this, from my main form:
drawOnDesktop dod = new drawOnDesktop();
drawOnDesktop.drawCircle(new Point(100,100));
If you run that code, you'll get a small black circle in the top left corner of your screen. The problem is that you can see the form's border. Now, try commenting out the FormBorderStyle line. The black dot will appear for a fraction of a second, and disappear. Why!? As you can see, I've set a lot of properties on this form, and still it refuses to work. Is it getting repainted over by the OS?
I don't need to worry about mouse events or things like that - the dots being placed on the screen are completely programmatic, and not from the user. As well, if I set dodF.ShowInTaskbar = false, the entire program crashes.
How can I fix this code so the dot appears and stays until I formGraphics.Clear(Color.Black)?
Don't keep a copy of the graphics around, that is just asking for trouble. As others have stated, you should use the paint event to draw on the screen:
class drawOnDesktop
{
public Form dodF = new Form();
List<Point> circles = new List<Point>();
public drawOnDesktop()
{
dodF.BackColor = Color.LightGreen;
dodF.TransparencyKey = Color.LightGreen;
dodF.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
dodF.Location = new Point(0, 0);
dodF.StartPosition = FormStartPosition.Manual;
dodF.FormBorderStyle = FormBorderStyle.None;
dodF.WindowState = FormWindowState.Maximized;
dodF.MinimizeBox = false;
dodF.MaximizeBox = false;
dodF.ControlBox = false;
dodF.TopMost = true; //For development in case something goes wrong
dodF.BringToFront();
dodF.Paint += dodF_Paint;
dodF.Show();
}
void dodF_Paint(object sender, PaintEventArgs e)
{
using (Graphics g = dodF.CreateGraphics())
{
foreach(Point location in circles)
g.FillEllipse(Brushes.Black, location.X, location.Y, 10, 10);
}
}
public void drawCircle(Point location)
{
circles.Add(location);
}
}
You can call it the same way, but now every time the form repaints, it will redraw the circles.
Is it possible to Draw any Form (without overridding the Paint method) in grayscale.
If I show a Form in a Modal() Dialog, I wan't do show its parent as grayscale.
I noticed this in the Visual Studio Extension Manager. If a progressbar is downloading a package, the underlying window is grayed out.
I am thinking of this:
private void Button1_Click(object sender, EventArgs e)
{
using (var dialog = new Form2())
{
SetGrayscale(this, true);
dialog.ShowDialog();
SetGrayscale(this, false);
}
}
Update
Just setting Form.Enabled = false; is not what I intended. That does not look as good as a grayscale representation of my form.
I think the compiz window decorator for Linux did this with apps that are unresponsive.
As has already been said the way to do this is to overlay another control / form on top of your existing form and have it render a grayscale version of this on top, you could either do this using an additional form placed exactly over the original form, or using something like a Panel positioned on top of all other controls.
Here is a working example of how you might do this when placing another form exactly over the client area of the first. How to use it
using (Grayscale(this))
{
MessageBox.Show("Test");
}
Implementation
public static Form Grayscale(Form tocover)
{
var frm = new Form
{
FormBorderStyle = FormBorderStyle.None,
ControlBox = false,
ShowInTaskbar = false,
StartPosition = FormStartPosition.Manual,
AutoScaleMode = AutoScaleMode.None,
Location = tocover.PointToScreen(tocover.ClientRectangle.Location),
Size = tocover.ClientSize
};
frm.Paint += (sender, args) =>
{
var bmp = GetFormImageWithoutBorders(tocover);
bmp = ConvertToGrayscale(bmp);
args.Graphics.DrawImage(bmp, args.ClipRectangle.Location);
};
frm.Show(tocover);
return frm;
}
private static Bitmap ConvertToGrayscale(Bitmap source)
{
var bm = new Bitmap(source.Width, source.Height);
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color c = source.GetPixel(x, y);
var luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
bm.SetPixel(x, y, Color.FromArgb(luma, luma, luma));
}
}
return bm;
}
private static Bitmap GetControlImage(Control ctl)
{
var bm = new Bitmap(ctl.Width, ctl.Height);
ctl.DrawToBitmap(bm, new Rectangle(0, 0, ctl.Width, ctl.Height));
return bm;
}
private static Bitmap GetFormImageWithoutBorders(Form frm)
{
// Get the form's whole image.
using (Bitmap wholeForm = GetControlImage(frm))
{
// See how far the form's upper left corner is
// from the upper left corner of its client area.
Point origin = frm.PointToScreen(new Point(0, 0));
int dx = origin.X - frm.Left;
int dy = origin.Y - frm.Top;
// Copy the client area into a new Bitmap.
int wid = frm.ClientSize.Width;
int hgt = frm.ClientSize.Height;
var bm = new Bitmap(wid, hgt);
using (Graphics gr = Graphics.FromImage(bm))
{
gr.DrawImage(wholeForm, 0, 0,
new Rectangle(dx, dy, wid, hgt),
GraphicsUnit.Pixel);
}
return bm;
}
}
Note that:
The implementation of Paint is fairly poor - really it should use double buffering so that the grayscale image is pre-rendered to a buffered graphics context so the Paint method just needs to paint the pre-drawn buffer contents. See Custom Drawing Controls in C# – Manual Double Buffering
ConvertToGrayscale is a tad on the slow side, but can probably be sped up
Things will go wrong if someone manages to move the original form for any reason
The image is static, if the base control gets redrawn then ideally the top form should redraw too. I'm not sure how best to detect when a portion of another form has been invalidated.
If I find the time I'll try and fix some of those problems, but the above at least gives you the general idea.
Note that in WPF this would be a lot easier.
Sources:
How to convert a colour image to grayscale
Get the image of a control or form, or a form's client area in C#
I don't think there is a way to do it directly - I think all forms are rendered with sRGB.
A hacky way could be to overlay the form with a copy of it as an image (this is simple to do with Control.DrawToBitMap) and then pass it through a simple GDI matrix to desaturate https://web.archive.org/web/20141230145627/http://bobpowell.net/grayscale.aspx.
Try something like this which would work for most simple controls (you would need to recurse into containers to switch all controls correctly).
private void button1_Click(object sender, EventArgs e)
{
using (var dialog = new Form())
{
Dictionary<Control, Tuple<Color, Color>> oldcolors = new Dictionary<Control, Tuple<Color, Color>>();
foreach (Control ctl in this.Controls)
{
oldcolors.Add(ctl, Tuple.Create(ctl.BackColor, ctl.ForeColor));
// get rough avg intensity of color
int bg = (ctl.BackColor.R + ctl.BackColor.G + ctl.BackColor.B) / 3;
int fg = (ctl.ForeColor.R + ctl.ForeColor.G + ctl.ForeColor.B) / 3;
ctl.BackColor = Color.FromArgb(bg, bg, bg);
ctl.ForeColor = Color.FromArgb(fg, fg, fg);
}
dialog.ShowDialog();
foreach (Control ctl in this.Controls)
{
ctl.BackColor = oldcolors[ctl].Item1;
ctl.ForeColor = oldcolors[ctl].Item2;
}
}
}
I have an image .I want to crop 10 px from left and 10px from right of the image.I used the below code to do so
string oldImagePath="D:\\RD\\dotnet\\Images\\photo1.jpg";
Bitmap myOriginalImage = (Bitmap)Bitmap.FromFile(oldImagePath);
int newWidth = myOriginalImage.Width;
int newHeight = myOriginalImage.Height;
Rectangle cropArea = new Rectangle(10,0, newWidth-10, newHeight);
Bitmap target = new Bitmap(cropArea.Width, cropArea.Height);
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(myOriginalImage,cropArea);
}
target.Save("D:\\RD\\dotnet\\Images\\test.jpg");
But this is not giving me the results which i expect. This outputs an image which has 10 px cropped from the right and a resized image.Instead of cropiing it is resizing the width i think.So the image is shrinked(by width). Can any one correct me ? Thanks in advance
Your new width should be reduced by twice the crop margin, since you'll be chopping off that amount from both sides.
Next, when drawing the image into the new one, draw it at a negative offset. This causes the area that you aren't interested in to be clipped off.
int cropX = 10;
Bitmap target = new Bitmap(myOriginalImage.Width - 2*cropX, myOriginalImage.Height);
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(myOriginalImage, -cropX, 0);
}
My guess is this line
Rectangle cropArea = new Rectangle(10,0, newWidth-10, newHeight);
should be
Rectangle cropArea = new Rectangle(10,0, newWidth-20, newHeight);
Set the width of the new rectangle to be 20 less than the original - 10 for each side.
Some indication what result it is giving you would be helpful in confirming this.
Corey Ross is correct. Alternately, you can translate along the negative x axis and render at 0.0, 0.0. Should produce identical results.
using (Graphics g = Graphics.FromImage(target))
{
g.TranslateTransform(-cropX, 0.0f);
g.DrawImage(myOriginalImage, 0.0f, 0.0f);
}
You need to use the overload that has you specify both Destination Rectangle, and Source Rectangle.
Below is an interactive form of this using a picture box on a form. It allows you to drag the image around. I suggest making the picture box 100 x 100 and have a much larger image such as a full screen window you've captured with alt-prtscr.
class Form1 : Form
{
// ...
Image i = new Bitmap(#"C:\Users\jasond\Pictures\foo.bmp");
Point lastLocation = Point.Empty;
Size delta = Size.Empty;
Point drawLocation = Point.Empty;
bool dragging = false;
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!dragging)
{
lastLocation = e.Location;
dragging = true;
}
delta = new Size(lastLocation.X - e.Location.X, lastLocation.Y - e.Location.Y);
lastLocation = e.Location;
if (!delta.IsEmpty)
{
drawLocation.X += delta.Width;
drawLocation.Y += delta.Height;
pictureBox1.Invalidate();
}
}
else
{
dragging = false;
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Rectangle source = new Rectangle(drawLocation,pictureBox1.ClientRectangle.Size);
e.Graphics.DrawImage(i,pictureBox1.ClientRectangle,source, GraphicsUnit.Pixel);
}
//...
Okay, I totally fail at explaining this, but hang on:
The DrawImage function requires the location of the image, as well as it's position. You need a second position for cropping as how the old relates to the new, not vice versa.
That was entirely incomprehensible, but here is the code.
g.DrawImage(myOriginalImage, -cropArea.X, -cropArea.Y);
I hope that explains it more then I did.