Autor Wątek: [C++][Allegro] Inny format plików graficznych  (Przeczytany 6879 razy)

Offline Pawlox

  • Użytkownik

# Czerwiec 11, 2009, 21:03:01
 Witam. Korzystam z programu Dev C++, Allegro w wersji 4.2.2 i chciałem ostatnio zainstalować jakąś bibliotekę dodatkową do wyświetlania grafiki w innych formatach niż bmp. Ściągnąłem i zainstalowałem AlPng (opisany w kursie Allegro) i po dodaniu poleceń load_png i alpng_init wyskakują mi błędy "undefined reference to load_png" oraz "undefined reference to alpng_init". Próbowałem też biblioteki Jpgalleg i otrzymałem podobne błędy. Dodawałem już polecenia do kompilatora i konsolidatora, ale nic nie pomogło. Wie ktoś jak to rozwiązać, bo jakoś nie napawa mnie optymizmem perspektywa dalszego korzystania z grafiki w formacie bmp, tym bardziej,że pracuję nad coraz większymi projektami  :'(  :'(

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline C'mons

  • Użytkownik

# Czerwiec 11, 2009, 21:16:49
To może biblioteka FreeImage. Za jej pomocą możesz załadować mnóstwo różnych formatów. Konwertujesz strukturę danych którą wczytałeś do tej co ma allegro i powinno wypalić.

Offline cybek

  • Użytkownik
    • Strona domowa!

# Czerwiec 11, 2009, 21:17:52
Skoro dalej jest ten błąd, to znaczy że nie dodałeś do linkera, albo coś źle dodałeś.
Poza tym przerzuć się na nowsze IDE, albo chociaż nowszego MinGW'a

Offline Oti

  • Użytkownik

# Czerwiec 11, 2009, 21:21:40
Znaczna większośc osób tutaj obecnych korzysta z Visual C++, a skoro mówisz, że pracujesz nad 'coraz większymi projektami', to znaczy, że nie jesteś początkującym i możesz spokojnie się przerzucic na MSVC. :)

Offline Pawlox

  • Użytkownik

# Czerwiec 11, 2009, 21:30:35
cybek - Do linkera dodawałem już wszystko co pisało w dokumentacji i na różnych forach. Hmm... a jakie nowsze IDE proponujesz? Bo mam jeszcze VS9 i CodeBlocks 8.02, ale do tej pory zawsze pracowałem na DEVie (poza tym w innych programach te błędy również występują).

C'mons - Na czym polega ta konwersja? Dużo kodu trzeba dodać? I najważniejsze - czy to trudne, bo ja raczej początkujący jestem  ::)  

Oti - Mam VS9 w wersji Express. Nie wiem co masz na myśli mówiąc "początkujący", ale pisaniem czegoś ponad konsolowe programy liczące zająłem się dopiero niedawno.

Offline C'mons

  • Użytkownik

# Czerwiec 11, 2009, 22:01:34
Pierwsze co musisz zrobić to dowiedzieć się w jakiej formie FreeImage zwraca wczytany obraz. Następnie dowiadujesz się jak allegro'wa struktura BITMAP przechowuje te dane. Przypisujesz je z tego co wczytałeś do struktury allegro'wej BITMAP i masz bitmapę.

Wczytywanie za użyciem FreeImage w pseudo kodzie (czytaj komentarze, wygląda to jak pulpa nieczytelnego kodu ale jak zwrócisz uwagę na komentarze to wszystko będzie jasne):

std::string sciezka = "mojObraz.png";

FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; //przechowuje typ pliku
FIBITMAP *dib(0); //tworzy pustą bitmapę FreeImage'ową
BYTE* bits(0); //tworzy "miejsce na piksele"

fif = FreeImage_GetFileType(sciezka.c_str(), 0); //pobiera typ pliku
if(fif == FIF_UNKNOWN) fif = FreeImage_GetFIFFromFilename(sciezka.c_str()); //jezeli FreeImage nie znalazło typu pliku to pobiera go z nazwy.
if(fif == FIF_UNKNOWN) return NULL; //jezeli nie znaleziono typu w nazwie to musi zakonczyc cala operacje niepowodzeniem.
//jezeli wszystko jest ok z typem pliku to przechodzi dalej
if(FreeImage_FIFSupportsReading(fif)) dib = FreeImage_Load(fif, sciezka.c_str()); //jezeli typ pliku jest obslugiwany to plik zostaje wczytany
if(!dib) return NULL; //jezeli cos poszlo nie tak przy wczytywaniu to musi zakonczyc cala operacje niepowodzeniem.
dib=FreeImage_ConvertTo32Bits(dib); //konwertuje wczytany obraz do 32 bitów
bits = FreeImage_GetBits(dib); //pobiera bity z obrazka.

