Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 17.06.2023, 23:41   #1
The_Immortal
Пользователь
 
Регистрация: 08.10.2008
Сообщений: 27
По умолчанию Обрезка текста при отрисовке на канве

Приветствую!

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

Упрощенный пример задачи:
Код:
procedure TForm2.Button1Click(Sender: TObject);
var
  i, WidthShift: Integer;
  str, delim: string;
  Font: TFont;
  Colors: TArray<TColor>;

begin
  Font := TFont.Create;
  Colors := TArray<TColor>.Create(clRed, clBlack, clGreen);
  WidthShift := 10;

  if FontDialog1.Execute then
  begin
    Font.Assign(FontDialog1.Font);
  end;

  Image1.Canvas.Brush.Color := clWhite;
  Image1.Canvas.FillRect(Image1.Canvas.ClipRect);

  Image1.Canvas.Font.Assign(Font);
  delim := '/';

  for i := 0 to 2 do
  begin
    str := '0';
    if i <> 0 then
      str := delim + str;
    Image1.Canvas.Font.Color := Colors[i];
    Image1.Canvas.TextOut(WidthShift, 100, str);
    WidthShift := WidthShift + Image1.Canvas.TextWidth(str);
  end;
  Font.Free;
end;
Ниже результат. В первом случае текст обычный и все равно обрезается. А во втором курсив - там вообще все плохо.
В качестве решения можно было бы рассчитывать какой-то промежуточный запас (относительно высоты шрифта или еще по какой-то зависимости) и добавлять его на каждой итерации, однако по условиям задачи пробелов быть не должно.

Подскажите, пожалуйста, как можно поборот данную проблему?

Спасибо!
Изображения
Тип файла: png 2023-06-17_23-23-18.png (8.1 Кб, 30 просмотров)

Последний раз редактировалось The_Immortal; 17.06.2023 в 23:59.
The_Immortal вне форума Ответить с цитированием
Старый 18.06.2023, 01:07   #2
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 161
По умолчанию

Не текст обрезается, а просто фон текстовой области накладывается на соседнюю букву, используйте кисть со стилем bsclear при отрисовке текста и не нужны будут костыли
Код:
//...
  Image1.Canvas.Brush.Style:=bsSolid;
  Image1.Canvas.Brush.Color := clWhite;
  Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
  Image1.Canvas.Font.Assign(Font);
  Image1.Canvas.Brush.Style:=bsClear;
//..
  delim := '/';
DIONISKA вне форума Ответить с цитированием
Старый 18.06.2023, 01:24   #3
The_Immortal
Пользователь
 
Регистрация: 08.10.2008
Сообщений: 27
По умолчанию

DIONISKA, забыл еще уточнить, что мне необходима белая подложка, т.к. текст этот отрисовывается на фоне других цветных элементов (того же цвета, что и сам текст), поэтому его надо выделять через белую подложку, соответственно bsclear использовать не могу...
The_Immortal вне форума Ответить с цитированием
Старый 18.06.2023, 01:45   #4
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 161
По умолчанию

Цитата:
Сообщение от The_Immortal Посмотреть сообщение
мне необходима белая подложка
вы же читали код выше? белый прямоугольник отрисовывается в самом начале, заливка области сплошной кистью белым цветом (bsSolid):
Код:
Image1.Canvas.Brush.Style:=bsSolid;
  Image1.Canvas.Brush.Color := clWhite;
  Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
а затем меняете тип кисти на bsClear и отрисовываете текст. Опционально после отрисовки текста можно вернуть стиль кисти bsSolid. Вам-же так надо?
Изображения
Тип файла: png coltext.PNG (3.7 Кб, 29 просмотров)
DIONISKA вне форума Ответить с цитированием
Старый 18.06.2023, 21:43   #5
The_Immortal
Пользователь
 
Регистрация: 08.10.2008
Сообщений: 27
По умолчанию

DIONISKA, я, вероятно, некорректно изъясняюсь.
Мне необходимо, чтобы фон самого текста был на белом фоне.

В примере ниже фон изображения не белый (например, черный) и средний черный '0' может быть виден только с не черной (например, белой) подложкой. Мне необходимо, чтобы текст выводился с белым фоном, т.к. на заднем плане (общий закраска Image) может быть любой цвет, но не белый. Именно по этим причинам:
Цитата:
Сообщение от The_Immortal Посмотреть сообщение
bsclear использовать не могу...
Изображения
Тип файла: png 2023-06-18_21-38-50.png (35.4 Кб, 22 просмотров)
The_Immortal вне форума Ответить с цитированием
Старый 18.06.2023, 22:56   #6
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,291
По умолчанию

The_Immortal, если с bsclear кистью текст не обрезается, то просто добавьте отрисовку белого прямоугольника-фона для текста перед выводом текста, что и предлагает DIONISKA.
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )
BDA вне форума Ответить с цитированием
Старый 18.06.2023, 23:51   #7
The_Immortal
Пользователь
 
Регистрация: 08.10.2008
Сообщений: 27
По умолчанию

BDA, я не врубаюсь как это сделать...
Пробовал вот так. Все равно обрезается.

Где я косячу?
Изображения
Тип файла: png 2023-06-19_00-00-32.png (48.0 Кб, 21 просмотров)

