Monthly archive for November, 2009

Bogata ikonografia

2009-11-10 13:25

Zajmę się dzisiaj pewnym rodzajem aplikacji, którą przeciętny programista wykorzystuje rzadko, ale którą mimo tego powinien mieć. Mam tu na myśli program graficzny służący do edycji ikon, czyli tych małych (a od niedawna i większych) obrazków, które w Windows (i nie tylko) pojawiają się na każdym kroku – zwłaszcza na pulpicie czy w menu Start. Może nieczęsto zdarza się konieczność stworzenia ikonki dla własnej aplikacji, lecz kiedy już trzeba to zrobić, warto posłużyć się w tym celu odpowiednim narzędziem (a nie Paintem na przykład :]).
Znalezienie dobrej i darmowej aplikacji do edycji ikon nie jest jednak takie łatwe, jako że najlepsze i najpopularniejsze z nich są licencjonowane jako shareware. Istnieje jednak przynajmniej jeden darmowy i wart polecenia program tego typu; sam dowiedziałem się o nim od Rega.

Logo programu IcoFXNazywa się on IcoFX i ze względu na swą niepozorną wielkość (1.5 MB) ma chyba jedną z lepszych proporcji użyteczności do rozmiaru. Zawiera on bowiem zdecydowaną większość funkcji (jeśli nie wszystkie), jakie można wymagać od tego rodzaju aplikacji.
Program ten obsługuje oczywiście wszystkie używane obecnie rozmiary (od 16×16 do 256×256), głębie kolorów (od 1 do 32 bitów z kanałem alfa) i formaty ikon (łącznie z PNG wykorzystywanym od Visty wzwyż). Oprócz całego wachlarza typowych narzędzi graficznych oferuje też wiele predefiniowanych filtrów (rozmycie, detekcja krawędzi itp.) wraz z możliwością definiowania własnych. Generalnie część “graficzna” programu jest bez zarzutu. Jedynym mankamentem, na jaki się zdołałem dotąd natknąć, jest brak możliwości określania tolerancji kolorów dla wypełniania typu flood fill.

Screen z programu IcoFX Screen z programu IcoFX Screen z programu IcoFX

Część “narzędziowa” też prezentuje się dobrze. Przy pomocy programu możemy nie tylko ekstrahować ikony z plików .exe i .dll (w razie potrzeby masowo przy pomocy batch processing), ale także edytować takie pliki (w zakresie ikon, rzecz jasna). Taka edycja mogłaby być wprawdzie nieco lepiej pomyślana (dodanie nowej ikony do pliku .exe/.dll jest możliwe tylko poprzez import z .ico), ale w sumie da się z nią wytrzymać.

Tak więc na te niezbyt częste okazje, gdy musimy/chcemy pobawić z ikonami, IcoFX wydaje się ogólnie całkiem dobrym rozwiązaniem. Zwłaszcza ze tę cenę :)

Tags: , , ,
Author: Xion, posted under Applications » 5 comments

Wartość pomysłów

2009-11-05 22:22

Żarówka z pomysłem :)Podobno w informatyce najcenniejszym zasobem są pomysły. Bo o ile zrealizowanie gotowej idei to praca czysto rzemieślnicza i – przynajmniej teoretycznie – możliwa zawsze do wykonania przy odpowiednim czasie i przy właściwej liczbie osób, to z kolei “wzięcie skądś” pomysłu nie jest taką prostą sprawą. W końcu, jak to ktoś powiedział, pomysły nie rosną przecież na drzewach :)

Tak to zwykle wygląda z rynkowego punktu widzenia. Dlatego bardzo ciekawy jest fakt, że np. na Warsztacie wygląda to – jak się wydaje – zupełnie odwrotnie. Objawem tego jest choćby fakt, że działy z pomysłami i projektami na forum są jednymi z większych i bardziej aktywnych. Jak to możliwe?
Wydaje mi się, że przyczyny są co najmniej dwie. Po pierwsze, na Warsztat trafiają osoby zainteresowane programowaniem gier i przynajmniej część z tych (a w rzeczywistości pewnie całkiem spora część) chcę zająć się tym tematem między innymi dlatego, że mają w głowie pomysł na jakąś grę. Albo na kilka od razu. A że na początkowym etapie nauki nijak nie da się tego zrealizować, owe genialne idee lądują we wspomnianym dziale forum.
Poza tym, nie ma co ukrywać: większość z nich jest w istocie marnej jakości – nawet jeśli litościwie odsiejemy projekty kolejnych MMORPG-ów, jakie dość często się pojawiają :) Oczywiście dla swoich autorów są one zawsze niezwykle innowacyjne i warte zrealizowania, ale nie łudźmy się: tak naprawdę podobne epitety można przypisać tylko ich małemu ułamkowi.

Innymi słowy, jest duża różnica pomiędzy pomysłem a dobrym pomysłem. Tych pierwszych każdy z nas ma pewnie dziesiątki tygodniowo. Nieuchronnie trzeba więc wybierać z nich tylko te najbardziej wartościowe. Do pozostałych najlepiej jest zaaplikować garbage collector :)

Tags: , ,
Author: Xion, posted under Computer Science & IT, Thoughts » 3 comments

Nowoczesne wyliczanie

2009-11-04 1:33

