13.10.2020
V předchozím článku o programování v GDK jsme si ukázali jak s využitím knihovny Cairo vykreslit požadovaný obsah okna. Šlo o jednoduché úsečky a výpis textu. Nyní si ukážeme jak zobrazit obrázek uložený v souboru.
Využijme k tomu GdkPixbuf. Na začátku programu si soubor načteme pomicí funkce gdk_pixbuf_new_from_file.
// globalni promenna mimo funkci main GdkPixbuf* pixbuf_orig = NULL; pixbuf_orig = gdk_pixbuf_new_from_file(IMAGE_FILE_PATH, NULL); if (NULL == pixbuf_orig) { printf("chyba načtení obrázku\n"); return EXIT_FAILURE; }
Při vykreslování budeme chtít aby se obrázek přizpůsobil aktuálnímu rozměru okna se zachováním poměru stran. Proto si vždy vytvoříme pomocný PixBuff o rozměrech odpovídajících aktuálním rozměrům kreslící oblasti. Pak použijeme trochu aritmetiky pro vypočítání poměru velikostí, který pak použijeme ve funkci gdk_pixbuf_scale, kterou přeneseme načtený PixBuff do tohoto pomocného, který pak použijeme jako zdroj cairo kontextu a vykreslíme pomocí funkce cairo_rectangle. Vše je nejlépe vidět na zdrojovém kódu funkce obsluhující událost GDK_EXPOSE.
void on_expose(GdkEventExpose* ev) { if (NULL == ev->region) return; GdkDrawingContext* dc = gdk_window_begin_draw_frame( window, ev->region); cairo_t* cr = gdk_drawing_context_get_cairo_context(dc); if (NULL == pixbuf_orig) { cairo_set_source_rgba(cr, 1.0, 1.0, 0.8, 1.0); cairo_paint(cr); gdk_window_end_draw_frame(window, dc); return; } GdkPixbuf* pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, ev->area.width, ev->area.height); double pomer; double pocX = 0; double pocY = 0; double sirkacil = (double)ev->area.width; double vyskacil = (double)ev->area.height; if ( ((double)gdk_pixbuf_get_width(pixbuf_orig) / ev->area.width) > ((double)gdk_pixbuf_get_height(pixbuf_orig) / ev->area.height) ) { pomer = (double)ev->area.width / gdk_pixbuf_get_width(pixbuf_orig); vyskacil = ((double)gdk_pixbuf_get_height(pixbuf_orig) * pomer); pocY = ((double)ev->area.height - vyskacil) / 2; } else { pomer = (double)ev->area.height / gdk_pixbuf_get_height(pixbuf_orig); sirkacil = ((double)gdk_pixbuf_get_width(pixbuf_orig)*pomer); pocX = ((double)ev->area.width - sirkacil)/2; } gdk_pixbuf_scale(pixbuf_orig, pb, 0, 0, ev->area.width, ev->area.height, 0, 0, pomer, pomer, GDK_INTERP_NEAREST); gdk_cairo_set_source_pixbuf(cr, pb, pocX, pocY); cairo_rectangle(cr, 0, 0, ev->area.width - pocX, ev->area.height - pocY); cairo_fill(cr); gdk_window_end_draw_frame(window, dc); g_object_unref(pb); }
Pokud si program vyzkoušíte s nějakým výrazně velkým obrázkem, zjistíte že vykreslování pomocí knihovny Cairo je velice rychlé i při rychlém opakování při roztahování okna.
Na závěr opět celý výpis programu, který lze sestavit překladačem GCC následujícím příkazem (pro ladicí sestavení):
gcc gdk-okno.c -Wall -g `pkg-config --cflags --libs gdk-3.0` -ogdk-okno
#include <gdk/gdk.h> #include <glib.h> #include <stdlib.h> #define IMAGE_FILE_PATH "kozel.png" GMainLoop* main_loop; GdkWindow* window; GdkPixbuf* pixbuf_orig = NULL; void on_expose(GdkEventExpose* ev) { if (NULL == ev->region) return; GdkDrawingContext* dc = gdk_window_begin_draw_frame( window, ev->region); cairo_t* cr = gdk_drawing_context_get_cairo_context(dc); if (NULL == pixbuf_orig) { cairo_set_source_rgba(cr, 1.0, 1.0, 0.8, 1.0); cairo_paint(cr); gdk_window_end_draw_frame(window, dc); return; } GdkPixbuf* pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, ev->area.width, ev->area.height); double pomer; double pocX = 0; double pocY = 0; double sirkacil = (double)ev->area.width; double vyskacil = (double)ev->area.height; if ( ((double)gdk_pixbuf_get_width(pixbuf_orig) / ev->area.width) > ((double)gdk_pixbuf_get_height(pixbuf_orig) / ev->area.height) ) { pomer = (double)ev->area.width / gdk_pixbuf_get_width(pixbuf_orig); vyskacil = ((double)gdk_pixbuf_get_height(pixbuf_orig) * pomer); pocY = ((double)ev->area.height - vyskacil) / 2; } else { pomer = (double)ev->area.height / gdk_pixbuf_get_height(pixbuf_orig); sirkacil = ((double)gdk_pixbuf_get_width(pixbuf_orig)*pomer); pocX = ((double)ev->area.width - sirkacil)/2; } gdk_pixbuf_scale(pixbuf_orig, pb, 0, 0, ev->area.width, ev->area.height, 0, 0, pomer, pomer, GDK_INTERP_NEAREST); gdk_cairo_set_source_pixbuf(cr, pb, pocX, pocY); cairo_rectangle(cr, 0, 0, ev->area.width - pocX, ev->area.height - pocY); cairo_fill(cr); gdk_window_end_draw_frame(window, dc); g_object_unref(pb); } void on_end_app() { gdk_window_destroy(window); g_main_loop_quit(main_loop); } void on_gdk_event(GdkEvent* event, gpointer data) { if (event->type == GDK_CONFIGURE) { gdk_window_invalidate_rect(window, NULL, TRUE); } else if (event->type == GDK_EXPOSE) { on_expose((GdkEventExpose*)event); } else if (event->type == GDK_DELETE) { on_end_app(); } else if (event->type == GDK_KEY_PRESS) { if (((GdkEventKey*)event)->keyval == GDK_KEY_Escape) on_end_app(); } } int main(int argc, char** argv) { if (!gdk_init_check(&argc, &argv)) return EXIT_FAILURE; pixbuf_orig = gdk_pixbuf_new_from_file(IMAGE_FILE_PATH, NULL); if (NULL == pixbuf_orig) { printf("chyba načtení obrázku\n"); return EXIT_FAILURE; } GdkWindowAttr attributes; gint attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_TITLE | GDK_WA_WMCLASS; memset(&attributes, 0, sizeof(attributes)); attributes.window_type = GDK_WINDOW_TOPLEVEL; attributes.x = 100; attributes.y = 50; attributes.event_mask = GDK_ALL_EVENTS_MASK; attributes.width = 1200; attributes.height = 800; attributes.wclass = GDK_INPUT_OUTPUT; attributes.title = "Image view"; attributes.wclass = GDK_INPUT_OUTPUT; gdk_event_handler_set(on_gdk_event, NULL, NULL); window = gdk_window_new(NULL, &attributes, attr_mask); gdk_window_show(window); main_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(main_loop); g_main_loop_unref(main_loop); g_object_unref(pixbuf_orig); return EXIT_SUCCESS; }
Školení
Kontakt
739 219 991
live:radekchalupa_1
Nové články