Nie chcesz mnie, Ben. Składam się z siedmiu warstw popieprzenia okraszonych odrobiną gównianego szaleństwa.
bmp")) ;
if (pbmfh[0] == NULL pbmfh(1] = NULL)
f
MessageBox (hwnd, TEXT ("Cannot load DIB file"),
szAppName, 0) ;
return 0 ;
)
// We wskanik do struktury informacyjnej
// i do bitw pikseli
pbmi [0] = (BITMAPINFO *) (pbmfh[0] + i) ;
pbmi [1] = (BITMAPINFO *) (pbmfh[1] + 1) ;
pBits [0] = (BYTE *) pbmfh[0] + pbmfh[0]->bfOffBits ;
pBits [1] = (BYTE *) pbmfh[1] + pbmfh[1]->bfOffBits ;
698 Cz II: Grafika
(cig dalszy ze strony 697)
// Odczytaj szeroko i wysoko DIB
// (zakadamy BITMAPINFOHEADER)
// Zauwa, e cyDib jest wartocid bezwzgldnd
// z wartoci odczytanej z nagwka!!!
cxDib CO] = pbmi[0]->bmiHeader.biWidth ;
cxDib C1] = pbmi[1]->bmiHeader.biWidth ;
cyDib CO] = abs (pbmi[0]->bmiHeader.biHeight) ;
cyDib C1] = abs (pbmi[1]->bmiHeader.biHeight) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam)
cyClient = HIWORD (lParam)
return 0 :
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
// Calkowity rozmiar DIB do gry nogami
SetDIBitsToDevice (hdc,
0, // xDst
cyClient / 4, // yDst
cx0ib[0], // cxSrc
cyDib[0], // cySrc
0, // xSrc
0, // ySrc
0, // pierwsza linia skanowania
cyDib[0], // liczba skanowanych linii
pBitsCO],
pbmi[0],
DIB RGB COLORS) ;
// Fragment DIB do gry nogami
SetDIBitsToDevice (hdc,
240, // xDst
cyClient / 4, // yDst
80, // cxSrc
166, // cySrc
80, // xSrc
60, // ySrc
0, // pierwsza linia skanowania
cyDibCO], // liczba skanowanych linii
pBitsCO],
pbmiCO],
DIB RGB COLORS) ;
// Calkowity rozmiar DIB z gry na dl
SetDIBitsToDevice (hdc,
340, // xDst
cyClient / 4, // yDst
cxDib[0], // cxSrc
Rozdzia 15: Bitmapa niezalena od urzdze ggg
cyDibCO7, // cySrc
0, // xSrc ;=
0. // ySrc ;',.
0, // pierwsza linia skanowania
cyDib[0], // liczba skanowanych linii !
pBitsCO],
pbmiC07, .
DIB RGB COLORS) ;
// Fragment DIB z gry na d61
SetDIBitsToDevice (hdc,
I,
580, // xDst i
.
cyClient / 4, // y0st
80, // cxSrc
i-
166. // cySrc
80. // xSrc
60. // ySrc .
0, // pierwsza linia skanowania
cyDibCl7, // liczba skanowanych linii "
pBitsClJ,
pbmiCl7, ;.,
DIBRGB COLORS) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
if (pbmfhC07)
free (pbmfhCO]) ;
if (pbmfhCl])
free (pbmfh[17) ;
PostOuitMessage (0) ;
return 0 ;
t
return DefWindowProc (hwnd, message, wParam, lParam) ;
Rysunek 15-6. Program APOLLOl1
Program wczytuje dwie wersje DIB, o nazwach APOLLOll.BMP (do gry noga-
mi) i APOLLOTD.BMP (z gry na d). Obie maj 220 pikseli szerokoci i 240
wysokoci. Zauwa, e gdy program okrela szeroko i wysoko DIB na pod-
stawie nagwkowej struktury informacyjnej, uywa funkcji abs, aby zna war-
to bezwzgldn pola biHeight. Podczas wywietlania DIB w caoci lub we frag-
mentach, wsprzdne xSrc, ySrc, cxSrc i cySrc s identyczne niezalenie od tego,
ktra bitmapa jest wywietlana. Wyniki pokazuje rysunek 15-7.
oo Cz II: Grafika
Rysunek 15-7. Ekran APOLLOl1
Zauwa, e argumenty "pierwsza linia skanowania' i "liczba skanowanych li-
n" pozostaj niezmienione. Wkrtce do tego wrc. Argument pBits take po-
zostaje taki sam. Nie prbuj zmienia pBits tak, eby wskazywa jedynie ten ob-
szar DIB, ktry chcesz wywietli.
Powicam temu zagadnieniu wiele czasu nie dlatego, e chc dogry twrcom
Windows za ich prby jak najlepszego uporzdkowania problematycznych ob-
szarw definicji API, ale po to, eby si nie denerwowa, jeli zostaniesz zbity
z tropu. To musi by mylce, bo jest naprawd pomylone.
Chc take, eby by czujny i nie wierzy lepo niektrym stwierdzeniom z do-
kumentacji Windows. Na przykad o funkcji SetDIBitsToDevice moesz przeczy-
ta, e pocztkiem DIB do gry nogami jest lewy dolny rg bitmapy; natomiast
pocztkiem DIB z gry na d - lewy grny rg. To jest nie tylko niejednoznacz-
ne, to jest wrcz bdne. IZnic moglibymy lepiej opisa w taki sposb: "Po-
cztkiem DIB do gry nogami jest lewy dolny rg obrazu bitmapowego, a jest to
pierwszy piksel pierwszego wiersza danych bitmapy. Pocztkiem DIB z gry na
d jest take dolny lewy rg obrazu bitmapowego, lecz w tym wypadku lewy
dolny rg jest pierwszym pikselem ostatniego wiersza danych bitmapy".
Problem nasila si wtedy, kiedy potrzebujesz napisa funkcj, ktra pozwala two-
im programom na dostp do indywidualnych bitw DIB. Powinna ona by spj-
na ze sposobem okrelenia wsprzdnych fragmentu obrazu DIB, ktry ma by
wywietlony. W moim rozwizaniu (ktre zaimplementuj w bibliotece DIB w
rozdziale 16) jednolicie odwouj si do pikseli i wsprzdnych DIB. Pocztek
(0,0) oznacza skrajny lewy piksel grnego wiersza obrazu DIB, tak jak na niego
patrzymy, gdy jest prawidowo wywietlony.
Rozdzia 15: Bitmapa niezalena od urzdze 701
Wywietlanie sekwencyjne
Dostpno duej iloci pamici na pewno uatwia programowanie. Wywietle-
nie DIB zapisanej w pliku dyskowym mona rozbi na dwa niezalene zadania:
wczytanie DIB do pamici oraz jej wywietlenie.
Mog jednak zdarzy si sytuacje, w ktrych chciaby wywietli DIB bez ko-
niecznoci wczytania caego pliku do pamici. Nawet jeli jest jej na tyle duo,
eby zmiecia si caa bitmapa, przeniesienie DIB do pamici moe wymusi na
systemie pamici wirtualnej Windows przerzucenie innego kodu lub danych na
dysk twardy. Bdzie to wandalizm, szczeglnie gdy DIB ma by tylko wywie-
tlona, a potem natychmiast wyrzucona z pamici.
Oto inny problem: zamy, e DIB jest zapisana na jakim wolnym noniku, ta-
kim jak dyskietka, lub przesyana przez modem. Moe te pochodzi z procedu-
ry konwersji, ktra uzyskuje dane o pikselach ze skanera lub urzdzenia ciga-
jcego fragmenty ekranu. Czy chcesz czeka, a do pamici zostanie wczytana
caa DIB, zanim j wywietlisz? Czy moe raczej wywietlaby DIB sekwencyj-
nie, w miar napywania informacji z dysku, linii telefonicznej lub skanera?
Rozwizanie tych problemw jest zadaniem argumentw yScan i cyScans funkcji
SetDIBitsToDevice. Chcc poshxy si t cech, wykonujesz seri wywoa SetDI-
BitsToDevice, zasadniczo z tymi samymi argumentami. Jednak dla kadeg wy-
woania argument pBits wskazuje rne czci tablicy pikseli bitmapy. Argument
yScan okrela wiersz pikseli wskazywany przez pBits, argument cyScans za to
liczba wierszy, do ktrej odnosi si pBits. To znacznie zmniejsza wymagania pa-
miciowe. Wystarczy alokowa tyle pamici, eby przechowa sekcj informa-
cyjn DIB (struktur BITMAPINFOHEADER i tablic kolorw) oraz przynajmniej
jeden wiersz danych pikseli
|
Wątki
|