Pliki graficzne w C/C++ - biblioteka FreeImage

freeimage-logo.jpgJakiś czas temu na forum linuxowo.pl pojawił się temat obsługi plików graficznych z programów w C. Ponieważ temat ten jest mi bliski postanowiłem napisać krótki tutorial jak tego dokonać posiłkując się darmową biblioteką FreeImage. Biblioteka FreeImage integruje w sobie dobrodziejstwa wielu innych bibliotek obsługujących pliki graficzne (libjpeg, libpng, …) w postaci prostego, zwięzłego i jednolitego API. Ponieważ opiera się na dobrze sprawdzonych komponentach jest niezawodna i szybka. Dla mnie odkrycie jej było lekarstwem na koszmar obsługi plików graficznych w C/C++. Zapraszam do przeczytania i komentarzy. Chętnie napiszę coś więcej na jej temat, jeśli będzie taka potrzeba.
Do tutoriala użyłem mojego Debiana Lennego, ale z powodzeniem powinno to wszystko działać także pod Ubuntu czy ogólnie dowolnym Linuksem. Pod systemem Windows także można użyć biblioteki FreeImage, lecz trzeba mieć kompilator (np. z Visual Studio C++ Express), ręcznie poustawiać kilka rzeczy i oczywiście sciągnąć bibliotekę.

Przygotowanie środowiska

Tutaj sprawa jest niezwykle prosta i sprowadza się do zainstalowania odpowiednich pakietów. Będziemy potrzebować dwóch z nich. Pierwszy to build-essential, który zawiera wszystkie potrzebne nagłówki standardowych bibliotek. Drugi to pakiet samej biblioteki o nazwie libfreeimage-dev. Instalka sprowadza się zatem do:

sudo apt-get install build-essential libfreeimage-dev

Dodam jeszcze, że w Ubuntu pakiet biblioteki FreeImage znajduje się w repozytorium Universe. Należy zatem zadbać o to, aby ów repozytorium było dodane do /etc/apt/sources.list.

Szybki przykład - konwersja formatów

convert-gif-jpg.jpg

Dla zobrazowania podstaw użycia biblioteki FreeImage rozpatrzymy prosty przykład: konwersję pliku GIF na JPEG. Weźmiemy na warsztat bardzo popularny obraz lenna.gif, który spróbujemy przekonwertować właśnie na JPEGa.

Proponuję zacząć po prostu od kodu:

// freeimage-test.c - przykładowy program używający FreeImage
#include 
#include 
#include 

int main(void)
{
	int return_value = EXIT_SUCCESS;
	FreeImage_Initialise(TRUE);
	puts("Loading...");
	FIBITMAP* bitmap = FreeImage_Load(FIF_GIF, "lenna.gif", 0);
	if (NULL != bitmap)
	{
		puts("Saving...");
		FreeImage_Save(FIF_JPEG, bitmap, "lenna.jpg", 0);
		FreeImage_Unload(bitmap);
	}
	else
	{
		puts("Image couldn't be loaded");
		return_value = EXIT_FAILURE;
	}

	FreeImage_DeInitialise();
	puts("Exit");

	return return_value;
}

No to jedziemy po koleji - co powyższy kod robi:

  • używa odpowiednich nagłówków; w przypadku biblioteki FreeImage załączamy plik nagłówkowy FreeImage.h poprzedzony dwoma standardowymi nagłówkami biblioteki standardowej języka C
  • inicjalizuje bibliotekę FreeImage; do tego celu służy wywołanie metody FreeImage_Initialise(TRUE); bez tego użycie funkcji biblioteki jest niemożliwe
  • wczytuje plik graficzny w formacie GIF; sprawa jest dość prosta, gdyż wystarczy użyć funkcji FreeImage_Load; jako parametry podajemy kolejno: typ pliku, jego nazwę oraz zero; jeśli operacja skończy się sukcesem funkcja ta zwróci wskaźnik do struktury FIBITMAP, która to zawiera wszelkie informacje o wczytanym obrazku; jeśli się to nie powiedzie to dostaniemy NULL
  • zapisuje plik graficzny w formacie JPEG; sprawa jest analogiczna do wczytywania; używamy w zamian funkcji FreeImage_Save; tutaj znowu podajemy parametry, czyli: format pliku, wskaźnik do struktury FIBITMAP, nazwę pliku wyjściowego i znowu zero
  • zwalnia miejsce zajmowane przez obrazek; właśnie po to jest wywołanie FreeImage_Unload; jeśli byśmy tego nie uczynili obrazek ciągle by okupował pamięć, co jest już niepotrzebne, bo nie będziemy go więcej używać
  • deinicjalizuje bibliotekę; gdy już nie potrzebujemy korzystać z usług biblioteki FreeImage należy ją o tym poinformować funkcją FreeImage_DeInitialise, aby mogła zwolnić pamięć przez siebie zajmowaną

Po więcej informacji zapraszam do oficjalnej dokumentacji FreeImage (znajduje się tam plik PDF).

Kompilacja

Na sam koniec tego mikro-tutoriala instrukcja jak to wszystko skompilować. Użyjemy kompulatora GCC, który jest standardowo dostępny w każdym Linuksie. Skompilować program można np. tak:

gcc freeimage-test.c -lfreeimage -o freeimage-test

Zostanie utworzony plik binarny freeimage-test, a kompilator do linkowania użyje, prócz standardowych bibliotek, także bibliotekę FreeImage (przełącznik -lfreeimage). Po tej całej operacji program jest gotowy do użycia. Wystarczy umieścić plik lenna.gif w katalogu z binarką i uruchomić program. Po tej czynności powinniśmy znaleźć nowy plik lenna.jpg.

Proste? Proste!
Powodzenia w bojach z FreeImage! :D
UPDATE: FreeImage posiada także wrapper dla C++, który nieco ułatwia zabawę. Więcej informacji w dokumentacji FreeImagePlus (rzeczony wrapper).

Photoshop pod Linuksem

Adobe Photoshop CS2 pod Linuksem

Największą bolączką grafików, którzy chcieli przenieść się z Windowsa czy Maca na Linuksa jest oczywiście brak Photoshopa w wersji dla Linuksa (firma Adobe nie kwapi się z wydaniem swojego flagowego produktu pod pingwina). Fakt ten dostrzegli twórcy Wine - warstwy emulacyjnej systemu Windows, którzy, wsparci finansowo przez firmę Google, pracowali nad odpaleniem Photoshopa pod Linuksem. Wszyscy śledzący wiadomości ze świata linuksowego pewnie już wiedzą, że wyszła nowa wersja Wine o numerku 0.9.55, która wspiera Photoshopa CS2. Tak więc z ciekawości, a także z pewnej potrzeby chwili, postanowiłem sprawdzić, jak działa tandem Linux + Photoshop CS2. Poniżej kilka moich spostrzeżeń w tej kwestii.

Testy przeprowadziłem na dwóch maszynach. Na pierwszej zainstalowany był Ubuntu 7.10, a na drugim Debian Lenny. Instalacja nowego Wine na Ubuntu nie sprawia specjalnych trudności. Wystarczy:

apt-get install wine

Sprawa nieco się komplikuje w przypadku Lennego, gdyż w jego repozytoriach jest stara wersja Wine’a. Oczywiście nie ma takiego problemu, którego nie można rozwiązać. Zdecydowałem się na ręczną kompilację ze źródeł. Po ich rozpakowaniu komenda ./configure wykazała brak pakietów flex i bison, po których zainstalowaniu udało się odpalić kompilację. Dodam tylko, że trwało to około 10 minut i nie sprawiło problemów. Dla niezorientowanych lub zapominalskich 3 komendy potrzebne do kompilacji i zainstalowania Wine ze źródeł (odpalać w katalogu z rozpakowanymi źródłami):

./configure
make depend && make
sudo make install

I gotowe. Mamy zainstalowanego Wine’a.

Kolejnym krokiem jest instalacja Photoshopa. Sam posłużyłem się wersją trial, którą każdy może bez większych problemów znaleźć na wielu serwisach z plikami (np. tutaj). Niestety, nie dysponuję oryginalnym pakietem, więc nie wiem czy są jakieś różnice w instalacji czy działaniu w stosunku do wersji testowej (ponoć nie ma). Tak czy inaczej przed samą instalacją Photoshopa należy zainstalować pewne dodatki, które pozwolą mu w miarę bezproblemowo działać. Przykładem mogą być oryginalne czcionki systemowe z Windowsa a także Visual C++ 6 Runtime. Na szczęście istnieje bardzo przyjemny skrypt, który robi to za nas. Sprawa sprowadza się do 2 komend:

wget http://kegel.com/wine/winetricks
sh winetricks corefonts vcrun6

Działanie skryptu polega na zassaniu odpowiednich plików z sieci i ich zainstalowaniu pod Wine. Z tego też powodu będzie trzeba potwierdzać chęć instalacji poszczególnych komponentów w ich instalatorach.

Jak już dodatki się zainstalują można przystąpić do odpalenia instalatora Photoshopa. Znajdziemy go w podkatalogu Photoshop CS2 w archiwum z instalacją. Plik nazywa się setup.exe (co za niespodzianka). Zakładam, że każdy sobie z tym poradzi, więc nie będę opisywał tej części. :)
No i to właściwie koniec procedur instalacyjnych. Odapalmy Photoshopa z menu Wine -> Programs -> Adobe Photoshop CS2 i po kilku dłuższych chwilach mamy go do dyspozycji.

To, niestety, nie koniec. O ile uruchomić Photoshopa za pierwszym razem można, o tyle już drugie podejście może skończyć się bardzo brzydkim komunikatem o błędzie:

Ojojo, jest buba!

Co robić? Na szczęście jest rozwiązanie. Wystarczy skasować plik konfiguracyjny Photoshopa, aby ten błąd nie występował. Robi się to tak (wszystko w jednej linijce!):

rm "~/.wine/drive_c/windows/profiles//Application Data/
Adobe/Photoshop/9.0/Adobe Photoshop CS2 Settings/Adobe*.psp"

I tutaj mała dygresja. O ile w Ubuntu wystarczyło zrobić to jeden raz, o tyle już pod Debianem muszę to robić za każdym razem - tuż przed uruchomieniem Photoshopa. Nie mam pojęcia czemu tak jest. Kolejną sprawą jest to, że pod Lennym z włączonym Compizem nie można zmienić trybu mieszania warstwy - nie rozwija się combobox. Jest pewnie jeszcze kilka innych niuansów (np. prędkość działania), które utrudniają pracę z Photoshopem pod Linuksem. Tak czy inaczej Photoshop działa i wszystko idzie w dobrym kierunku.

H-RT - podsumowanie

H-RayTracer został z grubsza przedstawiony przeze mnie w jednym z zeszłorocznych wpisów. Dzisiaj chcę przedstawić projekt bardziej szczegółowo i przy okazji podsumować moje - póki co skromne - osiągnięcia na jego polu. H-RT to silnik renderujący sceny 3D metodą śledzenia promieni. Docelowo ma on wspierać rendering oparty na algorytmach mających podstawy fizyczne. Droga do tego jest jeszcze dość długa, ale już dzisiaj H-RT potrafi generować proste obrazy. Przykład takiego renderingu jest poniżej:

hrt-sample1.png

Modele odbicia światła
Głównym zadaniem, jakie sobie postawiłem rozpoczynając pracę nad raytracerem było zbadanie możliwości współczesnych modeli lokalnego odbicia światła. Nie jest to jeszcze zadanie skończone, gdyż w kolejce jest jeszcze parę modeli. Do dzisiaj udało mi się jednak zaimplementować następujące:

  • Phong
  • Ashikhmin-Shirley
  • Cook-Torrance
  • Ward
  • He-Torrance-Sillion-Greenberg

Warto zwrócić uwagę zwłaszcza na ten ostatni model. Jest on chyba jednym z najbardziej skomplikowanych obliczeniowo, a przy okazji uwzględnia wiele efektów fizycznych związanych z odbiciem światła. Model ten jest około 90 razy wolniejszy od modelu AS (i to z prekalkulacją danych). Daje też dość ciekawe efekty (zakładając że go poprawnie zaimplementowałem :) ), o których nie omieszkam napisać kiedy indziej.

Inne możliwości
Póki co silnik potrafi renderować dość proste bryły/kształty, czyli: kule, walce, dyski, płaszczyzny i trójkąty. Do badań modeli odbicia to w zupełności wystarczy, natomiast w przyszłości zostaną dodane kolejne (np. możliwość renderowania siatki trójkątów). Zaimplementowany jest także system filtrów (gaussowski, box, trójkątny, sinc), które w końcowej fazie “składają” obraz z promieni. Ponadto zostały zaimplementowane światła punktowe i powierzchniowe. Obraz wyjściowy może zostać zapisany bądź w formacie PNG bądź w formacie HDR (High-Dynamic-Range). Engine także może wewnętrznie operować na danych spektralnych (światło można zdefiniować wtedy w postaci spektralnej), a nie tylko RGB. Aktualnie jestem w fazie dodawania wsparcia dla polaryzacji światła, więc i ten “aspekt optyczny” będzie brany pod uwagę w czasie generowania obrazu.

Słabością aktualnej wersji H-RT (co wyklucza jego szersze zastosowanie) jest brak wsparcia dla raytracingu stochastycznego. Zmieni się to w jednej z kolejnych wersji (gdzie planuję zaimplementować path-tracing). Na dzień dzisiejszy, po dopracowaniu wsparcia dla polaryzacji światła, mam zamiar zamrozić kod raytracera i skupić się na usuwaniu błędów i przyspieszaniu renderingu. Poza tym czeka mnie napisanie pracy magisterskiej, w czasie którego będą bardzo intensywnie używał H-RayTracera. Dopiero po - mam nadzieję udanej - obronie praca nad nowymi możliwościami ruszy na nowo.

Winieta CD/DVD dla xubuntu 7.04

Na podstawie materiałów z wiki ubuntu oraz pracy Sir_Yaro z forum ubuntu.pl sporządziłem winietkę na CD/DVD xubuntu 7.04. Jak znajdę jeszcze chwilę czasu to zrobię ją w wersji wektorowej przy pomocy Inkscape’a. Póki co do zassania wersja PNG oraz XCF. Obie w rozdziałce oryginalnej, czyli 800×800.

Preview:
xubuntu-7-04-bayger-mini.png

Powyższa praca powstała na podstawie innych prac. Mam nadzieję, że nie naruszyłem niczyich praw autorskich. W razie wystąpienia takiej sytuacji proszę o kontakt poprzez komentarz pod wpisem.

Projekt: H-RayTracer

H-RTByć może ktoś przeglądając mojego bloga zauważył w odsyłaczach link do strony domowej projektu H-RayTracer. Chciałbym w dzisiejszym wpisie przedstawić H-RT, gdyż jestem jego autorem. Wszystko zaczęło się w zeszłym roku, gdy musiałem sobie wybrać temat pracy magisterskiej. Jako promotora swojej pracy wybrałem dra Dariusza Sawickiego, który jest entuzjastą grafiki komputerowej (pozdrawiam!). Odkąd pamiętam grafika zawsze była mi bliska i już jakiś czas temu podjąłem decyzję, że chciałbym napisać magisterkę na ten temat. I tak oto zdobyłem temat pracy. Nie wdając się zbytnio w szczegóły praca polega na przeanalizowaniu pod kątem użyteczności i wydajności kilku modeli lokalnego odbicia światła (w tym jeden szczególny oparty na fizyce). Ponieważ do moich badań potrzebuję narzędzi powstał niejako produkt poboczny (nie związany bezpośrednio z samą pracą) czyli właśnie H-RayTracer.

H-RayTracer jest narzędziem do generowania grafiki 3D algorytmem ray tracingu. Póki co jest we wczesnej fazie rozwojowej, ale z dnia na dzień staje się coraz bardziej funkcjonalny. Jedyna jak dotąd wydana oficjalnie wersja (0.1) potrafi używać tylko bardzo prostego algorytmu śledzenia promieni (opisanego przez Whitteda ponad 20 lat temu). Obecnie pracuję nad ray tracingiem stochastycznym, który bierze pod uwagę także odbicia światła od obiektów, a nie tylko światło pochodzące bezpośrednio ze źródeł.
Program jest napisany w języku C++ w pełni obiektowo. Wydaje mi się, że jest na tyle elastyczny, że można będzie w nim zawrzeć większość algorytmów renderingu opartych na śledzeniu promieni. Kwestia jedynie ich poznania i zaimplementowania, co nie jest zazwyczaj proste, ale jest za to bardzo ciekawe. Zdecydowałem się także na pełną otwartość kodu mojego rozwiązania - H-RayTracer jest oprogramowaniem open source.
Tyle informacji na temat H-RayTracer w dniu dzisiejszym. Jednakże od czasu do czasu będę zamieszczał na blogu wpis tyczący się H-RT.

Do obejrzenia:
przykładowy rendering z wersji 0.1