Potrzebuję wydrukować cyfry, w których niektóre cyfry w środku są podkreślane przez zwiększenie rozmiaru i wagi czcionki. W poniższym przykładzie podkreślono 456
.GDI + rysowanie tekstu o różnych rozmiarach na linii bazowej ma problemy typu off-by-1px.
Czcionka i dwa rozmiary stosowane są konfigurowane przez użytkownika.
Obecny kod wykonuje to za pomocą trzech połączeń z numerem Graphics.DrawString(...)
.
Problem mam jest to, że w większości czcionek, widzę off-by-1pixel problemy (w stosunku do szarej linii, 456
siedzi dodatkowy piksel wyższa niż pozostałych cyfr):
Dołączyłem kilka zrzutów debugowania (z formuły Boba Powella) dla różnych czcionek na dole mojego postu. Inne techniki dały podobne wyniki.
Aby wydrukować tekst na wspólnej linii bazowej, należy obliczyć przesunięcie linii bazowej dla określonego Font
. Próbowałem przy użyciu trzech technik:
pierwsze MSDN Kod: http://msdn.microsoft.com/en-us/library/xwf9s90b(v=vs.80).aspx
ascent = fontFamily.GetCellAscent(FontStyle.Regular);
ascentPixel = font.Size * ascent/fontFamily.GetEmHeight(FontStyle.Regular)
Po drugie, kod od: Using GDI+, what's the easiest approach to align text (drawn in several different fonts) along a common baseline?
Wreszcie kod z postu Boba Powella: http://www.bobpowell.net/formattingtext.htm
Oto mój metoda rysowania:
private void DrawOnBaseline(Graphics g, string text, FontWithBaseline fwb, Brush brush, float x, float y) {
g.DrawString(text, fwb.Font, brush, x, y - fwb.Baseline, StringFormat.GenericTypographic);
}
Gdzie FontWithBaseline
prostu kojarzy czcionki z odpowiedniej kalkulacji bazowym:
public class FontWithBaseline {
private Font m_font;
private float m_baseline;
public FontWithBaseline(Font font) {
m_font = font;
m_baseline = CalculateBaseline(font);
}
public Font Font { get { return m_font; } }
public float Baseline { get { return m_baseline; } }
private static float CalculateBaseline(Font font) {
... // I've tried the three formulae here.
}
}
nie eksperymentowali z Graphics.TestRenderingHint
jeszcze. Czy to magiczny sos? Czego mi brakuje? Czy istnieje alternatywny interfejs API, z którego mogę skorzystać, gdy nazywam wywołanie, aby pobrać materiały wyjściowe o współrzędnej Y linii bazowej?
Aktualizacja 1
I interpolowane mój kod z @LarsTech. Robił jedno subtelnie inaczej; dodawał 0.5f
. Jednak nawet ten wariant nie rozwiązuje problemu. Oto kod:
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
TryLarsTechnique(e);
}
private void TryLarsTechnique(PaintEventArgs e) {
base.OnPaint(e);
Graphics g = e.Graphics;
GraphicsContainer c = g.BeginContainer();
g.Clear(Color.White);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
Font small = new Font("Arial", 13, FontStyle.Regular, GraphicsUnit.Pixel);
Font large = new Font("Arial", 17, FontStyle.Bold, GraphicsUnit.Pixel);
int x = 100;
int y = 100;
x += DrawLars(g, "12.3", small, x, y);
x += DrawLars(g, "456", large, x, y);
x += DrawLars(g, "8", small, x, y);
g.EndContainer(c);
}
// returns width of text
private int DrawLars(Graphics g, string text, Font font, int x, int y) {
float offset = font.SizeInPoints/
font.FontFamily.GetEmHeight(font.Style) *
font.FontFamily.GetCellAscent(font.Style);
float pixels = g.DpiY/72f * offset;
int numTop = y - (int)(pixels + 0.5f);
TextRenderer.DrawText(g, text, font, new Point(x, numTop), Color.Black, Color.Empty, TextFormatFlags.NoPadding);
return TextRenderer.MeasureText(g, text, font, Size.Empty, TextFormatFlags.NoPadding).Width;
}
Zastanawiam się, czy określenia rozmiaru czcionki korzystając GraphicsUnit.Pixel
jest winowajcą. Być może istnieje sposób na znalezienie preferowanych rozmiarów dla jakiejś konkretnej czcionki?
Aktualizacja 2
Próbowałem określić rozmiary czcionek w punktach zamiast pikseli, i to nie w pełni rozwiązać ten problem, albo. Zauważ, że używanie tylko całych rozmiarów punktów nie jest w moim przypadku opcją. Aby sprawdzić, czy jest to możliwe, próbowałem tego na Windows Wordpad. Rozmiary Używając 96 dpi (i 72 punktów na cal z definicji), 17px, 13px przetłumaczyć na 12,75 i 9,75. Oto wynik w porównaniu:
Wskazówki jak mniejsze czcionki są tej samej wysokości na poziomie pikseli. Tak więc Wordpad w jakiś sposób udaje się to zrobić bez zaokrąglania rozmiarów czcionek do wygodnych wartości.
Dzięki za to. Zaktualizowałem moje pytanie, aby dodać mój kod i uwzględnić Twoje podejście. Dodanie '0,5f' było czymś nowym. Niestety, nadal widzę problem. Spróbuj użyć rozmiarów czcionki 17 pikseli + 13 pikseli; Podejrzewam, że problem też będzie widoczny. –
@DilumRanatunga '0.5f' pochodzi prosto z przykładu Boba Powella (patrz dół tej połączonej strony). Tak, użycie 'GraphicsUnit.Pixel' powoduje przesunięcie go o piksel. Nie wiem, dlaczego, ale zostawienie go znowu przyciągnęło ich do kolejki. Wierzę, że 'GraphicsUnit.Point' jest domyślną wersją, a przy jej używaniu też zadziałało. – LarsTech
@DilumRanatunga Jeśli zmienię kod na GraphicsUnit.Pixel, a następnie użyję "12.75f" i "9.75" jako rozmiaru czcionki, linie zostaną poprawione. Nie * myślę, że * WorkPad robi jakieś zaokrąglenia, myślę, że po prostu pokazuje użytkownikowi całkowitą liczbę dla wygody. Mogę się mylić. Projektant Visual Studio pokazuje '8.25pt' dla domyślnej czcionki' Microsoft Sans Serif', ale jeśli klikniesz okno dialogowe, aby zmienić czcionkę, zobaczysz tylko liczby całkowite w rozwijanym menu. Nie jestem pewien, czy to ci pomoże, czy nie. – LarsTech