【问题标题】:How to Resize Center and Crop an image with ImageSharp如何使用 ImageSharp 调整中心和裁剪图像
【发布时间】:2019-03-22 11:13:59
【问题描述】:

我需要转换一些基于 System.Drawing 的代码来使用这个 .NET Core 兼容库:

https://github.com/SixLabors/ImageSharp

下面基于 System.Drawing 的代码调整图像大小并裁剪边缘,返回内存流以进行保存。 ImageSharp 库可以做到这一点吗?

private static Stream Resize(Stream inStream, int newWidth, int newHeight)
{
    var img = Image.Load(inStream);
    if (newWidth != img.Width || newHeight != img.Height)
    {
        var ratioX = (double)newWidth / img.Width;
        var ratioY = (double)newHeight / img.Height;
        var ratio = Math.Max(ratioX, ratioY);
        var width = (int)(img.Width * ratio);
        var height = (int)(img.Height * ratio);

        var newImage = new Bitmap(width, height);
        Graphics.FromImage(newImage).DrawImage(img, 0, 0, width, height);
        img = newImage;

        if (img.Width != newWidth || img.Height != newHeight)
        {
            var startX = (Math.Max(img.Width, newWidth) - Math.Min(img.Width, newWidth)) / 2;
            var startY = (Math.Max(img.Height, newHeight) - Math.Min(img.Height, newHeight)) / 2;
            img = Crop(img, newWidth, newHeight, startX, startY);
        }
    }

    var ms = new MemoryStream();
    img.Save(ms, ImageFormat.Jpeg);
    ms.Position = 0;
    return ms;
}

private static Image Crop(Image image, int newWidth, int newHeight, int startX = 0, int startY = 0)
{
    if (image.Height < newHeight)
        newHeight = image.Height;

    if (image.Width < newWidth)
        newWidth = image.Width;

    using (var bmp = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb))
    {
        bmp.SetResolution(72, 72);
        using (var g = Graphics.FromImage(bmp))
        {
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.PixelOffsetMode = PixelOffsetMode.HighQuality;
            g.DrawImage(image, new Rectangle(0, 0, newWidth, newHeight), startX, startY, newWidth, newHeight, GraphicsUnit.Pixel);

            var ms = new MemoryStream();
            bmp.Save(ms, ImageFormat.Jpeg);
            image.Dispose();
            var outimage = Image.FromStream(ms);
            return outimage;
        }
    }
}

【问题讨论】:

标签: c# imagesharp


【解决方案1】:

是的,超级简单。

using (var inStream = ...)
using (var outStream = new MemoryStream())
using (var image = Image.Load(inStream, out IImageFormat format))
{
    image.Mutate(
        i => i.Resize(width, height)
              .Crop(new Rectangle(x, y, cropWidth, cropHeight)));

    image.Save(outStream, format);
}

编辑 如果您想保持原始图像不变,可以使用Clone 方法。

using (var inStream = ...)
using (var outStream = new MemoryStream())
using (var image = Image.Load(inStream, out IImageFormat format))
{
    var clone = image.Clone(
                    i => i.Resize(width, height)
                          .Crop(new Rectangle(x, y, cropWidth, cropHeight)));

    clone.Save(outStream, format);
}

您甚至可以通过接受带有`ResizeMode.Crop 的ResizeOptions 实例的重载将其优化为对Resize 的单个方法调用。这将允许您调整到一个比例,然后裁剪掉超出该比例的任何多余部分。

【讨论】:

  • 太棒了,看来我可以完全放弃原来的 Resize 和 Crop 方法了。我用它们来保存三种不同的尺寸。每次保存后我是否需要从“instream”重新加载,或者如果我每次都剪得更小,我是否会通过不重新加载来获得性能优势?
  • 我也想知道 ResizeMode.Crop 是否会输出与 Resize 相同的图像,然后是 Crop?如果您有“给我买杯咖啡”页面需要支持?
  • 我只是使用了 github 页面底部的支持者链接(数量很少,但我的网站目前正在亏损),其他人:github.com/SixLabors/ImageSharp
  • 谢谢!我添加了一个额外的代码示例,说明如何克隆图像并调整大小,保持原始图像不变。这样,您可以一次加载图像并多次调整大小而不会降低质量。 ResizeMode.Crop 应该默认创建相同的输出,只要裁剪居中,尽管您可以设置坐标。
  • 嗨@JamesSouth,为死灵术道歉。我使用或多或少相同的方式从传入的图像生成缩略图,除了克隆部分。但是,一旦我将某些 jpeg 图像调整为缩略图,它们的一侧就会出现扭曲的边框。我了解到这与 ICC 颜色配置文件和 jpeg 编码器有关,但找不到(也不理解)究竟是什么原因造成的。你遇到过这个吗?你能建议一个解决方案吗? TIA。
【解决方案2】:

所以这里是转换为不使用原始方法后的相关代码:

using (var fullSizeStream = new MemoryStream())
using (var smallStream = new MemoryStream())
using (var thumbStream = new MemoryStream())
using (var reviewThumbStream = new MemoryStream())
using (var image = Image.Load(inStream))
{
    // Save original constrained
    var clone = image.Clone(context => context
        .Resize(new ResizeOptions
        {
            Mode = ResizeMode.Max,
            Size = new Size(1280, 1280)
        }));
    clone.Save(fullSizeStream, new JpegEncoder { Quality = 80 });

    //Save three sizes Cropped:
    var jpegEncoder = new JpegEncoder { Quality = 75 };
    clone = image.Clone(context => context
        .Resize(new ResizeOptions
        {
            Mode = ResizeMode.Crop,
            Size = new Size(277, 277)
        }));
    clone.Save(smallStream, jpegEncoder);

    clone = image.Clone(context => context
        .Resize(new ResizeOptions
        {
            Mode = ResizeMode.Crop,
            Size = new Size(100, 100)
        }));
    clone.Save(thumbStream, jpegEncoder);

    clone = image.Clone(context => context
        .Resize(new ResizeOptions
        {
            Mode = ResizeMode.Crop,
            Size = new Size(50, 50)
        }));
    clone.Save(reviewThumbStream, jpegEncoder);

    //...then I just save the streams to blob storage
}

【讨论】:

  • 编辑使用克隆。
猜你喜欢
  • 2015-03-05
  • 1970-01-01
  • 2011-09-23
  • 2013-02-11
  • 1970-01-01
  • 2012-05-15
  • 2018-07-21
  • 2017-03-06
  • 1970-01-01
相关资源
最近更新 更多