Создать миниатюру изображения с закругленными углами - PullRequest
0 голосов
/ 10 марта 2011

Мне нужно создать миниатюру изображения с прозрачными закругленными углами.Перед этим требованием я использовал простое:

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 ]

2 голосов
/ 15 марта 2011

Я написал пост в блоге, который объясняет, как именно это сделать.

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

Если вы посмотрите на первые образцы изображений, вы увидите 5), и я покажу, как добраться до 6). Удачи.

0 голосов
/ 18 марта 2011

Я использовал модифицированный метод 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;
0 голосов
/ 10 марта 2011

Я бы сначала скопировал изображение на второй с закругленными углами, а затем использовал GetThumbnailImage , чтобы уменьшить его.

...