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

Вертикальное смещение юникодных шрифтов


Вадим Смоленский

Вопрос

В своем проекте (это японско-русский словарь) мне приходится выводить на TImage.Bitmap.Canvas хранящиеся в юникоде иероглифы, причем шрифт пользователь может выбрать сам. Столкнулся с неприятным явлением: разные шрифты располагают выводимый символ на разной высоте, в результате чего иероглиф часто не вписывается в предназначенную для него область. По умолчанию принят шрифт Tahoma, с ним всё хорошо:

JI_tahoma.png.756f1d23bc94c79ad622f20e25f44271.png

Но вот шрифт Yu Mincho:

JI_Yu_Mincho.png.f63e2b85d50bf8ae202b587c7b30f652.png

А вот, еще хлеще, Kozuka Gothic:

JI_Kozuka_Gothic.png.1856d8711b3cd526b42c278ddf699957.png

Вопрос: что за параметр регулирует вертикальное смещение, можно ли его вынуть и с ним работать?

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

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

  • 0
2 часа назад, wamaco сказал:

Для мобильных платформ тоже на Delphi сделано?

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

Кстати, я еще не потерял надежды услышать Ваш комментарий к вопросу о сохранении стиля в разделе "Default". Очень обяжете, если прольете свет.

P.S. Отбой! С сохранением стиля помог dnekrasov. Ему мое спасибо. Но и вам тоже.

Изменено пользователем Вадим Смоленский
Ссылка на комментарий
  • 0
В 12.01.2018 в 14:47, Вадим Смоленский сказал:

В своем проекте (это японско-русский словарь) мне приходится выводить на TImage.Bitmap.Canvas хранящиеся в юникоде иероглифы

Чё-то я изначально затормозил... Если Вам просто надо отобразить иероглиф - то можно ведь сделать всё намного проще - через TPathLabel (она должна сама обрезать все отступы)

var
  F: TFont;
  FG: TFontGlyph;
  bmp: TBitmap;
begin
  F := TFont.Create;
  try
    F.Family := 'Kozuka Gothic Pr6N B';
    F.Size := 60;

    FG := TFontGlyphManager.Current.GetGlyph(Char.ConvertToUtf32('字', 0), F, 1, [TFontGlyphSetting.Path]);
    try
      PathLabel.Width := FG.Path.GetBounds.Width;
      PathLabel.Height := F.Size;
      PathLabel.Data := FG.Path;
      // ну и если всё-таки bitmap-ка нужна
      bmp := PathLabel.MakeScreenshot;
      try
        // что-то делаем с битмапкой
      finally
        bmp.Free;
      end;
    finally
      FG.Free;
    end;
  finally
    F.Free;
  end;
end;

 

Изменено пользователем dnekrasov
В коде замена "PathLabel.Width := F.Size;" на "PathLabel.Width := FG.Path.GetBounds.Width;"
Ссылка на комментарий
  • 0

В общем случае мне нужно выводить не просто одиночный иероглиф, а несколько японских символов, соседствующих на TCanvas с кириллицей и латиницей. Там это едва ли подойдет. Но на главную панель словарной статьи выводится именно одиночный иероглиф, крупным шрифтом (как показано на моих картинках). Именно там наиболее возможен выбор пользователем нестандартного шрифта. Так что вариант с TPathLabel я непременно опробую, спасибо!

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

Там это едва ли подойдет

Ну почему же:

var
  F: TFont;
  PD: TPathData;
begin
  F := TFont.Create;
  try
    F.Family := 'Kozuka Gothic Pr6N B';
    F.Size := 60;
    with TBitmap.Create do
    try
      Canvas.Font.Assign(F);
      PD := TPathData.Create;
      try
        if Canvas.TextToPath(PD, RectF(0, 0, 10000, F.Size), '字字字 AsD АыЩ', False, TTextAlign.Leading, TTextAlign.Leading) then
        begin
          PathLabel.Width := PD.GetBounds.Width;
          PathLabel.Data := PD;
        end;
      finally
        PD.Free;
      end;
    finally
      Free;
    end
  finally
    F.Free;
  end;
end;

 

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

Спустя три недели все-таки решил опробовать ваш вариант с TPathData, а то тестировщики продолжают жаловаться. Сделал, не задействуя TPathLabel, вот так:

with ThisImage.Bitmap.Canvas do
begin
 PD:=TPathData.Create;
 BeginScene;
 try
  if TextToPath(PD,RectF(X,Y,Width-1,Height-1),TheText,False,TTextAlign.Leading,TTextAlign.Leading) then
  FillPath(PD,1);
 finally
  PD.Free;
 end;
 EndScene;
end;

Увы, результат ровно тот же, с нежелательными вертикальными смещениями.

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

Увы, результат ровно тот же, с нежелательными вертикальными смещениями.

Перед FillPath попробуйте вставить

PD.Translate(-PD.GetBounds.Left, -PD.GetBounds.Top);

 

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

А еще можно попробовать FillText со смещением -PD.GetBounds.Left, -PD.GetBounds.Top

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

А вставка PD.Translate помогла, теперь иероглиф надежно прилепляется к левому и верхнему краям. Хорошо бы еще научиться выравнивать его, чтобы он не лепился к этим краям, а вставал бы в середину указанного прямоугольника. Не приходит пока в голову, как это сделать.

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

Я и рад бы это опробовать но не понял, куда именно нужно вставлять такое смещение в случае FillText

Ну как же? В первом параметре идет прямоугольник в который выводится текст. Ему и сделать Offset(-PD.GetBounds.Left, -PD.GetBounds.Top)

7 минут назад, Вадим Смоленский сказал:

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

Всё просто:

PD.Translate(-PD.GetBounds.Left + DestRect.Left + (DestRect.Width - PD.GetBounds.Width) / 2, -PD.GetBounds.Top + DestRect.Top + (DestRect.Height - PD.GetBounds.Height) / 2)
Ссылка на комментарий
  • 0

Впрочем, не всё так гладко. Вот, например, как теперь выводится иероглиф "Единица", состоящий из одного-единственного горизонтального штриха:

ichi.png.813e8a2e44d8237cba6c89fbb658cff5.png

А по идее, он должен быть всё-таки в середине. Так что, наверное, оставлю этот подход лишь для тех случаев, когда используется шрифт, которого нет в списке предусмотренных.

Хотя, может, есть способ вытащить откуда-то из TPathData информацию о реальных размерах символа и, исходя из нее, смещать его туда-сюда? Было бы замечательно.

 

 

 

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

Отвечаю сам себе: да, есть такой способ! У TPathData есть метод GetBounds:

if TextToPath(PD,DestRect,TheKanjiString,False,TTextAlign.Leading,TTextAlign.Leading) then
begin
 W:=(Width-PD.GetBounds.Width)/2;
 H:=(Height-PD.GetBounds.Height)/2;
 PD.Translate(X+W-PD.GetBounds.Left,Y+H-PD.GetBounds.Top);
 FillPath(PD,1);
end;

Теперь всё красиво:

ichi2.png.0aa5f411640e1aa8c349761623332e31.png

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

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

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

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

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

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

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

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

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

×
×
  • Создать...