8.2.2019
V úvodním díle jsme si připravili kostru aplikace se zobrazením ukázkového obrázku. Nyní je čas zapojit knihovnu ImageMagick, resp. Magick++, jak je nazváno její rozhraní pro jazyk C++. V Linuxovém prostředí musíme mít kromě gtkmm nainstalován také balíček Magick++, který v Ubuntu najdeme pod názvem libmagick++-dev. Do hlavičkového souboru s použitými knihovnami přidáme hlavičkový soubor Magick++.h. V nastavení kompilátoru pak opět použijeme pkg-config s tím že do voleb překladače přidáme `pkg-config --cflags Magick++` a do voleb linkeru `pkg-config --libs Magick++`
Nyní si vytvoříme pomockou třídu (zde nazvanou Obrazek), které bude jako členské proměnné obsahovat Magick::Image (pro načítání a různé úpravy obrázku) a Gdk::Pixbuf (pro zobrazování načteného obrázku v okně aplikace psané v gtkmm.
Nejprve její kompletní kód (soubor Obrazek.h):
#pragma once #include "includes.h" class Obrazek { private: std::unique_ptr<Magick::Image> _image; Glib::RefPtr<Gdk::Pixbuf> _pixbuf; public: ~Obrazek() noexcept { _pixbuf.reset(); _image.reset(); } public: void nacist(const char* soubor) { _image.reset(); _image = std::make_unique<Magick::Image>(soubor); aktualizovat_data(); } bool je_nacten() noexcept { return (_image && _image->isValid()); } void aktualizovat_data() noexcept { if (!je_nacten()) return; _pixbuf.reset(); Magick::Blob blob; _image->write(&blob); Glib::RefPtr<Gio::MemoryInputStream> ms = Gio::MemoryInputStream::create(); ms->add_data((const void*)blob.data(), blob.length()); _pixbuf = Gdk::Pixbuf::create_from_stream(ms); ms.reset(); } Gdk::Pixbuf* get_pixbuf() noexcept { assert(_image.get()); return _pixbuf.get(); } Magick::Image* get_image() noexcept { assert(_image.get()); return _image.get(); } };
Klíčovou metodou je aktualizovat_data, ve které s využitím tříd Magick::Blob a Gio::MemoryInputStream vytvoříme z načteného obrázku (Magick::Image) Pixbux pro zobrazení. Později si tuto metodu rozšíříme o parametry, na základě kterých nastavíme např. kvalitu jpeg komprese nebo grafický formát.
Nyní si do okna aplikace přidáme (hlavní) nabídku, ze které budeme vybírat soubor k otevření, volit cílový soubor pro ukládání upraveného obrázku a jako ukázku funkce třídy Magick::Image rotaci obrázků o 45 stupňů.
Hlavičkový soubor třídy hlavního okna vypadá nyní takto:
#pragma once #include "includes.h" #include "OblastObrazku.h" #include "Obrazek.h" class OknoHlavni : public Gtk::Window { private: Glib::RefPtr<Gdk::Pixbuf> _pixbuf; public: OknoHlavni(); private: Obrazek _obrazek; Glib::ustring _nacteny_soubor; private: Gtk::Box _box; OblastObrazku _oblast_obrazku; Gtk::Menu* _submenu_soubor; Gtk::MenuItem* _item_soubor; Gtk::MenuItem* _mi_konec; Gtk::MenuItem* _mi_soubor_otevrit; Gtk::MenuItem* _mi_soubor_ulozit; Gtk::Menu* _submenu_upravy; Gtk::MenuItem* _item_upravy; Gtk::MenuItem* _mi_rotace_45; private: void on_konec() noexcept; void on_rotace_45() noexcept; void on_soubor_otevrit() noexcept; void on_soubor_ulozit() noexcept; private: void nacist_soubor(const char* soubor) noexcept; void zprava_chyba(const char* text) noexcept; };
Implementace třídy OknoHlavní včetně pomocných funkcí pro zobrazení chybové hlášky a načtení vybraného souboru vypadá pak následovně:
#include "OknoHlavni.h" OknoHlavni::OknoHlavni() { _box.set_orientation(Gtk::ORIENTATION_VERTICAL); this->add(_box); _item_soubor = Gtk::manage(new Gtk::MenuItem("_Soubor")); _item_soubor->set_use_underline(true); _submenu_soubor = Gtk::manage(new Gtk::Menu); _mi_soubor_otevrit = Gtk::manage(new Gtk::MenuItem("_Otevřít")); _mi_soubor_otevrit->set_use_underline(true); _submenu_soubor->append(*_mi_soubor_otevrit); _mi_soubor_ulozit = Gtk::manage(new Gtk::MenuItem("_Uložit")); _mi_soubor_ulozit->set_use_underline(true); _submenu_soubor->append(*_mi_soubor_ulozit); _mi_konec = Gtk::manage(new Gtk::MenuItem("_Konec")); _mi_konec->set_use_underline(true); _submenu_soubor->append(*_mi_konec); _item_upravy = Gtk::manage(new Gtk::MenuItem("Ú_pravy")); _item_upravy->set_use_underline(true); _submenu_upravy = Gtk::manage(new Gtk::Menu); _mi_rotace_45 = Gtk::manage(new Gtk::MenuItem("Otočit o 45 stupňů")); _mi_rotace_45->set_use_underline(true); _submenu_upravy->append(*_mi_rotace_45); _item_soubor->set_submenu(*_submenu_soubor); _item_upravy->set_submenu(*_submenu_upravy); Gtk::MenuBar* menubar = Gtk::manage(new Gtk::MenuBar); menubar->append(*_item_soubor); menubar->append(*_item_upravy); _box.add(*menubar); _box.add(_oblast_obrazku); _oblast_obrazku.set_hexpand(true); _oblast_obrazku.set_vexpand(true); _mi_konec->signal_activate().connect(sigc::mem_fun(*this, &OknoHlavni::on_konec)); _mi_rotace_45->signal_activate().connect(sigc::mem_fun(*this, &OknoHlavni::on_rotace_45)); _mi_soubor_otevrit->signal_activate().connect(sigc::mem_fun(*this, &OknoHlavni::on_soubor_otevrit)); _mi_soubor_ulozit->signal_activate().connect(sigc::mem_fun(*this, &OknoHlavni::on_soubor_ulozit)); show_all_children(); this->set_default_size(1024, 780); set_title("Editor obrázků"); nacist_soubor("../derny-stitek.jpg"); } void OknoHlavni::on_konec() noexcept { close(); } void OknoHlavni::on_rotace_45() noexcept { _obrazek.get_image()->rotate(45.0); _obrazek.aktualizovat_data(); _oblast_obrazku.set_pixbuf(_obrazek.get_pixbuf()); } void OknoHlavni::on_soubor_otevrit() noexcept { Gtk::FileChooserDialog dialog("Načíst obrázek", Gtk::FILE_CHOOSER_ACTION_OPEN); dialog.set_transient_for(*this); dialog.add_button("_Zrušit", Gtk::RESPONSE_CANCEL); dialog.add_button("Vybrat", Gtk::RESPONSE_OK); auto filtr = Gtk::FileFilter::create(); filtr->set_name("Obrázky"); filtr->add_mime_type("image/jpeg"); filtr->add_mime_type("image/tiff"); filtr->add_mime_type("image/gif"); dialog.add_filter(filtr); int result = dialog.run(); if (Gtk::RESPONSE_OK != result) return; std::string str_soubor = dialog.get_filename(); nacist_soubor(str_soubor.c_str()); } void OknoHlavni::on_soubor_ulozit() noexcept { if (!_obrazek.je_nacten()) return; Gtk::FileChooserDialog dialog("Uložit obrázek", Gtk::FILE_CHOOSER_ACTION_SAVE); dialog.set_transient_for(*this); dialog.add_button("_Zrušit", Gtk::RESPONSE_CANCEL); dialog.add_button("Uložit", Gtk::RESPONSE_OK); auto filtr = Gtk::FileFilter::create(); filtr->set_name("Obrázky"); filtr->add_mime_type("image/jpeg"); filtr->add_mime_type("image/tiff"); filtr->add_mime_type("image/gif"); dialog.add_filter(filtr); int result = dialog.run(); if (Gtk::RESPONSE_OK != result) return; std::string str_soubor = dialog.get_filename(); _obrazek.get_image()->write(str_soubor.c_str()); } void OknoHlavni::zprava_chyba(const char* text) noexcept { std::unique_ptr<Gtk::MessageDialog> dialog; dialog = std::make_unique<Gtk::MessageDialog>(*this, text, false, Gtk::MESSAGE_ERROR); dialog->run(); dialog.reset(); } void OknoHlavni::nacist_soubor(const char* soubor) noexcept { try { _obrazek.nacist(soubor); _nacteny_soubor = soubor; _oblast_obrazku.set_pixbuf(_obrazek.get_pixbuf()); } catch (std::exception& ex) { zprava_chyba(ex.what()); } }
Projekt (v CodeLite) si můžete stáhnout v příloze níže.
Školení
Kontakt
739 219 991
live:radekchalupa_1
Nové články