簡體   English   中英

在WinForms應用程序中准確地測量,渲染,命中測試和打印文本

[英]Accurately measuring, rendering, hit testing and printing text in a WinForms application

我們要:

  1. 准確測量文字。
  2. 在存在應用於圖形上下文的轉換和縮放轉換的情況下,將文本逐行渲染到屏幕圖形上下文。
  3. 匹配測試:允許使用鼠標或顯示的插入符號精確選擇文本。
  4. 如有需要,請使用打印機盡可能准確地打印結果。 注意:這是次要的。 屏幕渲染和命中測試是主要的。
  5. 在Windows XP和更高版本的操作系統上運行。

在WinForms應用程序中,該應用程序還將圖形和圖像呈現到相同的圖形上下文中。

我們遇到了四種技術。 我們嘗試使用前兩個方法,並在幾個月的時間內遇到了上述問題。

GDI +

據說是與分辨率無關的文本。 但是根據此問題以及其他來源,由於質量問題,應避免使用此技術。

MSDN指出,將Graphics.MeasureString與StringFormat.GenericTypographicTextRenderingHint.AntiAlias一起調用可產生准確的字符串度量。 但是,根據我們以及其他人的經驗,情況並非如此-我們無法獲得准確的字符串測量結果。

  • 優點:快速
  • 缺點:字符串測量不准確。

結果:由於字符串測量不正確而無法使用。

通過TextRenderer進行GDI

引入它是為了克服GDI +的局限性。 但是,這引入了自身的局限性:

結果:由於這些原因而無法使用

通過p / invoke進行GDI

調用GetTextExtentExPoint進行文本測量,並調用DrawText / DrawTextEx / ExtTextOut進行渲染。

我們還沒有嘗試過。

DirectWrite

這似乎很有希望,因為它可以與其他技術(包括GDI / GDI +)互操作,因此其余的圖形渲染大概不會改變。 但是,它僅適用於Windows Vista和更新的Windows版本。 由於Windows XP仍具有重要的安裝基礎,因此這目前是一個問題。

在滿足要求的情況下,哪些技術可以工作?

注意:關於此主題的信息有很多誤解,因此,只有在您對此領域有專業知識的情況下,才請回答此問題。 另外,請不要建議使用WPF-這不是我們正在考慮使用的東西。

假設MeasureCharacterRanges函數比MeasureString更准確。

如果必須同時瞄准屏幕和打印機,則需要在確定使用哪種渲染引擎之前對方法進行一些決策。 這里有一些可能性:

  1. 布置屏幕單元,並為打印機做一個最好的近似值。
  2. 布置打印機單元,並為屏幕做一個最好的近似。
  3. 在理論上高分辨率的空間中進行布局,並對打印機和屏幕進行最佳近似。

在所有情況下,最好的近似可能是通過在每個步驟上非常仔細地近似來完成的,這可以以匹配的准確性為代價為每個設備提供最高的保真度,或者您可以渲染位圖並縮放到該設備,保真度較低,但對其他空間的最佳近似度。

我已經使用GDI完成了核心打印預覽。 這很困難,但是對於常規布局是可行的。 但是,如果要處理任意變換,尤其是+/- 90度以外的旋轉,則幾乎是不可能的。

很容易犯一些細微的錯誤,並認為您得到的測量結果是錯誤的。

  • 當筆划寬度與dpi處於相同的數量級時,字體提示使字體縮放非線性,因此,如果某些文本的寬度為w ,則如果將字體大小加倍,則寬度可能不完全是2*w

  • 字體替換在許多打印機驅動程序中很常見。 即使您選擇TrueType或OpenType字體,打印機上的字體也可能不會與屏幕上的字體相同。

  • 非正方形像素在某些打印機中很常見。 當您執行未與軸對齊的操作時,這些甚至會弄亂體面的光柵化器。

  • 緊縮可能令人驚訝。 不要假設width('a')+ width('b')== width(“ ab”)。

  • 舍入錯誤很容易造成。 有時,您必須了解基礎柵格化器使用的舍入規則。

  • 在錯誤的環境中進行測量太普遍了。 請勿嘗試在屏幕環境中進行測量並應用轉換以獲取打印機單元。 如果需要打印機單元,請在打印機環境中進行測量。

我今天認為,如果只需要打印預覽,則應該以打印機為單位將位圖布局為與頁面大小相同的位圖,然后根據DPI的比例將位圖縮放到屏幕。 那是最簡單的事情,而且效果很好。 但是尚不清楚您是否追求好的硬拷貝和打印預覽。

我有類似的要求,並且在文本渲染和縮放時遇到了相同的問題。 由於許多原因,即使我嘗試使用WPF(.NET 3.5)也是一場噩夢。

我最終使用了GDI + graphics.DrawString ,盡管已被“棄用”,但它有一個有趣的技巧來獲得准確的文本尺寸。

static public RectangleF MeasureInkBox(Graphics graphics, string text, Font font)
{
    var bounds = new RectangleF();
    using (var textPath = new GraphicsPath())
    {
        textPath.AddString(
            text,
            font.FontFamily,
            (int)font.Style,
            font.Size,
            new PointF(0, 0),
            StringFormat.GenericTypographic );
        bounds = textPath.GetBounds();
    }
    return bounds;
}

速度和質量都令人滿意。 另外, graphics.DrawString是使用winforms打印文本的推薦方法。

由於字距調整,測量單個角色的位置可能會很棘手,但是我猜想這種方法稍微復雜一點就可以解決問題。 例如,對於“ Hello”,它將測量“ H”,然后是“ He”,然后是Hel”,以此類推,它不會顯着降低性能,尤其是當您收到單詞的單擊時以他的飛行狀態進行測量時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM