Недавно добавленные исходники

•  DeLiKaTeS Tetris (Тетрис)  4 460

•  TDictionary Custom Sort  6 504

•  Fast Watermark Sources  6 290

•  3D Designer  9 236

•  Sik Screen Capture  6 624

•  Patch Maker  7 001

•  Айболит (remote control)  7 009

•  ListBox Drag & Drop  5 880

•  Доска для игры Реверси  97 112

•  Графические эффекты  7 209

•  Рисование по маске  6 510

•  Перетаскивание изображений  5 375

•  Canvas Drawing  5 748

•  Рисование Луны  5 457

•  Поворот изображения  4 987

•  Рисование стержней  3 541

•  Paint on Shape  2 810

•  Генератор кроссвордов  3 680

•  Головоломка Paletto  2 964

•  Теорема Монжа об окружностях  3 768

•  Пазл Numbrix  2 486

•  Заборы и коммивояжеры  3 169

•  Игра HIP  2 136

•  Игра Go (Го)  2 071

•  Симулятор лифта  2 441

•  Программа укладки плитки  2 116

•  Генератор лабиринта  2 591

•  Проверка числового ввода  2 265

•  HEX View  2 594

•  Физический маятник  2 208

 
скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



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



Автор: 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.