最近在开发一套系统,很多地方用到了缩略图,然而不同的地方用到的尺寸又不一样,上传的时候生成缩略图就没有意义了,因为你不知道会使用到哪些尺寸,于是想到即时生成的办法,前端判断图片是否存在,如果不存在则调用接口生成缩略图,同时接口返回缩略图的数据流。
本来功能都开发完成,可以达到目的,但是在会员头像使用Png生成缩略图是遇到了一个问题,就是生成的缩略图不是透明的,变成黑底色了。更奇怪的问题是并不是所有png图片都这样,同一张图片在不同的地方也有不一样的效果。
没有修改之前的代码如下:
/// <summary> /// 访问图片,接口调用方式 https://您的域名/WebApi/common/200/image%2F2022-06%2Fbb372369c3ad4d458ad2aee6c00ca4bd.png
///其中200是图片宽度,后面是图片的相对路径 /// </summary> /// <param name="width">所访问图片的宽度,高度自动缩放,大于原图尺寸或者小于等于0返回原图</param> /// <param name="name">所要访问图片的名称或者相对地址</param> /// <returns>图片</returns> [HttpGet] [Route("{width}/{name}")] public IActionResult GetImage(int width, string name) { var errorImage = "/static/common/images/404.png";//没有找到图片 if(name.IsEmptyString()) { name = errorImage; } else { name = HttpUtility.UrlDecode(name, Encoding.GetEncoding("utf-8")); name = name.Replace("/", "\\"); if(name.StartsWith("\\")) { name = name.Substring(1); } } var contentTypeStr = "image/jpeg"; var ext = Path.GetExtension(name); //未知的图片类型 if(!FileHelper.IsImageExt(ext)) { name = errorImage; } else { contentTypeStr = FileHelper.GetContentType(ext); } bool isThum = false;//是否是缩略图 var thumname = name;//缩略图路径 bool saveThum = false; //原图 if(width <= 0) { using(var sw = objectStorage.GetObject(name)) { var bytes = new byte[sw.Length]; sw.Read(bytes, 0, bytes.Length); sw.Close(); return new FileContentResult(bytes, contentTypeStr); } } else { thumname = name.Replace(ext, "_" + width + ext); isThum = true; } if(name != errorImage && !objectStorage.ExistObject(name)) { name = errorImage; } if(isThum && !objectStorage.ExistObject(thumname)) { saveThum = true; } //缩小图片 using(var imgBmp = new Bitmap(Image.FromStream(objectStorage.GetObject(name)))) { //找到新尺寸 var oWidth = imgBmp.Width; var oHeight = imgBmp.Height; var height = oHeight; if(width > oWidth) { width = oWidth; } else { height = width * oHeight / oWidth; } var newImg = new Bitmap(imgBmp, width, height); newImg.SetResolution(72, 72); var ms = new MemoryStream(); newImg.Save(ms, ImageFormat.Bmp); if(saveThum) {
//这里是调用的类似OSS保存图片的方法 objectStorage.PutObject(thumname, ms); ms.Position = 0; } var bytes = ms.GetBuffer(); ms.Close(); return new FileContentResult(bytes, contentTypeStr); } }
代码如上,表面上看起来看不出来问题,后来我认真检查了一下代码,发现newImg.Save(ms, ImageFormat.Bmp);这句代码有点问题,为什么是固定的bmp格式,于是我将这句代码改成如下代码:
switch(ext.ToLower()) { case ".jpg": case ".jpeg": case ".jpe": case ".jfif": newImg.Save(ms, ImageFormat.Jpeg); break; case ".png": newImg.Save(ms, ImageFormat.Png); break; case ".gif": newImg.Save(ms, ImageFormat.Gif); break; case ".tif": case ".tiff": newImg.Save(ms, ImageFormat.Tiff); break; case ".bmp": case ".wbmp": newImg.Save(ms, ImageFormat.Bmp); break; default: newImg.Save(ms, ImageFormat.Jpeg); break; }
问题解决,原来文件流里面也是要指定文件保存的格式的,不然就会出现想不到的问题。