Ładowanie obrazu do TImage ze strumienia

0

Witam, mam utworzony plik w ktorym sa zapisane ikony jedna po drugiej, potrzebuje wczytac konkretna ikone do strumienia a pozniej do komponentu TImage, ale nie wiem jak tego dokonac. Nie wiem takze jakiego z strumienia skorzystac, chyba ze da sie to obejsc bez strumieni. kazda ikona ma taki sam rozmiar 1466 kilobajtow, i zapisane jest w tym pliku 10 ikon, jedna poi drugiej. Proces kopiowania ikon do jednego pliku jest prosty - otwarty jest plik wyjsciowy, w petli otwierane sa poszczegolne ikony, po czym bajt po bajcie odczytywana jest ikona i zapisywana do pliku wyjsciowego, po ukonczeniu kazdej ikony plik wejsciowy jest zamykany (wyjsciowy nie) i otwierana jest nastepna ikona i kopiowana do pliku wyjsciowego.

Potrzebuje odczytac z pliku np trzecia ikone do strumienia (nie wiem jakiego) czy do tablicy sluzacej jako bufor, a potem skopiowania z bufora ikony do komponentu TImage; Kombinowalem juz z roznymi strumieniami, sam odczyt nie stanowi problemu, ale nie wiem jak skopiowac zawartosc strumienia do kontrolki TImage. Odczytuje w taki sposob:

var
  fikona: File;
  bufor: array[0..1466] of Byte;
//...
assignFile(fikona, 'c:\Ikony.icons');
try
  reset(fikona, 1);
  seek(fikona, 1466 * 2 {dwa jest przykladowo});
  blockread(fikona, bufor, 1466);
  {co teraz???}
finally
  closefile(fikona);
end;

Jakiego strumienia mam uzyc? TStream, TMemoryStream?

Sprawdzilem poprawnosc odczytywanych danych zapisujac odczytany blok do osobnego pliku - wszystko dziala, zostaja odczytane prawidlowe dane, ale nie wiem co zrobic dalej.

Pomozcie prosze, bede wdzieczny.

0

Poprawka: kazda ikona ma 1466 bajtow, nie kilobajtow.

0

Nie myśłisz co robisz. Coś tam dziubiesz, ale bez zastaniowienia. Przecież skoro używasz TImage czyli piszesz pod VCL, a nie z użyciem tylko WinAPI, to najprościej będzie użyć dwóch TMemoryStreamów. Przykład poniżej. Pewnie można to zrobić na mnóstwo innych sposobów, ale ja zrobiłem tak na szybko. I zawsze polecam pogooglowac, pomyśleć, pokombinować samodzielnie i dopiero pytać. I tak, wiem że to dział Newbie, ale według mnie nigdy nie można się "zwolnić" z myślenia.

const
  IcoSize = 1466;
  AFileName = ''C:\ikony.icons'';
var
  Img : TImage;
  I, APos : integer;
  SrcMs, DestMS : TMemoryStream;
  Buff : array[1..IcoSize] of Byte;
  ImagesArr : array[1..2] of TImage;
begin
  for I := Low(ImagesArr) to High(ImagesArr) do
  begin
    Img := TImage(Self.FindComponent('Image' + IntToStr(I)));
    if Img <> nil then
    begin
      ImagesArr[I] := Img;
    end;
  end;
  if FileExists(AFileName) then
  begin
    SrcMS := TMemoryStream.Create;
    SrcMS.LoadFromFile(AFileNAme);
    if SrcMS.Size div IcoSize = Length(ImagesArr) then
    begin
      for I := Low(ImagesArr) to High(ImagesArr) do
      begin
        APos := I * IcoSize - IcoSize;
        SrcMS.Position := APos;
        SrcMS.ReadBuffer(Buff, IcoSize);
        DestMS := TMemoryStream.Create;
        DestMS.WriteBuffer(Buff, IcoSize);
        DestMS.Position := 0;
        Img := ImagesArr[I];
        if Img <> nil then
        begin
          Img.Picture.Icon.LoadFromStream(DestMS);
        end;
        DestMS.Free;
      end;
    end;
    SrcMS.Free;
  end;
end;

EDIT: a i odpisał bym wcześniej, ale kod nie chciał działać, bo klepałem na szybko i zapomniałem żeby Position docelowego strumienia ustawić na zero. Gdyż jak możesz się przekonać to bardzo ważne.
EDIT 2: ewentualne modyfkacje lub dodatkową obsługę błędów zrób już sam.

0

A tak by się nie dało?

var
  ms:TMemoryStream;
  numer_ikony:Integer;//pierwsza w pliku ma numer 0
//...
  ms:=TMemoryStream.Create;
  ms.LoadFromFile('c:\Ikony.icons');
  ms.Position:=numer_ikony*1466;
  Image1.Picture.Icon.LoadFromStream(ms);
  ms.Free;
0

Twoj kod pelsta nie dziala poprawnie, powoduje blad EReadError - Stream read error. Kod olesia dziala w 100% tak jak chcialem. Wykonalem to w taki sposob:

var
  biblioteka, ikona: tmemorystream;
  bufor: array[1..1466] of byte;
{...}
  if fileexists('c:\Ikony.icons') then
  begin
    biblioteka := tmemorystream.create();
    Ikona := tmemorystream.create();
    try
      biblioteka.loadfromfile('c:\Ikony.icons');
      biblioteka.position := 1466 * indeksikony;
      biblioteka.readbuffer(bufor, 1466);
      ikona.writebuffer(bufor, 1466);
      ikona.position := 0;
      imgikona.picture.icon.loadfromstream(ikona);
    finally
      biblioteka.free;
      Ikona.free;
    end;
  end;

tylko dalej nie wiem co zrobic jak plik (biblioteka) z ikonami bedzie zawierac bardzo duzo ikon i rozmiar pliku wzrosnie do kilku megabajtow. wtedy nie bedzie sie oplacalo ladowac calego pliku do pamieci, tylko odczytac z dysku 1466 bajtow z okreslonego miejsca tak jak kombinowalem wczesniej. najpierw chcialem pobrac 1466 bajtow z pliku z okreslonego miejsca a pozniej te dane skopiowac albo do strumienia, albo bezposrednio do komponentu, ale nie wiedzialem i dalej nie wiem jak. olesio - mozesz podpowiedziec cos?

0
John Pablo napisał(a)

Twoj kod pelsta nie dziala poprawnie, powoduje blad EReadError - Stream read error.

Mój kod działa w 100% poprawnie. To Ty robisz coś nie tak.
A jeżeli nie chcesz całego pliku ładować do pamięci to skorzystaj z TFileStream i przesuwaj pozycję w strumieniu za pomocą Seek albo Position.

0

@John Pablo: kod @pelsta działa również ok, tylko numer ikony jest indeksowany od zera. Ja jednak przekombinowałem, bo myslałem, że jak pozycja TMemoryStrem będzie na zerze i rozmiar pozostały pamięc TMemoryStream będzie jeszcze nie ustawiona przez Position to ikony będą źle załadowany. Ale jednak sposób @pelsta jest bardziej optymalny i krótszy. A co do wczytywania z pliku zamiast do pamięci to tak, jak wspomniał @pelsta najlepiej będzie użyć TFileStream. Tylko i tak będziesz miał ikonki w pamięci, bo jak chcesz je wyświetlić na wielu Image albo załadować do TImageList, to zajmie to pamięć. A zauważ, że w naszych przykładowych kodach na końcu jest wywoływana metoda Free, która powinna zwolnić używaną pamięć i oczywiście to robi.

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