int width = FreeImage_GetWidth(dib); //pobiera szerokosc obrazka
int height = FreeImage_GetHeight(dib); //pobiera wysokosc obrazka

if( bits==0 || width ==0 || height==0 ) return NULL; //jezeli jakas dana jest zla to musi zakonczyc niepowodzeniem

BITMAP *mojaBitmapa;

mojaBitmapa = create_bitmap(width, height);


Dalej już przepisujesz każdy piksel z zmiennej bits do mojaBitmapa za użyciem chociażby put_pixel. Czy jak to się nazywało w allegro.
Dodam że bits przechowuje piksele w ten sposób:
0 0 255 0 0 255 - to są dwa piksele koloru czerwonego (kanał BGR).
« Ostatnia zmiana: Czerwiec 11, 2009, 22:32:54 wysłana przez C'mons »

Offline Oti

  • Użytkownik

# Czerwiec 11, 2009, 22:11:13
Oti - Mam VS9 w wersji Express. Nie wiem co masz na myśli mówiąc "początkujący", ale pisaniem czegoś ponad konsolowe programy liczące zająłem się dopiero niedawno.
Poprostu Dev jest raczej dla początkujących, jak ktoś już conieco umie to się przerzuca na coś 'lepszego', czyli np. MSVC. :) A to twoje 'pracuję nad coraz większymi projektami' zabrzmiało groźnie. :D Pozatym nie wiem, czy wiesz, ale Allegro w standardzie potrafi ładowac(poza *.bmp) też: *.lbm, *.pcx i *.tga. ;)

Offline Pawlox

  • Użytkownik

# Czerwiec 11, 2009, 22:33:49
Oti - no wiesz większymi - w skali tego, co robiłem do tej pory ;) Skoro tak mówisz to będę musiał się poważnie zastanowić nad zmianą środowiska... Tylko, że w DEVie łatwo się instaluje nowe biblioteki, a nie wiem jak jest w VS... Czy .tga lub .pcx nie pogarszają jakości obrazu?

C'mons - pseudokod zrozumiałem, a jeśli chodzi o ten komentarz pod spodem - są funkcje int getpixel(BITMAP *bmp, int x, int y); i void putpixel(BITMAP *bmp, int x, int y, int color); - nie orientuję się jak połączyć putpixel z bits. To bits ma być parametrem koloru? Napisałeś, że bits przechowuje piksele w postaci 0 0 255 0 0 255 - przechowuje 3 liczby czy 6 (to takie odwrócone RGB?)? Poza tym jak ma się odbywać to przepisywanie, w pętli? Wiem, że to sporo pytań, ale ten sposób jest taki trochę "na piechotę", a ja zawsze starałem się robić wszystko jak najprościej :)
« Ostatnia zmiana: Czerwiec 11, 2009, 22:45:10 wysłana przez Pawlox »

Offline C'mons

  • Użytkownik

# Czerwiec 11, 2009, 22:45:51
0 0 255 0 0 255 Poprawiłem się i teraz to tak wygląda.

A więc tak:

bits przechowuje po kolei każdy piksel w postaci kanału BGR czyli kolejno w tej tablicy jest tak

bits[0] to nasycenie niebieskiego koloru 1 piksela
bits[1] to nasycenie zielonego koloru 1 piksela
bits[2] to nasycenie czerwonego koloru 1 piksela
bits[3] to nasycenie niebieskiego koloru 2 piksela
bits[4] to nasycenie zielonego koloru 2 piksela
bits[5] to nasycenie czerwonego koloru 2 piksela
I tak dalej.

Dobrze myślisz, musisz użyć pętli a konkretnie dwóch zagnieżdżonych: :)

for( unsigned int x=0; x < width; x++ )
for( unsigned int y=0; y < height; y++ )
{
 int b = bits[(y*width+x)*3];
 int g = bits[(y*width+x)*3+1];
 int r = bits[(y*width+x)*3+2];
 putpixel(mojaBitmapa, x, y, makecol(r,g,b));
}

Siedze przy komputerze bez kompilatora więc nie sprawdzę czy działa ale powinno. W razie czego to napisz jak będzie coś nie teges. ;)
« Ostatnia zmiana: Czerwiec 11, 2009, 22:56:09 wysłana przez C'mons »

