2

I'm working on an C++ image viewer for Linux which is created using GTK+3 (gtkmm) for the GUI and Magick++ for image handling. My goal is to support as many image file formats as possible, including animated GIFs.

What is the best approach to take a Magick++ Image and draw it in a GTK+3 widget, such that it would work for (just about) any image file format?

Max
  • 189
  • 7

2 Answers2

2

What is the best approach to take a Magick++ Image and draw it in a GTK+3 widget, such that it would work for (just about) any image file format?

As long as ImageMagick has the format delegate, you should be able to draw the GtkWidget image.

image = Gtk::manage(new Gtk::Image());
// Load image into ImageMagick
Magick::Image img("wizard:");
/// Calculate how much memory to allocate
size_t to_allocate = img.columns() * img.rows() * 3;
// Create a buffer
guint8 * buffer = new guint8[to_allocate];
// Write pixel data to buffer.
img.write(0, 0, img.columns(), img.rows(), "RGB", Magick::CharPixel, buffer);
// Build a Pixbuf from pixel data in memory.
Glib::RefPtr<Gdk::Pixbuf> pBuff = Gdk::Pixbuf::create_from_data(buffer, Gdk::COLORSPACE_RGB, false, 8, img.columns(), img.rows(), img.columns()*3 );
// Set GtkImage from Pixbuf
image->set(pBuff);

GtkImage from Magick++

Original Answer mixing C/C++ methods.

Use the following Magick++ method signature to export the pixel data into memory.

Magick::Image.write(const ssize_t x_,
                    const ssize_t y_,
                    const size_t columns_,
                    const size_t rows_,
                    const std::string &map_,           //<= Usually "RGB"
                    const StorageType type_,           //<= Usually CharType
                    void *pixels_)                     //<= Be sure to allocate _all_ the memory required (size of storage * number of channels * columns * rows)

Create a GdkPixBuf from the pixels exported above with the following GTK method.

GdkPixbuf *
gdk_pixbuf_new_from_bytes (GBytes *data,               //<= Same as pixels_.
                           GdkColorspace colorspace,   //<= Match colorspace channels from map_.
                           gboolean has_alpha,         //<= Usually no.
                           int bits_per_sample,        //<= Match StorageType bits
                           int width,                  //<= Same as columns_.
                           int height,                 //<= Same as rows_.
                           int rowstride);             //<= size of data-type * number of channel * width.

Finally, build a GtkImage from the PixBuf with the following method.

GtkWidget * gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf);
emcconville
  • 23,800
  • 4
  • 50
  • 66
  • Those are the C APIs, OP is using C++. – liberforce Mar 02 '18 at 14:48
  • Facepalm! @liberforce is right. I'll updated the answer with examples. – emcconville Mar 02 '18 at 15:45
  • 1
    Thanks for your answer and example. Just for the record, for images with an alpha channel you can use the matte() property of a Magick++ Image to check if an image has an alpha channel, then write using "RGBA" and create the Pixbuf with the has_alpha parameter set to true. This seems to work fine for images without alpha too, but of course you have to extra memory for the extra channel. I don't know if there are any other (dis)advantages. – Max Mar 02 '18 at 21:17
  • 1
    Wasn’t matte deprecated with ImageMagick-7? – emcconville Mar 02 '18 at 21:19
  • @emcconville You seem to be correct about that. It appears to be called alpha() nowadays. – Max Mar 03 '18 at 00:18
1

I suppose @emcconville is right for the ImageMagick part, as I have no clue about it.

For the GTKmm part, though, you'll want to stick to the C++ API, so use Gdk::Pixbuf::create_from_data to read the image from ImageMagick.

Also, as you're creating an image viewer, you will want to change the image shown by a Gtk::Image. So at startup just use an empty Gtk::Image created with Gtk::Image::Image (or Glade and Gtk::Builder), and later change the image displayed in it with Gtk::Image::set, passing it your pixbuf.

liberforce
  • 11,189
  • 37
  • 48