简体   繁体   English

使用 ImageSharp 缩小图像文件

[英]Shrink image file using ImageSharp

I need to shrink every image I get that is more than 10MB.我需要缩小我得到的每张超过 10MB 的图像。 File types are png, jpg and gif.文件类型为 png、jpg 和 gif。 I saw that ImageSharp has an option to resize an image:我看到 ImageSharp 有一个调整图像大小的选项:

Resize(new ResizeOptions
{
    Mode = ResizeMode.Max,
    Size = new Size(maxFileSize)
}

I saw a lot of examples using the resize function with width and height, but none using this one size option, and no documentation explain exactly what "size" means.我看到了很多使用带有宽度和高度的 resize 函数的例子,但没有一个使用这个单一尺寸选项,也没有文档解释“尺寸”的确切含义。

I've tried the following: Shrinking an image of 22.2MB using maxFileSize=1024 yielded a picture of 527.9MB.我尝试了以下方法:使用maxFileSize=1024缩小 22.2MB 的图像产生了 527.9MB 的图片。 "Shrinking" the same image with maxFileSize=1024*2*10 yielded a 47.4MB picture.使用maxFileSize=1024*2*10 “缩小”相同的图像产生了 47.4MB 的图片。

How can I shrink an image to a size of roughly 10MB (can be a bit less)?如何将图像缩小到大约 10MB(可以小一点)? My goal here is to limit to 10MB, and, if exceeded, reduce the image to the maximal possible size under 10MB without affecting the ratio.我的目标是限制为 10MB,如果超过,则将图像减小到 10MB 以下的最大可能大小而不影响比率。

I don't think that there is an easy (and reliable) way to compute the compressed size of an image, without, well, compressing it.我不认为有一种简单(可靠)的方法来计算图像的压缩大小,而不是压缩它。

While ImageSharp doesn't seem to offer a native API for this, we can use existing functionality to find an optimal size which satisfies our constraints.虽然 ImageSharp 似乎没有为此提供本机 API,但我们可以使用现有功能来找到满足我们约束的最佳大小。

Idea:主意:

  1. We can assume that smaller images take less space on disk, ie, the file size is correlated with the number of pixels.我们可以假设较小的图像占用较少的磁盘空间,即文件大小与像素数相关。 This may not hold for some sophisticated compression algorithms on very similar image sizes;对于非常相似的图像大小的一些复杂的压缩算法,这可能不适用; however, even then we should still able to find a good estimation for the perfect image size.然而,即便如此,我们仍然应该能够为完美的图像尺寸找到一个很好的估计。
  2. Pick some rough lower and upper bounds for the image size.为图像大小选择一些粗略的下限和上限。 In the best case, our perfect image size lays somewhere in between.在最好的情况下,我们完美的图像尺寸介于两者之间。
  3. Perform a binary search between the aforementioned bounds, by repeatedly resizing and compressing our image, until it has our desired file size.通过反复调整和压缩我们的图像,在上述边界之间执行二分搜索,直到它具有我们想要的文件大小。

Corresponding C# code:对应的C#代码:

// Load original image
using Image image = Image.Load("image.jpg");

// Configure encoder
var imageEncoder = new JpegEncoder
{
    Quality = 95,
    Subsample = JpegSubsample.Ratio420
};

// Resize image, until it fits the desired file size and bounds
int min = ESTIMATED_MINIMUM_WIDTH;
int max = ESTIMATED_MAXIMUM_WIDTH;
int bestWidth = min;
using var tmpStream = new MemoryStream();
while(min <= max)
{
    // Resize image
    int width = (min + max) / 2;
    using var resizedImage = image.Clone(op =>
    {
        op.Resize(new ResizeOptions
        {
            Mode = ResizeMode.Max,
            Size = new Size(width, MAXIMUM_HEIGHT)
        });
    });

    // Compress image
    tmpStream.SetLength(0);
    resizedImage.Save(tmpStream, imageEncoder);

    // Check file size of resized image
    if(tmpStream.Position < MAXIMUM_FILE_SIZE)
    {
        // The current width satisfies the size constraint
        bestWidth = width;

        // Try to make image bigger again
        min = width + 1;
    }
    else
    {
        // Image is still too large, continue shrinking
        max = width - 1;
    }
}

// Resize and store final image
image.Mutate(op =>
{
    op.Resize(new ResizeOptions
    {
        Mode = ResizeMode.Max,
        Size = new Size(bestWidth, MAXIMUM_HEIGHT)
    });
});

// Store resized image
image.Save("image-resized.jpg", imageEncoder);

This loads the image "image.jpg" and finds the width bestWidth which yields a file size smaller than, but near to MAXIMUM_FILE_SIZE .这会加载图像“image.jpg”并找到宽度bestWidth ,它产生的文件大小小于但接近MAXIMUM_FILE_SIZE

The other constants are defined as follows:其他常量定义如下:

  • ESTIMATED_MINIMUM_WIDTH : The estimated lower bound for the perfect image width. ESTIMATED_MINIMUM_WIDTH :完美图像宽度的估计下限。 The image will never become smaller than this.图像永远不会比这更小。 Should be at least 0 .应该至少为0
  • ESTIMATED_MAXIMUM_WIDTH : The estimated upper bound for the perfect image width. ESTIMATED_MAXIMUM_WIDTH :完美图像宽度的估计上限。 The image will never become larger than this.图像永远不会变得比这更大。 Should be at most image.Width .最多应该是image.Width
  • MAXIMUM_HEIGHT : The maximum image height. MAXIMUM_HEIGHT :最大图像高度。 This is helpful if there are other constraints than the file size (eg, the image must fit a certain screen size);如果除了文件大小之外还有其他限制(例如,图像必须适合特定的屏幕大小),这会很有帮助; else, this can be simply set to image.Height .否则,这可以简单地设置为image.Height

While binary search offers good algorithmic complexity, this can still be quite slow for very large images.虽然二分搜索提供了良好的算法复杂度,但对于非常大的图像,这仍然很慢。 If time is important (the question doesn't specify this), the performance can be improved by using good initial estimations of the upper and lower bounds for bestWidth , eg, by linearly interpolating the file size through the ratio of pixels to bytes.如果时间很重要(问题没有具体说明这一点),可以通过对bestWidth的上限和下限使用良好的初始估计来提高性能,例如,通过像素与字节的比率线性插值文件大小。

After looking some more into the documentation I now see the single int constructor simply insert the same number to both width and height.在查看更多文档后,我现在看到单个 int 构造函数只是将相同的数字插入宽度和高度。

For now, I shrink the image way too much using the following:现在,我使用以下方法过度缩小图像:

            using (var image = Image.Load(imageFile))
            {
                var proportion = (double)imageFile.Length / maxFileSize;
                var maxWidth = (int)(image.Width / proportion);
                var maxHeight = (int)(image.Height / proportion);
                image.Mutate(x => x
                    .Resize(new ResizeOptions
                    {
                        Mode = ResizeMode.Max,
                        Size = new Size(maxWidth, maxHeight)
                    }));
                // Save the Image
            }

If anyone has better Idea I would love to hear it.如果有人有更好的想法,我很乐意听到。

The goal is to have the image shrink to just under 10MB (as close as possible).目标是将图像缩小到略低于 10MB(尽可能接近)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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