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`.