简体   繁体   中英

System.Drawing.Graphics.DrawString - “Parameter is not valid” exception

Sometimes Microsoft's exception messages are infuriatingly unhelpful. I have created a nice little MVC method to render text. The method body is below. When it reaches the "DrawString" method, I get an exception thrown saying "Parameter is not valid".

Note that the font, as best I can tell is constructed properly (I"m just using Arial at 10pt), the rect size is positive and valid looking, the brush is a white SolidBrush and the format flags do not affect the output; ie if I exclude the format flags from the call, I still get an error.

The DrawString call is right near the bottom.

public ActionResult RenderText(
    string fontFamily,
    float pointSize,
    string foreColor,
    string backColor,
    bool isBold,
    bool isItalic,
    bool isVertical,
    string align,
    string[] allText,
    int textIndex)
{
    // method renders a horizontal or vertical text image, taking all the text strings that will be rendered in each image
    // and sizing the final bitmap according to which text would take the most space, thereby making it possible to render
    // a selection of text images all at the same size.

    Response.ContentType = "image/png";

    var fmt = StringFormat.GenericTypographic;
    if(isVertical)
        fmt.FormatFlags = StringFormatFlags.DirectionVertical;

    Func<string,StringAlignment> getAlign = (s => {
        switch(s.ToLower())
        {
            case "right": return StringAlignment.Far;
            case "center": return StringAlignment.Center;
            default: return StringAlignment.Near;
        }
    });
    fmt.LineAlignment = isVertical ? StringAlignment.Center : getAlign(align);
    fmt.Alignment = isVertical ? getAlign(align) : StringAlignment.Center;

    var strings = (allText ?? new string[0]).Where(t => t.Length > 0).ToList();
    if(strings.Count == 0)
        strings.Add("[Missing Text]");

    FontStyle style = FontStyle.Regular;
    if(isBold)
        if(isItalic)
            style = FontStyle.Bold | FontStyle.Italic;
        else
            style = FontStyle.Bold;
    else if(isItalic)
        style = FontStyle.Italic;

    Font font = new Font(fontFamily, pointSize, style, GraphicsUnit.Point);
    Color fc = foreColor.IsHexColorString() ? foreColor.ToColorFromHex() : foreColor.ToColor();
    Color bc = backColor.IsHexColorString() ? backColor.ToColorFromHex() : backColor.ToColor();

    var maxSize = new Size(0,0);
    using(var tmp = new Bitmap(100, 200))
        using(var gfx = Graphics.FromImage(tmp))
            foreach(var txt in strings)
            {
                var size = gfx.MeasureString(txt, font, 1000, fmt);
                maxSize = new Size(
                    Math.Max(Convert.ToInt32(isVertical ? size.Height : size.Width), maxSize.Width),
                    Math.Max(Convert.ToInt32(isVertical ? size.Width : size.Height), maxSize.Width)
                );
            }

    using(var bmp = new Bitmap(maxSize.Width, maxSize.Height))
    {
        using(var gfx = Graphics.FromImage(bmp))
        {
            gfx.CompositingMode = CompositingMode.SourceCopy;
            gfx.CompositingQuality = CompositingQuality.HighQuality;
            gfx.SmoothingMode = SmoothingMode.HighQuality;
            gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;

            var rect = new RectangleF(new PointF(0,0), maxSize);
            gfx.FillRectangle(new SolidBrush(bc), rect);
            gfx.DrawString(strings[textIndex], font, new SolidBrush(fc), rect, fmt);
        }
        bmp.Save(Response.OutputStream, ImageFormat.Png);
    }
    return new EmptyResult();
}

Well I found out the cause of the problem. Something very obscure. The code works when I remove this line:

gfx.CompositingMode = CompositingMode.SourceCopy;

What could help while debugging, is making the methods smaller. For example, you could replace

FontStyle style = FontStyle.Regular;
if(isBold)
    if(isItalic)
        style = FontStyle.Bold | FontStyle.Italic;
    else
        style = FontStyle.Bold;
else if(isItalic)
    style = FontStyle.Italic;

by

FontStyle style = GetFontStyle(isBold, isItalic);

and

public FontStyle GetFontStyle(bool isBold, bool isItalic)
{
    if(isBold)
        if(isItalic)
            return FontStyle.Bold | FontStyle.Italic;
        else
            return FontStyle.Bold;
    else if(isItalic)
        return FontStyle.Italic;
    else
        return FontStyle.Regular;
}

It makes your code more readable and it makes it more easy for others to help you.

Really no offense meant!

Kind regards, Ans Vlug

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM