Delphi World - Двоичный файл с набором изображений
Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Двоичный файл с набором изображений

Автор: Ed Jordan

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

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

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

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

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

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


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.

Проект Delphi World © Выпуск 2002 - 2017
Автор проекта: Эксклюзивные курсы программирования