簡體   English   中英

使用 ImageSharp 縮小圖像文件

[英]Shrink image file using ImageSharp

我需要縮小我得到的每張超過 10MB 的圖像。 文件類型為 png、jpg 和 gif。 我看到 ImageSharp 有一個調整圖像大小的選項:

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

我看到了很多使用帶有寬度和高度的 resize 函數的例子,但沒有一個使用這個單一尺寸選項,也沒有文檔解釋“尺寸”的確切含義。

我嘗試了以下方法:使用maxFileSize=1024縮小 22.2MB 的圖像產生了 527.9MB 的圖片。 使用maxFileSize=1024*2*10 “縮小”相同的圖像產生了 47.4MB 的圖片。

如何將圖像縮小到大約 10MB(可以小一點)? 我的目標是限制為 10MB,如果超過,則將圖像減小到 10MB 以下的最大可能大小而不影響比率。

我不認為有一種簡單(可靠)的方法來計算圖像的壓縮大小,而不是壓縮它。

雖然 ImageSharp 似乎沒有為此提供本機 API,但我們可以使用現有功能來找到滿足我們約束的最佳大小。

主意:

  1. 我們可以假設較小的圖像占用較少的磁盤空間,即文件大小與像素數相關。 對於非常相似的圖像大小的一些復雜的壓縮算法,這可能不適用; 然而,即便如此,我們仍然應該能夠為完美的圖像尺寸找到一個很好的估計。
  2. 為圖像大小選擇一些粗略的下限和上限。 在最好的情況下,我們完美的圖像尺寸介於兩者之間。
  3. 通過反復調整和壓縮我們的圖像,在上述邊界之間執行二分搜索,直到它具有我們想要的文件大小。

對應的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);

這會加載圖像“image.jpg”並找到寬度bestWidth ,它產生的文件大小小於但接近MAXIMUM_FILE_SIZE

其他常量定義如下:

  • ESTIMATED_MINIMUM_WIDTH :完美圖像寬度的估計下限。 圖像永遠不會比這更小。 應該至少為0
  • ESTIMATED_MAXIMUM_WIDTH :完美圖像寬度的估計上限。 圖像永遠不會變得比這更大。 最多應該是image.Width
  • MAXIMUM_HEIGHT :最大圖像高度。 如果除了文件大小之外還有其他限制(例如,圖像必須適合特定的屏幕大小),這會很有幫助; 否則,這可以簡單地設置為image.Height

雖然二分搜索提供了良好的算法復雜度,但對於非常大的圖像,這仍然很慢。 如果時間很重要(問題沒有具體說明這一點),可以通過對bestWidth的上限和下限使用良好的初始估計來提高性能,例如,通過像素與字節的比率線性插值文件大小。

在查看更多文檔后,我現在看到單個 int 構造函數只是將相同的數字插入寬度和高度。

現在,我使用以下方法過度縮小圖像:

            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
            }

如果有人有更好的想法,我很樂意聽到。

目標是將圖像縮小到略低於 10MB(盡可能接近)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM