![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Сохранение произвольных данных с BitMap'ом
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]
писать размеры области, метки