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

[Win] [FMX] Создать Bitmap, имея в памяти массив Byte


Вячеслав

Вопрос

Всем добрый день! Написал я тут для своих нужд на Делфи оболочку для работы с SDK для камер PSEye. Примеры были на C++ и С#. Почти все работает, подключает несколько камер, 60fps при VGA-разрешении выдает влёгкую. Но реализацию пришлось делать через VCL.Graphics.TBitmap, а не через фаирманковский. Отчего VCL проект работает шустрее, чем FMX.

Данные с камеры я получаю в виде области памяти, имею указатель на начало и размер области (массив Byte, грубо говоря).

В VCL получение битмапа реализовал через WinAPI функцию GetDIBits, создав предварительно свой заголовок (TBITMAPINFOHEADER).

Хотелось бы узнать, можно ли в FMX как-то напрямую работать с памятью, занимаемой изображением? Где почитать про структуру FMX.Graphics.TBitmap?

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

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

  • 0
  • Администраторы

Еще есть специальный класс для работы с буфером изображения TBitmapSurface. Вы можете указать требуемые параметры и загрузить в него ваш буфер. Конвертация TBitmapSurface <-> TBitmap идет через метод Assign.

Bitmap.Assign(BitmapSurface)
Ссылка на комментарий
  • 0

Спасибо за ответы! Заглянул в исходники, в assign(bitmapSurface) тоже в конечном итоге все через Map/Unmap, плюс я не понял, как моему экземпляру TBitmapSurface задать значение Bits (свойство только для чтения, поле FBits недоступно, что и понятно). Еще поковыряюсь, чувствую, что уже скоро получу адекватный результат.

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

Я не понял, как моему экземпляру TBitmapSurface задать значение Bits (свойство только для чтения, поле FBits недоступно, что и понятно)

 

Командой Move

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

Почти заработало. Вот код:

function TCamPSEye.GetFMXBitmap: FMX.Graphics.TBitmap;
var
  bitdata: TBitmapData;
begin
  if not CLEyeCameraGetFrame(fInstance, fData, 750) then
  begin
    raise Exception.Create('Can not get image data');
    Exit;
  end;
  Result := FMX.Graphics.TBitmap.Create;
  Result.SetSize(Resolution.X, Resolution.Y);
  //Result.
  if (Result.Map(TMapAccess.Write, bitdata)) then
    try
      Move(fData^, bitdata.Data^, Resolution.X * Resolution.Y * 4)
    finally
      Result.Unmap(bitdata);
    end;
end;

На выходе получается битмап с данными камеры, который прекрасно сохраняется на диск. А вот в TImage почему-то я его вывести не могу, появляется белая картинка. Вывожу так:

procedure TFormMulticam.Button1Click(Sender: TObject);
var
  bmp: FMX.Graphics.TBitmap;
begin
  bmp := GCameraArray[0].GetFMXBitmap;
  bmp.SaveToFile('test2FMX.bmp');
  Image1.Bitmap.Assign(bmp);
  bmp.Free;
end;

Может, при создании битмапа нужно указывать какие-либо дополнительные атрибуты?

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

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

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

Что-то не то у меня с выводом в Image, возможно какие-то проблемы с PixelFormat. Попытался отвязаться от камеры и заполнить данные изображения каким-либо незамысловатым образом:

function TCamPSEye.GetFMXBitmap: FMX.Graphics.TBitmap;
var
  bitdata: TBitmapData;
  i, j: Integer;
begin
  Result := FMX.Graphics.TBitmap.Create;
  Result.SetSize(640, 480);
  if (Result.Map(TMapAccess.Write, bitdata)) then
    try
        for I := 0 to 640 - 1 do
          for j := 0 to 480 - 1 do
            begin
              bitdata.SetPixel(i, j, i * j);
            end;
    finally
      Result.Unmap(bitdata);
    end;
end; 

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

 

test3FMX.bmp

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

А в битмапдате нет случаем настройки pixelformat? Указать нужно 24бит,если есть такая возможность

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

В файл картинка сохраняется нормально. Пытаюсь сохранить в поток и загрузить потом из потока - не работает. Такое ощущение, что на этапе сохранения в файл изображение проходит через процедуру дополнительной проверки и каким-то образом преобразуется. 

Как Вы работали с потоком? Использовали TBitmapCodecManager.SaveToStream и указывали расширение .bmp?

У меня такой код правильно отображает Ваш тестовый test3FMX.bmp:

procedure TFormMulticam.Button1Click(Sender: TObject);
var
  bmp: FMX.Graphics.TBitmap;
  aSurf:       TBitmapSurface;
  aMemStream:  TMemoryStream;
begin
  bmp := GCameraArray[0].GetFMXBitmap;

  aMemStream := TMemoryStream.Create();
  try
    aSurf := TBitmapSurface.Create();
    try
      aSurf.Assign(bmp);
      TBitmapCodecManager.SaveToStream(aMemStream, aSurf, '.bmp');
      Image1.Bitmap.LoadFromStream(aMemStream);
    finally
      FreeAndNil(aSurf);
    end;
  finally
    FreeAndNil(aMemStream);
  end;  
  //Image1.Bitmap.Assign(bmp);
  bmp.Free;
end;

Пока не указано явно, что TBitmap имеет формат BMP, TImage в FMX работает с ним как с PNG.

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

Большое спасибо, этот метод работает, многое стало ясно. Правда, для меня это все равно не решение, т.к. в случае создания дополнительного потока только для пересохранения изображения в другом формате я получаю абсолютно такую же реализацию, как и с применением WinAPI и Vcl.Graphics.TBitmap. А это будет влиять на производительность, что в моем случае критично. 

Поэтому у меня такой вопрос: нельзя ли заставить TImage сразу воспринимать изображение в формате BMP?

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

Все, окончательно осознал механизм работы, теперь все стало на свои места. Все дело в том, что моя камера выдает данные в формате AARRGGBB, только вот значение старших двух бит равно $00, а не $FF. Поэтому картинка и воспринимается прозрачной для TImage. В итоге пробежался в цикле по памяти, поменял нули на $FF и все заработало. 

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

У меня такие же вопросы возникли и чего-то оно не пашет.

BitmapSurface создаю указывая пикселформат RGB, т.е. 3 байта.

Однако

    bitmap->Assign(BitmapSurface );

    bitmap->BytesPerPixel;

показывает число 4.. ну и на имадж ерунда выводится.
Собственно, от пикселформат нет никакой зависимости, разве что совсем не тот формат (в смысле бит на пиксель).

Насчет 4 байт - ну тут ясно, что округление до 8/16/32/64.. это английским по белому пишется. И что, никаких возможностей 24 бита считать?

 

Я на делфи переношу проект из-под VS - там они прям 24 бита поднимают.

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

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

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

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

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

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

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

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

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

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

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