Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.09.24;
Скачать: CL | DM;

Вниз

Сохранение произвольных данных с BitMap ом   Найти похожие ветки 

 
RASkov   (2006-08-29 00:51) [0]

Здраствуйте. Подскажите как осуществить сохранение и потом (самое главное) загрузку такой вот структуры. Проблема с 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;

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


 
Pavia ©   (2006-08-29 00:55) [1]

CloseFile(f);
Or Flush(f);


 
Zeqfreed ©   (2006-08-29 00:57) [2]

Самое простое сохранять битмап в стрим и стрим писать в файл.
См. TStream, TBitmap.SaveToStream.


 
RASkov   (2006-08-29 00:59) [3]

> [2] Zeqfreed ©   (29.08.06 00:57)

Можно поподробней. Со Стримами так мало работал...
Как Стрим с Битмапом дописать в мой файл и... потом его оттуда загрузить..ну это потом.


 
Pavia ©   (2006-08-29 01:01) [4]

Зачем TBitmap сохронять.
Открой файл и запиши его через
AssignFile(f1,"name");
reset(f1);
GetMem(buf,SizeOf(f1));
BlockRead(f1,buf^,SizeOf(f1));
BlockWrite(f,buf^,SizeOf(f1));
FreeMem(buf);
CloseFile(f1)


 
Ketmar ©   (2006-08-29 01:03) [5]

> [4] Pavia ©   (29.08.06 01:01)
это что такое???


 
Ketmar ©   (2006-08-29 01:04) [6]

fs := TFileStream.Create("outfile", fmCreate);
fs.WriteBuffer(data, SizeOf(data)); // или ещё как
pict.SaveToStream(fs);
fs.Free();


как упражнение -- расставить в нужных местах try/finally. %-)


 
RASkov   (2006-08-29 01:06) [7]

> [4] Pavia ©   (29.08.06 01:01)

Блин, хитро... f1 - это файл с картинкой, а f мой, так?
Попробую,... а Reset(f1) не надо так делать Reset(f1,1);?
И наверное перед BlockWrite(f,buf^,SizeOf(f1)); надо записать сам размер SizeOf(f1) ну для того что бы считать потом из моего файла. Правильно мыслю?


 
RASkov   (2006-08-29 01:09) [8]

> [6] Ketmar ©   (29.08.06 01:04)

Блин... еще хитрей да и проще вроде.
pict.SaveToStream(fs); оно допишется после моих данных?
И ... щед... здесь неуказываються размеры, а как потом читать?


 
RASkov   (2006-08-29 01:10) [9]

> [6] Ketmar ©   (29.08.06 01:04)

Ну с Data я, грубо, разберусь...


 
RASkov   (2006-08-29 01:12) [10]

> [9] RASkov   (29.08.06 01:10)

А Pict как помом вычитать, отделить от моих данных, или.. если данные пишутся первыми то считав их, останеться Pict... так? что ли...


 
Ketmar ©   (2006-08-29 01:13) [11]

> [8] RASkov   (29.08.06 01:09)
а так и читать: ReadFromStream(). проверять реализацию лень, но не вижу, отчего бы ему не работать. %-)


 
Ketmar ©   (2006-08-29 01:13) [12]

> [10] RASkov   (29.08.06 01:12)
да.


 
Pavia ©   (2006-08-29 01:13) [13]


> RASkov   (29.08.06 01:06) [7]

Да все верно.
Reset(f1,1) - не обязательно.
Я потоки не люблю больно криво сделанны. По этому предпочитаю, по старинки.


 
RASkov   (2006-08-29 01:16) [14]

> [6] Ketmar ©   (29.08.06 01:04)

try finally то я расставлю...
Спасибо. Остается только попробывать...


 
RASkov   (2006-08-29 01:17) [15]

> [13] Pavia ©   (29.08.06 01:13)

Спасибо.
Криво так криво, я и так попробую и так, а там... может че и получится.
Спасибо Pavia и Ketmar.


 
Ketmar ©   (2006-08-29 01:29) [16]

> [13] Pavia ©   (29.08.06 01:13)
> Я потоки не люблю больно криво сделанны
обосновать. или не врать.


 
Ketmar ©   (2006-08-29 01:30) [17]

> [15] RASkov   (29.08.06 01:17)
используй потоки и не занимайся ерундой. %-)


 
Gydvin ©   (2006-08-29 11:08) [18]


> RASkov   (29.08.06 01:12) [10]

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


 
RASkov   (2006-08-29 23:53) [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"ов... это он самый?
СПАСИБО.


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

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


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

а если мне понадобиться просто 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 будет указывать на конец потока.


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

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 :)


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

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

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


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

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


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

> [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;


 
kami ©   (2006-08-30 15:05) [26]

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

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 22:11) [27]

Вот еще такой трабл есть. У меня картинка сохраняется после данных. И состоит из кучи мелких присутствующих или нет в элементах массива Т.е. при сохранении файла пробегаемся по массиву и соответственно пишем данные элемента и если содержит рисунок то добавляем его в общую картину и после того как записали данные и сгенерили картинку собственно ее и дописываем в файл. Вот... а при чтении нужно заполнять массив данными из начала файла и на их основе резать картинку на мелкие куски...но она (картинка) находится в конце как лучше поступить: У меня появились некоторые соображения типа:
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;


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

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


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

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


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

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


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

Используй 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;


 
kami ©   (2006-08-31 01:18) [32]

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;  


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

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

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


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

Часть метода сохранения, использую 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-09-02 01:02) [35]

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

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


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


 
kami ©   (2006-09-02 10:50) [36]

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

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


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

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

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



Страницы: 1 вся ветка

Текущий архив: 2006.09.24;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.034 c
2-1157266289
Mozgan
2006-09-03 10:51
2006.09.24
Числа


15-1157202905
Копир
2006-09-02 17:15
2006.09.24
С Днём Рождения, Москва! Почти 860 лет!


15-1157186344
Vlad
2006-09-02 12:39
2006.09.24
Wi-Fi точки доступа


2-1157266025
Mozgan
2006-09-03 10:47
2006.09.24
Случайные числа


2-1157221445
Mops
2006-09-02 22:24
2006.09.24
Перетаскивание GroupBox