【问题标题】:How to shrink an image to a target size in bytes in C#? [duplicate]如何在 C# 中将图像缩小到以字节为单位的目标大小? [复制]
【发布时间】:2021-08-12 03:12:26
【问题描述】:

如何在 C# 中将图像缩小到以字节为单位的目标大小?具体来说,我正在寻找上传到 ASP.NET 完整框架应用程序的图像并将其缩小,使其小于或等于最大字节数(例如 1 MB)。我对缩小的图像尺寸感到满意,并且可以接受图像质量的一些损失。

【问题讨论】:

  • “那个,因为它已经关闭了。” -- 是的……是有原因的。首先,“好方法”是基于意见的,对具体要求非常敏感。其次,问题中没有任何内容表明具体问题是什么。您在此处发布的问题与已关闭的问题几乎相同。当然,对于这个呈现不佳的问题也已经有了答案。如果您认为问题不应该关闭,您可以投票重新打开它,如果它再次打开,您可以发布答案。
  • 谢谢彼得。我不知道如何投票来打开另一个问题。我确实有能力编辑问题,您是否建议我编辑另一个问题以使其更加集中,然后在那里发布我的答案?
  • 您可以标记问题以重新打开...我不确定。我不记得标志选项是什么。您当然可以编辑问题以改进它。但我要指出,你必须 a) 确保你保持原作者的意图,而 b) 提出一个比这些问题中的任何一个问题都少得多的基于意见/含糊不清的问题。
  • 我在上次编辑中从我的问题中删除了“好方法”并详细说明了要求。这是一个有具体答案的具体问题。
  • 还是太模糊了。正如现在所说,鉴于您“可以接受图像质量的一些损失”,完全不清楚为什么您不只是以较低质量将图像重新编码为 JPEG 以获得您想要的大小.相反,将图像大小调整为保证小于 1 MB 的大小是微不足道的。这个问题仍然与重复的问题没有明显不同。请阅读How to Ask

标签: c# system.drawing


【解决方案1】:

如果您有权访问 System.Drawing (.NET Full Framework),则此代码有效。这个算法有点幼稚,因为它只是简单地将图像的尺寸缩小 10%,直到达到目标大小或超过最大尝试次数。它可以改进并减少蛮力。

using System.Drawing;
using System.IO;

public static class ImgUtil
{
    /// <summary>
    /// Attempt to shrink an image down to a target size in bytes. If the input image is 
    /// already small enough, it will be returned unaltered. If the image needs to be 
    /// shrunk, the output image will be smaller in terms of width/height but the width/height
    /// ratio will be preserved. There can be some loss of quality. The method attempts to
    /// shrink the dimensions of he image incrementally until the number of bytes is equal or
    /// less than the target. There is a maximum number of attempts. If the maximum number of
    /// attempts is reached, the output image may be larger than the target size.
    /// </summary>
    /// <param name="imageBytes">>Byte array containing the image to be shrunk.</param>
    /// <param name="targetSizeBytes">Target size in bytes.</param>
    /// <param name="maxAttempts">Maximum number of shrink attempts, reducing the dimensions by 10% each attempt.</param>
    /// <returns></returns>
    public static byte[] ShrinkImage(byte[] imageBytes, int targetSizeBytes, int maxAttempts = 10)
    {
        using (var ms = new MemoryStream(imageBytes))
        using (var img = Image.FromStream(ms))
        {
            var attempts = 1;
            var newWidth = img.Width;
            var newHeight = img.Height;
            while ((imageBytes.Length > targetSizeBytes) && (attempts <= maxAttempts))
            {
                // Shrink by 10%
                newWidth = (int)(newWidth * 0.9);
                newHeight = (int)(newHeight * 0.9);

                using (var bitmap = new Bitmap(img, new Size(newWidth, newHeight)))
                using (var outputMs = new MemoryStream())
                {
                    bitmap.Save(outputMs, img.RawFormat);
                    imageBytes = outputMs.ToArray();
                }

                attempts++;
            }
        }

        return imageBytes;
    }
}

【讨论】:

  • 这绝对是可怕的,你无缘无故地泄漏本机内存。
  • 1) 由于缺少using 指令而导致内存泄漏,2) 通过创建缩小版本的缩小版本而不是使用原始图像作为每个图像的源来不必要地损失图像质量步。 (另外:你可以用与 newWidth 相同的方式计算 newHeight 精确
  • 如果你想使用原始图像格式,你可以算出来。问题是关于压缩图像。那个地区在那里做什么?流在哪里处理?
  • 感谢您的反馈。我根据建议更新了代码块。 Blindy/Franz,我在处理代码时确实忘记了将 IDisposables 包装在 usings 中。我还去掉了不必要的 HBitmap 的使用。弗朗茨,关于使用原始图像每次调整大小的好建议。盲目的,我同意有一种方法可以“计算出来”,但我不知道该怎么做,因为压缩会起作用。如果你能详细说明你的想法,那将是受欢迎的。
猜你喜欢
  • 1970-01-01
  • 2014-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 2015-01-22
  • 1970-01-01
相关资源
最近更新 更多