Blob Blame History Raw
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="image-viewer.js" xml:lang="cs">

  <info>
  <title type="text">Prohlížeč obrázků (JavaScript)</title>
    <link type="guide" xref="js#examples"/>

    <desc>O trošku složitější aplikace než jednoduché „Hello world“ – napíšeme prohlížeč obrázků v GTK+. Součástí je úvod do programovacího jazyka JavaScript.</desc>

    <revision pkgversion="0.1" version="0.1" date="2011-03-19" status="review"/>
    <credit type="author">
      <name>Jonh Wendell</name>
      <email its:translate="no">jwendell@gnome.org</email>
    </credit>
    <credit type="author">
      <name>Johannes Schmid</name>
      <email its:translate="no">jhs@gnome.org</email>
    </credit>
    <credit type="editor">
      <name>Marta Maria Casetti</name>
      <email its:translate="no">mmcasettii@gmail.com</email>
      <years>2013</years>
    </credit>
  </info>

<title>Prohlížeč obrázků</title>

<synopsis>
  <p>V této lekci napíšeme velmi jednoduchou aplikaci GTK, která načítá a zobrazuje soubory s obrázky. Naučíte se tyto věci:</p>
  <list>
    <item><p>Napsat základní uživatelské rozhraní GTK v jazyce JavaScript.</p></item>
    <item><p>Zacházet s událostmi pomocí připojení signálu na obsluhu signálu.</p></item>
    <item><p>Rozvrhnout uživatelské rozhraní GTK pomocí kontejnerů.</p></item>
    <item><p>Načíst a zobrazit soubor s obrázkem.</p></item>
  </list>
  <p>Abyste mohli pokračovat v této lekci, budete potřebovat následující:</p>
  <list>
    <item><p>Nainstalovanou kopii <link xref="getting-ready">IDE Anjuta</link></p></item>
    <item><p>Nainstalovanou kopii interpretu <em>gjs</em></p></item>
    <item><p>Základní znalosti objektově orientovaného programovacího jazyka</p></item>
  </list>
</synopsis>

<media type="image" mime="image/png" src="media/image-viewer.png"/>

<section id="anjuta">
  <title>Vytvoření projektu ve studiu Anjuta</title>
  <p>Než začnete s kódováním, musíte ve studiu Anjuta vytvořit nový projekt. Tím se vytvoří všechny soubory, které budete později potřebovat k sestavení a spuštění kódu. Je to také užitečné kvůli udržení všeho pohromadě.</p>
  <steps>
    <item>
    <p>Spusťte IDE Anjuta a klikněte na <guiseq><gui>Soubor</gui> <gui>Nový</gui> <gui>Projekt</gui></guiseq>, aby se otevřel průvodce projektem.</p>
    </item>
    <item>
    <p>Na kartě <gui>JS</gui> zvolte <gui>Obecný JavaScript</gui>, klikněte na <gui>Pokračovat</gui> a na několika následujících stránkách vyplňte své údaje. Jako název projektu a složky použijte <file>image-viewer</file>.</p>
   	</item>
    <item>
    <p>Klikněte na <gui>Použít</gui> a vytvoří se vám projekt. Otevřete <file>src/main.js</file> na kartě <gui>Projekt</gui> nebo <gui>Soubor</gui>. Bude obsahovat úplně základní příklad kódu.</p>
    </item>
  </steps>
</section>


<section id="js">
  <title>Základy v jazyce JavaScript: Hello World</title>
  <p>Než začneme s psaním prohlížeče obrázků, pojďme se dozvědět něco víc o tom, jak se JavaScript používá v GNOME. Váš první kontakt s kterýmkoliv programovacím jazykem by samozřejmě měl být „Hello World“, který již najdete v <file>main.js</file>:</p>
  <code mime="application/javascript">print ("Hello world!");</code>
  <p>Jestli jste seznámení s kterýmkoliv programovacím jazykem, tohle by vám mělo připadat povědomé. Funkce <code>print</code> je volána s argumentem <code>"Hello world!"</code>, který bude vypsán na obrazovku. Všimněte si, že každý řádek je zakončen středníkem.</p>
</section>

<section id="classes">
  <title>Třídy v jazyce JavaScript</title>
  <p>Toto je standardní způsob, jak definovat třídu v jazyce JavaScript:</p>
  <code mime="application/javascript" style="numbered">
function MyClass () {
  this._init ();
}

MyClass.prototype = {

  _init: function () {
    this.propertyA = "This is an object's field";
    this.propertyB = 10;
  },

  aMethod: function (arg1, arg2) {
    print ("inside aMethod: " + arg1 + " " + arg2);
  },

  dumpProperties: function () {
    print (this.propertyA);
    print (this.propertyB);
  }

}</code>
  <p>Zde se definuje třída nazvaná <code>MyClass</code>. Pojďme si projít jednotlivé části definice třídy:</p>
  <steps>
    <item>
    <p><code>function MyClass</code> je konstruktor třídy – jeho název musí odpovídat názvu třídy. Ke kterémukoliv členu třídy můžete přistupovat pomocí objektu <code>this</code>. Zde konstruktor volá metodu <code>_init</code> této třídy.</p>
    </item>
    <item>
    <p>Blok <code>MyClass.prototype</code> je místo, kde se definuje <em>struktura</em> třídy. Každá třída se skládá z metod (funkce) a vlastností (proměnné). V tomto příkladu jsou tři metody a dvě vlastnosti.</p>
    </item>
    <item>
    <p>První zde definovaná metoda se nazývá <code>_init</code> a specifikujeme ji, jako funkci bez argumentů:</p>
    <code>_init: function ()</code>
    <p>Napíšeme funkci dovnitř mezi složené závorky. Jsou zde definována dvě pole, <code>propertyA</code> a <code>propertyB</code>. První je nastavena na řetězec a druhá na celé číslo (10). Funkce nevrací žádnou hodnotu.</p>
    </item>
    <item>
    <p>Následující metoda se nazývá <code>aMethod</code> a má dva argumenty, které se při svém zavolání vypíše. Poslední metodou je <code>dumpProperties</code> a ta vypíše pole <code>propertyA</code> a <code>propertyB</code>.</p>
    </item>
    <item>
    <p>Všimněte si, jak je definice třídy (prototyp) uspořádaná. Definice každé funkce je oddělena čárkou.</p>
    </item>
  </steps>

  <p>Nyní je třída MyClass nadefinována a můžeme si s ní hrát:</p>
  <code mime="application/javascript" style="numbered">
var o = new MyClass ();
o.aMethod ("Hello", "world");
o.propertyA = "Just changed its value!";
o.dumpProperties ();</code>
  <p>Tento kód vytvoří novou instanci třídy nazývanou <var>o</var>, spustí <code>aMethod</code>, změní <code>propertyA</code> na jiný řetězec a pak zavolá <code>dumpProperties</code> (která vypíše vlastnosti).</p>
  <p>Uložte kód do <file>main.js</file> a následně jej spusťte pomocí <guiseq><gui>Spustit</gui> <gui>Provést</gui></guiseq> v nabídce nebo pomocí nástrojové lišty.</p>
</section>

<section id="gtk">
  <title>První aplikace Gtk</title>
  <p>Podívejme se, jak vypadá úplně základní aplikace Gtk v jazyce JavaScript:</p>
  <code mime="application/javascript" style="numbered">
const Gtk = imports.gi.Gtk;

Gtk.init (null, null);

var w = new Gtk.Window ({title: "Image Viewer Demo"});
w.show ();

Gtk.main ();</code>
  <p>Podívejme se, co se stane:</p>
  <list>
    <item>
    <p>První řádek importuje jmenný prostor Gtk (tzn. vloží knihovnu Gtk). Knihovny jsou poskytovány pomocí GObject Introspection (gi), který poskytuje vazbu jazyka pro řadu knihoven GNOME.</p>
    </item>
    <item>
    <p><code>Gtk.init</code> inicializuje knihovnu Gtk. Tato část je povinná pro všechny programy Gtk.</p>
    </item>
    <item>
    <p>Následující řádek vytvoří hlavní okno vytvořením nového objektu <code>Gtk.Window</code>. Konstruktoru okna můžete předat několik vlastností pomocí syntaxe <code>{vlastnost: hodnota, vlastnost: hodnota, …}</code>. V tomto případě nastavujeme název okna.</p></item>
    <item><p>Následující řádek zajistí zobrazení okna. V Gtk je každý widget ve výchozím stavu skrytý.</p></item>
    <item><p>Nakonec <code>Gtk.main</code> spustí hlavní smyčku – jinými slovy provádění programu. Hlavní smyčka naslouchá událostem (signálům) od uživatelského rozhraní a následně volá obsluha signálu, které provede něco užitečného. Krátce si povíme něco o signálech.</p></item>
  </list>

  <p>Uložte kód do <file>main.js</file> a spusťte jej. Budete upozorněni, že aplikace se neukončí, když zavřete okno. To je tím, že zatím nemáme nastavenu obsluhu signálu <code>"destroy"</code> (close) od okna. Uděláme to za chvíli, prozatím ale použijte k ukončení programu zmáčknutí <keyseq><key>Ctrl</key> <key>C</key></keyseq> v terminálu.</p>