W chyba każdy języku posiadającym pojemniki (jak wektory czy listy) istnieje koncepcja iteratorów: obiektów, które pozwalają na przeglądanie kolekcji i są uogólnieniem wskaźników. W najprostszym pozwalają one tylko na pobranie aktualnego elementu i przejście do następnego, ale jest to zupełnie wystarczające do celów wyliczania.
Z wierzchu więc wyglądają one całkiem prosto i przejrzyście – zwłaszcza, jeśli język udostępnia pętlę typu foreach, która ładnie i przezroczyście je opakowuje. Dlatego może wydawać się dziwne, czemu zazwyczaj mechanizm ten jest używany właściwie tylko dla pojemników; w teorii bowiem za pomocą iteratorów (zwanych gdzieniegdzie enumeratorami) można by było przeglądać dosłownie wszystko.
Weźmy chociażby wyszukiwanie plików na dysku – sporo programów w jakimś momencie swojego działania musi znaleźć pliki np. o danej nazwie w określonym katalogu. Wtedy zwykle zakasujemy rękawy i piszemy odpowiednią procedurę rekurencyjną lub bawimy się ze stosem czy kolejką. A czy nie fajniej byłoby, gdyby dało się to zrobić po prostu tak:

  1. for (FsIterator it = ListFiles("c:\\", "*.exe"); it; ++it) { /* zrób coś */ }

oczywiście przeszukując w ten sposób również podkatalogi bez jawnego “wchodzenia” do nich?… Według mnie to by było bardzo fajne :)

Od razu zaznaczę więc, że wbrew pozorom taki iterator jest jak najbardziej możliwy do napisania. Problemem jest jednak to, jak należy przechowywać jego stan. Kiedy wyszukiwanie czy przeglądanie zaimplementowane jest bezpośrednio jako jedna funkcja, robi się to w zasadzie samo: w postaci zmiennych lokalnych (stos/kolejka) albo parametrów (rekurencja). Nikt specjalnie nie zwraca na ten fakt uwagi. Jednak w momencie próby “wyciągnięcia” z algorytmu operacji Next (w celu stworzenia iteratora) okazuje się nagle, że wymaga to jawnego pamiętania tych wszystkich danych, które pozwalają obliczyć następny element. Przy przeszukiwania katalogów trzeba by na przykład pamiętać jakiś systemowy uchwyt wyszukiwania dla aktualnego katalogu, poziom zagnieżdżenia oraz analogiczne uchwyty… dla każdego takiego poziomu!
Zawracanie głowy, prawda? :) Nic dziwnego, że traktowanie wyszukiwania “per iterator” nie jest popularną praktyką. Z punktu widzenia piszącego algorytm wyliczania nieporównywalnie łatwiej jest po prostu wymusić jakiś callback i wywołać go dla każdego elementu; niech się programista-klient martwi o to, jak ten callback wpasować w swój kod. A że ten byłby o wiele czytelniejszy, gdyby w grę wchodziły iteratory? No cóż, iteratorów tak łatwo pisać się nie da…

…chyba że programujemy w Pythonie. Tam bowiem “iteratory” (zwane generatorami) piszemy w zupełnie unikalny, łatwy sposób. Weźmy dla przykładu taką oto klasę drzewa binarnego (BST – Binary Search Tree):

  1. class Tree:
  2.     def __init__(self, key, left = None, right = None):
  3.         self.key = key
  4.         self.left = left
  5.         self.right = right
  6.     def __insert(self, k): # wstawianie elementu
  7.         if (k < self.key):
  8.             if (self.left != None): self.left.__insert (k)
  9.             else:                   self.left = Tree(k)
  10.         else:
  11.             if (self.right != None): self.right.__insert (k)
  12.             else:                   self.right = Tree(k)
  13.     def insert(self, *keys): # wst. wielu elementów
  14.         for k in keys: self.__insert(k)&#91;/python]
  15. Żeby dało się je przeglądać zwykła pętlą <code>for</code> w porządku <em>inorder</em> (dającym posortowanie kluczy), piszemy do niego odpowiedni generator:
  16. [python]    def inorder(self):
  17.         if (self.left != None):
  18.             for t in self.left.inorder(): yield t
  19.         yield self.key
  20.         if (self.right != None):
  21.             for t in self.right.inorder(): yield t

I już – to wystarczy, by poniższa pętla:

  1. for i in tree.inorder():

rzeczywiście “chodziła” po krawędziach drzewa “w czasie rzeczywistym” – bez żadnego buforowania elementów na liście.

Tajemnica tkwi tutaj w instrukcji yield – działa ona jak “tymczasowe zwrócenie” elementu, który jest przetwarzany przez ciało pętli for. Gdy konieczny jest następny element, funkcja inorder podejmuje po prostu działanie począwszy od kolejnej instrukcji – i tak do następnego yielda, kolejnego cyklu pętli i dalszej pracy funkcji. yield działa więc jak callback, tyle że w obie strony. Całkiem zmyślne, czyż nie?
Aż chciałoby się zapytać, czy w innych językach – zwłaszcza kompilowanych – nie dałoby się zrobić czegoś podobnego. Teoretycznie odpowiedź jest pozytywna: przy pomocy zmyślnych sztuczek na stosie wywołań funkcji (technika zwana ‘nawijaniem stosu’ – stack winding) można uzyskać efekt “zawieszenia funkcji” po zwróceniu wyniku i mieć możliwość powrotu do niej począwszy od następnej instrukcji. Nie jestem jednak przekonany, jak taki feature mógłby współpracować z innymi elementami współczesnych języków programowania, jak choćby wyjątkami. Trudno powiedzieć, czy jest to w ogóle możliwe.

Ale skoro w Pythonie się da, to może już C++2x będzie to miał? ;-)

Tags: , , , , ,
Author: Xion, posted under Programming » 4 comments
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.