由于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对上传的图片流进行压缩相关推荐

  1. [译]如何在.NET Core中使用System.Drawing?

    你大概知道System.Drawing,它是一个执行图形相关任务的流行的API,同时它也不属于.NET Core的一部分.最初是把.NET Core作为云端框架设计的,它不包含非云端相关API.另一方 ...

  2. linux docker 中使用 System.Drawing.Common 异常 System.Drawing.Common 仅在 Windows 上受支持

    System.Drawing.Common NuGet 包现在被归类为特定于 Windows 的库.为非 Windows 操作系统编译时,平台分析器会在编译时发出警告. 在非 Windows 操作系统 ...

  3. .net core 使用 ZKWeb.system.drawing 在centos下使用gdi 画图

    使用ZKWeb.system.drawing 背景 system.Drawing.Common 和 ZKWeb 的比较 项目中引用ZKWeb CentOS 中环境搭建 CentOS 字体库安装 1.拷 ...

  4. EF Core中关于System.Linq.Dynamic.Core的使用(转载)

    项目中经常用到组合条件查询,根据用户配置的查询条件进行搜索,拼接SQL容易造成SQL注入,普通的LINQ可以用表达式树来完成,但也比较麻烦.有个System.Linq.Dynamic.Core用起来比 ...

  5. .net + html5上传,在.net Core中如何使用HTML5上传视频

    最近刚做了视频上传的功能,有一些心得还有注意事项,这里不贴全部代码,主要是讲述编码思路.本代码基于.net core .html5示例 完成视频上传的两种思路 1.视频分片上传,比如把整个视频拆分成2 ...

  6. .Net Core上用于代替System.Drawing的类库

    目前.Net Core上没有System.Drawing这个类库,想要在.Net Core上处理图片得另辟蹊径. 微软给出了将来取代System.Drawing的方案,偏向于使用一个单独的服务端进行各 ...

  7. 第五节:EF Core中的三类事务(SaveChanges、DbContextTransaction、TransactionScope)

    一. 说明 EF版本的事务介绍详见: 第七节: EF的三种事务的应用场景和各自注意的问题(SaveChanges.DBContextTransaction.TransactionScope). 本节主 ...

  8. transactionscope 中的异步 处理 异常_.NET Core中TransactionScope事务处理方法介绍及注意事项...

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712.html 今天在写CzarCms的UnitOfWork的使用使用到了这个Transacti ...

  9. unity 引用using System.Drawing.Printing

    .NET类库System.Drawing提供了一系列的图形函数,但由于其使用的是GDI接口,与DirectX和OpenGL之间不兼容,在Unity中默认是不被支持的. 但有时候,我们想在Unity中使 ...

最新文章

  1. K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means)介绍与对比
  2. Mysql基础--常见的表的约束介绍(一)
  3. StringWriter/PrintWriter在Java输出异常信息中的作用
  4. 【Python基础】Python开发环境设置和小技巧
  5. 王道考研 计算机网络8 物理层基本概念 数据通信相关术语
  6. Docker简介与简单使用 | 技术头条
  7. android 控制流混淆 反向,AST混淆实战:仿obfuscator混淆控制流平坦化
  8. 下了班----你干啥
  9. windownavigatorscreenlocation
  10. 基于Docker布署伪分布式hadoop环境(一)
  11. 关键词堆砌生成器_网络推广软件的使用和24种关键词挖掘方法
  12. Windows Server2003添加超级终端组件的方法【组图】
  13. u盘坏了在计算机不显示,u盘坏了电脑上不显示不出来怎么办
  14. 全面图解路由器接口及连接
  15. vm安装android,Vmware虚拟机安装安卓4.0系统教程
  16. java语音识别毕业设计,HMM的语音识别技术的毕业设计
  17. 老绅士+1,白嫖Wallpaper Engine创意工坊壁纸
  18. CSharp和.net的简单介绍
  19. python sed awk_观点|awk sed ,一个老派系统管理员的基本素养
  20. ROS实现串口GPS数据的解析与通信(这篇文章所用的代码和我买的带有ROS功能包的GPS模块的功能包的代码一样)

热门文章

  1. 谈谈目前工作的收获和不足
  2. MyBatisPlus--多数据源
  3. 某文学网站的优化具体方案
  4. Windows Server® 2008 Enterprise 组件服务 找不到 ”Microsoft Word 97 - 2003 文档“组件
  5. uniapp 一键登录
  6. (英语)热门话题词汇整理 (更完)
  7. 微信小程序珊瑚文本检测分享(Java案例)
  8. 云服务器 nginx配置SSL证书
  9. 海思35XX系列芯片型号规律
  10. 吐槽一下一些垃圾网站