Radek Chalupa   konzultace a školení programování, vývoj software na zakázku

Grafický editor využívající ImageMagick a gtkmm - úvod

6.2.2019

V následující sérii článků si ukážeme vytvoření ukázkového grafického editoru využívajícího pro manipulaci s obrázky třídu (z knihovny ImageMagick/Magick++) Magick::Image a pro zobrazení v grafickém uživatelském rozhraní knihovnu gtkmm.

V tomto úvodním díle si vytvoříme kostru aplikace a vykreslíme "natvdro zadaný" grafický soubor.

Pro vykreslení obrázku do okna použijeme widget Gtk::DrawingArea, který umístíme na (hlavní) okno aplikace, přesněji řečeno vytvoříme si vlastní třídu odvozenou od Gtk::DrawingArea, v ní implementujeme virtuální funkci on_draw, která je výchozí obsluhou signálu signal_draw. V této funkci pak vykreslíme obrázek zadaný pomocí členské funkce set_pixbuf do členské proměnné Gdk::Pixbuf* _pixbuf tak, že se velikost přizpůsobí aktuálnímu rozměru okna (resp. widgetu DrawingArea) a příslušným výpočtem zajistíme zachování poměru stran obrázku.

Takto bude vypadat kompletní kód naší třídy:

class OblastObrazku : public Gtk::DrawingArea
{
private:
	Gdk::Pixbuf* _pixbuf = nullptr;

public:
	void set_pixbuf(Gdk::Pixbuf* pixbuf) noexcept
	{
		_pixbuf = pixbuf;
		queue_draw();
	}

protected:
	bool on_draw(const Cairo::RefPtr& cr) override
	{
		if (!_pixbuf)
			return false;
		Gtk::Allocation allocation = get_allocation();
		const int width = allocation.get_width();
		const int height = allocation.get_height();
		Glib::RefPtr pb =
			Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, width, height);
		double pomer;
		double pocX = 0;
		double pocY = 0;
		double sirka_cil = (double)width;
		double vyska_cil = (double)height;
		if (_pixbuf)
		{
			if (((double)_pixbuf->get_width() / width) > ((double)_pixbuf->get_height() / height))
			{
				pomer = (double)width / _pixbuf->get_width();
				vyska_cil = ((double)_pixbuf->get_height()*pomer);
				pocY = ((double)height - vyska_cil)/2;
			}
			else
			{
				pomer = (double)height / _pixbuf->get_height();
				sirka_cil = ((double)_pixbuf->get_width()*pomer);
				pocX = ((double)width - sirka_cil)/2;

			}
			_pixbuf->scale(pb,  0, 0, width, height,  0, 0,
				(double)pomer,
				(double)pomer, Gdk::InterpType::INTERP_NEAREST);
		}
		Gdk::Cairo::set_source_pixbuf(cr, pb, pocX, pocY);
		cr->rectangle(0, 0, width - pocX, height - pocY);
		cr->fill();
		pb.reset();
		return true;
	}
};

Do kódu třídy okna aplikace si přidáme (jako členské proměnné) widget Gtk::Box a instanci naší třídy OblastObrazku

Deklarace třídy (hlavičkový soubor OknoHlavni.h) bude vypadat takto

#pragma once

#include "includes.h"
#include "OblastObrazku.h"

class OknoHlavni : public Gtk::Window
{
private:
	Glib::RefPtr<Gdk::Pixbuf> _pixbuf;

public:
  OknoHlavni();

private:
	Gtk::Box _box;
	OblastObrazku _oblast_obrazku;
};

Vložený soubor includes.h bude obsahovat všechny použité knihovny, zatím obsahuje pouze

#pragma once

#include <gtkmm.h>

Vytvoření zmíněných widgetů a základní nastavení okna aplikace provedeme v konstruktoru třídy OknoHlavní. Implementační soubor OknoHlavni.cpp vypadá (prozatím) takto:

#include "OknoHlavni.h"

OknoHlavni::OknoHlavni()
{
	_box.set_orientation(Gtk::ORIENTATION_VERTICAL);
	this->add(_box);
	_box.add(_oblast_obrazku);
	_oblast_obrazku.set_hexpand(true);
	_oblast_obrazku.set_vexpand(true);
	show_all_children();
	this->set_default_size(1024, 780);
	set_title("Editor obrázků");
	_pixbuf = Gdk::Pixbuf::create_from_file("../kozel.png");
	_oblast_obrazku.set_pixbuf(_pixbuf.get());
}

A takto vypadá hlavní funkce main, resp. hlavní zdrojový soubor main.cpp:

#include "OknoHlavni.h"

int main (int argc, char *argv[])
{
  Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "radekchalupa.gtkmm.example");
  OknoHlavni okno;
  return app->run(okno);
}

Projekt je vytvořen v CodeLite, což je komplexní vývojové prostředí, obsahující pokročilé nástroje pro ladění a správu kódu. Pokud chcete použít jiný editor a překladač, je nutné nastavit překlad a sestavení knihovny gtkmm. V překladači GCC resp. G++ použijeme parametr `pkg-config --cflags --libs gtkmm-3.0`.