Jak wrzucic do pamieci kilkaset bitmap?

0

Witam!

Mam następujący problem:
Muszę trzymać w pamięci, równocześnie kilkaset bitmap. Bitmapy muszą być dostępne bardzo szybko dlatego nie wchodzi w rachubę ładowanie ich z dysku - one muszą być w pamięci. Nie mogę trzymac tego jako klasyczne obiekty TBitmap bo bardzo szybko zobacze komunikat Out of Resources.

Jak to zrobić???

Mój pomysł jest w zarysie taki:

  1. Wczytuje bitmape jako TBitmap
  2. Likwiduje TBitmap jako obiekt ale tak żeby nie zwolnić pamięci w której znajdują się dane obiektu.
  3. Zapamietuje w tablicy wskaznik do zlikwidowanego obiektu.
  4. W odpowiednim momenci gdy potrzebuje danej bitmapy tworze obiekt TBitmap ale tak żeby wskazywał mi te dane które znajdują się w pamięci

To jest schemat mojego pomyslu ale nie wiem za bardzo jak to wykonac. Tzn w jaki sposób zniszczyć obiekt bez zwolnienia pamięci w której dane się znajdują?
Jak potem utworzyć nowy obiekt żeby wykorzystywał te dane?

Tomek

0

Dziwny jest twój pomysł. Przecież jak zwolnisz obiekt, to ta część pamięci w której on był może zostać zamazana przez cokolwiek innego.

0

No właśnie wiem.

I dlatego napisałem że nie wiem jak to zrobić. Taki jest tylko ogólny zarys rozwiązania problemu.

Pytanie jest w jaki sposób sprawić, żeby obiekt z jednej strony zwolnić ale z drugiej zeby nie zwolnić pamięci i żeby nic mi tego nie zamazało. Czy to jest w ogóle możliwe?

Tomek

0

Stwórz sobie rekord taki:

type
 TKolorki=array[0..szerokosc, 0..wysokosc] of TColor;

To ci będzie mniej zajmować niż TBitmap.

[dopisane]
Czyli chcesz oszukać system? :)

[dopisane2]
Użyj wskaźników

0

Mozna zrobic to tak:


var z : array [0..1000] of ^TBitmap;
    i: integer;
begin
  for i:=0 to 1000 do
  begin
    New(z[i]);
    z[i]^ := TBitmap.create();
    z[i]^.LoadFromFile('c:\z.bmp');
  end;

gdzie z zadeklarowane globalnie aby zawsze bylo dostepne. dostep do tego jest poprzez z[i]. zalezy jeszcze czy te bitmapy sa duze moze warto je jeszcze w locie konwertowac na jpg. jak cos to kontakt na gg.</delphi>

0

I to będzie działało w każdym systemie, także w Win98?

Przetestowałem sobie na swoim komputerze (1Gb RAM, WinXp)
Do około 4500 Bitmap działa dobrze ale potem dostaję błąd:

"Code 87 Parametr jest niepoprawny."

Dlaczego?

I jeszcze jedno

Jak się dobrze zastanowić to właściwie potrzebuje nawet nie kilkaset bitmap ale 2000 - 3000.

0

nie wiem w czym problem. zaladowalem sobie 5000 bitmap (kazda po 50k) i nie mialem zadnego bledu. to predzej wina wczytywanej bitmapy - sprawdz czy dobrze podajesz nazwy bitmap i czy ma odpowedni format. jak duze te btmapy wczytujesz?

mam WINXP i 512 ramu

0

I jeszcze jedna sprawa

Co do tablicy to odpada. Te bitmapy będa musiały bardzo szybko się wyświetlać, na nich będą wykonywane inne operacje i przepisywanie z tablicy do TBitmap i zpowrotem zajmie zbyt dużo czasu.

A ta metoda ze wskaźnikami to właściwie niewiel wnosi. Niezaleznie od tego czy uzywam wskaznikow czy żywych bitmap działa tak samo:

var z : array [0..1000] of TBitmap;
i: integer;
begin
for i:=0 to 1000 do
begin
z[i] := TBitmap.create();
z[i].LoadFromFile('c:\z.bmp');
end;

Problem jest z uchwytami. W systemie jest ograniczona ilość uchwytów (Handle) dla Bitmap i nie można utworzyć ich zbyt wiele. W WinXP to działa lepiej. W Win98 i Me kończą się znacznie szybciej. Tyle wyczytałem i podejrzewam że stąd jest ten błąd - dlatego pytam czy to będzie działało na Win98?

Być może masz otwarte mniej programów i dlatego u ciebie działa dla 5000 a u mnie nie. Plik wczytuje za każdym razem ten sam i jest niewielki (po wczytaniu zajęte jest tylko około 650 Mb RAM)

Tomek

0

A konwersja na JPG przy wczytywaniu i pozostawienie w pamięci w formacie JPEG? :>

0
var Dane:TStringList;

