Перейти к содержанию
Fire Monkey от А до Я
  • 0

Передача изображения в потоке


zekelive

Вопрос

Добрый день товарищи. Вчера столкнулся с такой проблемой, не могу отправить изображение в стрим. Ошибка: stream write error. 

 

var

 ms:tStream;
Temp:tBitmap;
begin
  Temp: TBitmap;
  begin
Temp := TBitmap.Create;
Temp.Assign(Circle1.Fill.Bitmap.Bitmap);
 MS := TMemoryStream.Create;
Temp.SaveToStream(MS);   //где то на этом моменте происходит ошибка
MS.Position := 0;
ms.Free;

 

Подскажите, что не так?

Ссылка на комментарий

Рекомендуемые сообщения

  • 0
function SaveBitmapToStream(const AStream: TStream; const Bitmap: TBitmap; const Extension: string;
  SaveParams: PBitmapCodecSaveParams = nil): Boolean;
var
  surf: TBitmapSurface;
begin
  Result := False;
  surf:= TBitmapSurface.Create;
  surf.Assign(Bitmap);
  try
    Result := TBitmapCodecManager.SaveToStream(AStream, surf, Extension, SaveParams);
  finally
    surf.Free;
  end;
end;

ну и вызывать типа так:

var
  tmpBitmap  : FMX.Graphics.TBitmap;
  SaveParams : FMX.Graphics.TBitmapCodecSaveParams;
  Stream     : TMemoryStream;
// .....
tmpBitmap := TBitmap.Create;
// ..............
Stream := TMemoryStream.Create;
try
  SaveParams.Quality := 85;
  SaveBitmapToStream(Stream, tmpBitmap, '.jpg', @SaveParams);
  Stream.Position := 0;
  // ....................
  // ....................
finally
  FreeAndNil(Stream);
end;
Ссылка на комментарий
  • 0

Никак не могу справится с задачей. Расскажу все как есть. Имеется клиентское (мобильное) приложение для Андроид. И серверная часть на ПК (VCL). Связь между ними при помощи DataSnap. Смысл в том, чтобы передать картинку из клиентской части на сервер, а затем записаться в БД. Собственно, как это выглядит:

Клиент:

varTemp: TBitmap;

begin
Temp := TBitmap.Create;
Temp.Assign(Circle1.Fill.Bitmap.Bitmap);
MS := TMemoryStream.Create;
Temp.SaveToStream(MS);
MS.Position := 0;

ms.Free;

Код ошибку не выдает. Но при этом, ничего не происходит.

 

Сервер: 

 MS := TMemoryStream.Create;
  MS.Position := 0;
  ADOQuery.SQL.Clear;
  ADOQuery.SQL.Text :='UPDATE Users SET Фото=:Foto WHERE Сериал=:id';
  ADOQuery.Parameters.ParamByName('id').Value :='760e2c20';
  ADOQuery.Parameters.ParamByName('Foto').LoadFromStream(MS, ftBlob);
  ADOQuery.ExecSQL;
  Form2.Image1.Picture.Bitmap.LoadFromStream(ms);

Тут тоже тишина. Картинка в Image не грузится. Не пойму почему. Сама функция на сервере выглядит так:

function TServerMethods1.foto(ms,jpeg: TMemoryStream; a,b:string): String;

Вопрос:

Нужно ли создавать снова объект Stream, на стороне сервера? не обнуляет ли он данные с клиента. Проверял код чисто на стороне сервера (все работает!). И загрузка и чтение.

Выкладываю чистый код, на котором проверял работу на стороне сервера:

Загрузка:

if OpenPictureDialog1.Execute(Handle) = True then
  begin
      Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
      MyJpeg := TJpegImage.Create;
      MyJpeg.Assign(Image1.Picture);
      // MyJpeg.CompressionQuality := 90;
      // MyJpeg.Compress;
      MS := TMemoryStream.Create;
      MyJpeg.SaveToStream(MS);
      MS.Position := 0;


      ADOQuery1.SQL.Clear;
      ADOQuery1.SQL.Text :='UPDATE Users SET Фото=:Foto WHERE Сериал=:id';
      ADOQuery1.Parameters.ParamByName('id').Value :='760e2c20';
      ADOQuery1.Parameters.ParamByName('Foto').LoadFromStream(MS, ftBlob);
      ADOQuery1.ExecSQL;


      MS.Position := 0;
      Image1.Picture.Assign(MyJpeg);
      MS.Free;
      MyJpeg.Free;
  end;

