创建带圆角的图像缩略图

时间:2011-03-10 13:14:59

标签: c# .net gdi+

我需要创建一个带有透明圆角的缩略图。在此要求之前,我使用了简单的:

using (var b = new Bitmap(dataSize.Width, dataSize.Height, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(b))
{
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
    g.DrawImage(original, 0, 0, b.Width, b.Height);
}

即使没有任何插值也能产生很好的效果(减少到约50x50px)。现在有了圆角,我使用了下面的算法(4'如果有的话,我可以在4个角上的每一个都有可变的圆度):

using (var b = new Bitmap(dataSize.Width, dataSize.Height, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(b))
{
    // set interpolation
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.SmoothingMode = SmoothingMode.HighQuality;

    // transformation to scale and shift the brush
    var transform = new Matrix();
    transform.Scale(ratio, ratio);
    transform.Translate(start.X / ratio, start.Y / ratio);
    var brush = new TextureBrush(original) { Transform = transform };

    // create path for stamping the iamge
    var gp = new GraphicsPath(FillMode.Winding);
    if (descriptor.CornerRadiusLeftTop > 0)
        gp.AddArc(descriptor.GetLeftTopCorner(b.Size), 180, 90);
    else
        gp.AddLine(-1, -1, -1, -1);

    if (descriptor.CornerRadiusRightTop > 0)
        gp.AddArc(descriptor.GetRightTopCorner(b.Size), 270, 90);
    else
        gp.AddLine(b.Width + 1, -1, b.Width + 1, -1);

    if (descriptor.CornerRadiusRightBottom > 0)
        gp.AddArc(descriptor.GetRightBottomCorner(b.Size), 0, 90);
    else
        gp.AddLine(b.Width + 1, b.Height + 1, b.Width + 1, b.Height + 1);

    if (descriptor.CornerRadiusLeftBottom > 0)
        gp.AddArc(descriptor.GetLeftBottomCorner(b.Size), 90, 90);
    else
        gp.AddLine(-1, b.Height + 1, -1, b.Height + 1);
    // stamp the image with original
    g.FillPath(brush, gp);
}

但是这种方法产生了丑陋的非插值图像,具有非常锯齿状的渐变。是否有更好的方法来创建透明缩略图,或者是否有一些设置可以用来改善输出?

3 个答案:

答案 0 :(得分:2)

我写了一篇博文,详细解释了如何做到这一点。

http://danbystrom.se/2008/08/24/soft-edged-images-in-gdi/

如果你看第一张样本图像,你会看到5)我会展示如何到达6)。祝你好运。

答案 1 :(得分:0)

我首先将图像复制到带圆角的第二个图像,然后使用GetThumbnailImage将其缩小。

答案 2 :(得分:0)

我使用了一个修改过的TransferChannel方法来添加掩码,这在danbystrom的博客文章中并不安全。

    public static void TransferChannel(Bitmap src, Bitmap dst, ChannelARGB sourceChannel, ChannelARGB destChannel)
    {
        if (src.Size != dst.Size)
            throw new ArgumentException();

        var r = new Rectangle(Point.Empty, src.Size);
        var bdSrc = src.LockBits(r, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        var bdDst = dst.LockBits(r, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

        var s = bdSrc.Stride * src.Height;
        var baSrc = new byte[s];
        var baDst = new byte[s];

        Marshal.Copy(bdSrc.Scan0, baSrc, 0, s);
        Marshal.Copy(bdDst.Scan0, baDst, 0, s);

        for (var counter = 0; counter < baSrc.Length; counter += 4)
            baDst[counter + (int)destChannel] = baSrc[counter + (int)sourceChannel];

        Marshal.Copy(baDst, 0, bdDst.Scan0, s);

        src.UnlockBits(bdSrc);
        dst.UnlockBits(bdDst);
    }

我调整大小和圆角的方法是:

        var b = new Bitmap(dataSize.Width, dataSize.Height, PixelFormat.Format32bppArgb);

        using (var g = Graphics.FromImage(b))
        {
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.DrawImage(original, start.X, start.Y, original.Width * ratio, original.Height * ratio);

            if (hasRoundedCorners)
                using (var mask = CreateMask(dataSize, radius))
                    TransferChannel(mask, b, ChannelARGB.Blue, ChannelARGB.Alpha);
        }
        return b;