Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Сохранение произвольных данных с BitMap'ом


Страницы:   1 2

RASkov ©   (2006-08-29 00:51:00) 

Здраствуйте. Подскажите как осуществить сохранение и потом (самое главное) загрузку такой вот структуры. Проблема с PICT. TData могу а PICT туда еще вписать не могу. Т.е. должно все в один файл записаться сначала данные Data а потом картинку из PICT. Что выделил жирным ясен пень неправильно - это я так для ясности написал.
Код ниже это только для примера у меня немного подругому но это неважно мне нужна суть как туда засунуть битмап и потом считать его. Можно даже както по байтам, что бы сохранить исходный формат. Картинка в основном маленького размера но может быть и приличная... но... думаю не более 200 кил. это если в *.bmp формате. При подключенном модуле JPEG, можно в переменную TBitMap загрузить jpg? Он наверное преобразовывается в формат bmp? Это не важно...

type TData = record
     Name: String[20];
     DInt: Integer;
     DBt: Byte;
     .....
    end;  
var Data: TData;
   PICT: TBitMap;

procedure TForm1.bbSaveClick(Sender: TObject);
var F: File;
begin
  if SvDlg.Execute then begin
   PICT:=TBitMap.Create;
   PICT.LoadFromFile('namefile');
   AssignFile(F, SvDlg.FileName);
   Rewrite(F,1);
   BlockWrite(F, Data.Name, SizeOf(Data.Name));
   BlockWrite(F, Data.DInt, SizeOf(Data.DInt));
   BlockWrite(F, Data.DBt, SizeOf(Data.DBt));
    BlockWrite(F, PICT, SizeOf(PICT));
  end;
end;

Собственно, приведите пожалуйста, пример сохранения а загрузку я думаю сам допру.


RASkov   (2006-09-03 15:02:00) [1]

> [36] kami ©   (02.09.06 10:50)

Да... Спасибо:)


kami   (2006-09-02 10:50:00) [2]

RASkov   (02.09.06 1:02) [35]
Там в [26] в алгоритме записи это было упущено

Нет, это не упущено.
Я имел ввиду конструкцию типа FS.CopyFrom(BmpFS, 0);. См.справку по TStream.CopyFrom.


RASkov   (2006-09-02 01:02:00) [3]

Кажись просек только что.

  SzBmp:=TBmpFS.Size;
  BmpFS.Position:=0;
 FS.WriteBuffer(SzBmp, SizeOf(SzBmp));
 FS.CopyFrom(BmpFS, SzBmp);


Там в [26] в алгоритме записи это было упущено...


RASkov   (2006-09-02 00:39:00) [4]

Часть метода сохранения, использую 3 способ предложенный [31] kami
procedure SaveDate(...
var FS, BmpFS: TStream; SzBmp: Integer;
............
  FS:=TFileStream.Create(SvDlg.FileName, fmCreate);
............
     BmpFS:=TMemoryStream.Create;
     try
     Dts[i].Bmp.SaveToStream(BmpFS);
     SzBmp:=BmpFS.Size;
     FS.WriteBuffer(SzBmp, SizeOf(SzBmp));
     FS.CopyFrom(BmpFS, SzBmp);
     finally
      BmpFS.Free;
     end;
.............

И вот на строке FS.CopyFrom(BmpFS, SzBmp);вылетает ошибка. Размер записываеться и следом ошибка "Stream read error" с выделением в редакторе кода этой строки. Что я не так делаю?


RASkov   (2006-08-31 03:05:00) [5]

> [31] kami ©   (31.08.06 00:48)

Спасибо. Будем пробывать.


kami   (2006-08-31 01:18:00) [6]

2 - извращения, но все же :

запись:
var
 TempPos:integer; {или если надо - int64}
begin
 // создаем FS, подготавливаем что-то еще
 // каким-то боком синтезируем общую картинку в PICT:TBitMap, вот только - зачем, ведь потом ее опять разрезать...
 FS.Write(TempPos, SizeOf(integer));// зарезервировали место под позицию, с которой начнется "глобальный" битмап
 // записываем DTS в FS :), в этом случае Wudth и Height поля будут нужны, иначе как потом разрезать?
 TempPos:=FS.Position;// запомнили позицию после записи всех полей из DTS. Именно отсюда в потоке начинаются
                      // данные PICT.
 Pict.SaveToStream(FS);
 FS.Position:=0;// предполагаем, что записывать данные мы начали с начала потока, а не где-то с середины
                // то есть изначально FS был пустой
 FS.Write(TempPos, SizeOf(integer));// и записали в начало потока указатель на начало данных для PICT
 FS.Free;
end;


Чтение:
  FS.Read(TempPos, SizeOf(integer));// прочитали, откуда начинаются данные для PICT
 FS.Position:=TempPos;// сместились туда
 PICT.LoadFromStream(FS);//прочитали картинку
 FS.Position:=SizeOf(integer);// опять на начало, пропуская указатель на данные PICT
 // читаем данные DTS
 FS.Free;  


kami   (2006-08-31 00:48:00) [7]

Используй 3.

Получится что-то типа следующего :

procedure SaveBitmapToStream(Bitmap:TBitMap; Stream:TStream);
begin
 // алгоритм записи из [26]
end;

procedure LoadBitmapFromStream(Bitmap:TBitMap; Stream:TStream);
begin
 // алгоритм чтения из [26]
end;

procedure SaveData(Data:TData; Stream:TStream);
begin
 // тут сохраняем все поля, кроме BMP
 // к стати, зачем хранить BmpWidth и BmpHeight - разве свойств TData.BMP не хватит?
 SaveBitmapToStream(Data.BMP, Stream);
end;

procedure LoadData(var Data:TData; Stream:TStream);
begin
 // читаем поля, кроме BMP
 LoadBitmapFromStream(Data.BMP, Stream);
end;

ну и, само применение :

var
 Dts:array of TData;
 DataCount, i:integer;
 FS:TFileStream;
begin
 FS:=TFileStream.Create(...);
 FS.Read(DataCount, SizeOf(integer));
 SetLength(Dts, DataCount);
 for i:=0 to DataCount-1 do
   begin
     Dts[i].BMP:=TBitMap.Create;
     LoadData(Dts[i], FS);
   end;
 FS.Free;
 // делаем с DataArray что нужно
end;


Ketmar   (2006-08-31 00:07:00) [8]

если переведёшь на русский, то, может, и ответят.


RASkov   (2006-08-30 22:15:00) [9]

Но мне интересен второй... можно ли так?


RASkov   (2006-08-30 22:14:00) [10]

Третий способ похоже описан  [26] kami ©   (30.08.06 15:05) но его я оставил как вариант.... И наверное так и надо или...


RASkov   (2006-08-30 22:11:00) [11]

Вот еще такой трабл есть. У меня картинка сохраняется после данных. И состоит из кучи мелких присутствующих или нет в элементах массива Т.е. при сохранении файла пробегаемся по массиву и соответственно пишем данные элемента и если содержит рисунок то добавляем его в общую картину и после того как записали данные и сгенерили картинку собственно ее и дописываем в файл. Вот... а при чтении нужно заполнять массив данными из начала файла и на их основе резать картинку на мелкие куски...но она (картинка) находится в конце как лучше поступить: У меня появились некоторые соображения типа:
1- открыть файл пробежаться до картинки считав все необходимые данные в массив, затем считали картику и опять с начала, только уже по массиву, брать данные и на их основе резать картинку и добавлять в соот. элемент
2- (можно ли так) при сохранении данных делать в принципе тоже самое как и в 1 только когда дело дойдет до записи собственно картинки, запомнить N:=FS.Position в переменной, сместить FS.Position:=0; записать эту переменную
FS.WriteBuffer(N, SizeOf(Int64));сместить назад FS.Position:=N+SizeOf(Int64);и записать саму картинку... ну и при чтении первым делом считываем позицию картинки грузим ее возвращаем FS.Position:=SizeOf(Int64);ну и с этого места за один проход все читаем и режем картинку.
3- при сохранении данных массива после очередного элемента писать мелкую картинку затем следующий элемент. И при чтении вопрос - как?... но тут еще и сомнения вызваны [21] kami ©   (30.08.06 00:17) P.S. где он говорил что при PICT.LoadFromStream(FS) FS.Positionбудет указывать на конец потока. Т.е. каким то другим способом читать такой файл где вперемешку идут данные и картинки?

P.S. У элемента массива может присутствовать а может и нет мелкая картинка. Массив описан так:

type TData = record
     BMP: TBitMap;
     IsBmp: Boolean;
     Name: String;
     Color: TColor;
     BmpWidth, BmpHeight: Integer;
  ........
    end;

var Dts: array of TData;


kami   (2006-08-30 15:05:00) [12]

Запись - такая же, как и чтение :

int:=Length(Edit1.text);
FS.Write(int, SizeOf(integer));
if int>0 then
 FS.Write(Edit1.Text [1], int);


К p.s. [21] :

Алгоритм записи без указанной особенности:
1. Создаем временный поток (например, TempStream : TMemoryStream)
2. Записываем в него битмап
3. Записываем в основной поток размер TempStream
4. Копируем в основной поток сам TempStream
5. Освобождаем TempStream.

Загрузка:
1. Читаем размер записанного битмапа (BmpSize)
2. Создаем временный поток
3. Копируем в него из основного потока BmpSize байт
4. Устанавливаем позицию временного потока в 0
5. Загружаем битмап из временного потока
6. Освобождаем TempStream


RASkov   (2006-08-30 14:11:00) [13]

> [21] kami ©   (30.08.06 00:17)

А... и вот еще... это Вы привели метод чтения строк а запись остается такой же как было у меня

S:=Edit1.Text; Int:=Length(S);
FS.WriteBuffer(Int, SizeOf(Int)); FS.WriteBuffer(S, Int);

P.S. var S: String;


RASkov   (2006-08-30 13:36:00) [14]

т.е. это было для [21] к части P.S.


RASkov   (2006-08-30 13:34:00) [15]

> [22] kami ©   (30.08.06 00:25)

Спасибо. Т.е. я так понимаю, что свои данные нужно писать первыми, а картинку последней? Кстати я вот уже думал что будет если записать кусок своих данных потом картинку потом еще своих данных.... т.е. такая фигня не прокатит? так?


kami   (2006-08-30 00:25:00) [16]

RASkov   (29.08.06 0:51)
При подключенном модуле JPEG, можно в переменную TBitMap загрузить jpg?


//сохраняем
if SaveDialog1.Execute then begin
.........
jpg.Assign(PICT);
jpg.SaveToStream(fs);
.........
end;

// загружаем
if OpenDialog1.Execute then begin
.......
jpg.LoadFromStream(FS);
PICT.Assign(jpg);
.......
end;


Само собой, не забыть своевременно уничтожить jpg и PICT :)


