2010-12-10 5 views
6

Это вопрос о очень простой конструкции - У меня есть следующий код XAML:TextBlock внутри Viewbox - странный рендеринг

<Viewbox Height="100" Stretch="Uniform"> 
     <TextBlock FontFamily="Georgia">My Cool Text</TextBlock> 
    </Viewbox> 

Это довольно просто понять. Тем не менее, когда я запускаю программу, я получаю странный размытый текст (в моем проекте нет никаких растровых эффектов). alt text

(левая сторона - вид дизайнера в VS2010, правая сторона - запущенное приложение)

Кто-нибудь есть какие-либо предложения о том, почему это происходит ??

+0

отлично смотрится на моей машине – 2010-12-10 12:20:16

+0

Выглядит неплохо на моей машине! Какую версию WPF вы используете? Можете ли вы протестировать его в новом окне, поскольку это только контент? – decyclone 2010-12-10 12:25:35

ответ

27

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

Объяснение немного длинное для комментария, поэтому я помещаю его в отдельный ответ.

В этом примере используются две взаимоисключающие функции WPF. Эти особенности:

  1. Способность оказывать визуальными последовательно в любом масштабе
  2. Способность визуализации текста таким же образом gdi32 делает текст

Вы не можете использовать обе функции одновременно. GDI32 отображает текст таким образом, который нельзя масштабировать последовательно: если конкретный фрагмент текста с определенным размером шрифта имеет ширину 200 пикселей, если вы умножаете размер шрифта на 3 и отображаете один и тот же текст в том же семействе шрифтов в что новый размер шрифта, в GDI32 он, вероятно, не будет 600 пикселей - он будет близок, но, как правило, это будет не совсем правильно.

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

Хотя это дает вам красивый текст, выглядящий ужасно, это выглядит абсолютно ужасно, если вы пытаетесь постепенно менять масштаб. Если вы попытаетесь оживить размер шрифта какого-либо текста, представленного таким образом, вещь будет казаться мерцающей и дрожащей, потому что корректировки, сделанные во имя ясности, в результате немного отличаются при каждом размере шрифта.Даже если вы не анимируете, он все равно может дать плохие результаты - если у вас есть один шрифт, показанный на разных размерах, он может выглядеть совсем по-разному при каждом размере; если ваше приложение имеет функцию масштабирования, характер текста может заметно измениться по мере увеличения и уменьшения масштаба. (И так может быть и макет. Если вы используете Microsoft Word, возможно, вы заметили, что иногда вы получаете необычные пространственные пробелы между определенными словами. Это результат взаимодействия Word с GDI32 - Word пытается сохранить экранную компоновку как можно ближе к тому, как будут выглядеть вещи при печати, а это значит, что иногда он сталкивается с сеткой GDI32.)

Таким образом, WPF предлагает другой подход к текстовому рендерингу: он может визуализировать текст так, насколько это возможно к оригинальному дизайну шрифта. Это искажает текст меньше, а это означает, что вы не получаете разрывов по мере масштабирования.

Недостатком является то, что текст выглядит размытым по сравнению с тем, как выглядит текст, визуализируемый GDI32. (Искажения, сделанные GDI32, направлены на улучшение ясности.)

Итак, в WPF 4.0 Microsoft добавила возможность визуализации текста способом GDI32. Вот что делает TextOptions.TextFormattingMode="Display".

Включив эту опцию, вы говорите: «Я не нуждаюсь в последовательном масштабировании, и я бы предпочел ясность, поэтому создайте те же пиксели, которые вы сделали бы в GDI32». Если вы затем примените масштабирование, сообщив WPF, что вам не нужна масштабируемость, вы получите дрянные результаты. WPF тщательно сгенерировал растровое представление текста точно в соответствии с вашими спецификациями, и затем вы сказали, чтобы он отображал этот текст в другом масштабе. И так оно выглядит так: масштабированное растровое изображение некоторого текста, который был сгенерирован для другого разрешения.

Вы можете утверждать, что WPF мог бы сделать что-то другое: если вы примените масштабное преобразование в GDI32, вы увидите другое поведение - вы увидите несогласованность в разных масштабах, описанных ранее. Если вы действительно хотите получить этот эффект в WPF, вы можете получить его, изменив размер шрифта напрямую. Но WPF не ставит перед собой приоритет в получении такого же эффекта - его целью является получение текста с четким текстом в формате GDI32, когда он вам действительно нужен, и обеспечить постоянное масштабирование по умолчанию.

И что вы здесь используете, это «согласованное масштабирование». Включение текстового рендеринга в стиле GDI32 не нарушает согласованного масштабирования: применение масштабного коэффициента (либо напрямую, через ScaleTransform, либо косвенно через Viewbox) изменит размеры визуального изображения точно заданным коэффициентом масштабирования. Если бы было регенерация текстовых изображений с помощью привязки сетки к вновь масштабированному размеру, текст выходил бы на другой ширине. Это фактически вызовет проблемы Viewbox: он применяет масштабный коэффициент, основанный на натуральном размере контента, предназначенном для того, чтобы он соответствовал доступному пространству. Но если он изменил сетку после масштабирования, это фактически изменило бы ширину. Из-за несоответствий, присущих тому, как работает текстовый рендеринг GDI32, для может оказаться невозможным найти подходящий масштаб - можно придумать фрагмент текста, который при визуализации в определенном шрифте никогда не появится шириной 200 пикселей. Для некоторых размеров шрифта округление, связанное с подгонкой сетки, может привести к уменьшению размера до, скажем, 198, и это может повлиять на это, поскольку вы делаете крошечные приращения размера шрифта, пока не пройдете какой-то порог, после чего он может прыгать до 202 пикселей.

Для получения Viewbox попыток заставить текст вписаться в ровно 200 пикселей, это будет проблемой. Но Viewbox не работает таким образом - он использует согласованное масштабирование WPF, расположенное ниже точки, в которой вы выбрали размер шрифта, с которым работает текстовый рендеринг в стиле GDI32. Таким образом, Viewbox всегда сможет делать то, что он предназначен, но это задача, которая принципиально несовместима с визуализацией текста в стиле GDI32.

Итак, WPF отображает текст для требуемого размера шрифта, а затем масштабирует результат.

Итак, вам нужно выбрать только одну функцию - вы не можете иметь обоих, потому что это просто невозможно. Либо не пытайтесь отображать текст в контексте, в котором может применяться произвольный масштабный коэффициент (например, Viewbox), либо не включать текстовый рендеринг в стиле GDI32. В противном случае вы получите тот странный пиксельный текст, с которым вы столкнулись.

8

Хорошо, обнаружена ошибка. Мой стиль Окно имеет следующий сеттер:

<Setter Property="TextOptions.TextFormattingMode" Value="Display"/> 

Если установить его обратно в «Ideal» (который является значением по умолчанию), то она делает текст внутри ViewBox правильно. Я бы сказал, что это ошибка внутри WPF. В основном, если вы попробуете это:

<Viewbox Height="100" Stretch="Uniform" TextOptions.TextFormattingMode="Display"> 
    <TextBlock FontFamily="Georgia">My Cool Text</TextBlock> 
</Viewbox> 

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

Смежные вопросы