Net core中使用System.Drawing对上传的图片流进行压缩
由于net core 中默认没有System.Drawing,可以通过nuget下载一个来代替System.Drawing.Common
直接压缩图片
/// <summary>
/// 图片压缩
/// </summary>
/// <param name="sFile">原图片位置</param>
/// <param name="dFile">压缩后图片位置</param>
/// <param name="dHeight">图片压缩后的高度</param>
/// <param name="dWidth">图片压缩后的宽度</param>
/// <param name="flag">图片压缩比0-100,数值越小压缩比越高,失真越多</param>
/// <returns></returns>
public static bool GetPicThumbnailTest(string sFile, string dFile, int dHeight, int dWidth, int flag)
{System.Drawing.Image iSource = System.Drawing.Image.FromFile(sFile);//如果为参数为0就保持原图片的高宽嘛(不然想保持原图外面还要去读取一次)if (dHeight == 0){dHeight = iSource.Height;}if (dWidth == 0){dWidth = iSource.Width;}ImageFormat tFormat = iSource.RawFormat;int sW = 0, sH = 0;//按比例缩放Size tem_size = new Size(iSource.Width, iSource.Height);if (tem_size.Width > dHeight || tem_size.Width > dWidth){if ((tem_size.Width * dHeight) > (tem_size.Width * dWidth)){sW = dWidth;sH = (dWidth * tem_size.Height) / tem_size.Width;}else{sH = dHeight;sW = (tem_size.Width * dHeight) / tem_size.Height;}}else{sW = tem_size.Width;sH = tem_size.Height;}Bitmap ob = new Bitmap(dWidth, dHeight);Graphics g = Graphics.FromImage(ob);g.Clear(Color.WhiteSmoke);g.CompositingQuality = CompositingQuality.HighQuality;g.SmoothingMode = SmoothingMode.HighQuality;g.InterpolationMode = InterpolationMode.HighQualityBicubic;g.DrawImage(iSource, new Rectangle((dWidth - sW) / 2, (dHeight - sH) / 2, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel);g.Dispose();//以下代码为保存图片时,设置压缩质量 EncoderParameters ep = new EncoderParameters();long[] qy = new long[1];qy[0] = flag;//设置压缩的比例1-100 EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy);ep.Param[0] = eParam;try{ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();ImageCodecInfo jpegICIinfo = null;for (int x = 0; x < arrayICI.Length; x++){if (arrayICI[x].FormatDescription.Equals("JPEG")){jpegICIinfo = arrayICI[x];break;}}if (jpegICIinfo != null){ob.Save(dFile, jpegICIinfo, ep);//dFile是压缩后的新路径 }else{ob.Save(dFile, tFormat);}return true;}catch{return false;}finally{iSource.Dispose();ob.Dispose();}
}
通过文件流压缩图片
有些时候我们不想先把图片保存后,然后在去读取压缩,我们想通过文件流就直接对图片进行压缩了,比如我们要把图片上传到七牛云
先把流进行压缩在上传到七牛云就比较科学了
1:首先我们需要通过图片上传的流来获取图片
foreach (IFormFile file in files)//获取多个文件列表集合{if (file.Length > 0){//获取图片上传的流Stream stream = file.OpenReadStream();//直接从流里边变成图片System.Drawing.Image iSource = System.Drawing.Image.FromStream(stream);}}
2:通过图片压缩算法把图片进行压缩
这里有一个参数是输入流,后面还有一个是压缩后的输出流
/// <summary>/// 上传图片文件/// </summary>/// <returns></returns>[HttpPost]public async Task<IActionResult> UploadImageFile_WeChat(){var file = IHttpContextAccessor.HttpContext.Request.Form.Files;if (file == null || file.Count == 0){return Fail("未上传有效文件");}var result = new List<dynamic>();foreach (var item in file){var ExtensionName = Path.GetExtension(item.FileName).ToLower();var RemotePath = getRemotePath(ExtensionName);if (string.IsNullOrEmpty(RemotePath) || !"image".Equals(RemotePath)){return Fail("不支持此类型文件的上传");}string remotePath = PathFormatter.Format(item.FileName + "." + ExtensionName, "/upload/" + RemotePath + "/image" + "/{yyyy}{mm}/{dd}{time}{rand:6}");string savePath = AppDomain.CurrentDomain.BaseDirectory + "/wwwroot/" + remotePath;MemoryStream memoryStream = new MemoryStream();//ob.Save(memoryStream, jpegICIinfo, ep);//这里的ob就是压缩后的Bitmap对象var k = GetPicThumbnail(item.OpenReadStream(), 0, 0, 70, memoryStream);System.Drawing.Image imgSource = System.Drawing.Image.FromStream(memoryStream);imgSource.Save(savePath);if (k){result.Add(new { url = Config.FileConfig.fileUrl + remotePath, remoteUrl = remotePath, name = item.FileName });}}return Success("上传成功", result);}private bool GetPicThumbnail(Stream stream, int dHeight, int dWidth, int flag, Stream outstream){//可以直接从流里边得到图片,这样就可以不先存储一份了System.Drawing.Image iSource = System.Drawing.Image.FromStream(stream);//如果为参数为0就保持原图片if (dHeight == 0){dHeight = iSource.Height;}if (dWidth == 0){dWidth = iSource.Width;}ImageFormat tFormat = iSource.RawFormat;int sW = 0, sH = 0;//按比例缩放Size tem_size = new Size(iSource.Width, iSource.Height);if (tem_size.Width > dHeight || tem_size.Width > dWidth){if ((tem_size.Width * dHeight) > (tem_size.Width * dWidth)){sW = dWidth;sH = (dWidth * tem_size.Height) / tem_size.Width;}else{sH = dHeight;sW = (tem_size.Width * dHeight) / tem_size.Height;}}else{sW = tem_size.Width;sH = tem_size.Height;}Bitmap ob = new Bitmap(dWidth, dHeight);Graphics g = Graphics.FromImage(ob);g.Clear(Color.WhiteSmoke);g.CompositingQuality = CompositingQuality.HighQuality;g.SmoothingMode = SmoothingMode.HighQuality;g.InterpolationMode = InterpolationMode.HighQualityBicubic;g.DrawImage(iSource, new Rectangle((dWidth - sW) / 2, (dHeight - sH) / 2, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel);g.Dispose();//以下代码为保存图片时,设置压缩质量 EncoderParameters ep = new EncoderParameters();long[] qy = new long[1];qy[0] = flag;//设置压缩的比例1-100 EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy);ep.Param[0] = eParam;try{ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();ImageCodecInfo jpegICIinfo = null;for (int x = 0; x < arrayICI.Length; x++){if (arrayICI[x].FormatDescription.Equals("JPEG")){jpegICIinfo = arrayICI[x];break;}}if (jpegICIinfo != null){//可以存储在流里边;ob.Save(outstream, jpegICIinfo, ep);}else{ob.Save(outstream, tFormat);}return true;}catch{return false;}finally{iSource.Dispose();ob.Dispose();}}
3:把压缩后的图片转化成流,很简单用一个内存流来中转一下就好了
MemoryStream memoryStream = new MemoryStream();ob.Save(memoryStream, jpegICIinfo, ep);//这里的ob就是压缩后的Bitmap对象
为了验证一下转化是否正确,我们可以把流在转化成图片然后在图片进行存储
System.Drawing.Image imgSource = System.Drawing.Image.FromStream(memoryStream);imgSource.Save("url");
如果能够成功压缩并成功保存就说明这些步骤都成功了!
这里说一下图片传输的思路:
图片文件这种本身是无法进行传输的,就像跨语言的对象也是无法进行传输。但是我们可以事先约定一种标准,
让双方都可以认识都可以解析的一种标准,比如base64,比如对象的json序列化,比如光纤信号的光波表示,其实原理都是一样。
上传到七牛云前压缩图片
通过上面的方法可以得到一个输出流,我们可以通过它进行图片的保存,但是如果直接把这个输出流传递到七牛云的方法中去,图片是不能被上传成功的,存储大小会是0kb,说明我们这个流七牛云的接口识别不到,也就是约定的内容不一样,我们要改造成七牛云能够被识别的状态
换一个方法尝试,直接用流不行,就从流里边读出来字节数组试试
//实例化一个内存流,存放压缩后的图片MemoryStream ysstream = new MemoryStream();bool issuc = ImageTool.GetPicThumbnail(stream, 300, 300, 80, ysstream);if (issuc){//通过流上传图片到七牛云//HttpResult result = um.UploadStream(stream, saveKey, uploadToken);//从内存流里边读出来字节数组上传到七牛云HttpResult result = um.UploadData(ysstream.ToArray(), saveKey, uploadToken);if (result.Code == 200){return Json(result.Text);}else{throw new Exception(result.RefText);//上传失败错误信息}}else{throw new Exception("图片压缩失败");//上传失败错误信息}
成功了
换回流试试呢,不应该啊。传递流进去他里边也应该是读取的直接哇,本质上都一样哇
还是不行,看来得看一下他这个源码了,看一下他拿到这个流过后是怎么去用的,就能针对性解决问题了
部署问题
在Windows环境下直接运行是没问题的,但是发布到Linux上就会报错
在Linux中安装
开始安装libgdiplus,执行【docker ps -a 】查看所有容器
【docker start 容器ID】 将容器运行起来
【docker exec -it e90f2b9d448d /bin/bash】进入该容器bash界面
执行【apt-get update】
【apt-get install -y libgdiplus】安装libgdiplus类库
【 ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll】创建链接文件
【eixt】退出docker bash到宿主机的bash,执行 【docker restart 容器ID】,此时接口已经能正确访问了
上面的方法有个弊端,假如容器被误删,又要重新给容器安装libgdiplus库。
我们可以把修改好的容器制作成镜像,执行【docker commit e90f2b9d448d skyapi_libgdiplus】,然后执行【docker images】,
可以看到名字叫skyapi_libgdiplus的Docker镜像已经制作好了。今后只需要在 docker run -t 参数后面指定 skyapi_libgdiplus镜像即可。
当前还可以将镜像保存到docker hub,本地硬盘都可以。
喜闻乐见的是,.NET 6发布了,但是避免不了新框架带来各种问题。在以往的跨平台应用中,往往采用System.Drawing.Common这个库作为图形编辑组件。
在.NET 6之前,在Linux操作系统中需要用到这个库时,只需要安装libgdiplus和libc6-dev这两个依赖即可。但是在.NET 6中,System.Drawing.Common被归为Windows特定的库,编译时产生“'Image.xxx()' is only supported on: 'windows'.”这样的警告。这不是最重要的,严重的是,在Linux中调用时,会产生“The type initializer for 'Gdip' threw an exception.”这样的异常。
产生原因
在设计上System.Drawing.Common 是 Windows 技术的精简包装器,因此其跨平台实现欠佳。
具微软文档中描述,在旧的行为上,libgdiplus 是本机端 System.Drawing.Common 跨平台实现的主要提供程序。 libgdiplus 实际上是对 System.Drawing.Common 所依赖的 Windows 部分的重新实现。 该实现使 libgdiplus 成为一个重要的组件。 它大约有 30,000 行 C 代码,大部分未经测试,而且缺少很多功能。 libgdiplus 还具有许多用于图像处理和文本呈现的外部依赖项,例如 cairo、pango 和其他本机库。 这些依赖项使得维护和交付组件更具挑战性。 自从包含 Mono 跨平台实现以来,我们已将许多从未得到修复的问题重定向到 libgdiplus。 相比之下,我们采用的其他外部依赖项,例如 icu 或 openssl,都是高质量的库。 使 libgdiplus 的功能集和质量与 .NET 堆栈的其余部分相媲美是不可行的。
在这之后,System.Drawing.Common 将仅在 Windows 窗体和 GDI+ 项目中使用。
解决方案
1、项目不会在Linux平台运行,仅在Windows中运行
可以忽略这个警告。
2、通过将 runtimeconfig.json 文件中的 System.Drawing.EnableUnixSupport 运行时配置开关设置为 true 来启用对非 Windows 平台的支持。
{"runtimeOptions": {"configProperties": {"System.Drawing.EnableUnixSupport": true}}
}
3、换用其它支持跨平台的图像处理库
如:
- ImageSharp
- SkiaSharp
需要注意的是,这些库并不与System.Drawing.Common的API兼容,所以更换相应的库之后需要重新编写相关代码。
Net core中使用System.Drawing对上传的图片流进行压缩相关推荐
- [译]如何在.NET Core中使用System.Drawing?
你大概知道System.Drawing,它是一个执行图形相关任务的流行的API,同时它也不属于.NET Core的一部分.最初是把.NET Core作为云端框架设计的,它不包含非云端相关API.另一方 ...
- linux docker 中使用 System.Drawing.Common 异常 System.Drawing.Common 仅在 Windows 上受支持
System.Drawing.Common NuGet 包现在被归类为特定于 Windows 的库.为非 Windows 操作系统编译时,平台分析器会在编译时发出警告. 在非 Windows 操作系统 ...
- .net core 使用 ZKWeb.system.drawing 在centos下使用gdi 画图
使用ZKWeb.system.drawing 背景 system.Drawing.Common 和 ZKWeb 的比较 项目中引用ZKWeb CentOS 中环境搭建 CentOS 字体库安装 1.拷 ...
- EF Core中关于System.Linq.Dynamic.Core的使用(转载)
项目中经常用到组合条件查询,根据用户配置的查询条件进行搜索,拼接SQL容易造成SQL注入,普通的LINQ可以用表达式树来完成,但也比较麻烦.有个System.Linq.Dynamic.Core用起来比 ...
- .net + html5上传,在.net Core中如何使用HTML5上传视频
最近刚做了视频上传的功能,有一些心得还有注意事项,这里不贴全部代码,主要是讲述编码思路.本代码基于.net core .html5示例 完成视频上传的两种思路 1.视频分片上传,比如把整个视频拆分成2 ...
- .Net Core上用于代替System.Drawing的类库
目前.Net Core上没有System.Drawing这个类库,想要在.Net Core上处理图片得另辟蹊径. 微软给出了将来取代System.Drawing的方案,偏向于使用一个单独的服务端进行各 ...
- 第五节:EF Core中的三类事务(SaveChanges、DbContextTransaction、TransactionScope)
一. 说明 EF版本的事务介绍详见: 第七节: EF的三种事务的应用场景和各自注意的问题(SaveChanges.DBContextTransaction.TransactionScope). 本节主 ...
- transactionscope 中的异步 处理 异常_.NET Core中TransactionScope事务处理方法介绍及注意事项...
作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712.html 今天在写CzarCms的UnitOfWork的使用使用到了这个Transacti ...
- unity 引用using System.Drawing.Printing
.NET类库System.Drawing提供了一系列的图形函数,但由于其使用的是GDI接口,与DirectX和OpenGL之间不兼容,在Unity中默认是不被支持的. 但有时候,我们想在Unity中使 ...
最新文章
- K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means)介绍与对比
- Mysql基础--常见的表的约束介绍(一)
- StringWriter/PrintWriter在Java输出异常信息中的作用
- 【Python基础】Python开发环境设置和小技巧
- 王道考研 计算机网络8 物理层基本概念 数据通信相关术语
- Docker简介与简单使用 | 技术头条
- android 控制流混淆 反向,AST混淆实战:仿obfuscator混淆控制流平坦化
- 下了班----你干啥
- windownavigatorscreenlocation
- 基于Docker布署伪分布式hadoop环境(一)
- 关键词堆砌生成器_网络推广软件的使用和24种关键词挖掘方法
- Windows Server2003添加超级终端组件的方法【组图】
- u盘坏了在计算机不显示,u盘坏了电脑上不显示不出来怎么办
- 全面图解路由器接口及连接
- vm安装android,Vmware虚拟机安装安卓4.0系统教程
- java语音识别毕业设计,HMM的语音识别技术的毕业设计
- 老绅士+1,白嫖Wallpaper Engine创意工坊壁纸
- CSharp和.net的简单介绍
- python sed awk_观点|awk sed ,一个老派系统管理员的基本素养
- ROS实现串口GPS数据的解析与通信(这篇文章所用的代码和我买的带有ROS功能包的GPS模块的功能包的代码一样)