</section>

<section id="classes2">
  <title>Přidání tříd</title>
  <p>Správný způsob, jak programovat s Gtk, je používat třídy. Pojďme přepsat jednoduchý kód, který jste již napsali, pomocí tříd:</p>
  <code mime="application/javascript" style="numbered">
const Gtk = imports.gi.Gtk;

function ImageViewer () {
  this._init ();
}

ImageViewer.prototype = {
  _init: function () {
    this.window = new Gtk.Window ({title: "Image Viewer Demo"});
    this.window.show ();
  }
}

Gtk.init (null, null);
var iv = new ImageViewer ();
Gtk.main ();</code>
  <!-- FIXME: Throws an error, "JS ERROR: !!!   Unhandled type int32 releasing GArgument" on Ubuntu 10.10 -->
  <p>Všimněte si, že program je ten stejný. Jen jsme přesunuli kód vytvářející okno do samostatné třídy <code>ImageViewer</code>. Konstruktor třídy volá metodu <code>_init</code>, která vytvoří a zobrazí okno. Potom vytvoříme instanci třídy před spuštěním hlavní smyčky (<code>Gtk.main</code>).</p>
  <p>Tento kód je modulární a můžeme jej snadno rozdělit do více souborů. Díky tomu bude čistější a snadnější ke čtení.</p>
</section>

<section id="signals">
  <title>Signály</title>
  <p>Signály jsou klíčovým konceptem programování v Gtk. Kdykoliv se něco stane u nějakého objektu, tak onen objekt vyšle signál. Například, když je kliknuto na tlačítko, vyšle signál <code>"clicked"</code>. Pokud chcete, aby váš program něco udělal, když tato událost nastane, musíte napojit funkci („obsluhu signálu“) na tento signál. Zde je příklad:</p>
  <code mime="application/javascript" style="numbered">
function button_clicked () {
  print ("you clicked me!");
}
var b = new Gtk.Button ({label:"Click me"});
b.connect ("clicked", button_clicked);</code>
  <p>Poslední dva řádky vytvoří <code>Gtk.Button</code> nazvané <code>b</code> a napojí jeho signál <code>clicked</code> na funkci <code>button_clicked</code>, která byla definována dříve. Pokaždé, když je kliknuto na tlačítko, provede se kód ve funkci <code>button_clicked</code>. Ten akorát vypíše zprávu.</p>
  <p>Syntax pro připojení nějakého signálu k funkci je:</p>
  <code mime="application/javascript">
object.connect (&lt;název_signálu&gt;, &lt;funkce_která_se_má_volat&gt;);</code>
  <p>Definice signálů pro všechny možné objekty najdete v <link href="https://developer.gnome.org/gtk3/stable/gtkobjects.html">Příručce ke třídám GTK</link>.</p>

  <note>
    <p>Můžeme kód zjednodušit použitím vložené definice funkce:</p>
    <code mime="application/javascript">
b.connect ("clicked", function () { print ("you clicked me!"); });</code>
  </note>

</section>

<section id="close">
  <title>Zavření okna</title>
  <p>Když zavřete okno Gtk, ve skutečnosti se nezavře, ale skryje. To umožňuje zachovat si okno bokem (což se například hodí, když se chcete uživatele zeptat, jestli chce okno opravdu zavřít).</p>
  <p>V našem případě opravdu chceme okno zavřít. Nejjednodušší způsob, jak to udělat, je napojit signál <code>"hide"</code> objektu <code>GtkWindow</code> na funkci, která zavře aplikaci. Běžte zpět do souboru <file>image-viewer.js</file> a přidejte následující kód do metody <code>_init</code> na řádek na <code>this.window.show</code>:</p>
  <code mime="application/javascript" style="numbered">this.window.connect ("hide", Gtk.main_quit);</code>
  <p>Tímto se napojí signál <code>"hide"</code> okna na funkci <code>main_quit</code> z Gtk, která ukončí provádění hlavní smyčky Gtk. Jakmile je hlavní smyčka dokončena, dojde k návratu z funkce <code>Gtk.main</code>. Náš program by pokračovat během kódu napsaného za řádkem <code>Gtk.main ()</code>, ale zatím tam žádný kód nemáme, takže program skončí.</p>
