用C#

时间:2016-02-03 16:27:19

标签: c# asp.net-mvc image bitmap memorystream

我想要减少图像尺寸的功能。

该函数应该采用图像URL,检查图像是4MB大小还是更大,如果是,则调整大小为4MB并返回字节。

我有下一个方法:

public byte[] ResizeImage(string url)
{
    var uri = new Uri(url);
    var c = new WebClient();
    var oldImgStream = new MemoryStream(c.DownloadData(uri));

    if (oldImgStream.Length <= 4194304)
    {
        return oldImgStream.ToArray();
    }

    using (var oldImage = new Bitmap(oldImgStream))
    using (var newImageStream = new MemoryStream())
    {
        var format = oldImage.RawFormat;
        float resizePercent = (float)4194304 / oldImgStream.Length;
        var newImage =  ResizeImageByPercent(oldImage, resizePercent);

        newImage.Save(newImageStream, format);

       return newImageStream.ToArray();
    }
}

public static Bitmap ResizeImageByPercent(Bitmap image, float resizePercent)
{
    //Set minimum resizePercentage to 80%
    resizePercent = resizePercent > 0.8 ? (float)0.8 : resizePercent;

    int newWidth = (int)(image.Width * resizePercent);
    int newHeight = (int)(image.Height * resizePercent);

    var newImage = new Bitmap(newWidth, newHeight);
    using (var graphics = Graphics.FromImage(newImage))
    {
        graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
        graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        graphics.FillRectangle(Brushes.Transparent, 0, 0, newWidth, newHeight);
        graphics.DrawImage(image, 0, 0, newWidth, newHeight);
        return newImage;
    }
}

但这不行。

我有一个jpg图片作为例子。

图像大小略大于4MB(4194587字节)。 分辨率为2272 x 1704。

所以当我尝试使用上面的方法调整此图像的大小时。 它首先将“resizePercentage”计算为:

float resizePercent = (float)4194304 / oldImgStream.Length;
resizePercent = (float)4194304 / 4194587;
resizePercent = 0.9999325 //(99.99325%)

但是因为我设置了resizePercent的最小值,所以它将被设置为0.8(80%)。

resizePercent = 0.8;

然后它将使用此resizePercent计算新的宽度和高度。

新的分辨率将是:1817 x 1363并将图像调整为新分辨率。 但在将其保存为流并且它读取字节后,它会返回更大的图像。 返回图像的站点是“5146056字节”5MB

所以有人知道如何实现这个,或者我的方法有什么不对,所以它会返回更大的图像,甚至分辨率会降低。

我应该能够减少图像png,jpg和gif的大小

2 个答案:

答案 0 :(得分:1)

在处理压缩位图时,图像文件大小和分辨率之间不存在一对一的关联。这种相关确实存在于真正的位图(例如BMP),因为1个像素总是等于定义的字节数(基于颜色空间)。

然而,在谈论压缩位图(如JPEG)时,文件大小是基于压缩效率(总体上需要编码多少种颜色,基于相同颜色可以组合多少像素,或者抖动多少可以创建更多可以组合的相同颜色的像素。对于较低分辨率的图像,这可能最终会减少,但它也可以很容易地保持不变甚至增加,这取决于原始压缩的效率以及总体上较少像素数对压缩效率的影响。

无论多长时间,您都无法在分辨率上应用简单的基于百分比的缩减来确保某个文件大小。您可以真正做到的最好是逐渐降低分辨率,每次迭代测试文件大小,直到它低于您的阈值,假设它实际上低于阈值。有4MB可以使用,可以想象一定的分辨率肯定会低于这个分辨率,但这一点几乎无法计算。

此外,这将根据图像格式的类型而有所不同。 JPEG功能主要是通过尝试尽可能地扩散颜色(抖动)。这就是低质量JPEG显示伪像的原因。但是,PNG和GIF主要是索引,其中尝试减少颜色的总量(尽管两者也可以采用抖动)。 PNG进一步使问题变得复杂,因为它还可以具有无损PNG,其中保留所有颜色和像素,但是应用简单压缩(很像ZIP存档)以减小文件大小。所有这些都会在不同的分辨率下产生不同的行为。

答案 1 :(得分:0)

尝试更改InterpolationMode,SmoothingMode,CompositingQuality,PixelOffsetMode的质量。您可以看到所有这些都设置为高质量