Delphi/Bitmapy

BitmapyEdytuj

Bitmapy, inaczej mapy bitowe, są odwzorowaniem obrazu rastrowego (złożonego z pikseli) w pamięci. Pamięcią może być pamięć RAM, ale także pamięć zewnętrzna (plik). W systemie Windows pliki map bitowych mają rozszerzenie *.bmp. W tym rozdziale nie będą omawiane jednak pliki bitmap, a bitmapy trzymane w pamięci.

Bitmapę można przechowywać w pamięci za pomocą obiektu TBitmap. Podobnie jak płótno (Canvas), bitmapa nie jest komponentem i - co może wydawać się dziwne - nie jest wyświetlana na ekranie. Można natomiast skopiować bitmapę na płótno i tym samym ją wyświetlić.

W tej części spróbujemy wyświetlić bitmapę na płótnie formularza. Dobrze byłoby, gdybyś przygotował sobie plik mapy bitowej (o dowolnej rozdzielczości, maksymalnie 24 bity koloru). Możesz to zrobić za pomocą programu Paint dostarczanego z Windows lub dołączonego do Delphi Edytora (menu Tools → Image Editor).

Utwórz nowy projekt. Rysowanie odbędzie się w zdarzeniu OnPaint formularza.

Pierwszym krokiem przy używaniu bitmap jest jej utworzenie. Robimy to tak samo, jak w przypadku dynamicznego tworzenia komponentów:

procedure TForm1.FormPaint(Sender: TObject);
var
bitmapa: TBitmap;
begin
bitmapa:=TBitmap.Create; // konstruktor
// tu nastąpi obsługa bitmapy
bitmapa.Free; // destruktor
end;

Zauważ, że konstruktor bitmapy nie wymaga podania właściciela. Jak wspomniano wyżej, bitmapa nie jest komponentem i nie jest związana z formularzem ani żadnym innym komponentem, jedynie tkwi w pewnym miejscu pamięci.

Druga linia wywołuje destruktora (ang. destructor) obiektu. Destruktor zwalnia całą przydzieloną na obiekt pamięć. Każdy komponent (obiekt) ma swój destruktor. Kiedy zamykasz aplikację, Twój program uruchamia przygotowanego przez Delphi destruktora formularza. Destruktor formularza wywołuje destruktory wszystkich komponentów, które znajdują się wewnątrz niego. Tym samym zwolnienie pamięci programu odbywa się automatycznie. Jednak obiektem "bitmapa" nie włada żaden inny komponent i nieusunięcie go może spowodować problemy dla aplikacji a nawet systemu. Powinieneś pamiętać, aby zawsze wywoływać destruktory obiektów, które utworzyłeś, a które nie są usuwane automatycznie!

Obiekt TBitmap ma przygotowaną metodę "LoadFromFile". Służy ona do wczytania pliku typu *.bmp do pamięci przygotowanej na Twoją bitmapę. Wczytajmy:

bitmapa:=TBitmap.Create; // konstruktor
bitmapa.LoadFromFile('{ tu wstaw ścieżkę do swojego pliku }');
bitmapa.Free; // destruktor

Jeżeli plik istnieje, to obrazek zostanie wczytany do pamięci. Bitmapa przyjmie od razu odpowiednie właściwości, zależne od tego pliku. Dodaj do formularza komponent TLabel i dodaj linię:

bitmapa.LoadFromFile('{ tu wstaw ścieżkę do swojego pliku }');
label1.Caption:='Szerokość: '+IntToStr(bitmapa.Width)+', wysokość: '+IntToStr(bitmapa.Height);
bitmapa.Free; // destruktor

To są rozmiary Twojej bitmapy. A więc wiemy, że znajdowała się ona w pamięci. Nie odwołuj się do bitmapy wtedy, gdy została usunięta (za pomocą bitmapa.Free) - wystąpi błąd.

Kiedy bitmapa jest w pamięci, trzeba ją wyświetlić. Można tego dokonać na klika sposobów; jako pierwszy spróbujemy użyć pędzla.

Jak wspomnieliśmy w poprzednim rozdziale, pędzlem może być bitmapa. Przypiszmy więc naszą bitmapę do pędzla na płótnie formularza:

label1.Caption:='Szerokość: '+IntToStr(bitmapa.Width)+', wysokość: '+IntToStr(bitmapa.Height);
Canvas.Brush.Bitmap:=bitmapa;
bitmapa.Free; // destruktor

Tutaj małe wyjaśnienie: zarówno bitmapa jak i Canvas.Brush.Bitmap są wskaźnikami na pewien obszar pamięci. Takie przypisanie sprawia, że kiedy bitmapa zostanie usunięta, pędzel płótna będzie wskazywał w puste teraz miejsce pamięci. Aby unikąć ewentualnych kłopotów, po usunięciu bitmapy przypisz pędzlowi pusty wskaźnik:

bitmapa.Free; // destruktor
Canvas.Brush.Bitmap:=nil;

Przyszedł czas na narysowanie bitmapy:

Canvas.Brush.Bitmap:=bitmapa;
Canvas.FillRect(Rect(0,0,bitmapa.Width,bitmapa.Height));
bitmapa.Free;

Uruchom program. Wszystko wygląda bardzo ładnie. W rzeczywistości pędzel rysuje zawsze od współrzędnych (0,0), co prowadzi czasem do dziwnych efektów. Spróbuj zmienić współrzędne prostokąta, np. w ten sposób:

Canvas.FillRect(Rect(bitmapa.Width div 2,bitmapa.Height div 2,bitmapa.Width*2, bitmapa.Height*2));

Stosowanie pędzla nie zawsze ma więc sens. Druga metoda polega na kopiowaniu fragmentu jednego płótna na inne. Obiekt TBitmap ma również swoje płótno. TBitmap jest niewidoczny, więc jego płótno też jest niewidoczne, ale można na nim rysować. Skopiujemy więc fragment płótna bitmapy na płótno formularza.

Słuzy do tego metoda CopyRect, w której podaje się prostokąt, w który kopiujemy, źródło (płótno), oraz prostokąt, który będziemy kopiować.

procedure TForm1.FormPaint(Sender: TObject);
var
bitmapa: TBitmap;
prostokat1, prostokat2: TRect;
begin
bitmapa:=TBitmap.Create;
bitmapa.LoadFromFile('C:\Documents and Settings\Wojtek\Moje dokumenty\Moje obrazy\bez tytułu.bmp');
label1.Caption:='Szerokość: '+IntToStr(bitmapa.Width)+', wysokość: '+IntToStr(bitmapa.Height);
prostokat1:=Rect(0,0,bitmapa.Width,bitmapa.Height);
prostokat2:=Rect(10,10,10+bitmapa.Width,10+bitmapa.Height);
Canvas.CopyRect(prostokat2,bitmapa.Canvas,prostokat1);
bitmapa.Free;
end;

Jeśli chcesz, pozmieniaj rozmiary obu prostokątów i popatrz, jak bitmapa będzie kopiowana na płótno formularza.

ZadanieEdytuj

Każda bitmapa ma swoje płótno (Canvas). Stwórz bitmapę (np. o rozmiarach 100x100), narysuj na niej czerwoną elipsę o grubości pióra 2 piksele. Na formularzu umieść przycisk. Niech po kliknięciu przycisku bitmapa zostanie skopiowana na formularz. Tło bitmapy poza elipsą może pozostać białe.

(rozwiązanie)


« Poprzednia lekcjaSpis treściNastępna lekcja »