</section>

<section id="containers2">
  <title>Kontejnery: Rozvržení uživatelského rozhraní</title>
  <p>Widgety (ovládací prvky, jako jsou tlačítka a popisky) lze v okně uspořádat pomocí <em>kontejnerů</em>. Můžete dohromady kombinovat různé kontejnery, jako jsou boxy nebo mřížky.</p>
  <p><code>Gtk.Window</code> je samo o sobě kontejner, ale přímo do něj můžete vložit jen jeden widget. My bychom měli rádi dva widgety, obrázek a tlačítko, takže musíme do okna vložit „vysokokapacitní“ kontejner, pro tyto další widgety. Je dostupná řada <link href="http://library.gnome.org/devel/gtk/stable/GtkContainer.html">typů kontejnerů</link>, ale my zde použijeme <code>Gtk.Box</code>. Ten může obsahovat několik widgetů uspořádaných vodorovně nebo svisle. Složitější rozvržení můžete udělat vložením několika boxů do jiného boxu atd.</p>
  <note>
  <p>Existuje návrhář grafického uživatelského rozhraní nazývaný <app>Glade</app>, který je zaintegrován i do IDE <app>Anjuta</app>. S ním můžete navrhovat uživatelské rozhraní opravdu snadno. V tomto příkladu ale vše napíšeme ručně.</p>
  </note>
  <p>Pojďme přidat box a widgety do okna. Vložte následující kód do metody <code>_init</code>, hned nad řádek <code>this.window.show</code>:</p>
  <code mime="application/javascript" style="numbered">
var main_box = new Gtk.Box ({orientation: Gtk.Orientation.VERTICAL, spacing: 0});
this.window.add (main_box);</code>
  <p>První řádek vytvoří <code>Gtk.Box</code> nazvaný <var>main_box</var> a nastaví dvě jeho vlastnosti: <code>orientation</code> (otočení) je nastavena na svislou (takže widgety jsou uspořádány do sloupce) a <code>spacing</code> (rozestupy) mezi widgety jsou nastaveny na 0 pixelů. Následující řádek pak přidá nově vytvořený <code>Gtk.Box</code> do okna.</p>
  <p>Zatím okno obsahuje jen prázdný <code>Gtk.Box</code> a pokud spustíte program nyní, neuvidíte oproti dřívějšku žádné změny (<code>Gtk.Box</code> je průhledný kontejner, takže jej tam nemůžete vidět).</p>
</section>

<section id="packing2">
  <title>Balení: Přidání widgetů do kontejneru</title>
  <p>Abyste přidali nějaké widgety do <code>Gtk.Box</code>, vložte následující kód přímo pod řádek <code>this.window.add (main_box)</code>:</p>
  <code mime="application/javascript" style="numbered">
this.image = new Gtk.Image ();
main_box.pack_start (this.image, true, true, 0);</code>
  <p>První řádek vytvoří nový <code>Gtk.Image</code> nazvaný <code>image</code>, který bude použit k zobrazení souboru s obrázkem. Následně je widget obrázku přidán (<em>zabalen</em>) do kontejneru <var>main_box</var> pomocí metody <link href="http://library.gnome.org/devel/gtk/stable/GtkBox.html#gtk-box-pack-start"><code>pack_start</code></link> widgetu <code>Gtk.Box</code>.</p>
  <p><code>pack_start</code> přebírá 4 argumenty: widget, který je přidáván do boxu (<code>child</code>); zda by se měl box zvětšit, když je přidán nový widget (<code>expand</code>); zda by měl nový widget zabrat všechno vytvořené dodatečné místo, když je box větší (<code>fill</code>); jak moc místa, v pixelech, by mělo být mezi widgetem a jeho sousedem uvnitř boxu (<code>padding</code>).</p>
  <p>Kontejnery Gtk (a widgety) se dynamicky roztahují, aby zaplnily dostupné místo, pokud jim to tedy dovolíte. Neumisťujte widgety zadáváním přesných souřadnic x,y v okně. Místo toho je umisťujte relativně vůči sobě. To umožní oknu, které se o ně stará, jednodušeji měnit velikost a widgety by tak měli dostat automaticky rozumnou velikost ve většině situací.</p>
  <p>Všimněte si také, jak jsou widgety uspořádány do hierarchie. Jakmile jsou zabaleny v <code>Gtk.Box</code>, je <code>Gtk.Image</code> považován za potomka <em>Gtk.Box</em>. To umožňuje zacházet se všemi potomky widgetu jako se skupinou. Například byste mohli skrýt <code>Gtk.Box</code>, což by zároveň skrylo i všechny jeho potomky.</p>
  <p>Nyní vložte tyto dva řádky pod ty dva, které jsme již přidali:</p>
  <code mime="application/javascript" style="numbered">
