views:

2991

answers:

2

I'm trying to draw images on a C# form (in PictureBoxes, as well as using Graphics.DrawImage()), and am looking for a way to draw them smooth. The images must be a format that supports transparency, so PNG, GIF, SVG, and WMF. C# doesn't support SVG files out of the box, and I haven't found a good third-party library to use (I found SvgNet, but couldn't figure it out).

I need to draw a WMF file, which C# can do via the Image.FromFile() function, but it's not anti-aliased. I was wondering if there's any way to smooth this out?

Thanks,

-Mike

+3  A: 

When drawing the image to a canvas, you can change the interpolation mode to something nicer then nearest neighbor to make resized images smooth:

Graphics g = ...
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(...);

You'll need to add System.Drawing.Drawing2D to get the InterpolationMode enum.

Using PictureBox will be a problem - it doesn't expose an InterpolationMode property, so you'll need to roll your own or download one.

David
Any idea where I could find a downloadable one, or how to go about doing my own? I'm a novice C# developer, and writing my own might be a task that's slightly beyond my current capabilities.
As a novice the easiest way to start rolling your own class might be to place a Panel control, and then write its Paint event (on the properties window, select events [the lightning icon] then double click beside the Paint event in the list). Use the e.Graphics param to write replacement draw code.
David
+3  A: 

The previous answers, while well intended were only partially correct.

What was correct? PictureBox doesn't expose InterpolationMode.

What was off base?

1) While you can easily set that property in the Paint event from the picture box, in its parent, or via an override in a derived class. . . Either way works and both are just as easy. However, unless SmoothingMode is set, the InterpolationMode will be ignored. You won't get any anti-aliasing without SmoothingMode set to SmoothingMode.AnitAlias.

2) Using a Panel when you've clearly expressed an interest in using the features of PictureBox is the wrong direction to go. You will lack any ability to load, save, or assign images directly to it without explicitly coding those properties. . . Why re-invent the wheel? By deriving off of PictureBox you get all of that for free.

The news gets even better as I've done the hard work for you and it took me less time than writing this message.

I've provided two version both of which derive from PictureBox. First is a simple example which always uses the best quality rendering possible. This is also the slowest rendering. Second is a class that allows anyone to set the various rendering parameters via properties off the derived class. Once set these are used in the OnPaint override.

public class HighQualitySmoothPictureBox : PictureBox
{
    protected override void OnPaint(PaintEventArgs pe)
    {
        // This is the only line needed for anti-aliasing to be turned on.
        pe.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

        // the next two lines of code (not comments) are needed to get the highest 
        // possible quiality of anti-aliasing. Remove them if you want the image to render faster.
        pe.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
        pe.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        // this line is needed for .net to draw the contents.
        base.OnPaint(pe);
    }
}

...

public class ConfigurableQualityPictureBox : PictureBox
{
    // Note: the use of the "?" indicates the value type is "nullable."  
    // If the property is unset, it doesn't have a value, and therefore isn't 
    // used when the OnPaint method executes.
    System.Drawing.Drawing2D.SmoothingMode? smoothingMode;
    System.Drawing.Drawing2D.CompositingQuality? compositingQuality;
    System.Drawing.Drawing2D.InterpolationMode? interpolationMode;

    public System.Drawing.Drawing2D.SmoothingMode? SmoothingMode
    {
        get { return smoothingMode; }
        set { smoothingMode = value; }
    }

    public System.Drawing.Drawing2D.CompositingQuality? CompositingQuality
    {
        get { return compositingQuality; }
        set { compositingQuality = value; }
    }

    public System.Drawing.Drawing2D.InterpolationMode? InterpolationMode
    {
        get { return interpolationMode; }
        set { interpolationMode = value; }
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        if (smoothingMode.HasValue)
            pe.Graphics.SmoothingMode = smoothingMode.Value;
        if (compositingQuality.HasValue)
            pe.Graphics.CompositingQuality = compositingQuality.Value;
        if (interpolationMode.HasValue)
            pe.Graphics.InterpolationMode = interpolationMode.Value;

        // this line is needed for .net to draw the contents.
        base.OnPaint(pe);
    }
}
Jason D