Последний раз редактировалось The_Immortal; 19.06.2023 в 00:03.
The_Immortal вне форума Ответить с цитированием
Старый 19.06.2023, 00:37   #8
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,291
По умолчанию

Можно, например, вывести весь текст белым цветом на белом фоне, а потом уже нужным цветом на прозрачном:
Код:
begin
  Font := TFont.Create;
  Colors := TArray<TColor>.Create(clRed, clBlack, clGreen);
  WidthShift := 10;

  if FontDialog1.Execute then
  begin
    Font.Assign(FontDialog1.Font);
  end;

  Image1.Canvas.Brush.Style := bsSolid;
  Image1.Canvas.Brush.Color := clBlack;
  Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
  Image1.Canvas.Font.Assign(Font);

  Image1.Canvas.Brush.Color := clWhite;
  Image1.Canvas.Font.Color := clWhite;
  Image1.Canvas.TextOut(WidthShift, 100, '0/0/0');

  Image1.Canvas.Brush.Style := bsClear;
  delim := '/';

  for i := 0 to 2 do
  begin
    str := '0';
    if i <> 0 then
      str := delim + str;
    Image1.Canvas.Font.Color := Colors[i];
    Image1.Canvas.TextOut(WidthShift, 100, str);
    WidthShift := WidthShift + Image1.Canvas.TextWidth(str);
  end;
  Font.Free;
end;
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )
BDA вне форума Ответить с цитированием
Старый 19.06.2023, 01:27   #9
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 161
По умолчанию

Странная у вас конечно задача..
Тут если подумать есть минмум 4 решения:
1. Просто отисовать текст дважды: первый с заливкой, второй без заливки - это самый простой и быстрый костыль.
2. Отрисовывать текст с последней буквы и до первой в обратном порядке, но тут может что-то пойти не так на italic/bold italic шрифтах с наклоном в обратную сторону или шрифтах с завитушками
3. Отрисовывать где-нибудь отдельно, например на отдельном битмапе, а потом уже его рисовать на вашем Image1.Canvas, можно также с задействованием blend-функций, и тп
4. Как предлагал ранее товарищ BDA: сначала подсчитать размеры всего текста (с помощью TextWidth/TextHeight/TextRect), нарисовать прямоугольник, а потом уже поверх отрисовывать текст.

Цитата:
Сообщение от The_Immortal Посмотреть сообщение
Все равно обрезается.
А не получается у вас потому, что нужно сначала посчитать размеры текстовой области, затем нарисовать прямоугольник, а потом уже в цикле рисовать текст с bsclear.
Собственно почему происходит такой эффект? Потому что когда вы посимвольно выводите/получаете размеры текста, то область, в которую вписывается каждая буква перекрывает область предыдущей и опционально следующей(у рукописных шрифтов, с завитушками и тп) буквы, а если эту область залить, то она закрасит часть окружающих букв.
PS: если ограничиться моноширными шрифтами, то эта проблема не возникнет

Последний раз редактировалось DIONISKA; 19.06.2023 в 01:32.
DIONISKA вне форума Ответить с цитированием
Старый 19.06.2023, 17:02   #10
The_Immortal
Пользователь
 
Регистрация: 08.10.2008
Сообщений: 27
По умолчанию

DIONISKA,

Цитата:
Сообщение от DIONISKA Посмотреть сообщение
4. Как предлагал ранее товарищ BDA: сначала подсчитать размеры всего текста (с помощью TextWidth/TextHeight/TextRect), нарисовать прямоугольник, а потом уже поверх отрисовывать текст
Полагаю, что этот вариант ничем по сути не отличается от варианта № 1 - надо заранее знать всю строку текста, так?

Цитата:
Сообщение от DIONISKA Посмотреть сообщение
3. Отрисовывать где-нибудь отдельно, например на отдельном битмапе, а потом уже его рисовать на вашем Image1.Canvas, можно также с задействованием blend-функций, и тп
А можно попросить какой-нибудь мини-пример? Плохо понимаю как его реализовать в своей задаче и как это решит проблему?

Цитата:
Сообщение от DIONISKA Посмотреть сообщение
Собственно почему происходит такой эффект? Потому что когда вы посимвольно выводите/получаете размеры текста, то область, в которую вписывается каждая буква перекрывает область предыдущей и опционально следующей(у рукописных шрифтов, с завитушками и тп) буквы, а если эту область залить, то она закрасит часть окружающих букв.
Так вопрос почему именно так происходит? Я так понимаю это связано с тем, что ширина текста что курсивом, что обычным - идентична, т.е. в случае курсива она определяется некорректно. И из-за этого и возникают перекрывания. Так ведь?

Последний раз редактировалось The_Immortal; 19.06.2023 в 21:30.
The_Immortal вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Обрезка текста в ячейке таблицы Владимир1989 JavaScript, Ajax 5 28.01.2016 20:21
Пробелы при отрисовке текста quqeiqa2 C# (си шарп) 0 29.10.2015 01:36
Баг в отрисовке и подсчете на Канве Silwerwing Помощь студентам 1 23.04.2013 19:04
Баг в отрисовке и подсчете на Канве Silwerwing Общие вопросы Delphi 0 14.04.2013 12:08
отображение текста на канве belyjj Компоненты Delphi 3 12.04.2011 13:38