var open_button = new Gtk.Button ({label: "Open a picture..."});
main_box.pack_start (open_button, false, false, 0);</code>
  <p>Tyto řádky jsou podobné jako první dva, ale tentokrát vytváří <code>Gtk.Button</code> a přidávají ho do widgetu <var>main_box</var>. Všimněte si, že zde nastavujeme argument <code>expand</code> (ten druhý) na <code>false</code>, zatímco pro <code>Gtk.Image</code> byl nastaven na <code>true</code>. To způsobí, že obrázek zabere všechno dostupné místo a tlačítko jen tolik místa, kolik potřebuje. Když okno maximalizujete, zůstane velikost tlačítka stejná, ale obrázek se zvětší, aby zabral celý zbytek okna.</p>
  <p>Nakonec musíme změnit řádek <code>this.window.show ();</code> takto:</p>
  <code>this.window.show_all ();</code>
  <p>Tím se zobrazí potomci v okně Gtk a všichni jejich potomci a potomci těchto potomků atd. (Pamatujte, že widgety Gtk jsou ve výchozím stavu skryté.)</p>
</section>

<section id="loading2">
  <title>Načtení obrázku: Napojení signálu <code>clicked</code> od tlačítka</title>
  <p>Když uživatel klikne na tlačítko <gui>Open</gui>, mělo by se objevit dialogové okno, ve kterém si uživatel může vybrat obrázek. Až jej má vybraný, měl by se obrázek načíst a zobrazit ve widgetu obrázku.</p>
  <p>Prvním krokem je napojení signálu <code>"clicked"</code> od tlačítka na funkci obsluhující signál, kterou nazveme <code>_openClicked</code>. Vložte tento kód hned za řádek <code>var open_button = new Gtk.Button</code>, kde je tlačítko vytvořeno:</p>
  <code mime="application/javascript">
open_button.connect ("clicked", Lang.bind (this, this._openClicked));</code>
  <p>Používáme zde pomocnou třídu jazyka JavaScript <code>Lang</code>. Ta umožňuje napojit na signál <em>metodu třídy</em> namísto prosté funkce (bez třídy), což jsem udělali před tím pro signál <code>"hide"</code> u okna. Teď si s tím nedělejte starosti, je to jen drobný technický detail. Aby to fungovalo, potřebujete navíc na začátek souboru vložit následující řádek:</p>
  <code mime="application/javascript">const Lang = imports.lang;</code>
</section>

<section id="loading3">
  <title>Načítání obrázku: Psaní zpětných volání pro signály</title>
  <p>Nyní můžeme vytvořit metodu <code>_openClicked()</code>. Vložte následující do bloku <code>ImageViewer.prototype</code> za metodu <code>_init</code> (a nezapomeňte na čárku):</p>
    <code mime="application/javascript" style="numbered">
  _openClicked: function () {
    var chooser = new Gtk.FileChooserDialog ({title: "Select an image",
                                              action: Gtk.FileChooserAction.OPEN,
                                              transient_for: this.window,
                                              modal: true});
    chooser.add_button (Gtk.STOCK_CANCEL, 0);
    chooser.add_button (Gtk.STOCK_OPEN, 1);
    chooser.set_default_response (1);

    var filter = new Gtk.FileFilter ();
    filter.add_pixbuf_formats ();
    chooser.filter = filter;

    if (chooser.run () == 1)
      this.image.file = chooser.get_filename ();

    chooser.destroy ();
  }</code>
  <p>Toto je trochu komplikovanější než vše, o co jsme se doposud pokusili, takže si to pojďme rozebrat:</p>
  <list>
    <item>
      <p>Řádek začínající <code>var chooser</code> vytvoří dialogové okno <gui>Open</gui>, které může uživatel použít k výběru souboru. Nastavíme čtyři vlastnosti: název dialogového okna; akci (typ) dialogového okna (jde o dialogové okno <gui>Open</gui>, ale mohli bychom použít <code>SAVE</code>, pokud by záměrem bylo uložení souboru; <code>transient_for</code>, která nastaví rodičovské okno dialogového okna; <code>modal</code>, která, když je nastavena na <code>true</code>, zabrání uživateli kliknout na jiné místo aplikace, dokud není dialogové okno zavřeno.</p>
    </item>
    <item>
    <p>Následující dva řádky přidají do dialogového okna tlačítka <gui>Cancel</gui> a <gui>Open</gui>. Druhým argumentem metody <code>add_button</code> je celočíselná hodnota, která bude vrácena při zmáčknutí tlačítka: 0 pro <gui>Cancel</gui> a 1 pro <gui>Open</gui>.</p>
    <p>Všimněte si, že používáme <em>standardní</em> názvy tlačítek z Gtk, místo abychom ručně psali „Cancel“ nebo „Open“. Výhodou použití standardních názvů je, že popisky tlačítek budou vždy přeloženy do uživatelova jazyka.</p>
    </item>
    <item>
    <p><code>set_default_response</code> určuje tlačítko, které bude aktivováno, když uživatel dvojitě klikne na soubor nebo zmáčkne <key>Enter</key>. V našem případě používáme jako výchozí tlačítko <gui>Open</gui> (které má hodnotu 1).</p>
    </item>
    <item>
    <p>Následující tři řádky omezí dialogové okno <gui>Open</gui>, aby zobrazovalo jen soubory, které lze otevřít pomocí <code>Gtk.Image</code>. Nejprve je vytvořen filtr a pak do něj přidáme všechny druhy souborů podporované v <code>Gdk.Pixbuf</code> (což zahrnuje většinu obrázkových formátů, včetně PNG a JPEG). Nakonec tento filtr nastavíme aby byl filtrem dialogového okna <gui>Open</gui>.</p>
    </item>
    <item>
    <p><code>chooser.run</code> zobrazí dialogové okno <gui>Open</gui>. Dialogové okno bude čekat na uživatele, než si vybere obrázek. Až tak učiní, vrátí <code>choose.run</code> hodnotu <output>1</output> nebo by mohl vrátit <output>0</output>, když uživatel klikne na <gui>Cancel</gui>. Otestujeme to výrazem <code>if</code>.</p>
    </item>
    <item><p>Předpokládejme, že uživatel klikl na <gui>Open</gui>. Následující řádek nastaví vlastnost <code>file</code> v <code>Gtk.Image</code> na název souboru s obrázkem, který si uživatel vybral. <code>Gtk.Image</code> vybraný obrázek načte a zobrazí.</p>
    </item>
    <item>
    <p>Na posledním řádku této metody zlikvidujeme dialogové okno <gui>Open</gui>, protože jej již nebudeme potřebovat.</p>
    </item>
  </list>

  </section>

<section id="run">
  <title>Spuštění aplikace</title>
  <p>Všechen kód, který potřebujete, je nyní nachystaný, takže jej můžete zkusit spustit. Tím jste během krátké chvíle získali, co jsme slíbili – plně funkční prohlížeč obrázků (a tím končí naše cesta jazykem JavaScript a knihovnou Gtk).</p>
</section>

<section id="impl">
 <title>Ukázková implementace</title>
 <p>Pokud v této lekci narazíte na nějaké problémy, porovnejte si svůj kód s tímto <link href="image-viewer/image-viewer.js">ukázkovým kódem</link>.</p>
</section>

<section id="next">
  <title>Další postup</title>
  <p>Zde je pár nápadů, jak byste mohli tuto jednoduchou ukázku rozšířit:</p>
  <list>
   <item>
   <p>Umožnit uživateli výběr složky místo souboru a poskytnout ovládání pro procházení všech obrázků v této složce.</p>
   </item>
   <item>
   <p>Použít při načtení obrázku náhodné filtry a efekty a umožnit uživateli takto změněný obrázek uložit.</p>
   <p><link href="http://www.gegl.org/api.html">GEGL</link> poskytuje mocné schopnosti pro práci s obrázky.</p>
   </item>
   <item>
   <p>Umožnit uživateli načíst obrázky ze síťového sdílení, skenerů a dalších složitějších zdrojů.</p>
   <p>Pro práci se síťovými přenosy můžete použít <link href="http://library.gnome.org/devel/gio/unstable/">GIO</link> a pro obsluhu skeneru <link href="http://library.gnome.org/devel/gnome-scan/unstable/">GNOME Scan</link>.</p>
   </item>
  </list>
</section>

</page>