Ćwiczenie 1 OBSŁUGA OBRAZÓW W FORMACIE BMP Zakres
Transkrypt
Ćwiczenie 1 OBSŁUGA OBRAZÓW W FORMACIE BMP Zakres
Ćwiczenie 1
OBSŁUGA OBRAZÓW W FORMACIE BMP
Zakres pracy
W ramach ćwiczenia należy do dostarczonego interfejsu dodać możliwość wyświetlania
wczytanych z pliku obrazów typu BMP, konwertowania ich na format 8-bitowy o 256
poziomach szarości, a następnie wyświetlania i zapisywania wyniku przekształcenia. Lewe
okno ma przedstawiać obraz źródłowy, a prawe - wynikowy. Wyświetlane obrazy mają
maksymalnie wypełniać okno, zachowując jednak proporcje boków.
Implementacja musi być wykonana w języku C++ bez użycia zewnętrznych bibliotek, przy
wykorzystaniu metod podanych w sekcji Wskazówki implementacyjne.
Do obsługi plików BMP należy stworzyć klasę przechowującą zawartość obrazu i
udostępniającą następujące metody:
bool LoadDIB(CString sciezka_do_pliku)
do wczytywania obrazów z plików BMP,
bool PaintDIB(HDC kontekst, CRect prost_docelowy, CRect prost_zrodlowy)
do wyświetlania wczytanych obrazów,
bool CreateGreyscaleDIB(CRect rozmiar_obrazu, int xPPM, int yPPM)
do tworzenia pustych 8-bitowych bitmap w odcieniach szarości o zadanym rozmiarze
(PPM oznacza rozdzielczość pixels per meter),
bool GetPixel1(int x, int y)
do odczytywania wartości pikseli w bitmapach 1-bitowych,
BYTE GetPixel8(int x, int y)
do odczytywania wartości pikseli w bitmapach 8-bitowych,
RGBTRIPLE GetPixel24(int x, int y)
do odczytywania wartości pikseli w bitmapach 24-bitowych,
bool SetPixel8(int x, int y, BYTE val)
do ustawiania wartości pikseli w bitmapach 8-bitowych,
bool SaveDIB(CString sciezka_do_pliku)
do zapisywania plików BMP.
Informacje pomocnicze
Format BMP służy do przechowywania map bitowych niezależnych od urządzenia (ang.
device independent bitmap, DIB) i występuje w wielu wariantach. Typowy plik BMP ma
strukturę opisaną poniżej.
1. Nagłówek pliku BMP, zdefiniowany następująco:
tagBITMAPFILEHEADER{
UINT bfType;
DWORD bfSize;
UNIT bfReserved1;
UINT bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER
bfType (2B)
bfSize (4B)
bfReserved1 (2B)
bfReserved2 (2B)
bfOffBits (4B)
typ pliku - to pole jest równe "BM" (dwa znaki w kodzie ASCII)
rozmiar pliku w bajtach
zarezerwowane - powinno mieć wartość 0
zarezerwowane - powinno mieć wartość 0
odległość (offset) od początku pliku do właściwej mapy bitowej
2. Struktura BITMAPINFO definiująca rozmiary i kolory mapy bitowej:
tagBITMAPINFO{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
struktura BITMAPINFOHEADER, która zawiera informacje o rozmiarach i formacie kolorów
mapy bitowej DIB
tablica struktur RGBQUAD definiująca kolory w mapie bitowej
bmiHeader
bmiColors
Uwaga! Rozmiar struktury BITMAPINFO nie uwzględnia rozmiaru palety kolorów (bmiColors to tylko wskaźnik).
tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
bfSize (4B)
biWidth (4B)
biHeight (4B)
biPlanes (2B)
biBitCount (2B)
biCompression (4B)
biSizeImage (4B)
biXPelsPerMeter (4B)
biYPelsPerMeter (4B)
biClrUsed (4B)
biClrImportant (4B)
tagRGBQUAD{
BYTE
BYTE
BYTE
BYTE
} RGBQUAD;
liczba bajtów używanych przez strukturę BITMAPINFOHEADER
szerokość mapy bitowej w pikselach
wysokość mapy bitowej w pikselach
to pole powinno być ustawione na 1
liczba bitów na piksel (1, 4, 8 lub 24)
typ kompresji w przypadku skompresowanej mapy bitowej, dopuszczalne są następujące
wartości: BI_RGB (0) - mapa bitowa nie skompresowana, BI_RLE8, BI_RLE4
rozmiar obrazu w bajtach (powinna być 0 w przypadku formatu BI_RGB)
pozioma rozdzielczość w pikselach na metr
pionowa rozdzielczość w pikselach na metr
liczba pozycji w tablicy kolorów (gdy wartość tego pola równa się 0, mapa bitowa
używa maksymalnej liczby kolorów, odpowiednio do wartości pola biBitCount)
liczba kolorów niezbędnych do wyświetlenia mapy bitowej (gdy pole to jest równe 0,
wszystkie kolory są niezbędne)
rgbBlue;
rgbGReen;
rgbRed;
rgbReserved;
rgbBlue (1B)
rgbGreen (1B)
rgbRed (1B)
rgbReserved (1B)
intensywność koloru niebieskiego
intensywność koloru zielonego
intensywność koloru czerwonego
Nieużywane - powinno być równe 0
3. Właściwa mapa bitowa - tablica bajtów
Bity w tej tablicy są ułożone kolejno, jednak każda linia obrazu jest w razie potrzeby wydłużona, tak aby jej rozmiar
był wielokrotnością typu DWORD (4 bajty).
Punkt początkowy mapy bitowej to dolny lewy róg obrazu.
Liczbę bajtów, którą w pamięci zajmuje jedna linia mapy bitowej, można obliczyć
korzystając z następującego wzoru:
bity _ na _ piksel szerokosc _ obrazu 31
liczba _ bajtow
4 .
32
W obrazach 24-bitowych nie występuje tablica kolorów (paleta). Odpowiadające
pojedynczemu pikselowi 3 kolejne bajty opisują, kolejno, składową niebieską, zieloną i
czerwoną (BGR).
Pomiędzy tablicą kolorów a właściwą mapą bitową może występować przerwa. Dlatego
zawsze należy korzystać z wartości zapisanej w polu bfOffBits struktury
BITMAPINFOHEADER.
BITMAPFILEHEADER
‘BM’
rozmiar pliku
0
0
odległość od początku pliku do tablicy pikseli
BITMAPINFOHEADER
rozmiar BITMAPINFOHEADER
szerokość
wysokość
0
bity na piksel
kompresja
rozmiar obrazu
rozdzielczość pozioma
rozdzielczość pionowa
liczba użytych kolorów
liczba ważnych kolorów
TABLICA KOLORÓW (PALETA)
kolor 1
…
kolor n
przerwa (opcjonalnie)
TABLICA PIKSELI (BITMAPA)
ostatnia linia obrazu
…
pierwsza linia obrazu
Wskazówki implementacyjne
1. Zasadniczy kod przykładowego programu (np. reakcje na przyciski) zawiera klasa CPODlg.
2. Wykorzystując tzw. Class View (Ctrl+Shift+C) można łatwo dodać nową klasę (prawy
przycisk Add Class).
3. Obsługę operacji na plikach zapewnia dostępna w MFC klasa CFile. Przykładowo:
CFile f;
f.Open(nazwa_pliku, CFile::modeReadWrite))
f.Write(wskaznik_na_bufor, liczba_bajtow);
f.Read(wskaznik_na_bufor, liczba_bajtow);
4. Do przydzielania i zwalniania pamięci należy wykorzystać odpowiednie funkcje systemu
Windows:
wskaznik_na_bufor = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, rozmiar_bufora);
HeapFree(GetProcessHeap(), 0, wskaznik_na_bufor);
5. Do wyświetlania obrazów służy klasa CImgWnd - należy obsłużyć metodę OnPaint(). W
interfejsie programu lewe i prawe okno to obiekty klasy CImgWnd (zmienne m_imgIN i
m_imgOUT).
6. Obsługując metodę OnPaint() kontekst urządzenia pobieramy w następujący sposób:
HDC kontekst = dc.GetSafeHdc();
7. Tak zwany sposób rozciągania (ang. stretching mode) definiuje to, jak system łączy dane
bitmapy z pikselami już istniejącymi w kontekście urządzenia wyświetlającego. W
naszym przypadku ustawiamy tryb, który kopiuje bitmapę do kontekstu usuwając tło:
SetStretchBltMode(kontekst, COLORONCOLOR);
8. Do wyświetlania zawartości bitmapy służy poniższa funkcja:
StretchDIBits(kontekst, Xdocelowy, Ydocelowy, szer_docelowa, wys_docelowa,
Xzrodlowy, Yzrodlowy, szer_zrodlowa, wys_zrodlowa,
wskaznik_na_tablice_bajtow,
wskaznik_na_BITMAPINFO,
DIB_RGB_COLORS,
SRCCOPY);
9. Aby wyznaczyć rozdzielczość pionową i poziomą (PPM), należy skorzystać z funkcji
GetDeviceCaps(), np.:
liczba_pikseli_w_poziomie = GetDeviceCaps(kontekst, HORZRES);
rozmiar_ekranu_w_poziomie = GetDeviceCaps(hDC, HORZSIZE);
10. Aby ustalić aktualny rozmiar okna, należy posłużyć się funkcją GetClientRect():
CRect r;
GetClientRect(r);