I am making an application that will allow users to apply certain tools to analyse videos & images. I need help with how i actaully draw/write on the video loaded into windows media player within my form and being able to save it on. It needs to be able to lert the user draw freehand and shapes on it.
Thanks in Advance,
Chris :)
This is a non-trivial, if not impossible task to accomplish with the wmp control in winforms.
I don't know of any way to actually draw on the wmp but you could draw on a transparent panel overlaid over the wmp. This will not work will the video is playing but you can show the drawing while it is paused. I have used this technique to draw over a 3rd party video control that works similarly to wmp.(Edit - this does not seem to work with the wmp control)
However, as real transparent panels are also rather tricky in winforms, another way would be to grab an image from the video and draw on the overlaid image. Again, only when it is paused.
This commercial control does enable drawing over the video. It has an event that fires every frame that you can use to do the drawing. The big downside, though is that you can't really do anything too fancy as your drawing routine needs to finish before the next frame is drawn.
I would strongly encourage you to use WPF(even if its a wpf control hosted within a winforms app) to show your video. It is a whole lot easier to draw on video(including playing video) in wpf.
EDIT
I just tested drawing over the wmp using a transparent panel and its doesn't behave as my 3rd party control did,so I suggest you do the video playing bit in WPF and host that in your winforms app. (I just tested that too using #Callums inkcanvas suggestion and it works like a charm)
If you are using WPF, try placing an InkCanvas on top of your video and setting the Background to transparent. You can then save and load up the shapes the users draw on top of the video.
A little proof-of-concept with a picture instead of a video:
I suspect you may be using WinForms though, where this may be more difficult. If so, a good excuse to learn WPF!
EDIT: With WinForms, you would have to make your own custom control that acts as a transparent overlay and add brush strokes to it. It would be extremely hard to implement well (with transparent background, which doesn't play well with
WinForms). I would recommend using WPF if you are still at a stage you can change your application's UI. WPF works on XP and up.
EDIT2: After googling, there are some InkCanvas equivalents that people have made for WinForms, but I have no idea how good they are and may not support transparent backgrounds.
You could always have the video that you want annotated in a new WPF window and the rest of your application in WinForms.
I have found how to do this.
Here is one way in WPF using Canvas
private void buttonPlayVideo_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = "All Files|*.*";
Nullable<bool> result = dlg.ShowDialog();
if (result == true) {
MediaPlayer mp = new MediaPlayer();
mp.Open(new Uri(filename));
VideoDrawing vd = new VideoDrawing();
vd.Player = mp;
vd.Rect = new Rect(0, 0, 960, 540);
DrawingBrush db = new DrawingBrush(vd);
canvas.Background = db;
mp.Play();
}
}
then create mouse events for Canvas and draw with it
Point startPoint, endPoint;
private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(canvas);
}
private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
endPoint = e.GetPosition(canvas);
Line myLine = new Line();
myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
myLine.X1 = startPoint.X;
myLine.Y1 = startPoint.Y;
myLine.X2 = endPoint.X;
myLine.Y2 = endPoint.Y;
myLine.HorizontalAlignment = HorizontalAlignment.Left;
myLine.VerticalAlignment = VerticalAlignment.Center;
myLine.StrokeThickness = 2;
canvas.Children.Add(myLine);
}
This can be done in WinForms but it is not easy. There is transparent form support with alpha blending in WinForms. Use the following CreateParams for the transparent overlay form: WS_EX_LAYERED, WS_EX_TRANSPARENT. Check the MSDN references for this type of window: http://msdn.microsoft.com/en-us/library/ms997507.aspx, http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#layered.
Put a transparent form above your video control and you can draw anything you want on it. Move and resize events need to be coordinated between your video window and the transparent form above it. Redrawing the overlay needs to use UpdateLayeredWindow() in user32.dll.
I learned quite a bit from this example: http://www.codeproject.com/Articles/13558/AlphaGradientPanel-an-extended-panel.
You might look at XNA (www.xna.com) from Microsoft. It is made for managed languages like c# and should support video.
I've only used it for drawing in c#, but it gets the job done.
I should also note that XNA will function as part of a regular Windows Forms app. For what it's worth, I have also prototyped something like this with Flash; Flash allows you to import each frame of the movie file into the editor and create a SWF that can respond to user interaction.
However, this approach is useless if you need to update the movie in real-time. Flash (last I checked) could only import the movie at design time.
Ok, by far and away the best way of doing this is to use Silverlight. Silverlight supports all of the major streaming formats and also provides complete access to the framebuffer.
Easy :-)
Related
I am having a difficult time finding details on the draw order of a DirectX 11 application when rendered in a Windows Form. I know that I can assign my SwapChain to render to the handler of a control (such as a panel) which I have done already. The question here is more focused on being able to paint over the content that is rendered via DirectX in the same control. I already know that I can add controls to the panel and they will paint over the rendered content. I attempted utilizing the Paint event for the panel and doing a simple draw:
private void panel1_Paint(object sender, PaintEventArgs e) {
using (Pen p = new Pen(Brushes.Red))
e.Graphics.FillEllipse(p, new Rectangle(0, 0, 250, 250));
}
However, I believe this is painting the requested content below the scene content rendered by DirectX. I haven't been able to find any details on the draw order and which events to utilize. If anyone has any ideas on which events to use to paint over the rendered scene, that would be helpful. If controls can be rendered on top of the scene, then I would like to believe custom painting could be achieved as well.
Maybe I'll have to go the long way around?
Update
I have found a post over on MSDN that doesn't fully answer the question at hand, but helps with my comprehension, and also sheds light on an alternate route which appears to require being done at the end of the render method for my engine (which makes sense seeing as rendering typically follows a FIFO system).
You can have GDI(+) calls on top of a DX render. The d3d device can
return a Graphics g suitable to do gdi calls. At least, I've done it
in windowed mode.
Microsoft.DirectX.Direct3D.Surface bb = device.GetBackBuffer(0, 0);
System.Drawing.Graphics g = bb.GetGraphics();
g.DrawRectangle(...); // or whatever
bb.ReleaseGraphics();
bb.Dispose();
Also, I don't see what's to stop somebody from adding controls to the
panel one uses as the DX panel.
Clarified Question
My original question however, still remains. Does anyone know what the draw order is between Windows Forms and DirectX 11? Does anyone know of an event that can be utilized as part of this order to draw on top of the rendered content?
In the software products I'm currently working on, we have several 3D View controls. Appeared the need to have overlay information on top of these 3D Views. I won't go into too much background details, because it is not the point, but here are the constraints we face :
we must use two different 3D View controls
we don't have the source code for them
they are embedded in Windows Forms controls, and all our own GUIs around these controls are in Windows Forms
we use .NET Framework 3.5SP1 and Windows 7
We want to be able to display various overlay informations and controls on top of these 3D views, because we usually demo our products by showing full screen 3D views on big screens, and not show our GUIs, which have the necessary information and controls.
Back in the days we used only one type of 3D view, I managed, via various hacks involving reflection, to hook my own overlay window system written in DirectX (based on WorldWind .NET overlay widgets, the 3D view was indeed based on WorldWind at the time). The next version of the 3D View product made huge changes to the rendering core code and of course made these hacks incompatible (yeah, I had it coming, I know :-)). Moreover, we are now using, because of different needs in other products, another type of 3D View, closed source as well.
I emphasize the fact that we don't have the source code for them because we can't have access to the rendering loop and therefore cannot hook a windowing system made for 3D Engines, such as CEGUI (search for it yourself, I'm not allowed to post much hyperlinks yet, sorry).
Consequently, I had the following idea : since our 3D Views are embedded in winforms controls, why don't we code our overlay controls in plain winforms, and overlay it on top of the 3D views? The advantages of this solution are huge :
this would be compatible with both 3D Views, enabling us to reuse overlays across engines, if needed
we would be able to reuse custom controls or forms we already developed for the rest of the GUI. Indeed, it is a pretty big project, and we are beginning to have quite a library of such controls.
The only slight (!) problem is that we want to be able to manage overlay transluency, like I did with my former system in DirectX. We can't afford fully opaque overlays, because it would clutter the view too much. Imagine something like a barely visible overlay, becoming more opaque when the mouse is hovering over it for example.
Windows offer the possibility to have child windows inside other windows or controls (Win32 API doesn't really make a difference between windows and controls, this is pretty much a MFC/WinForms abstraction as I understood it), but since it is not top-level windows, we cannot adjust the transluency of these, so this is not something we can use. I saw here, that this is however possible on Windows 8, but switching to windows 8 is not possible anytime soon, because our software is deployed on quite a few machines, running 7.
So I started an intense googling session on how could I work around such a problem. It appears I must "enslave" top level windows to my 3D View controls. I already tried out something like that directly in winforms, having a form owned (not parented, there is a clear distinction, read about it in the previously linked MS page) by a control, and "following" its movements on screen. As expected, it kind of worked, but the issues are difficult to overcome. The most important is a clipping issue. If the parent form of the owner control changes its size, the overlay form is still shown in full. In my sample, I have a simple form with a menu, and a black panel containing a calendar (to show clipping differences between child controls and owned ones). I "enslaved" a borderless form containing a property grid to the black panel. It successfully follows the forms movements, but if I shrink the main form, I get this :
Clipping issue screenshot
Note how the calendar is clipped correctly (child window), and the overlay is not (owned window). I also get weird effects when minimizing/restoring the main form. Indeed, my overlay disappears when minimizing, but when restoring, it just "spawns" while the restoring animation of the main form is occuring. But this is less of an issue, and I guess can be worked around by handling proper events (but which ones?).
From what I understood, I must handle at least some of the clipping myself, using win32 API calls and hooks. I already begun to document myself, but it is quite complicated stuff. The Win32 API being a real mess, and myself being a former Unix developer introduced to Windows programming via the great .NET framework, I don't have any real experience in Win32, and therefore don't really know where to begin, and how to make myself a path in this jungle...
So if a winapi guru is passing by, or if someone has some other idea to achieve my goals given the constraints above, I'll be glad to read about it :-)
Thanks in advance, and apologies for being such a stackoverflow "leecher" by subscribing only to ask a question, but I don't have no direct internet access on my workstation (yeah, for real, I have to go to a specific computer for this), so participating in this great community is not that easy for me.
Finally, here is my sample code (designer code available if you ask) :
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Point _myLoc;
private void formToolStripMenuItem_Click(object sender, EventArgs e)
{
var ctrl = new PropertyGrid();
var obj = this.panel1;
ctrl.SelectedObject = obj;
var form = new Form();
ctrl.Dock = DockStyle.Fill;
form.Controls.Add(ctrl);
form.Opacity = 0.7;
var rect = obj.RectangleToScreen(obj.DisplayRectangle);
form.StartPosition = FormStartPosition.Manual;
form.Location = new Point(rect.Left + 10, rect.Top + 10);
var parentForm = this;
_myLoc = parentForm.Location;
form.FormBorderStyle = FormBorderStyle.None;
parentForm.LocationChanged += (s, ee) => {
int deltaX = parentForm.Location.X - _myLoc.X;
int deltaY = parentForm.Location.Y - _myLoc.Y;
var loc = form.Location;
form.Location = new Point(loc.X + deltaX, loc.Y + deltaY);
_myLoc = parentForm.Location;
};
form.Show(this.panel1);
}
}
Clipping can be easily implemented using Region property. Each window can have an associated Region object, which defines window rendering constraints:
static void ManualClipping(Control clipRegionSource, Form formToClip)
{
var rect = clipRegionSource.DisplayRectangle;
rect = clipRegionSource.RectangleToScreen(rect);
rect = formToClip.RectangleToClient(rect);
rect = Rectangle.Intersect(rect, formToClip.ClientRectangle);
if(rect == formToClip.ClientRectangle)
{
formToClip.Region = null;
}
else
{
formToClip.Region = new Region(rect);
}
}
usage:
/* ... */
parentForm.SizeChanged += (s, ee) => ManualClipping(panel1, form);
form.Show(this.panel1);
UPDATE: I took a break from messing with the transparency stuff for a few days. I started messing with it again tonight. I got a new result using Hans Passant's solution:
http://img3.imageshack.us/img3/4265/icontransp.jpg
Passant's solution does solve the issue of the transparent background gradient. However, I'm still running into the problem with the transparent colors in my icon blending with the form's BackColor. You can see the fuchsia around various parts of the icon in the above image.
ORIGINAL CONTENT:
I've been going at this for several hours now, and I haven't had much luck. I've messed with Control.Region, Form.TransparencyKey, Form.Opacity, and a couple other random things with some funky effects.
Lately I've been trying to customize my desktop and decided to mess with Application Docks. After seeing what the Mac dock and a few third-party Windows implementations had to offer, I decided I wanted to build my own.
Eventually I want to move on to using the Win32 API. For now I just want to get something working using as much C# and .Net framework capabilities as possible.
There are a few things I want to be able to do in this application:
Display a form/menu with a gradient background.
Allow the form/menu to have transparency while keeping icons opaque.
Display icons that contain transparent backgrounds.
The Menu and Icons should be able to receive mouse-related events (hover, leave, click, dragover, dragdrop, and a few others).
This is the effect I'm shooting for:
http://img207.imageshack.us/img207/5716/desired.jpg
This image shows the visual effects I'm trying to achieve. This was a skin I made for a program called Rainmeter. The image shows Notepad++ behind the skin with a few of the skin's files open in the editor. The menu is transparent, but the icons remain opaque.
My Approach:
Using a Form to act as the menu seemed like a logical first choice to me. I have a basic understanding of events. I'm not quite sure how to create my own click events, so a form would make working with events a tad easier. I considered a few options for the icons. I decided I'd use PictureBoxes for the icons, since they can hold images and receive events.
Once I finished the code for all the structural logic of my menu, I started playing around with it to try to get the visual effect I wanted. Form.Opacity affected the transparency of everything on the form. Since I want the icons to be fully opaque, I left this property alone. I tried setting the BackColor to Color.Transparent, but that gives an error. I played around with a few combinations...
http://img204.imageshack.us/img204/757/effectsi.jpg
I drew the gradient with a Drawing2D.LinearGradientBrush into a Bitmap. This Bitmap was then placed as the Form.BackgroundImage or as a PictureBox.Image. If used, the PictureBox was sized to cover the entire Form and sent to the back.
I noticed that some of the Form.BackgroundColor would be mixed in with the outlines of my icons. The icons have transparency along the edges for a smoother appearance. Since the icons are picking up the Form's BackgroundColor, this makes me think that the PictureBoxes are creating new images when the icons are loaded into the form. The semi-transparent portions of the image are then merged with the Form's BackgroundColor when they should merge with whatever colors are behind the form.
http://img838.imageshack.us/img838/8299/whitedesktop.jpg
In this image you can see the Fuchsia existing in the icons even though the Form's Fuchsia color is now completely transparent. I forgot to point out that the same green to yellow gradient with an Alpha value of 150 was used in every case. In the images where the gradient doesn't look green, it's because the transparent colors are blending with the Fuchsia background.
I'm not really sure what to do from here. I feel like I could get what I want if I could somehow make the Form alone completely transparent. I was also thinking I may have better luck just drawing the icons instead of using PictureBoxes. The problem then would be setting up the icons to receive mouse events. (I've never made my own events, and I think it would involved some Win32 API calls.)
Is there something else I can do with the PictureBoxes to get the effect I want? Whichever the case, I'm open to any ideas or suggestions for the overall effect I'm trying to achieve.
This is pretty easy to do in Winforms. What you need is a sandwich of two forms. The bottom one should provide the transparent gradient background, the top one should draw the icons and handle mouse clicks. Some sample code:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.TopMost = true;
this.FormBorderStyle = FormBorderStyle.None;
this.TransparencyKey = this.BackColor = Color.Fuchsia;
this.Opacity = 0.3;
var overlay = new Form();
overlay.FormBorderStyle = FormBorderStyle.None;
overlay.TransparencyKey = overlay.BackColor = Color.Fuchsia;
overlay.StartPosition = FormStartPosition.Manual;
overlay.Location = this.Location;
overlay.MouseDown += HandleIconClick;
this.Resize += delegate { overlay.Size = this.Size; };
this.LocationChanged += delegate { overlay.Location = this.Location; };
overlay.Paint += PaintIcons;
this.Paint += PaintBackground;
this.Load += delegate { overlay.Show(this); };
}
private void PaintBackground(object sender, PaintEventArgs e) {
var rc = new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height);
using (var br = new LinearGradientBrush(rc, Color.Gainsboro, Color.Yellow, 0f)) {
e.Graphics.FillRectangle(br, rc);
}
}
private void PaintIcons(object sender, PaintEventArgs e) {
e.Graphics.DrawIcon(Properties.Resources.ExampleIcon1, 50, 30);
// etc...
}
void HandleIconClick(object sender, MouseEventArgs e) {
// TODO
}
}
Which looks like this with the somewhat random colors and icon I selected:
OK, I got a bit lost in all that, but from the description in the original paragraph, I would make sure the background rectangle is NOT the visual parent of the pictureboxes. Make them overlapping siblings, with the pictureboxes in front using Panel.Zindex.
Then you can just change the opacity of the rectangle, without affecting the icons. Also make sure the icon source image files have a transparent background.
Should work I think.
I am developing the smart device application in C#. I am new to the windows mobile. I have added the background image to the form in my application by using the following code. I want to make label & other controls on this form transparent so that my windows form will be displayed properly.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Bitmap CreateCustomerImage = new Bitmap(#"/Storage Card/background.png");
e.Graphics.DrawImage(CreateCustomerImage, 0, 0);
}
how to do this ? How to solve this problem? Can you provide me any code or link through which I can solve the above issue?
Windows CE doesn't inherently support transparent controls, which tends to be a huge pain. You have to use something like ColorKey transparency, so in your OnPaint, you need to fill the background with a color (magenta is a popular one) and use SetColorKey to make that color transparent.
There are several tutorials online for colorkey transparency. Here is one that I just found with a search engine that looks reasonable but feel free to search for others as well.
The place this falls down is when you have controls in a container control, which is then on the Form. To get that to work right you have to cascade calls to clipping regions from the Form all the way down. I don't have a ready sample of this that isn't inside a shipping project, so I can't easily post it. If you run into this, though, update the question and I'll see if I can extract something.
After some help here, I've got WPF using the windows.forms notifyIcon class (It's not a major app so not worried about purity). And I was wondering if its possible to overlay some text on the icom?
Basically I need it to visually show how many entries is in my gridview. And run this on everytime the SizeChanged event. This is what I have come up with so far, but not sure how to go on from here.
Stream iconStream = Application.GetResourceStream(new Uri("pack://application:,,,/ReturnJourneyPreparation;component/Resources/favicon.ico")).Stream;
System.Drawing.Icon notIcon = new Icon(iconStream);
System.Drawing.Image canvas = new Bitmap(notIcon.Width, notIcon.Height);
Graphics artist = Graphics.FromImage(canvas);
artist.DrawString(_Messages.Count().ToString(), new Font("Arial", 4), System.Drawing.Brushes.Black, (float)(notIcon.Width), (float)(notIcon.Height));
(PS. I can't use Philipp Sumi's NotifyIcon module)
Thanks, Psy
It looks like you're trying to add a watermark on top of your image/icon. For more information check out the following site: http://www.c-sharpcorner.com/UploadFile/scottlysle/WatermarkCS05072007024947AM/WatermarkCS.aspx
You'll be able to add custom text on top of the original icon graphic. This is a great solution if you're not updating often--but if it's something that will be run many times in a short period of time (I'm thinking progress bar here) you'll be adding unneeded lag to your program.