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).

Komentarzy:7 Responses to “Pliki graficzne w C/C++ – biblioteka FreeImage”

  1. sadasd:

    Trochę dziwne te unload, mogło by to być destruktorem robione.

  2. bayger:

    @sadasd: jest to czyste C, więc dlatego tak jest. ale jest i dobra wiadomość: jest wrapper dla C++, który takie rzeczy załatwia automatycznie. docs tutaj:

    http://freeimage.sourceforge.net/fip/index.html

  3. sadasd:

    Kapnąłem się w sumie jak dodałem komentarz. :)

  4. Witek:

    Fajna biblioteka. Są może bindingi do języka D?

  5. bayger:

    @Witek: Niestety, tylko “C++, C#, Delphi and VB6″. Tak przynajmniej twierdzi strona projektu.

    UPDATE: http://svn.dsource.org/projects/bindings/trunk/freeimage/freeimage.d

  6. Witek:

    Dzięki. Działa!

  7. Nowa Dragonia a w niej…:

    [...] numerze znajduje się mój skromny artykuł na temat biblioteki FreeImage. Jest to rozwinięcie wpisu blogowego, który popełniłem paręnaście dni [...]

Skomentuj