草庐IT

.NET 6使用ImageSharp给图片添加水印

gmval 2023-03-28 原文


.NET 6 中,使用System.Drawing操作图片,生成解决方案或打包的时候,会有警告,意思是System.Drawing仅在 'windows' 上受支持。微软官方的解释是:

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

在非 Windows 操作系统上,除非设置了运行时配置开关,否则将引发 TypeInitializationException 异常,其中 PlatformNotSupportedException 作为内部异常

在 .NET 6 之前,使用 System.Drawing.Common 包不会产生任何编译时警告,也不会引发任何运行时异常。

从 .NET 6 开始,当为非 Windows 操作系统编译引用代码时,平台分析器会发出编译时警告。

当然,使用windows操作系统没有任何问题,Linux的话,需要单独的配置。

可以通过在runtimeconfig.json文件中将System.Drawing.EnableUnixSupport 运行时配置开关设置为来启用对 .NET 6 中的非 Windows 平台的支持:true

或者使用第三方库

ImageSharp
SkiaSharp
Microsoft.Maui.Graphics
正如标题,我使用了ImageSharp来操作图片,并给图片添加水印

//ImageFile为图片物理路径,如下方的注释
        public async Task<ImageResult> WaterMark(string ImageFile)
        {
            ImageResult result = new ImageResult();
            //var ImageFile = "D:\www\wwwroot\upload\5176caebc1404caa8b0b350181ae28ab.jpg";
            var WaterMark = "D:\\www\\wwwroot\\watermark.png";
            string FileName = Guid.NewGuid().ToString("N") + ".jpg";
            string SavePath = "D:\\www\\wwwrootupload\\" + FileName;
            string imgurl = "/upload/"+FileName;
            //为了与System.Drawing.Common有所区别,引用使用全路径
            using (var image = await SixLabors.ImageSharp.Image.LoadAsync(ImageFile))
            {
                using (var clone = image.Clone(ctx => ctx.ApplyScalingImageWaterMark("center")))
                {
                    await clone.SaveAsync(SavePath);
                }
                result.width = image.Width;
                result.height = image.Height;

                result.url = imgurl;
                result.format = ".jpg";
                result.state = true;
            }
            return result;
        }

代码比较简单,首先使用SixLabors.ImageSharp.Image.LoadAsync打开图片,然后使用ImageSharp的自定义扩展方法给图片添加水印。

ApplyScalingImageWaterMark扩展方法:

public static class ImageSharpExtention
{
    public static IImageProcessingContext ApplyScalingImageWaterMark(this IImageProcessingContext processingContext, string waterPosition = "center",string waterPath)
    {
         using (var mark_image = SixLabors.ImageSharp.Image.Load(waterPath))
            {
                int markWidth = mark_image.Width;
                int markHeight = mark_image.Height;

                var imgSize = processingContext.GetCurrentSize();

                if (markWidth >= imgSize.Width || markHeight >= imgSize.Height) //对水印图片进行缩放
                {
                    if (imgSize.Width > imgSize.Height)//横的长方形
                    {
                        markWidth = imgSize.Width / 2; //宽缩放一半
                        markHeight = (markWidth * imgSize.Height) / imgSize.Width;
                    }
                    else
                    {
                        markHeight = imgSize.Height / 2;
                        markWidth = (markHeight * imgSize.Width) / imgSize.Height;
                    }
                    mark_image.Mutate(mk => mk.Resize(markWidth, markHeight));
                }
                //水印图片完成成立,开始根据位置添加水印
                var position = waterPosition;
                if (string.IsNullOrEmpty(position))
                {
                    position = "center";
                }
                position = position.ToLower();
                if (string.IsNullOrEmpty(position))
                {
                    position = "center";
                }
                SixLabors.ImageSharp.Point point = new SixLabors.ImageSharp.Point();
                //左上
                if (position.Contains("lefttop"))
                {
                    point.X = 10;
                    point.Y = 10;
                }
                //上中
                if (position.Contains("topcenter"))
                {
                    point.X = (imgSize.Width - mark_image.Width) / 2;
                    point.Y = 10;
                }
                //右上
                if (position.Contains("righttop"))
                {
                    point.X = (imgSize.Width - mark_image.Width) - 10;
                    point.Y = 10;
                }
                //右中
                if (position.Contains("rightcenter"))
                {
                    point.X = (imgSize.Width - mark_image.Width) - 10;
                    point.Y = (imgSize.Height - mark_image.Height) / 2;
                }
                //右下
                if (position.Contains("rightbottom"))
                {
                    point.X = (imgSize.Width - mark_image.Width) - 10;
                    point.Y = (imgSize.Height - mark_image.Height) - 10;
                }
                //下中
                if (position.Contains("bottomcenter"))
                {
                    point.X = (imgSize.Width - mark_image.Width) / 2;
                    point.Y = (imgSize.Height - mark_image.Height) - 10;
                }
                //左下
                if (position.Contains("leftbottom"))
                {
                    point.X = 10;
                    point.Y = (imgSize.Height - mark_image.Height) - 10;
                }
                //左中
                if (position.Contains("leftcenter"))
                {
                    point.X = 10;
                    point.Y = (imgSize.Height - mark_image.Height) / 2;
                }
                if (position.Contains("center"))
                {
                    point.X = (imgSize.Width - mark_image.Width) / 2;
                    point.Y = (imgSize.Height - mark_image.Height) / 2;
                }
                float opacity=(float)0.8;//设置不透明度,0-1之间
                
                //添加水印
                return processingContext.DrawImage(mark_image,point,opacity);

            }
    }
}

ImageResult类:

public class ImageResult
    {
        /// <summary>
        /// 文件名
        /// </summary>
        public string id { get; set; }

        /// <summary>
        /// 文件大小
        /// </summary>
        public string size { get; set; }

        /// <summary>
        /// 文件路径
        /// </summary>
        public string url { get; set; }

        /// <summary>
        /// 文件格式
        /// </summary>
        public string format { get; set; }

        /// <summary>
        /// 上传状态
        /// </summary>
        public bool state { get; set; }

        /// <summary>
		/// 上传消息
		/// </summary>
		public string msg { get; set; }

        /// <summary>
        /// 图片宽
        /// </summary>
        public int width { get; set; }

        /// <summary>
        /// 图片高
        /// </summary>
        public int height { get; set; }
    }

如有不正确的地方,还望不吝指教。

有关.NET 6使用ImageSharp给图片添加水印的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  10. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

随机推荐