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

Размытие текста у функции Canvas.FillText


Tumaso

Вопрос

Пользуюсь для отрисовки текста функцией Canvas.FillText. Но при выводе на канве текст получается немного размытым, особенно если сравнивать отображаемый текст с TLabel (тот же текст с теми же параметрами TFont у TLabel выглядит четче).

Подскажите, как вывести текст без размытия?

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

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

  • 0
function MakeItemImage(const AWidth, AHeight: Double; const ALabel: TLabel): TBitmap;
begin
  Result := TBitmap.Create(Trunc(AWidth), Trunc(AHeight));
  with Result.Canvas do
  begin
    if BeginScene then
    begin
      try
        Clear(TAlphaColorRec.Null);
        // текст 
        Font.Assign(ALabel.Font);
        Fill.Color := ALabel.FontColor;
        FillText(
          TRectF.Create(0, 0, Result.Width, Result.Height),
          ALabel.Text, True, 1, [], TTextAlign.Leading, TTextAlign.Center
          );
      finally
        EndScene;
      end;
    end;
  end;
end;

Этот метод вызывается для формирования изображения для элемента в TListView (по событию OnUpdateObjects, режим DynamicAppearance). Вроде все элементарно, но текст немного искажен.

Но вот насчет возможного растягивания этого сформированного изображения в ListView я не подумал, спасибо за подсказку

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

Если на Timage то 

 Image1.WrapMode := TImageWrapMode.Original;

Чтобы не растягивало. 

 

Также обратите внимание на параметр BitmapScale.

Он должен быть равен текущему scale, иначе изображение будет тоже искажено.

var
  lScale: Single;
  lScreenService: IFMXScreenService;
begin            // FMX.Platform
  if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService, lScreenService) then
     lScale := lScreenService.GetScreenScale
  else
    lScale := 1;

Если у вас свой компонент от TControl , то там есть переменная Scene. и конструкция выше не нужна.

  Result := TBitmap.Create(Trunc(AWidth), Trunc(AHeight));
  Result.BitmapScale := lScale;

 

Есть одно но, если указать правильный Scale в Bitmap - то на Windows (если там scale > 1) часть рисунка на канве будет отрезаться, видимо какой то баг с просчетом координат с новым Scale в FMX, при это на мобильных системах все прекрасно работает и корректно рисуется и масштабируется с разными Scale. Я так рисую со сглаживанием через NativeDraw - сначала на Bitmap, для кэша, затем на канву. 

Возможно  Ярослав знает в чем дело. 

Используйте этот метод BitmapScale на Android\iOS (рендер GlobalUseGPUCanvas := true; чтобы посмотреть на Win, но без сглаживания). 

 

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

Попробовал поиграться с BitmapScale, WrapMode, флагами GlobalXXXX - результат без изменений.

Но что интересно - однострочный текст с помощью FillText выводится без искажений, аналогично TLabel (разницы не видно).

Но вот если выводится текст, который переносится на две строки и более, то немного искажается во всех перепробованных вариантах. У меня как раз весь такой вывод текста занимает всегда больше 1 строки, и искажается. Попробовал для теста вывести в одну строчку - тогда все ок.

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

Значит Bitmap растягивается. Странно что WrapMode Original + BitmapScale не помог. Вы для каких платформ пишите? Scale какой возвращает система?

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

Проект для Android и iOS, wrapmode = original. Значение scale не смотрел, просто кодом присваивал.

Да как то непонятно с этой растяжкой. Размеры я все проверил, всё идеально. Изображения и однострочный текст выводятся без проблем. Но если выводится текст с переносом (многострочный), так он выводится с размытием (я про текущую версию формирования Bitmap для ListView). У paintBox всё выводится как надо, поэтому тут какой то непонятный момент именно у FillText.

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

Я бы на вашем месте сначала вывел текст в Timage.Bitmap, чтобы исключить другие направления. 

Если бы вы подготовили простой проект с этим багом, чтобы другие могли запустить, - было бы больше помощи. Т.к. у всех работа, и отвлекаться на создание нового проекта мало кому охота.

 

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

Так вы и так уже мне помогли с идеей решения проблемы :)

Изначально я просто создавал TBitmap.Create, выводил в него текст и копировал полученный буфер в элемент ListView. При многострочном тексте получался эффект размытого текста.

Я немного переписал код, теперь создаю TPaintBox.Create, вывожу текст в него и копирую этот буфер в TListView, теперь все ок

Ссылка на комментарий
  • 0
19 минут назад, Tumaso сказал:

ENERGY,

копирую с помощью DrawBitmap