function AddFile(const Name:String);
var S:TStringStream;
var B:TBitmap;
begin
  B:=TBitmap.Create;
  try
    B.LoadFromFile(Name);
    S:=TStringStream.Create('');
    try
      B.SaveToStream(S);
      Dane.Add(S.DataString);
    finally
      S.Free;
    end;
  finally
    B.Free;
  end;
end;

procedure GetBitmap(B:TBitmap;I:Integer);
var S:TStringStream;
begin
  S:=TStringStream.Create(Dane[I]);
  try
    B.LoadFromStream(S);
  finally
    S.Free;
  end;
end;

initialization Dane:=TStringList.Create;

finalization Dane.Free;

end.
0

O własnie!
To jest jakiś pomysł

Tylko że jeszcze fajnie by było gdyby można było uniknąć tego ładowania bitmap.
Bitmapy będą bardzo duże i ich przepisywanie zajmie dużo czasu. Muszę jeszcze testy zrobić ale przypuszczam że to będzie trochę zbyt wolne.

A nie dałoby się zamiast ładować bitmapę to jakiś wskaźnik tylko przekazać. No bo tak:
String jest zapisany i siedzi w pamięci. Gdzieś się zaczyna, gdzieś się kończy.

To zamiast przepisywać może wystarczyłby tylko pokazać nowej bitmapie początek stringa?

Tylko że stringi zachowują się jak tablice i to chyba nie jest ciągły fragment pamięci.

Próbowałem z TMemoryStream ale wywala mi błędy i nic z tego :-(

Tomek

0

Swoja droga ciekawi mnie po co komus takie ilosci bitmap w pamieci i to tak strasznie i koniecznie szybko dzialajacych. Dlugo myslalem ale nie wymyslilem do czego bym tego potrzebowal. Moje (raczej niewielkie) doswiadczenie mowi mi jednak, ze chyba nie trzeba az tak...

0
brodny napisał(a)

A konwersja na JPG przy wczytywaniu i pozostawienie w pamięci w formacie JPEG? :>
Miało być szybko a Twoje rozwiązanie wiąże się z każdorazowym dekodowaniem JPEG przy wyświetlaniu... Poza tym jakość...

0

hmm, chyba najlepiej bedzie uzyc klase TStream i jej klasy pochodne (TMemoryStream).
Nie mam przy sobie delphi weic cos tu moze sie nie zgadzac ale robisz mniej wiecej tak:

Tworzysz strumien, jako parametr podajesz nazwe pliku:
Stream := TFileStream('bitmapa.bmp', tutaj paramentr-zobacz do pomocy);

Ladujesz bitmape do strumienia:
Stream.LoadFromFile('bitmapa.bmp');

I tyle, teraz jesli chcesz z tego skorzystac robisz mniej wiecej tak:

Bitmapa.LoadFromStream(Stream); - I masz zaladowana bitmapke.

To jeszcze nie rozwiazuje twojego problemu, bo jak zaladujesz 3000 bitmap do jednego strumienia to musisz zapamietac ich pozycje, a wiec przy ladowaniu pobierasz do jakiejs tablicy wlasciwosc - Stream.Position.
Mysle ze to na pewno rozwiaze twoj prblem - musisz tylko troche poglowkowac (nigdy nie daje na forum gotowych rozwiazan)

fakt faktem nie mam pojecia po co czlekowi tyle bitmap w pamieci, napisz do czego ci to potrzebne - moze jest inne rozwiazanie tego problemu
pozdrawiam

0

Bardzo dziękuję wszystkim za pomoc!

A tyle bitmap jest mi potrzebnych bo próbuję napisać niewielki GISowy programik.
Ma być naprawdę skormny i przeznaczony tylko do konkretnych celów ale musi obsługiwać tyle bitmap

A dlaczego tak dużo? W programach gisowych nie jest niczym dziwnym że użytkownik posługuje się np setką zeskanowanych map równocześnie. Każa mapa jest skalibrowana (ma nadane odpowiednie współrzędne) i można wszystkie naraz dowolnie powiększać i pomniejszać.

A dlaczego aż 2000 - 3000 a nie tylko 100?
Otóż te bitmapy mogą być bardzo duże (10000 na 7000 pikseli BW to jest standard). Skalowanie tak wielkich bitamp w czasie rzeczywistym byłoby bardzo czasochłonne. A skalować trzeba, żeby je płynnie wyświetlać na ekranie.

Chcę to rozwiązać w taki sposób:
Dla każdej dużej bitmapy tworzę tak zwaną piramidę obrazu, czyli zestaw bitmap, każda trochę mniejsza od poprzedniej. Takich bitmap w jednej piramidzie może być np 20 (Ile ich jest to zależy od wielkości pierwszego obrazu). 100 Bitmap razy 20 daje 2000 :-)

Potem podczas wyświetlania na ekranie dobieram i ostatecznie skaluję tylko tę bitampę która jest najbardziej zbliżona do ostatecznego rozmiaru.

No i w efekcie mam nadzieję że otrzymam płynne wyświetlanie wielu, bardzo dużych bitmap równocześnie.

Pozdrawiam wszystkich
Tomek

1 użytkowników online, w tym zalogowanych: 0, gości: 1