Чтение:

var
  Ss : TStringStream;
  St : string;
  jpg: TJpegImage;
begin
  AdoQuery2 .SQL.Text := 'select * from users where сериал=:id';
  ADOQuery2.Parameters.ParamByName('id').Value :='760e2c20';
  AdoQuery2.Open;
  st := AdoQuery2.FieldByName('Фото').AsString;
  Ss := TStringStream.Create(st);
  if Ss.Size > 0 then begin
  //  if AdoQuery2.FieldValues['Typ'] = 1 then begin
      jpg := TJpegImage.Create;
      jpg.LoadFromStream(Ss);
      Image2.Picture.Assign(jpg);
      jpg.Free;
  //  end;
//    if AdoQuery2.FieldValues[TypN] = 0 then
  //    Image2.Picture.Bitmap.LoadFromStream(Ss)
  end;
  Ss.Free;
  AdoQuery2.Close;
//  AdoQuery2.Transaction.Commit;

Если у кого был опыт работы с потоками и DataSnape, прошу отзовитесь) Спасибо.

Изменено пользователем zekelive
Ссылка на комментарий
  • 0

Ну я бы не стал использовать лишние операции в данном случае.

MS := TMemoryStream.Create;
try
  Circle1.Fill.Bitmap.Bitmap.SaveToStream(MS);
finally
  MS.Free;
end;

а на серверной стороне

Form2.Image1.Picture.Bitmap.LoadFromStream(ms);

что-то грузит?

 

и еще

Circle1.Fill.Bitmap.Bitmap.SaveToStream(MS);

в этот момент ничего с интерфейсом происходить не может случаем?

может стот сделать что-то типа

Circle1.BeginUpdate и Circle1.EndUpdate ?

или заключить все в

TThread.Synchronize(TThread.CurrentThread, procedure
begin
  MS := TMemoryStream.Create;
  try
    Circle1.Fill.Bitmap.Bitmap.SaveToStream(MS);
  finally
    MS.Free;
  end;
end);
Ссылка на комментарий
  • 0
Circle1.Fill.Bitmap.Bitmap.SaveToStream(MS);

При такой команде, тоже ничего не происходит. Точнее можно сказать, непонятно, происходит что или нет.

TThread.Synchronize(TThread.CurrentThread, procedure
begin
  MS := TMemoryStream.Create;
  try
    Circle1.Fill.Bitmap.Bitmap.SaveToStream(MS);
  finally
    MS.Free;
  end;
end);

В данном случае получается, что мы посылаем команду в отдельном потоке? Если да, то как правильно это оформить на стороне клиента? 

Изменено пользователем zekelive
Ссылка на комментарий
  • 0

Как раз не в отдельном, а наоборот - синхронизируем операцию с GUI с основным потоком.

Ну и еще:

просто надо бы тупо проверить - вывести изображение в тот же файл, локально, из Circle1.Fill.Bitmap.Bitmap.

операциями типа Circle1.Fill.Bitmap.Bitmap.SaveToFile и еще попробовать сохранить поток тоже в локальный файл.

ну и посмотреть содержимое. А то как-то все не понятно...

Ссылка на комментарий
  • 0

Аналогичная проблема возникла. Наткнулся на эту тему и решил свою проблему )

Вот таким кодом.

var
  MS: TMemoryStream;
  Bitmap: TBitmap;
...
TThread.Synchronize(TThread.CurrentThread, procedure
begin
  Bitmap.LoadFromStream(MS);
end);
Ссылка на комментарий
  • 0

Не знаю как на XE8, но на XE10 (на стороне получателя Datasnap либо Android) спасает пропуск полученной в стриме картинки через следующую процедуру:

procedure CopyStreamToMemoryStream(const ASource: TStream; var ADest: TMemoryStream; const Rewind: Boolean = True);
const
  LBufSize = $F000;