Offline Pawlox

  • Użytkownik

# Czerwiec 11, 2009, 22:58:09
Ok teraz już wszystko jasne, ale czy nie dałoby rady zrobić tego jakoś prościej? Np. na tej stronie http://bayger.pl/2008/03/11/pliki-graficzne-w-cc-biblioteka-freeimage/ znalazłem opis jak zrobić konwerter, który pobiera obrazek i zapisuje go w zmienionym formacie do pliku. Nie wiesz czy dałoby się zapisać to np. do nowej bitmapy? Może wtedy nie musiałbym męczyć tego po jednym pikselu...

Offline C'mons

  • Użytkownik

# Czerwiec 11, 2009, 23:02:30
Jak chcesz wczytany obrazek zapisać jako bmp i potem tego bmp'eka wczytać już normalnie przez allegro to przecież podałeś już tą stronę tam wszystko masz. A prościej niż podałem hmm może się da coś tam uprościć ale raczej nie wiele. Jak będę jutro przy swoim komputerze to będę mógł takową funkcje Ci napisać. Chyba, że masz ambicje i wolisz sam napisać tą funkcje dla satysfakcji i doświadczenia. :)
« Ostatnia zmiana: Czerwiec 11, 2009, 23:07:47 wysłana przez C'mons »

Lukaz

  • Gość
# Czerwiec 11, 2009, 23:23:51
Do autora: Robisz problem, użyj poprostu podstawowego .pcx zamiast .bmp
Umnie rozmiary na pliku 290x71 wyglądają tak:
.bmp : 60,5 kB
.pcx  : 12,0 kB
.jpg   : 9,95 kB

No i jak widać między .pcx a .jpg jest mała różnica a pozatym .jpg nie zachowa chyba przezroczystości, znaczy sie tego różowego kolor, będzie kilka jego odcieni, co uniemożliwi dobrą przezroczystość. Natomiast .pcx bardzo dobrze zachowuje przezroczystość.
FreeLunchDesign używa nawet .pcx  :)

Offline Oti

  • Użytkownik

# Czerwiec 12, 2009, 00:12:07
A tam gadacie, nie ma złej jakości formatu, tylko złe programy do konwersji. ;)

Offline Pawlox

  • Użytkownik

# Czerwiec 12, 2009, 10:21:58
C'mons chyba trochę źle mnie zrozumiałeś. Chodziło mi o to, żeby przekonwertować .jpg na .bmp wewnątrz programu, czyli nie zapisywać już tego .bmp do pliku, tylko od razu do bitmapy. Spróbuję dziś napisać tą funkcję twojego pomysłu, a jak nie wyjdzie to chyba się przerzucę na to .pcx lub .tga, tak jak sugerował kolega Lukaz.

Edit:
Lukaz - przed chwilą też przeprowadziłem test:
Obraz 1024x4096:
.bmp : 16 MB
.tga  : 1,04 MB
.pcx  : 1,22 MB
.jpg   : 219 kB (4x mniej niż .tga!)
« Ostatnia zmiana: Czerwiec 12, 2009, 10:44:07 wysłana przez Pawlox »

Offline C'mons

  • Użytkownik

# Czerwiec 12, 2009, 10:39:29
Tak czy siak musiałbyś przepisać dane z FreeImage'owej struktury do tej co ma allegro czyli BITMAP. FreeImage nie potrafi sam zamienić, musisz sam o to zadbać albo skorzystać z gotowej funkcji:
Działa w 100% sprawdziłem. Napisanie tego zajęło mi tylko 15min.

http://www.komons.republika.pl/freeImageWithAllegro.rar

Są tam wszystkie potrzebne pliki. Pokusiłem się o też mały dodatek, mianowicie możesz podać przy wczytywaniu jaki kolor ma być kolorem kluczowym tzn. przeźroczystym. Standardowo zawsze będzie ten różowy(255 0 255) ale możesz przy wczytywaniu podać inny.
BITMAP *obrazek = loadBitmap("obrazek.png", makecol(255, 255, 255)); w ten sposób kolor biały będzie tłem przeźroczystym. A jak chcesz nie ustawiać koloru przeźroczystego to po prostu używasz tej funkcji tylko z jednym parametrem:
BITMAP *obrazek = loadBitmap("obrazek.png");
Podałem przykład który akurat wczytuje plik typu png, ale FreeImage oferuje mnóstwo innych, między-innymi ICO, GIF, JPG itd.

« Ostatnia zmiana: Czerwiec 12, 2009, 10:45:48 wysłana przez C'mons »