Create a bitmap and display it using Gtk# in C# - c#

I'm a MAC user so I can't use Windows Forms. I'm trying to figure out Gtk# myself but there is little to no tutorials and documentation to be found on the internet. I want to create a bitmap, draw something in it and display it. So far, I came with this and that displays a window:
Application.Init();
Window Win = new Window("Ray Tracing #2");
Win.Resize(480, 480);
Win.ShowAll();
Application.Run();
However, I would like to manipulate with the window, so let's say: add a bitmap for a start.
I know that to create a bitmap I must write:
System.Drawing.Image IMG = new Bitmap(640, 640);
but what then?

All right, let's try to fix all the problems at once:
You can find a Gtk# tutorial in ZetCode.
If you are going to mess with graphics, then you need to know about Cairo#.
I have a Github repository for my students with a simple demo using both Gtk# and Cairo.
I have another Github repository with a CSV-based spreadsheet application.
My advise is not to rely on the visual designer present in MonoDevelop/XamarinStudio, but to understand how the toolkit works and use it directly. Nowadays graphic toolkits are easy to use enough, and this way you are not tied to any editor/environment.
About your specific question, Bitmap pertains to the WinForms's universe (in fact, it is within the Drawing namespace), you should use a Gtk.Image. Let's create a scrolled panel (though it is called a "window"), and use it to show the bitmap.
var swScroll = new Gtk.ScrolledWindow();
var picBox = new Gtk.Image( "/path/to/image.jpg" );
var vbox = new VBox( false, 5 );
swScroll.AddWithViewport( picBox );
vbox.PackStart( swScroll, true, true, 5 );
this.Add( vbox );
this.ShowAll();
You can build an empty image with a specific size or whatever. Explore the constructors available for Gtk.Image.
Hope this helps!

Related

Print visual as grayscale WPF

How can I print a visual as grayscale without actually showing the PrintDialog, e.g.
PrintDialog dialog = new Dialog();
dialog.PrintQueue = new PrintQueue(new PrintServer(), printerNameAsString);
dialog.PrintTicket.InputBin = InputBin.AutoSelect;
// Further settings, e.g. PageMediaSize and scaling the visual.
dialog.PrintVisual(myVisual, "myDescription");
Can I somehow get the PrinterDialog to print the visual in grayscale? Or is there a completely other way to achieve a grayscale printout of my visual?
Edit: myVisual (the Visual I want to print) is a Grid, so it inherits from UIElement.
Edit 2: If possible I would prefer not to use any external libraries (because of company policies).
In the PrintDialog the OutputColor can be set:
myPrintDialog.PrintTicket.OutputColor = OutputColor.Grayscale;
Also, the PrintCapabilities make it possible to actually check which OutputColors are possible:
PrintCapabilities capabilities = myPrintDialog.PrintQueue.GetPrintCapabilities(myPrintDialog.PrintTicket);
ReadOnlyCollection<OutputColor> possibleColors = capabilities.OutputColorCapability;
On the hardware available to me this works fine.
You can try using the standard lib in Microsoft.Expression.Effects assembly. The effect here is MonochromeEffect. Just apply this effect before printing your visual:
myVisual.Effect = new MonochromeEffect();//make grayscale
dialog.PrintVisual(myVisual, "myDescription");
myVisual.Effect = null; //turn it off
You have to import the library I mentioned above and add this using instruction:
using Microsoft.Expression.Media.Effects;
I ran into a similar problem where DrawString would always print solid black--even though the Brushes specified a lighter shade. I finally discovered that by placing an image onto the graphics object, it would print lighter shades that were in the image. It feels like a hack, but it works! (The printdialog solution might have worked too--I don't know since I'm printing automatically from a service where there is no printdialog.)

OpenCv CvWindow removal

I am trying to get the output of a camera and display it in a c# gui using OpenCvSharp. This is the code I have based on samples. However, this code pops up a second window, CvWindow, which I would like to remove. Is this possible? Removing the CvWindow from my code makes the camera stream not appear.
CvCapture cap= CvCapture.FromCamera(0);
CvWindow win= new CvWindow("camera");
while (CvWindow.WaitKey(10) < 0)
{
IplImage img= Capture.QueryFrame();
Bitmap bmp= BitmapConverter.ToBitmap(img);
pictureBox1.Image = bmp;
}
win.Close();
This is how I display OpenCvSharp video feeds in a Windows Form. http://www.prodigyproductionsllc.com/articles/programming/use-opencv-in-a-windows-form-application-in-c/.
The best way to hide the window is to not show it in the first place. So, remove the line where you construct a new CvWindow. Then, you need to move your while-loop into a new thread and make it continuous with something like "while(true)". If you do not run it on a separate thread, your app will freeze.
Well, it turns out using the Win32 API to hide the window was the way to go. However, you have to make sure to hide parent window of the CvWindow.

Drawing on Video within C#

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 :-)

Overlaying Notification Icon with text

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.

How do I get access to an image of the desktop buffer in .NET?

I am making a very simple app in C# with Visual Studio, so I'm using that Forms package. I need to get access to an image of everything below it, so that I can manipulate the image. How can I do this?
It doesn't have to be real time very much, since I'll probably be polling it not more than say 10fps.
You could use Graphics.CopyFromScreen, but you will need to hide your window before you call it or otherwise it will appear in the image.
You can use Interop to get a hook to the "Desktop Window", if that's what you mean, and then you can use that to get your screenshot...this link might help:
Getting the Desktop Window from .NET
Another option (you said WinForms, right) is to create a placeholder Bitmap and use the Graphics.CopyFromScreen method:
int screenWidth = 1024;
int screenHeight = 768;
Bitmap holder = new Bitmap(screenWidth, screenHeight);
Graphics graphics = Graphics.FromImage(holder);
graphics.CopyFromScreen(0,0,0,0,new Size(screenWidth, screenHeight), CopyPixelOperation.SourceCopy);

Categories