DrawBitmap(
  ASource,
  AlignToPixel(ARect),
  AlignToPixel(TRectF.Create(0, 0, AWidth, AHeight)),
  1,
  False
  );

 

1. Уберите AlignToPixel - здесь он не нужен

2. Попробуйте поставить вместо False - True в последнем параметре.

3. Проверьте идентичность ARect.Width, ARect.Height и AWidth, AHeight

Изменено пользователем dnekrasov
Ссылка на комментарий
  • -1
1 час назад, Tumaso сказал:

Так я же уже решил проблему, путем построения промежуточного буфера в TPaintBox вместо TBitmap

Просто какая-то странная проблема, впрочем как и её решение. Я FillText использую довольно активно, но никогда ничего подобного не наблюдал. Да и что-то мне подсказывает что дело совсем не в том, что надо использовать в качестве буфера TPaintBox вместо TBitmap. Ведь у людей, которые прочитают эту ветку форума может сложиться не правильное мнение, как надо решать подобные проблемы.

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

Автор, мне кажется, если бы вы прикрепили пример проекта, где баг воспроизводится (напр на TImage.Bitmap), было бы больше помощи, втч и тем кто будет спрашивать в будущем об этом.

Ваше решение не добавит производительности программе, тем более вы используете это для каждого Item в списке. 

 

Изменено пользователем ENERGY
Ссылка на комментарий
  • 0
59 минут назад, dnekrasov сказал:

Просто какая-то странная проблема, впрочем как и её решение. Я FillText использую довольно активно, но никогда ничего подобного не наблюдал. Да и что-то мне подсказывает что дело совсем не в том, что надо использовать в качестве буфера TPaintBox вместо TBitmap. Ведь у людей, которые прочитают эту ветку форума может сложиться не правильное мнение, как надо решать подобные проблемы.

Если бы не было этой проблемы, я бы ее и не спрашивал бы, как с ней бороться.

Суть в том, что я использую TListView с динамической высотой элементов (высота может быть различной) и динамической формированием элементов. В качестве шрифта используется устанавливаемый с приложением шрифт (если быть точным - plumb). Изначально я формировал изображение, рисуя на Bitmap у ListView.ItemAppearance.Item.TImageObjectAppearance. В данной ситуации FillText при выводе теста, содержащего больше одной строки, приводил к формированию текста с небольшим искажением, но при этом текст в одну строку выводится без проблем.

В качестве решения я использовал формирование в промежуточном буфере на базе TPaintBox, после чего копировал сформированное изображение в Bitmap. Искажения текста исчезли. Почему в исходном варианте наблюдается такое поведение FillText, я не знаю. Все scales, width / height и т.д. рассчитываются верно.

Поэтому предлагаю лично вам свое мнение об этой проблеме и способах ее решения либо оставить при себе, либо озвучивать в другой теме. Желаете, что бы я начал комментировать ваши рассуждения об использовании FMX на этом форуме? ))))))))))

Сразу отвечаю на замечание ENERGY - формируемые изображения кэшируются, ListView заполняется в коде очень быстро, и также шустро работает, скролится без лагов. Для пользователей программы это важно, по моему скромному мнению.

 

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

Проблема в том что ваш битмап растягивается ,т.к. у него не правильный масштаб (масштаб 1, а нужен системный который больше).

Значит

1. Получите текущий Scale из системы (если отнаследовались от TControl, то есть Scene.GetSceneScale).

2. Установите правильный размер у битмапа - Bitmap.SetSize(Ceil(Width * Scale), Ceil(Height * Scale))

Вместо Ceil можно Trunc попробовать, что лучше.

BitmapScale не трогайте (его нужно менять, если рисуете векторный Path ). Теперь попробуйте вывести на него текст, а затем этот битпам отобразить на PaintBox. Должно все получиться с высокой вероятность, я так отрисовываю примитивы, напр. круг через китайский модуль NativeAPI, чтобы было сглаживание на Android/iOS.

 

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

@ENERGY,

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

А вот насчет рисования кругов со сглаживанием через nativeAPI, можно поподробнее? А то TCircle в андроиде это полный треш

Ссылка на комментарий
  • 0
4 часа назад, Tumaso сказал:

А вот насчет рисования кругов со сглаживанием через nativeAPI, можно поподробнее? А то TCircle в андроиде это полный треш

Native Api (google translate ) :

https://github.com/OneChen/FMXNativeDraw (там же ссылка на описаниеl)

Равиль сделал на основе этого модуля готовые компоненты:  

https://github.com/rzaripov1990/ZMaterialComponents

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

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

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

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

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

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

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

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

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

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

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