Пользовательский рендеринг текста DirectWrite + Direct2D является волосатым

Я оцениваю Direct2D в исследовательских целях, и пока я занимался этим, я решил отобразить свой обычный текст справки с помощью пользовательского средства визуализации текста DirectWrite, которое преобразует текст в геометрию пути, чтобы добавить контур (как показано в < пример href="https://docs.microsoft.com/en-us/windows/win32/direct2d/direct2d-and-directwrite" rel="nofollow noreferrer">DWriteHelloWorld в MSDN).

Однако на некоторых буквах есть странные волоски или рожки (рисунок: ширина штриха 3 и 5).

контур текста с разной шириной обводки

Также пробовал с другими шрифтами (например, Consolas), эффект тот же.

Исходный код (VS 2015): https://www.dropbox.com/s/v3204h0ww2cp0yk/FOR_STACKOVERFLOW_12.zip?dl=0


person Asylum    schedule 30.03.2021    source источник


Ответы (2)


Я подозреваю, что причина этого в том, что допуск выравнивания по умолчанию в D2D плохо работает для рендеринга контуров глифов при достаточно малых размерах. Обычно вы используете растровый рендеринг для небольших размеров и контуры для больших, в соответствии с GetRecommendedRenderingMode(). У вас есть такие же артефакты, если вы увеличиваете размер шрифта, скажем, в 10 раз?

person bunglehead    schedule 30.03.2021
comment
если я увеличу размер шрифта, то он будет выглядеть нормально, но цель состоит в том, чтобы он хорошо выглядел с этим размером шрифта. Интересно, что GDI+ может это сделать. Как бы вы визуализировали контуры с помощью растрового шрифта? - person Asylum; 31.03.2021
comment
Вы имеете в виду, если вы передаете геометрию D2D методам GDI+? Я предполагаю, что GDI+ работает по-другому. Что вы подразумеваете под растровым шрифтом? Если для данного глифа нет контура, GetGlyphRunOutline, я думаю, пропустит его и перейдет к следующему. - person bunglehead; 31.03.2021
comment
Я имел в виду, что GDI+ может просто идеально отображать контурный текст с этим размером шрифта (используя GraphicsPath::AddString, Graphics::DrawPath и Graphics::FillPath). Хотел написать «растеризатор» (не растровый шрифт, это совершенно другое), например, если этот метод геометрии пути не подходит для небольших размеров шрифта, то как мне отобразить контурный текст другими средствами? - person Asylum; 31.03.2021
comment
Я не пробовал сам, если это действительно касается допуска, вы можете попробовать ID2D1DeviceContext1::CreateFilledGeometryRealization() и поиграть со значением допуска, чтобы увидеть, помогает ли это вообще. Если это так, вы можете придумать некоторую оценку допуска на основе размера шрифта. Другой вариант — использовать ID2D1Geometry::Simplify(), который также принимает аргумент допуска. Рендерер по умолчанию в D2D использует рекомендуемый режим, который переключается на контур примерно при ~100,0 emsize. Может быть, вы нашли причину, почему она не ниже. - person bunglehead; 31.03.2021
comment
Я поэкспериментировал с Simplify() и параметром допуска, но волоски остались. - person Asylum; 31.03.2021

Решение так же просто, как я и надеялся. Волосы на самом деле вызваны стыками линий, которые генерирует D2D. Поэтому решение состоит в том, чтобы создать объект ID2D1StrokeStyle следующим образом:

ID2D1StrokeStyle* strokestyle = nullptr;
D2D1_STROKE_STYLE_PROPERTIES strokeprops = D2D1::StrokeStyleProperties();

strokeprops.lineJoin = D2D1_LINE_JOIN_ROUND;

d2dfactory->CreateStrokeStyle(strokeprops, NULL, 0, &strokestyle);

// draw
rendertarget->DrawGeometry(transformedgeometry, blackbrush, 3.0f, strokestyle);

При таком решении текст отображается так, как ожидалось (возможно, немного более округлым на стыках).

person Asylum    schedule 31.03.2021