0

如何在 C# 中使用 System.Drawing 绘制字符串时增加/减少字符间距?换句话说,我想在打印标签时实现字体字距调整。

我已经尝试过winapi SetTextCharacterExtra,但它根本不起作用。我能想到的另一种方法是分别打印每个字符并更改宽度/x 坐标,但它看起来并不漂亮。

大家还有什么想法吗?

4

1 回答 1

0

下面是实现字符间距的方法:

var inputString = "This is drawn by ";
var fontSize = 31f;
//var font = new Font("Avenir", fontSize, new FontStyle());
// var font = new Font("Times New Roman", fontSize, new FontStyle());
var font = new Font("Avenir Black", fontSize, new FontStyle());

var startX1 = 50;
var startY1 = 50;
// Draw string by Graphics
e.Graphics.DrawString(inputString + "DrawString", font, new SolidBrush(Color.Black), startX1, startY1);

// Draw string by ExtTextOut
LOGFONT lf = new LOGFONT();
font.ToLogFont(lf, e.Graphics);

IntPtr hPrinterDC = e.Graphics.GetHdc();
StringBuilder sbText = new StringBuilder(inputString + "ExtTextOut");
if (hPrinterDC != IntPtr.Zero)
{
    int nPrintHorzRes = GetDeviceCaps(hPrinterDC, HORZRES);
    int nPrintVertRes = GetDeviceCaps(hPrinterDC, VERTRES);
    int nPhysWidth = GetDeviceCaps(hPrinterDC, PHYSICALWIDTH);
    int nPhysHeight = GetDeviceCaps(hPrinterDC, PHYSICALHEIGHT);
    int nPhysOffsetX = GetDeviceCaps(hPrinterDC, PHYSICALOFFSETX);
    int nPhysOffsetY = GetDeviceCaps(hPrinterDC, PHYSICALOFFSETY);

    IntPtr hDCScreen = GetDC(IntPtr.Zero);
    float nLogPixelsXScreen = GetDeviceCaps(hDCScreen, LOGPIXELSX);
    float nLogPixelsYScreen = GetDeviceCaps(hDCScreen, LOGPIXELSY);
    ReleaseDC(hDCScreen, IntPtr.Zero);
    float nLogPixelsXPrinter = GetDeviceCaps(hPrinterDC, LOGPIXELSX);
    float nLogPixelsYPrinter = GetDeviceCaps(hPrinterDC, LOGPIXELSY);

    float nScaleX = Math.Max(nLogPixelsXScreen, nLogPixelsXPrinter) / Math.Min(nLogPixelsXScreen, nLogPixelsXPrinter);
    float nScaleY = Math.Max(nLogPixelsYScreen, nLogPixelsYPrinter) / Math.Min(nLogPixelsYScreen, nLogPixelsYPrinter);

    System.Drawing.Drawing2D.Matrix transform = new System.Drawing.Drawing2D.Matrix();
    transform.Scale(nScaleX, nScaleY);
    XFORM renderTransform = new XFORM();
    var elements = transform.Elements;
    var m11 = elements[0];
    var m12 = elements[1];
    var m21 = elements[2];
    var m22 = elements[3];
    var dx = elements[4];
    var dy = elements[5];

    renderTransform.eM11 = (float)m11;
    renderTransform.eM12 = (float)m12;
    renderTransform.eM21 = (float)m21;
    renderTransform.eM22 = (float)m22;
    // Test offsets for (50, 50) showing font sizes are different when they start at same positions
    // int nOffsetX = 34;
    // int nOffsetY = -14;
    int nOffsetX = 0;
    int nOffsetY = 0;
    renderTransform.eDx = (float)transform.OffsetX + nOffsetX;
    renderTransform.eDy = (float)transform.OffsetY + nOffsetY;
    SetGraphicsMode(hPrinterDC, GM_ADVANCED);
    //SetMapMode(hPrinterDC, MM_LOENGLISH);
    SetMapMode(hPrinterDC, MM_TEXT);
    bool bRet = SetWorldTransform(hPrinterDC, ref renderTransform);

    var startX2 = startX1;
    var startY2 = startY1;
    RECT rc = new RECT(startX2, startY2, nPhysWidth, nPhysHeight);

    //Rectangle margins = e.MarginBounds;
    //// inches => mm => pixels
    //int nLeftPixels = MulDiv(margins.Left, 2540, 100000);
    //nLeftPixels = MulDiv(nLeftPixels, (int)nLogPixelsXScreen, 72);
    //startX2 += nLeftPixels;

    //// inches => mm => pixels
    //int nTopPixels = MulDiv(margins.Top, 2540, 100000);
    //nTopPixels = MulDiv(nTopPixels, (int)nLogPixelsYScreen, 72);
    //startY2 += nTopPixels;

    //rc.left = startX2;
    //rc.top = startY2;

    SetViewportOrgEx(hPrinterDC, -nPhysOffsetX, -nPhysOffsetY, IntPtr.Zero);

    //lf.lfHeight = MulDiv((int)-font.Size, (int)nLogPixelsYPrinter, 72);
    lf.lfHeight = (int)(lf.lfHeight / nScaleY);   

    IntPtr hFontNew = CreateFontIndirect(lf);
    IntPtr hFontOld = SelectObject(hPrinterDC, hFontNew);

    SetBkMode(hPrinterDC, TRANSPARENT);
    SetTextColor(hPrinterDC, ColorTranslator.ToWin32(Color.Blue));      
    ExtTextOut(hPrinterDC, rc.left, rc.top, ETO_OPAQUE, IntPtr.Zero, sbText, (uint)sbText.Length, IntPtr.Zero);

    rc.top += -lf.lfHeight;
    SetTextColor(hPrinterDC, ColorTranslator.ToWin32(Color.Green));
    ExtTextOut(hPrinterDC, rc.left, rc.top, ETO_OPAQUE, IntPtr.Zero, sbText, (uint)sbText.Length, IntPtr.Zero);

    var nExtra = -10.0f / nScaleX;
    //SetTextCharacterExtra(hPrinterDC, MulDiv(nExtra, 1440, nLogPixelsXPrinter));
    SetTextCharacterExtra(hPrinterDC, (int)nExtra);
    rc.top += -lf.lfHeight;
    SetTextColor(hPrinterDC, ColorTranslator.ToWin32(Color.Red));
    ExtTextOut(hPrinterDC, rc.left, rc.top, ETO_OPAQUE, IntPtr.Zero, sbText, (uint)sbText.Length, IntPtr.Zero);

    SelectObject(hPrinterDC, hFontOld);
    DeleteObject(hFontNew);
}

请通过此链接了解更多详情。

于 2021-03-11T05:13:32.760 回答