3

How can I convert a System.Drawing.Bitmap to GDK# Image so that I can set to the image widget.

I have tried this...

System.Drawing.Bitmap b = new Bitmap (1, 1);
Gdk.Image bmp = new Gdk.Image (b);

UPDATE:

Bitmap bmp=new Bitmap(50,50);
        Graphics g=Graphics.FromImage(bmp);
        System.Drawing.Font ff= new System.Drawing.Font (System.Drawing.FontFamily.GenericMonospace, 12.0F, FontStyle.Italic, GraphicsUnit.Pixel);
        g.DrawString("hello world",ff,Brushes.Red,new PointF(0,0));
        MemoryStream ms = new MemoryStream ();
        bmp.Save (ms, ImageFormat.Png);
        Gdk.Pixbuf pb= new Gdk.Pixbuf (ms); 
        image1.Pixbuf=pb;

Exception:

    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> GLib.GException: Unrecognized image file format
   at Gdk.PixbufLoader.Close()
   at Gdk.PixbufLoader.InitFromStream(Stream stream)
   at Gdk.PixbufLoader..ctor(Stream stream)
   at Gdk.Pixbuf..ctor(Stream stream)
techno
  • 6,100
  • 16
  • 86
  • 192

3 Answers3

2

One ugly, but working, way is to store the bitmap as a PNG in a MemoryStream.

To save the Bitmap, you can use the Save method:

b.Save(myMemoryStream, ImageFormat.Png);

That was easy enough. Loading the PNG data into the Gdk# Pixbuf is also rather easy; you can use the appropriate constructor:

Pixbuf pb = new Gdk.Pixbuf(myMemoryStream);

You may need to reset the memory stream so the reading position is at the start of the stream before creating the Pixbuf.

A word of caution: I do not consider this the best, or even a "good" solution. Transferring data between two object-oriented data structures by serializing and deserializing the data has a certain code smell to it. I genuinely hope someone else can come up with a better solution.

EDIT: As for the used libraries: This answer uses only plain GDI+ (System.Drawing.Bitmap) and Gdk# (Gdk.Pixbuf). Note that a Gtk.Image is a widget that displays a Gdk.Pixbuf. As such, Gtk.Image is the equivalent of Windows Forms' PictureBox, whereas Gdk.Pixbuf is roughly equivalent to Windows Forms' System.Drawing.Bitmap.

EDIT2: After testing your code, I have found that there are three additional preconditions to ensure before you can run your minimum example:

  • As suspected above, you must reset the stream position to the beginning of the after saving your Bitmap and before loading your Pixbuf: ms.Position = 0;
  • You must compile the application for x86 CPUs.
  • You must invoke Gtk.Application.Init(); before you do anything with Pixbuf.
O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114
  • Thanks,i have code already written using Bitmap and graphics object.I dont want to learn new stuff like cairo to do the same thing – techno Dec 11 '13 at 09:09
  • @techno: I am not using Cairo in this response. Please see the edit that explains what libraries were used. – O. R. Mapper Dec 11 '13 at 09:14
  • Yeah i know:) I did not say you were using cairo.I told why i was going for this approach rather than using cairo.And i know how GDI,GDK# stuff works :) – techno Dec 11 '13 at 09:16
  • @techno: Ah, ok. Wasn't sure based on your comment, but now at least the explanation is here for future people to cite ;-) – O. R. Mapper Dec 11 '13 at 09:17
  • @techno: Oh, and that said, I don't think Cairo would be of any further help as I understand that's focused on vector graphics rather than raster graphics manipulation. I'd guess that a "prettier" way of transferring that data could only be provided by some library that knows both GDI+ and Gdk# and that is written with knowledge about the internals of both the `Bitmap` and the `Pixbuf` classes. – O. R. Mapper Dec 11 '13 at 09:19
  • 1
    I see.I find GDK# a little bit confusing starting from UI design(GTK) – techno Dec 11 '13 at 09:29
  • @techno: True, I'm getting the same here, too, when using your code. And frankly, I have no idea what you're doing differently than I am in one of my projects here that do work :-/ – O. R. Mapper Dec 11 '13 at 09:57
  • @techno: Ooh, I have just got your code to run. See my second edit :-) – O. R. Mapper Dec 11 '13 at 10:07
  • okay:) what does Gtk.Application.Init() do and why you say compile it for X86,any way im not creating 64 bit version,so i think it will be okay – techno Dec 11 '13 at 10:12
  • @techno: It seems to invoke something that matches `g_type_init()`. Without that call, the program will emit a critical message to stderr about `g_type_init()` not having been called, and after that, some class is not found as stated by a warning. The result is that the image format is not recognized. – O. R. Mapper Dec 11 '13 at 10:14
  • @techno: The Mono assemblies are supplied for x86 only. By default, C# compiles to *anycpu*, which means that on an x64 system, the program will execute as x64, fail to load x86 Mono and thus crash. At least superficially, that's what's happening. (I'm working on an x64 system here so that was one of the problems I ran into when trying to run your sample code.) – O. R. Mapper Dec 11 '13 at 10:15
  • im using Mono Develop and im working on X64 system too. – techno Dec 11 '13 at 10:16
  • @techno: Well, fine if it works. It crashes for me when compiling for either *x64* or *anycpu*, but works when compiling for *x86*. (Tried with Notepad++ and `csc` via the console.) – O. R. Mapper Dec 11 '13 at 10:22
  • I get Glib Exception saying Unrecognized Image File format when i try your code now. Please see the update – techno Apr 05 '14 at 12:28
  • @techno: Have you tried resetting the stream position as pointed out in my EDIT2? – O. R. Mapper Apr 05 '14 at 12:33
  • Can you help me with this please http://stackoverflow.com/questions/23495203/gtk-multiple-file-filter – techno May 06 '14 at 13:33
1

You may draw in Gtk# like in Winforms. For this you must obtain System.Drawing.Graphics object and then you may draw lines, images and text on it. You may do it like this: 1. Create new Widget. 2. Subscribe on ExposeEvent. 3. On event handler write some code:

protected void OnExposeEvent(object o, ExposeEventArgs e)
{
    Gdk.Window window = e.Event.Window;      
    using (System.Drawing.Graphics graphics =
        Gtk.DotNet.Graphics.FromDrawable(window))
    {
        // draw your stuff here...
        graphics.DrawLine(new System.Drawing.Pen(System.Drawing.Brushes.Black), 0, 0, 30, 40);
    }
}

Also you need to add reference on gtk-dotnet.dll.

Deffiss
  • 1,136
  • 7
  • 12
  • While valid for the sample code, this doesn't really answer the question how to get data from an existing `System.Drawing.Bitmap` into a `Gdk.Pixbuf`. – O. R. Mapper Dec 11 '13 at 10:32
  • @O.R.Mapper Agree with you but I think he just want to draw like in Winforms and asked this question because don't know how to do this. – Deffiss Dec 11 '13 at 10:40
  • @Deffiss Could you answer this question please http://stackoverflow.com/questions/23495203/gtk-multiple-file-filter – techno May 06 '14 at 12:56
-4

try this ....

Gdk.Pixbuf pixbufImage = mew Gdk.Pixbuf(@"images/test.png");
Gtk.Image gtkImage = new Gtk.Image(pixbufImage);
Gdk.Image gdkImage = gtkImage.ImageProp;