How to render an image on the screen C# - c#

I have been trying to create a test program that just displays a bitmap image on the screen for a while now. Ideally, the image would be translucent (have an alpha channel) and "click throughable." However, I have not found any way to do this.
The application that I have for this is a keyboard indicators app that runs in the background and displays a popup image onscreen for a couple seconds whenever a modifier like num lock or caps lock is pressed.
What I have found is an MSDN example for how to render an image on the screen, but I haven't been able to make this work properly in a Windows Forms app. In the Form1.cs of a blank WFA app, I have:
using System.Drawing;
using System.Windows.Forms;
namespace KeyboardIndicators
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
PictureBox pictureBox1 = new PictureBox();
pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
}
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs pe)
{
Bitmap myBitmap = new Bitmap("Profile Image.jpg");
Graphics g = pe.Graphics;
g.DrawImage(myBitmap, 100, 100);
}
}
}
I am probably missing a lot here, but I am not having much luck debugging it in Visual Studio.
I have yet to find a site online that fully describes how to do something like what I would like to do. I have seen this kind of thing done before in other apps, so I know it can be done somehow.

I found the answer to my question thanks to the initial answer by #Habeeb on this question, which inspired me to research that method. By looking at this Q/A, I realized I didn't need to create a helper function to do this. To #Idle_Mind's point also, I set the WS_EX_TRANSPARENT flag to transparent.
This is the code I ended up with in my Form1.cs file: (I ended up changing the test image to cube.png, a .png image with an alpha channel)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KeyboardIndicators {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
PictureBox pictureBox = new PictureBox();
Image myBitmap = Image.FromFile("cube.png");
Size bitmapSize = new Size(myBitmap.Width, myBitmap.Height);
this.Size = bitmapSize;
pictureBox.ClientSize = bitmapSize;
pictureBox.Image = myBitmap;
pictureBox.Dock = DockStyle.Fill;
this.Controls.Add(pictureBox);
this.FormBorderStyle = FormBorderStyle.None;
}
protected override CreateParams CreateParams {
get {
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
}
}
When run, the following is shown onscreen:
This works for me, as it is overlayed on all apps I need, is semi-transparent and is click-throughable.

From your code, I do not see the Bitmap image is set to the PictureBox.
Please try the below code:
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage ;
MyImage = new Bitmap(fileToDisplay);
pictureBox1.ClientSize = new Size(xSize, ySize);
pictureBox1.Image = (Image) MyImage ;
If you want to add PictureBox via code, see below:
private void Form1_Load(object sender, EventArgs e)
{
var picture = new PictureBox
{
Name = "pictureBox1",
Size = new Size(xSize, ySize),
Location = new Point(100, 100),
Image = Image.FromFile("hello.jpg"),
};
this.Controls.Add(picture);
}
The first piece of code shows how to update image, but a different approach.

Related

C# Main Form BackColor moves in front of image

