温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Net core中怎么使用System.Drawing对上传的图片流进行压缩

发布时间:2022-08-25 11:34:34 来源:亿速云 阅读:132 作者:iii 栏目:开发技术

这篇文章主要介绍“Net core中怎么使用System.Drawing对上传的图片流进行压缩”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“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上就会报错

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    在Linux中安装

    开始安装libgdiplus,执行【docker ps -a 】查看所有容器

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    【docker start 容器ID】 将容器运行起来

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    【docker exec -it e90f2b9d448d /bin/bash】进入该容器bash界面

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    执行【apt-get update】

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    【apt-get install -y libgdiplus】安装libgdiplus类库

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    【ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll】创建链接文件

    【eixt】退出docker bash到宿主机的bash,执行 【docker restart 容器ID】,此时接口已经能正确访问了

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    上面的方法有个弊端,假如容器被误删,又要重新给容器安装libgdiplus库。

    我们可以把修改好的容器制作成镜像,执行【docker commit e90f2b9d448d skyapi_libgdiplus】,然后执行【docker images】,

    可以看到名字叫skyapi_libgdiplus的Docker镜像已经制作好了。今后只需要在 docker run -t 参数后面指定skyapi_libgdiplus镜像即可。

    当前还可以将镜像保存到docker hub,本地硬盘都可以。

    Net core中怎么使用System.Drawing对上传的图片流进行压缩

    喜闻乐见的是,.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对上传的图片流进行压缩”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI