Двоичный файл с набором изображений

Previous  Top  Next

    
 

Автор: Ed Jordan

 

Может кто-либо обеспечить меня хорошим примером как сохранить множество изображений в единственном бинарном файле?

 

Хорошо, вот пример. Я не могу сказать что это лучшее решение, но это работает. Я надеюсь данный совет побудит моих читателей придумать более мудрое решение, коротое я потом и опубликую.

 

Данный пример помещает вашу запись в объект. Хотя это и не было строго необходимым, я сконфигурировал алгоритм имеенно так, потому что рано или поздно вы это сделаете... В качестве средства для чтения и записи он использует потоки. Возможно вы уже использовали потоки, поэтому моя технология не будет для вас открытием. Одно из преимуществ использования потока в том, что для работы с графическими объектами -- bitmap, icon, metafile -- можно использовать методы SaveToStream и LoadFromStream.

 

У меня была проблема с использованием LoadFromStream, и она была похожей на вашу. При вызове Graphic.LoadFromStream, графика "оставляла" позицию потока с самом его конце, а не в конце записи. Другими словами, если графический объект первый раз записывал себя в поток, данные заканчивались в позиции 247. Но когда графический объект "читал себя", он не останавливался в позиции 247, а читал себя из всего потока. Поэтому мог быть прочитан только один объект.

 

Мое решение проблемы заключается в установке позиции, на которой действительно заканчивается запись. Затем, после того как графический объект прочтет себя из потока, я снова перемещаю позицию, готовля тем самым поток для чтения следующего объекта. Эти детали делают реализацию объекта чуть сложнее. Вот и вот, код смотрите ниже.

 

Кое-то еще: я сделал объект, способным обрабатывать иконки, метафайлы, а также простые изображения. Не знаю, понадобиться ли вам это, и может быть я выбрал не самое элегантное решение...

Code:

unit Unit2;

 

interface

uses Graphics, Classes;

 

type

TAlbumRec = class

private

   FGraphic: TGraphic;

   FDescription: string; { ...Просто пример поля }

   FItemType: ShortInt;  { ...Просто пример поля }

   procedure SetGraphic(AGraphic: TGraphic);

public

   constructor Create;

   destructor Destroy; override;

   procedure LoadFromStream(Stream: TStream);

   procedure SaveToStream(Stream: TStream);

   property Graphic: TGraphic read FGraphic write SetGraphic;

   property Description: string read FDescription write FDescription;

   property ItemType: ShortInt read FItemType write FItemType;

end;

 

implementation

 

constructor TAlbumRec.Create;

begin

inherited Create;

end;

 

destructor TAlbumRec.Destroy;

begin

FGraphic.Free;

inherited Destroy;

end;

 

procedure TAlbumRec.LoadFromStream(Stream: TStream);

var

GraphicTypeCode: Char;

EndPosition: LongInt;

begin

{ Считываем в потоке позицию где заканчивается запись... }

Stream.Read(EndPosition, SizeOf(EndPosition));

 

{ Считываем в Delphi 1.0 строку... }

Stream.Read(FDescription[0], SizeOf(Byte));

Stream.Read(FDescription[1], Byte(FDescription[0]));

 

{ Читаем целое... }

Stream.Read(FItemType, SizeOf(FItemType));

 

{ Считываем код, сообщающий тип графического объекта,

который необходимо создать... }

Stream.Read(GraphicTypeCode, SizeOf(GraphicTypeCode));

 

{ Освобождаем текущий графический объект и пересоздаем его.. }

FGraphic.Free;

FGraphic := nil;

case GraphicTypeCode of

   'B': FGraphic := TBitmap.Create;

   'I': FGraphic := TIcon.Create;

   'M': FGraphic := TMetafile.Create;

end;

 

{ Загружаем из потока графику... }

if FGraphic <> nil then

   FGraphic.LoadFromStream(Stream);

 

{ Ищем в потоке конечную позицию для данной записи. Почему мы это делаем?

Я обнаружил это, когда графический объект читал себя из потока, и при этом

"оставлял" позицию потока с самом его конце, а не в конце записи. Поэтому

мог быть прочитан только один объект... }

Stream.Seek(EndPosition, 0);

end;

 

procedure TAlbumRec.SaveToStream(Stream: TStream);

var

GraphicTypeCode: Char;

StartPosition,

   EndPosition: LongInt;

begin

{ Запоминаем позицию потока для дальнейшей записи наших объектов... }

StartPosition := Stream.Position;

 

{ Здесь мы собираемся записать позицию где заканчиваются данные записи.

Мы пока не знаем как это позиционируется, поэтому пока записываем ноль

чтобы сохранить место... }

EndPosition := 0;

Stream.Write(EndPosition, SizeOf(EndPosition));

 

{ Записываем строку Delphi 1.0... }

Stream.Write(FDescription[0], SizeOf(Byte));

Stream.Write(FDescription[1], Byte(FDescription[0]));

 

{ Записываем целое... }

Stream.Write(FItemType, SizeOf(FItemType));

 

{ Записываем код, сообщающий тип графического объекта,

который мы собираемся писать... }

if (FGraphic = nil) or (FGraphic.Empty) then

   GraphicTypeCode := 'Z'

else if FGraphic is TBitmap then

   GraphicTypeCode := 'B'

else if FGraphic is TIcon then

   GraphicTypeCode := 'I'

else if FGraphic is TMetaFile then

   GraphicTypeCode := 'M';

Stream.Write(GraphicTypeCode, SizeOf(GraphicTypeCode));

 

{ Записываем графику... }

if (GraphicTypeCode <> 'Z') then

   FGraphic.SaveToStream(Stream);

 

{ Возвращаемся к месту откуда мы начинали и записываем

конечную позицию, которую мы сохранили... }

EndPosition := Stream.Position;

Stream.Seek(StartPosition, 0);

Stream.Write(EndPosition, SizeOf(EndPosition));

 

{ Возвращаем конечную позицию, после этого поток готов

для следующей записи... }

Stream.Seek(EndPosition, 0);

end;

 

procedure TAlbumRec.SetGraphic(AGraphic: TGraphic);

begin

FGraphic.Free;

FGraphic := nil;

if AGraphic <> nil then

begin

   FGraphic := TGraphic(AGraphic.ClassType.Create);

   FGraphic.Assign(AGraphic);

end;

end;

 

end.

 

 

©Drkb::03635

http://delphiworld.narod.ru/

DelphiWorld 6.0