var
  LBuffer: PByte;
  LReadCount: Integer;
begin
  GetMem(LBuffer, LBufSize);
  ADest.Clear;
  try
    repeat
      LReadCount := ASource.Read(LBuffer^, LBufSize);
      if LReadCount > 0 then
        ADest.WriteBuffer(LBuffer^, LReadCount);
    until LReadCount < LBufSize;
  finally
    FreeMem(LBuffer, LBufSize);
  end;
  if Rewind then
    ADest.Seek(0, TSeekOrigin.soBeginning);
end;

взято отсюда http://codeverge.com/embarcadero.datasnap/howto-send-huge-data-via-datasnap/1095276

Ссылка на комментарий
  • 0

Добрый день, друзья. Снова обращаюсь к Вашей помощи) В потоке создаю вторую форму и компоненты на ней. Все работает с одним НО! Когда создаю TImage и загружаю в него изображение из удаленной БД, то поток своего рода зависает на моменте загрузки фото из БД. Если я закомментирую строчку с загрузкой картинки, то все работает отлично. Выше приведенные способы не помогают. Может взглянув на код, появятся мысли.

 
procedure LoadProcess.Execute;
  begin
  Application.CreateForm(TForm2, Form2);
  imgcount:=ClientModule2.ServerMethods1Client.CountMainPhoto(a,;
  Stream := TMemoryStream.Create;

  if(imgcount<>'') and (imgcount<>'0')
  then
  begin
  for i:=1 to StrToInt(imgcount) do
  begin
  a:=IntToStr(i);
  url:=ClientModule2.ServerMethods1Client.LoadMainPhoto(a,;
  http:=TIdHttp.Create(Form1);
  HTTP.Get(URL, Stream);
  Stream.Position := 0;

  with img do
  begin
  img:=TImage.Create(Form2);
  Parent:=Form2.ScrollBox2;
  Align:=TAlignLayout(1);
  MarginWrapMode:=TImageWrapMode(2);
  WrapMode:=TImageWrapMode(2);
  //Bitmap.LoadFromStream(stream);           //Собственно проблемная строчка
  size.Height:=240;
  //OnTap:=Form2.ImgClick;
  name:='img'+IntToSTr(i);
  end;

  with lab do
  begin
  lab:=TLabel.Create(Form1);
  Parent:=img;
  Align:=TalignLayout(4);
  margins.Bottom:=30;
  FontColor:=TAlphaColors.Black;
  DefaultTextSettings.Font.Size:=30;
  Font.Size:=30;
  DefaultTextSettings.Font.Family:='RobotoThin';
  TextSettings.HorzAlign:=TTextAlign(0);
  a:=IntToStr(i);
  Text:=ClientModule2.ServerMethods1Client.LoadPhotoName(a,;;
  end;
  end;
  end;

  Form2.TabControl1.ActiveTab:=Form2.MainTab;
  Form1.Hide;
  Form2.Show;
  LoadPhoto.Free
  end; 
Ссылка на комментарий
  • 0

Обсуждали уже это. TBitmap "потоконебезопасный" в FMX (в VCL с этим намного лучше). Нельзя использовать TBitmap в потоке, используйте Syncronyse . Сам обжегся об это.

Ссылка на комментарий
  • 0

оно и будет зависать если большую картинку будешь обрабатывать в основном потоке. она же в простой Bitmap разжимается. при этом ты в цикле кучу их создаешь. хочешь что бы не висло уменьшай размеры картинок и свой цикл sleep ставь что бы поток притормаживал работу. 

Изменено пользователем haword
Ссылка на комментарий
  • 0
  • Модераторы

Нельзя создавать визуальные объекты в доп. потоке

Изменено пользователем ZuBy
Ссылка на комментарий
  • 0
  • Модераторы

кто сказал :) я правда не пробовал но через синхронизацию управлять ими менять им видимость очищать их получается без проблем. 

почитайте любую книжку или статью связанную с потоками

Ссылка на комментарий
  • 0
  • Модераторы

fmx это самопал со своими компонентами так что может и прокатить если создавать в синхронизированном потоке.

когда не сможете отловить баг, вспомните что вы создаете в доп. потоке компоненты. :ph34r:

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...