• 0
Камышев Александр

Сглаживание при рисовании в буфер bitmap

Вопросы

в разделе Антиалиасинг обсуждалось присвоение свойству Quality формы HighQuality и рисование на канве.

если рисовать сразу к примеру в PaintBox или на канву формы, то это работает.

по опыту GDI, стандартно отрисовывают буфер, а уже его копируют на канву визуальных компонентов.

 

по коду, буфер:

bmp_buf = new TBitmap();bmp_buf->Width = window_rect.Width();
bmp_buf->Height = window_rect.Height();

рисование:

TPathData *pd = new TPathData;

pd->MoveTo( Point( 100, 100 ) );
pd->LineTo( Point( 150, 100 ) );
pd->LineTo( Point( 100, 150 ) );

bmp_buf->Canvas->Stroke->Thickness = 5;
bmp_buf->Canvas->Stroke->Kind = TBrushKind::Solid;
bmp_buf->Canvas->Stroke->Dash = TStrokeDash::Solid;
bmp_buf->Canvas->Stroke->Color = (TAlphaColor)TAlphaColorRec::Black;

bmp_buf->Canvas->DrawPath( pd, 1 );

delete pd;

на OnPaint копирование буфера:

pbMap->Canvas->BeginScene();pbMap->Canvas->DrawBitmap( bmp_buf, bmp_rect, window_rect, 1, false );
pbMap->Canvas->EndScene();

в результате все быстро, без морганий, но антиалиасинга нет.

у канвы буфера bmp_buf есть свойство Quality: 
__property TCanvasQuality Quality = {read=FQuality, nodefault}; - только чтение

принимает значения:

enum class DECLSPEC_DENUM TCanvasQuality : unsigned int { ccSystemDefault, ccHighPerformance, ccHighQuality };

по умолчанию ccSystemDefault

 
вот как бы и вопрос, как создать буферный TBitmap с TCanvas, у которого Quality == ccHighQuality?
возможно есть другие варианты рисовать ломаные линии с антиалиасинг?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 ответов на этот вопрос

  • 0

В общем для битмапа нельзя установить качество.

Могу вам предложить только дежурный вариант. Открываете файл FMX.Graphics.pas и находите метод TBitmap.GetCanvas (ориентировочно 3621 строка):

function TBitmap.GetCanvas: TCanvas;
begin
  if FCanvas = nil then
  begin
    CopyToNewReference;
    FCanvas := CanvasClass.CreateFromBitmap(Self);
  end;
  Result := FCanvas;
end;

И там можете добавить вторым параметром в CreateFromBitmap качество:

function TBitmap.GetCanvas: TCanvas;
begin
  if FCanvas = nil then
  begin
    CopyToNewReference;
    FCanvas := CanvasClass.CreateFromBitmap(Self, TCanvasQuality.HighQuality);
  end;
  Result := FCanvas;
end;

Но имейте в виду, что это будет работать сразу для всех битмапов.

 

После добавить исправленный юнит в проект.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

сори не написал, под андроид пишу приложение с графикой, канва FMX

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Так, прежде, чем читать мое сообщение выше, есть еще другой легальный способ. Создать канву из битмапа:

MyCanvas := TCanvasManager.CreateFromBitmap(Bitmap, quality);

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

протестировал 3 варианта:

1. правка FMX.Graphics.pas как указано выше

2. пишу на с++, можно исправить файл FMX.Graphics.hpp

 заменить код 

__property TCanvasQuality Quality = {read=FQuality, nodefault};

на 

__property TCanvasQuality Quality = {read=FQuality, write=FQuality, nodefault};

после этого можно 

bmp_buf->Canvas->Quality = TCanvasQuality::HighQuality;

3. Создать новую канву как указано выше

TCanvas *MyCanvas = TCanvasManager::CreateFromBitmap( bmp_buf, TCanvasQuality::HighQuality );

во всех трех случаях свойство Quality под debug имеет значение HighQuality, проверял перед DrawPath:

bool b = MyCanvas->Quality == TCanvasQuality::HighQuality;

и во всех вариантах эффекта не было... :(

неспроста Quality для формы нужно ставить в design-time

что происходит при сборке, из-чего включается антиалиасинг?

.

Изменено пользователем Камышев Александр

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

искал информацию по теме, необязательно Quality для формы устанавливать в design-time, в FormCreate срабатывает 

Quality = TCanvasQuality::HighQuality;
RecreateCanvas();
Invalidate();

по нажатию кнопки этот код не дает эффекта

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

А решение для битмапа внутри стиля так и не существует?

http://fire-monkey.ru/topic/1047-smoothing-dlia-izobrazheniia-iz-stilia/

Изменено пользователем POV

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

А решение для битмапа внутри стиля так и не существует?

http://fire-monkey.ru/topic/1047-smoothing-dlia-izobrazheniia-iz-stilia/

для этого придумали Scale

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

для этого придумали Scale

 

 

 

 

Мммм, а подробнее? Что за scale и как он относится к качестве перемесштабированного растра?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

 

для этого придумали Scale

 

 

 

 

Мммм, а подробнее? Что за scale и как он относится к качестве перемесштабированного растра?

 

напрямую относится, подробней тут

грузить картинку нужно самому в соответствии скейла или хотя бы подготовить

Изменено пользователем ZuBy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Вижу, понимаю.. Согласен, что это поможет. Хотя странно, что нет алгоритмов сглаживания.

Изменено пользователем POV

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Сделать антиалиасинг пока не получилось, но... Изначально неправильная постановка задачи, не нужен буфер для рисования, это же не GDI. Прорисовка в PaintBox на OnPaint с заливанием фона, копированием слоя подложки и иконок, рисование ломаных линий и фигур, прозрачность, антиалиасинг и т.д. абсолютно не вызывает  проблем с ресурсами и морганием, все рисуется быстро и плавно.

Изменено пользователем Камышев Александр

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Итак на Android и iOS нет сглаживания при отрисовке примитивов (линий, кругов, вектора).

Метод 1 (Native Draw, Delphi ONLY ) - лучший и простой. 

На Canvas PaintBox рисуем как обычно.

Если нужно нарисовать на Canvas Bitmap'a, а не на PaintBox, тогда нужно правильно подготовить Bitmap: 

if Scene <> nil then
  lScale := Scene.GetSceneScale
else
  lScale := 1;

fBitmap.BitmapScale := lScale; 
fBitmap.SetSize(Ceil(Width * lScale), Ceil(Height * lScale) );

 

Все детали здесь, также там ссылка на сайт (используйте гугл переводчик)

https://github.com/OneChen/FMXNativeDraw

Если нужно сохранить в Bitmap, то делаем PaintBox.MakeScreenshot (TControl.PaintTo) в результате получаем сглаженный Bitmap. Кстати вызвать PaintTo не получится в Paint и Afterpaint методах текущего контрола - будет циклический вызов Paint и в результате переполнение стэка, нужно делать это в AfterPaint формы или фрейма. 

Метод 2.

http://riversoftavg.com/blogs/index.php/2016/06/09/use-supersampling-for-offscreen-bitmaps-on-delphi-mobile/

Изменено пользователем ENERGY

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти


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

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