最近在做图片上传功能,类似于微信朋友圈的功能,现在的手机像素都比较高,手机上的图片一般都比较大(几M),对于大图,在上传之前,我们需要对图片进行压缩(分辨率和质量),再上传到服务器,以减少网路流量传输
实现思路:
判断图片是否大于指定的大小
否:原图上传
是:通过BitmapImage检测出图片分辨率,然后将分辨率限制在1200*1200分辨率以内(保持宽高比),然后通过SaveJpeg方法写入到流中
笔者测试,绝大部分图片处理后都能控制在300kb以内(部分超过一点)
using System; using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; namespace XTuOne.Utility.Helpers { public class ImageHelper { /// <summary> /// 压缩图片 /// </summary> /// <param name="imageStream">输入</param> /// <param name="quality">压缩质量</param> /// <param name="maxKb">最大大小(单位kb)只供参考</param> public static Stream CompressImage(Stream imageStream, int quality = 80, int maxKb = 300) { if (imageStream.Length > 300*1024) { if (imageStream.CanSeek) { imageStream.Seek(0, SeekOrigin.Begin); } var bitmapImage = new BitmapImage(); bitmapImage.SetSource(imageStream); var writeableBitmap = new WriteableBitmap(bitmapImage); var tempStreamm = new MemoryStream(); var size = GetSize(bitmapImage.PixelWidth, bitmapImage.PixelHeight); writeableBitmap.SaveJpeg(tempStreamm, (int)size.Width, (int)size.Height, 0, 80); return tempStreamm; } return imageStream; } private static Size GetSize(Size size) { return GetSize(size.Width, size.Height); } private static Size GetSize(double width, double height) { if (width > height) { if (width > 1200) { return new Size(1200, Convert.ToInt32(height * 1200 / width)); } return new Size(width, height); } else { if (height > 1200) { return new Size(Convert.ToInt32(width * 1200 / height), 1200); } return new Size(width, height); } } } }
测试中发现一个问题:如果图片太大(5000*5000)的话,BitmapImage读取出来的宽高会被限制在4096*4096之内,如果超过4096,则取4096,保持宽高比,所以如果图片过大,通过BitmapImage是无法获取到图片的真实分辨率的
下面演示读取SavePicture文件夹中的图片,并进行压缩
var library = new MediaLibrary(); foreach (var savedPicture in library.SavedPictures) { using (var stream = savedPicture.GetImage()) { using (var tempStream = ImageHelper.CompressImage(stream)) { Debug.WriteLine("图片压缩前大小:{0:f2}kb, 图片压缩后大小:{1:f2}kb", stream.Length/1024.0, tempStream.Length/1024.0); } GC.Collect(); } }
注意:对图片的处理(特别是比较大的图片)很容易造成内存不足的情况(笔者在测试的时候,处理到第三张图片(比较大的图片5-10M)的时候就会出现内存不足的情况)
所以在使用的时候,没用的Stream应该及时释放掉(using),如果有多张图片需要处理
为了防止内存不足造成异常,可以通过延迟处理,在处理完一张图片后,等待100毫秒,然后继续
//延迟0.1秒 await Task.Delay(100);