kami   (2006-08-30 00:17:00) [17]

а если мне понадобиться просто String
FS.Read(int, SizeOf(integer));
SetLength(s,int);// если с string, а не string[xx]
if i>0 then
 FS.Read(s[1], int);


P.S. Если после битмапа должны быть записаны (и считаны впоследствии) еще данные, то учти, что после PICT.LoadFromStream(FS)  fs.positionбудет указывать на конец потока.


RASkov   (2006-08-29 23:54:00) [18]

Блин... код выделить неуспел...


RASkov   (2006-08-29 23:53:00) [19]

В первую очередь попробовал по совету Кетмара... ну понятней как то у него.. и... получилось, довольно не плохо для моей проги (прога собственно относится к безделушкам, я на ней просто пытаюсь кое в чем разобраться) и вот как сделал:

procedure TForm1.bbSaveClick(Sender: TObject);
var FS: TStream; PICT: TBitMap; S: String[20]; Int: Integer; F: Boolean;
begin
 if SaveDialog1.Execute then begin
  PICT:=TBitMap.Create;
  try FS:=TFileStream.Create(SaveDialog1.FileName, fmCreate);
  try PICT.LoadFromFile(OpenPictureDialog1.FileName);   //здесь это нормально
  S:=Edit1.Text;                     FS.WriteBuffer(S, SizeOf(S));
  S:=Edit2.Text;                     FS.WriteBuffer(S, SizeOf(S));
  S:=Edit3.Text;                     FS.WriteBuffer(S, SizeOf(S));
  Int:=StrToIntDef(Edit4.Text, 100); FS.WriteBuffer(Int, SizeOf(Integer));
  F:=CheckBox1.Checked;              FS.WriteBuffer(F, SizeOf(F));
  PICT.SaveToStream(FS);
  finally FS.Free; end; finally PICT.Free; end;
 end;
end;

procedure TForm1.bbLoadClick(Sender: TObject);
var FS: TStream; PICT: TBitMap; S: String[20]; Int: Integer; F: Boolean;
begin
 if OpenDialog1.Execute then begin
  PICT:=TBitMap.Create;
  try FS:=TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
  try
  FS.ReadBuffer(S, SizeOf(S));         Edit1.Text:=S;
  FS.ReadBuffer(S, SizeOf(S));         Edit2.Text:=S;
  FS.ReadBuffer(S, SizeOf(S));         Edit3.Text:=S;
  FS.ReadBuffer(Int, SizeOf(Integer)); Edit4.Text:=IntToStr(Int);
  FS.ReadBuffer(F, SizeOf(F));         CheckBox1.Checked:=F;
  PICT.LoadFromStream(FS);
  Image1.Picture.Assign(PICT);
  finally FS.Free; end; finally PICT.Free; end;
 end;
end;

Это просто обучающий для меня пример, мною проверенный - работает. Может блоки try раставлены не оптимально... не в этом суть.

Суть.. т.е. вопрос вот в чем переменная S в обоих методах описана как String[20]; а если мне понадобиться просто String - как быть? или тут уже нужно код от Pavia применять? Я пытался так:
запись
procedure TForm1.bbSaveClick(Sender: TObject);
var FS: TStream; PICT: TBitMap; S: String; Int: Integer; F: Boolean;
begin
 if SaveDialog1.Execute then begin
.........
 S:=Edit1.Text; Int:=Length(S);
 FS.WriteBuffer(Int, SizeOf(Int)); FS.WriteBuffer(S, Int);
 S:=Edit2.Text; Int:=Length(S);
 FS.WriteBuffer(Int, SizeOf(Int)); FS.WriteBuffer(S, Int);
.........
end;

чтение
var FS: TStream; PICT: TBitMap; S: String; Int: Integer; F: Boolean;
begin
 if OpenDialog1.Execute then begin
.........
 FS.ReadBuffer(Int, SizeOf(Integer)); FS.ReadBuffer(S, Int);
 Edit1.Text:=S;
.........
end;
Не работает. Почему?
Много слышал про "косяки" String'ов... это он самый?
СПАСИБО.


Gydvin   (2006-08-29 11:08:00) [20]


> RASkov   (29.08.06 01:12) [10]

писать размеры области, метки


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо