[英]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,但我们可以使用现有功能来找到满足我们约束的最佳大小。
主意:
对应的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.