Drawing Images
| Chapter 18. The DrawingArea Widget |

## Drawing Images

There is a method for drawing from a `Gdk::Pixbuf` to a `Cairo::Context`. A `Gdk::Pixbuf` buffer is a useful wrapper around a collection of pixels, which can be read from files, and manipulated in various ways.

Probably the most common way of creating `Gdk::Pixbuf`s is to use `Gdk::Pixbuf::create_from_file()` or `Gdk::Pixbuf::create_from_resource()`, which can read an image file, such as a png file into a pixbuf ready for rendering.

The `Gdk::Pixbuf` can be rendered by setting it as the source pattern of the Cairo context with `Gdk::Cairo::set_source_pixbuf()`. Then draw the image with either `Cairo::Context::paint()` (to draw the whole image), or `Cairo::Context::rectangle()` and `Cairo::Context::fill()` (to fill the specified rectangle). `set_source_pixbuf()` is not a member of `Cairo::Context`. It takes a `Cairo::Context` as its first parameter.

Here is a small bit of code to tie it all together: (Note that usually you wouldn't load the image every time in the draw signal handler! It's just shown here to keep it all together.)

    void MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr, int width, int height)
    {
      auto image = Gdk::Pixbuf::create_from_file("myimage.png");
      // Draw the image at 110, 90, except for the outermost 10 pixels.
      Gdk::Cairo::set_source_pixbuf(cr, image, 100, 80);
      cr->rectangle(110, 90, image->get_width()-20, image->get_height()-20);
      cr->fill();
    }

### Example

Here is an example of a simple program that draws an image. The program loads the image from a resource file. See the Gio::Resource and glib-compile-resources section. Use glib-compile-resources to compile the resources into a C source file that can be compiled and linked with the C++ code. E.g.

    $ glib-compile-resources --target=resources.c --generate-source image.gresource.xml

Figure 18.7. Drawing Area - Image

Source Code

File: `myarea.h` (For use with gtkmm 4)

    #ifndef GTKMM_EXAMPLE_MYAREA_H
    #define GTKMM_EXAMPLE_MYAREA_H

    #include <gtkmm/drawingarea.h>
    #include <gdkmm/pixbuf.h>

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

    protected:
      void on_draw(const Cairo::RefPtr<Cairo::Context>& cr, int width, int height);

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

    #endif // GTKMM_EXAMPLE_MYAREA_H

File: `main.cc` (For use with gtkmm 4)

    #include "myarea.h"
    #include <gtkmm/application.h>
    #include <gtkmm/window.h>

    class ExampleWindow : public Gtk::Window
    {
    public:
      ExampleWindow();

    protected:
      MyArea m_area;
    };

    ExampleWindow::ExampleWindow()
    {
      set_title("DrawingArea");
      set_default_size(300, 200);
      set_child(m_area);
    }

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

      return app->make_window_and_run<ExampleWindow>(argc, argv);
    }

File: `myarea.cc` (For use with gtkmm 4)

    #include "myarea.h"
    #include <cairomm/context.h>
    #include <giomm/resource.h>
    #include <gdkmm/general.h> // set_source_pixbuf()
    #include <glibmm/fileutils.h>
    #include <iostream>

    MyArea::MyArea()
    {
      try
      {
        // The fractal image has been created by the XaoS program.
        // http://xaos.sourceforge.net
        m_image = Gdk::Pixbuf::create_from_resource("/image/fractal_image.png");
      }
      catch(const Gio::ResourceError& ex)
      {
        std::cerr << "ResourceError: " << ex.what() << std::endl;
      }
      catch(const Gdk::PixbufError& ex)
      {
        std::cerr << "PixbufError: " << ex.what() << std::endl;
      }

      // Show at least a quarter of the image.
      if (m_image)
      {
        set_content_width(m_image->get_width()/2);
        set_content_height(m_image->get_height()/2);
      }

      // Set the draw function.
      set_draw_func(sigc::mem_fun(*this, &MyArea::on_draw));
    }

    MyArea::~MyArea()
    {
    }

    void MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr, int width, int height)
    {
      if (!m_image)
        return;

      // 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();
    }

File: `image.gresource.xml` (For use with gtkmm 4)

    <?xml version="1.0" encoding="UTF-8"?>
    <gresources>
      <gresource prefix="/image">
        <file>fractal_image.png</file>
      </gresource>
    </gresources>

Drawing Text |  | Example Application: Creating a Clock with Cairo