我在网站上进行了一项操作,即裁剪图像,但是文件大小合成的裁剪图像显得更大(原始图像为24k,裁剪后的图像为650k)。所以我发现在保存之前我需要对图像应用一些压缩。我想出了以下内容:
public static System.Drawing.Image CropImage(System.Drawing.Image image, Rectangle cropRectangle, ImageFormat format)
{
var croppedImage = new Bitmap(cropRectangle.Width, cropRectangle.Height);
using (var g = Graphics.FromImage(croppedImage))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(
image,
new Rectangle(new Point(0,0), new Size(cropRectangle.Width, cropRectangle.Height)),
cropRectangle,
GraphicsUnit.Pixel);
return CompressImage(croppedImage, format);
}
}
public static System.Drawing.Image CompressImage(System.Drawing.Image image, ImageFormat imageFormat)
{
var bmp = new Bitmap(image);
var codecInfo = EncoderFactory.GetEncoderInfo(imageFormat);
var encoder = System.Drawing.Imaging.Encoder.Quality;
var parameters = new EncoderParameters(1);
var parameter = new EncoderParameter(encoder, 10L);
parameters.Param[0] = parameter;
using (var ms = new MemoryStream())
{
bmp.Save(ms, codecInfo, parameters);
var resultImage = System.Drawing.Image.FromStream(ms);
return resultImage;
}
}
我将质量设置得很低,只是为了看看是否有任何变化。没有。作物正在外观上得到正确保存,但压缩并不是一种乐趣。如果我完全绕过CompressImage(),文件大小和图像质量都不会有任何不同。
所以,2个问题。为什么没有发生?是否有一种更简单的方法将结果图像压缩为“网络优化”,类似于photoshop保存网页图像的方式(我认为它只是从中删除了大量信息以减小尺寸)。
答案 0 :(得分:3)
您的问题是您必须在保存图像时“压缩”(真正编码)图像,而不是在保存图像之前。程序中的Image对象始终是未压缩的。
通过保存到MemoryStream并从流中读回来将对图像进行编码,然后再将其解码回相同的大小(如果使用JPEG,则在此过程中会有一些质量损失)。但是,如果将其保存到具有压缩参数的文件中,您将获得压缩的图像文件。
在153 KB源图像上使用JPEG质量等级为90的例程可以得到102 KB的输出图像。如果您想要更小的文件大小(具有更多编码伪像),请将编码器参数更改为小于90的值。
public static void SaveJpegImage(System.Drawing.Image image, string fileName)
{
ImageCodecInfo codecInfo = ImageCodecInfo.GetImageEncoders()
.Where(r => r.CodecName.ToUpperInvariant().Contains("JPEG"))
.Select(r => r).FirstOrDefault();
var encoder = System.Drawing.Imaging.Encoder.Quality;
var parameters = new EncoderParameters(1);
var parameter = new EncoderParameter(encoder, 90L);
parameters.Param[0] = parameter;
using (FileStream fs = new FileStream(fileName, FileMode.Create))
{
image.Save(fs, codecInfo, parameters);
}
}
答案 1 :(得分:-1)
我相信在使用引用流的Image.FromStream创建的图像时,不应该丢弃MemoryStream。直接从流创建位图也不起作用。
试试这个:
private static Image CropAndCompressImage(Image image, Rectangle rectangle, ImageFormat imageFormat)
{
using(Bitmap bitmap = new Bitmap(image))
{
using(Bitmap cropped = bitmap.Clone(rectangle, bitmap.PixelFormat))
{
using (MemoryStream memoryStream = new MemoryStream())
{
cropped.Save(memoryStream, imageFormat);
return new Bitmap(Image.FromStream(memoryStream));
}
}
}
}