first of all, I'm new to C# Forms (and also new to StackOverflow). I want to have a small launcher window. I disabled the title bar, so the Main Form is supposed to just be there and hold the UI elements. I added a slightly smaller PictureBox that I want to be the "real" background so it will create a neat border between the main form and the background image. So far so good.
The issue is now that all UI elements that use transparent background and are placed on top of the PictureBox will now display the background of the main form instead of the PictureBox and it looks terrible.
I am confused. I tried sending the main form to back, I tried to add the PictureBox manually by code.. but it's all the same result. The PictureBox seems to be in front of the main form, but transparent UI elements will use the BackColor of the main form instead of the Background Image of the PictureBox that's there.
What am I missing? Any help appreciated. :)
I added a slightly smaller PictureBox that I want to be the "real" background so it will create a neat border between the main form and the background image.
That background PictureBox is causing this. The smaller picture boxes with the transparent back color need to be placed directly into a container with a background image and nothing in between. For example, you could remove the background picture box and override the Form's OnPaint method to draw the background image and leave some margins:
using System;
using System.Drawing;
using System.Windows.Forms;
public partial class LauncherForm : Form
{
public LauncherForm() : base()
{
DoubleBuffered = true;
ResizeRedraw = true;
BackColor = Color.Black;
Padding = new Padding(20);
ControlBox = false;
FormBorderStyle = FormBorderStyle.None;
}
private Image bgImage;
public new Image BackgroundImage
{
get => bgImage;
set { bgImage = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
var r = new Rectangle(Padding.Left, Padding.Top,
Width - Padding.Left - Padding.Right,
Height - Padding.Top - Padding.Bottom);
g.Clear(BackColor);
if (BackgroundImage != null)
g.DrawImage(BackgroundImage, r);
g.DrawRectangle(Pens.DimGray, r);
}
}
Another option is to do the same but with a Panel control to host the other picture boxes:
Select your project.
Right click and select Add -> Class...
In the add dialog, rename the class to LauncherPanel.cs and hit the Add button.
Replace the class block only (keep the namespace) in the new class with the code below.
Save and rebuild.
Open the designer, check the top of the ToolBox window, you'll find the new control LauncherPanel under the components of your project.
Drop an instance into the designer.
Select the control and press F4 key to activate the Properties window. Set the Image property and optionally the BorderColor and BorderWidth properties.
Add the other picture boxes into the launcherPanel1 or whatever you name it.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
// Within the namespace of your project..
[DesignerCategory("")]
public class LauncherPanel : Panel
{
public LauncherPanel() : base()
{
DoubleBuffered = true;
ResizeRedraw = true;
BackColor = Color.Black;
}
private Image bgImage;
public Image Image
{
get => bgImage;
set { bgImage = value; Invalidate(); }
}
private Color borderColor = Color.DimGray;
[DefaultValue(typeof(Color), "DimGray")]
public Color BorderColor
{
get => borderColor;
set { borderColor = value; Invalidate(); }
}
private int borderWidth = 1;
[DefaultValue(1)]
public int BorderWidth
{
get => borderWidth;
set { borderWidth = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
var r = ClientRectangle;
r.Width--;
r.Height--;
g.Clear(BackColor);
if (Image != null)
g.DrawImage(Image, r);
using (var pn = new Pen(borderColor, borderWidth))
g.DrawRectangle(pn, r);
}
}
Choosing the Panel option, you will get something like this at design time:
And like this at runtime:
Make sure you have transparent PNG images for the picture boxes in the Panel.

New form is not reporting its size as I expect

Continue from the overlay window's incorrect size problem.
So here is the minimum system:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Size = new Size(1920, 1080);
MessageBox.Show("x:" + this.Size.Width + " y:" + this.Size.Height);
}
}
}
It says my window size is 1438x818 (even though it does appear to fill the desktop area of the screen)....
Did some new research
The problem starts to occur when my size is set larger than 14xx by 83x
Any size larger than that will be restricted to 14xx by 83x
if I say
this.size = new Size (500,500);
then it is okay...
[Final edit]
Well. I think I found the problem.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/60e3b413-7746-46d4-8351-0c7f4e38378f/does-form-size-has-any-limitation-like-maximum-width-or-maximum-height?forum=netfxbcl
The form size does have a hidden limit and it seems that fixing it is out of my ability as an indie developer. I cannot find where is a hidden limitation is..
What I need to do is map the logic coordinate of anything in my form to a new world coordinate based on 1436/1920 scale ratio. Problem bypassed.
If you want to set size as 1920x1080 you can try this.
this.MinimumSize = new Size(1920, 1080);
this.MaximumSize = new Size(1920, 1080);
The size of the form must be lesser than or equal to current screen size.
Besides you can change the ClientSize of the form by
this.ClientSize = new System.Drawing.Size(1920, 1080);

SharpDX drawing a form without using RenderLoop to actualize it infinitely

Hi so like the title says, i'm trying to make an image Viewer for a project ( a bit in the kind of Windows Image viewer). I saw a lot of code displaying their RenderForm into a RenderLoop, but I don't like this solution since I don't want to refresh the image infinitely in the RenderLoop. I want to call the Draw method only when I need to redraw(on a zoom by example.) The problem is, now I've tried to use renderLoop.Show() but it does not stay on the screen and close right after all code has been executed...
using SharpDX;
using SharpDX.Windows;
using SharpDX.D3DCompiler;
using SharpDX.Direct2D1;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics;
using System.Drawing;
using System.Windows.Forms;
using Device = SharpDX.Direct3D11.Device;
using Color = SharpDX.Color;
namespace SharpDXWic
{
public class SharpDXDisplay : IDisposable
{
private const int WIDTH = 1500;
private const int HEIGHT = 800;
private Device device;
private SwapChain swapChain;
private RenderForm renderForm;
private RenderTargetView targetView;
public SharpDXDisplay(string display_title)
{
renderForm = new RenderForm(display_title);
renderForm.Width = WIDTH;
renderForm.Height = HEIGHT;
Texture2D target;
SwapChainDescription scd = new SwapChainDescription()
{
BufferCount = 1,
Flags = SwapChainFlags.None,
IsWindowed = true,
ModeDescription = new ModeDescription(WIDTH,HEIGHT, new Rational(60, 1),Format.R8G8B8A8_UNorm),
OutputHandle = renderForm.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};
Device.CreateWithSwapChain( SharpDX.Direct3D.DriverType.Hardware,DeviceCreationFlags.Debug, scd, out device, out swapChain);
target = Texture2D.FromSwapChain<Texture2D>(swapChain, 0);
targetView = new RenderTargetView(device, target);
device.ImmediateContext.OutputMerger.SetRenderTargets(targetView);
renderForm.Show();
device.ImmediateContext.ClearRenderTargetView(targetView, Color.CornflowerBlue);
swapChain.Present(0, PresentFlags.None);
}
private void OnClosing()
{
Dispose();
}
public void Dispose()
{
device.Dispose();
swapChain.Dispose();
renderForm.Dispose();
targetView.Dispose();
}
}
}
My goal here would be to Draw() a form without entering the RenderLoop. I only want to refresh the image on-demand and not refresh it constantly.
It is in fact possible to display an image into a Windows Form without using an infinite loop. Adding action like zooming or resizing to your form and perform action (such has redraw your image) works perfectly.
Of course, if you are making a video game, that is not the best solution because you want constant render of your graphics. However, for an image viewer, it is perfectly fine to draw everything to a windows form only once and update it on ActionEvents.

Capture screen shot as video and display live but mirrored?

I'm trying to develop a c# windows form application that captures part of the screen and display it's mirror live video like in the windows form picturebox.
The problem that I'm facing is that when I set the form's visibility=false to capture part of the screen without capturing the form itself, then back to form visibility=true, I get this flickering mirrored and not mirrored picture displaying in the picturebox.
My issue is that I'm trying to mirror any video playing on what ever application i.e: youtube, windows media player or any other application by capturing multiple screenshots and displaying them in a picture box so that when the video is playing and the application is running in front of it, the user see's a mirror of whatever is playing behind the form live.
How do I stop the flickering and make this like video like live stream like of the back video but mirrored as the video is playing. Thank you in advance
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mirror
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region Form Design and Controls
private void btnFlip_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
Bitmap myBitmap = new Bitmap(this.Size.Width, this.Size.Height);
this.Visible = false;
using (Graphics g = Graphics.FromImage(myBitmap))
{
g.CopyFromScreen(0, 0, 0, 0, myBitmap.Size, CopyPixelOperation.SourceCopy);
}
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
this.pictureBox1.Image = myBitmap;
pictureBox1.Image.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipY);
GC.Collect();
}
this.Visible = true;
}
#endregion
}
}

Dynamically adding shapes to a panel

Alright, i have been struggling with a specific issue. On a web page in C# i would like to build a diagram. It will consist of some rectangles (i want the rectangles to have extra functionality later, later it will have arrows and other images).
After quite some research i discovered that it is not possible to dynamically draw stuff from the c# code to the user web page.
All the things i can find tell me to make a bitmap and then save it to the outputstream or something, which i did. But it had a strange result, after clicking the button (it should build a rectangle and add it to the panel) :
http://imgur.com/ddfjgAZ
code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
//toegevoegd
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Text;
namespace Drawing.Usercontrols
{
public partial class WebUserControl1 : System.Web.UI.UserControl
{
Panel Panel1 = new Panel();
Panel Panel2 = new Panel();
View View1 = new View(); //how does this even work
Bitmap objBitmap = new Bitmap(400, 440);
protected void Page_Load(object sender, EventArgs e)
{
//adding a square... on a Panel...
Panel2.Width=500;
Panel2.Height = 500;
Panel2.BackColor = Color.BlueViolet;
this.Controls.Add(Panel2);
//Making a graphicsobject from the bitmap
Graphics objGraphics = Graphics.FromImage(objBitmap);
//objGraphics.Clear(Color.Blue);
Pen p = new Pen(Color.Yellow, 3);
Brush x = new SolidBrush(Color.BlueViolet);
//This piece will put up a sweet ellipse on the rectangle
Rectangle rect = new Rectangle(200, 100, 60, 20);
objGraphics.DrawEllipse(p, rect);
Panel1.Controls.Add(Panel2);
//This will add the bitmap to the page, but not really, everything on the page will dissapear and this dude will show up
//objBitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
//This will add an image from the internet to the panel, which works
//Panel2.Controls.Add(new System.Web.UI.WebControls.Image { ImageUrl = String.Format("http://ecx.images-amazon.com/images/I/518rMVxp3qL._SL75_SS50_.jpg") });
// textboxes adding
this.Controls.Add(Panel1);
Label FeedbackLabel = new Label();
TextBox Inputtextbox = new TextBox();
Button Submitbutton = new Button();
FeedbackLabel.ID = "lblFeedback";
FeedbackLabel.Text = "Hello world";
Submitbutton.ID = "btnSubmit";
Submitbutton.Text = "Submit";
Inputtextbox.ID = "txtInput";
Submitbutton.Click += SubmitButton_Click;
Panel1.Controls.Add(FeedbackLabel);
Panel1.Controls.Add(Submitbutton);
Panel1.Controls.Add(Inputtextbox);
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
// this is the part where the black rectangle is drawn
objBitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
}
}
}
So my final question is: Can i build rectangles with shapes in it and place them across a panel/layout
(later i want to use those rectangles as objects (adding onclick events to them, but i wont bother you with that just yet)
Thanks a lot in advance!

Categories