[Solved] Using Magick++ in a GTK app

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
danieru
Posts: 10
Joined: 2014-06-13T11:48:15-07:00
Authentication code: 6789

[Solved] Using Magick++ in a GTK app

Post by danieru »

Hello everyone,

I was for a while trying to load this image file with Magick++ and then show it in a simple GTK app.

But in my attempt I get a runtime error of GTK when load a blob in a pixbuf.

Here's my code until now:

Code: Select all

#include <Magick++.h>
#include <gtkmm.h>
#include <iostream>

using namespace std;

class MyArea : public Gtk::DrawingArea
{
public:
  MyArea();
  virtual ~MyArea();

protected:
  //Override default signal handler:
  virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr);

  Glib::RefPtr<Gdk::Pixbuf> m_image;
};

int main(int argc, char** argv)
{
  Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

  Gtk::Window win;
  win.set_title("magick++ && gtkmm");
  win.set_default_size(445, 287);

  MyArea area;
  win.add(area);
  area.show();

  return app->run(win);
}

MyArea::MyArea()
{
  try
  {

   Magick::Image image( "fractal_image.png" );
   Magick::Blob blob;
   image.magick( "XPM" );  //  using "JPEG" or "PNG" cause a segmentation fault  //
   image.write( &blob );

   const void *pblob = blob.data();
   const char *pdata;
   const char **ppdata;
   pdata = static_cast<const char*>(pblob);
   ppdata = &pdata;

   m_image = Gdk::Pixbuf::create_from_xpm_data(ppdata);   // This try to load the blob to a pixbuf //

  }
  catch(const Glib::FileError& ex)
  {
    std::cerr << "FileError: " << ex.what() << std::endl;
  }
  catch(const Gdk::PixbufError& ex)
  {
    std::cerr << "PixbufError: " << ex.what() << std::endl;
  }

}

MyArea::~MyArea()
{
}

bool MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
   if (!m_image)
      return false;

   Gtk::Allocation allocation = get_allocation();
   const int width = allocation.get_width();
   const int height = allocation.get_height();

   // Draw the image in the middle of the drawing area, or (if the image is
   // larger than the drawing area) draw the middle part of the image.
   Gdk::Cairo::set_source_pixbuf(cr, m_image,
    (width - m_image->get_width())/2, (height - m_image->get_height())/2);

   cr->paint();

   return true;
}
This compile's with:
g++ `Magick++-config --cxxflags --cppflags` main.cpp -o main `pkg-config gtkmm-3.0 --cflags --libs` `Magick++-config --ldflags --libs`
But, again. GTK gives a runtime error saying "Inline XPM data is Broken: Invalid XPM header".
Is there a way to convert an image to xpm and pass it to create_from_xpm_data() properly?

I really appreciate any clue you can provide.
Last edited by danieru on 2014-06-14T16:19:25-07:00, edited 1 time in total.
danieru
Posts: 10
Joined: 2014-06-13T11:48:15-07:00
Authentication code: 6789

Re: Using Magick++ in a GTK app

Post by danieru »

After more searching I found this

So I took advice and changed the code to:

Code: Select all

#include <Magick++.h>
#include <gtkmm.h>
#include <iostream>

using namespace std;
using namespace Magick;

class MyArea : public Gtk::DrawingArea
{
public:
  MyArea();
  virtual ~MyArea();

protected:
  //Override default signal handler:
  virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr);

  Glib::RefPtr<Gdk::Pixbuf> m_image;
};

int main(int argc, char** argv)
{
  Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

  Gtk::Window win;
  win.set_title("magick++ && gtkmm");
  win.set_default_size(445, 287);

  MyArea area;
  win.add(area);
  area.show();

  return app->run(win);
}

MyArea::MyArea()
{
  try
  {

   Image image( "fractal_image.png" );

   int width;
   int height;
   width = image.columns();
   height = image.rows();
   unsigned char *myblock = (unsigned char*)malloc(width*height*3);

   image.write(0, 0, width, height, "RGB", CharPixel, myblock);

   guint8 *pdata;
   pdata = static_cast<guint8*>(myblock);

   Glib::RefPtr<Gdk::Pixbuf> pixbuf;
   int rowstride;

   pixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, width, height);
   rowstride = pixbuf->Gdk::Pixbuf::get_rowstride();

   m_image = Gdk::Pixbuf::create_from_data(pdata, Gdk::COLORSPACE_RGB, false, 8, width, height, rowstride);

  }
  catch(const Glib::FileError& ex)
  {
    std::cerr << "FileError: " << ex.what() << std::endl;
  }
  catch(const Gdk::PixbufError& ex)
  {
    std::cerr << "PixbufError: " << ex.what() << std::endl;
  }

}

MyArea::~MyArea()
{
}

bool MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
   if (!m_image)
      return false;

   Gtk::Allocation allocation = get_allocation();
   const int width = allocation.get_width();
   const int height = allocation.get_height();

   // Draw the image in the middle of the drawing area, or (if the image is
   // larger than the drawing area) draw the middle part of the image.
   Gdk::Cairo::set_source_pixbuf(cr, m_image,
    (width - m_image->get_width())/2, (height - m_image->get_height())/2);

   cr->paint();

   return true;
}
And when i run it get this:
Image
Which is close, but the image still does not appear correctly.

I think the problem might be the myblock variable type, which is an unsigned char. But here a signed char was used.
Maybe I lose some data using an unsigned char?
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Using Magick++ in a GTK app

Post by magick »

Set your row stride to 3*445.
danieru
Posts: 10
Joined: 2014-06-13T11:48:15-07:00
Authentication code: 6789

Re: Using Magick++ in a GTK app

Post by danieru »

Thank you very much for the tip! Now rowstride has the value that should (image width * number of bits per pixel), and that solved the problem :D
Image

Here's a function that takes a Magick::Image object and returns a Gdk::Pixbuf, just for the record:

Code: Select all

#include <Magick++.h>
#include <gtkmm.h>

Glib::RefPtr<Gdk::Pixbuf> im_to_pixbuf(Magick::Image image)
{
   int bits_per_pixel = 3;
   int width = image.columns();
   int height = image.rows();
   int rowstride = width*bits_per_pixel;
   unsigned char *block = (unsigned char*)malloc(width*height*bits_per_pixel);
   image.write(0, 0, width, height, "RGB", Magick::CharPixel, block);
   guint8 *pdata;
   pdata = static_cast<guint8*>(block);

   return Gdk::Pixbuf::create_from_data(pdata, Gdk::COLORSPACE_RGB, false, 8, width, height, rowstride);
}
Post Reply