专栏首页汪宇杰博客ASP.NET Core 给上传的图片加水印

ASP.NET Core 给上传的图片加水印

图片加水印是网站中使用非常广泛的技术,可以保护网站内容的版权,例如我博客这样的网站。在传统ASP.NET(.NET Framework)中,我们可以使用System.Web.Helpers.WebImage来添加水印,就像这样:

var image = new WebImage(imageBytes);
image.AddTextWatermark(
    Settings.Instance.WatermarkText, "White", Settings.Instance.WatermarkFontSize,
    opacity: Settings.Instance.WatermarkTextOpacityPercentage
    );

但是在.NET Core中,没有WebImage这个类型了。我们如何给图片加水印呢?

我们从图片上传开始。在ASP.NET Core中,我们用IFormFile来上传文件,也包括图片文件。需要详细了解可以参考微软官方文档:https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.1

在我的博客系统里,我写了一个Action用来上传图片,将图片文件塞到一个MemoryStream对象里,之后的图片存储服务就可以把它保存到目标位置

[Route("image/upload")]
public async Task<IActionResult> UploadImageAsync(IFormFile file)
{
...
    using (var stream = new MemoryStream())
    {
        await file.CopyToAsync(stream);
        ... // call underlying image storage service
    }
...
}

要添加水印,我们需要修改图片stream。

但是.NET Core默认情况下没有处理图片的能力,因为System.Drawing命名空间里的API是非常有限的。我们需要引用一个微软官方的NuGet包来引入我们在.NET Framework中曾经熟悉的那些API:

Install-Package System.Drawing.Common -Version 4.5.1

现在我们就可以访问System.Drawing.ImageSystem.Drawing.Graphics等API了。

下面的代码将会使用这些类型在上传的图片的stream上添加文字水印:

// Add watermark
var watermarkedStream = new MemoryStream();
using (var img = Image.FromStream(stream))
{
    using (var graphic = Graphics.FromImage(img))
    {
        var font = new Font(FontFamily.GenericSansSerif, 20, FontStyle.Bold, GraphicsUnit.Pixel);
        var color = Color.FromArgb(128, 255, 255, 255);
        var brush = new SolidBrush(color);
        var point = new Point(img.Width - 120, img.Height - 30);
        graphic.DrawString("edi.wang", font, brush, point);
        img.Save(watermarkedStream, ImageFormat.Png);
    }
}

结果就是这样的:

其中有一些要注意的地方:

1. 你不能更改原始stream,如果你尝试把图片存储覆盖原始stream的话,是不会有效果的,就像这样:

img.Save(stream, ImageFormat.Png);

这就是为啥我定义了另一个watermarkedStream对象。

2. 针对水印的位置,也就是point对象。我的计算方式是添加水印到图片右下角,你需要根据自己需要修改这个位置。

3. 我建议字体采用跨平台的字体,因为.NET Core不止能部署在Windows上。

最后,我博客里上传图片加水印的完整样例代码如下:

[Authorize]
[HttpPost]
[Route("image/upload")]
public async Task<IActionResult> UploadImageAsync(IFormFile file)
{
    try
    {
        if (null == file)
        {
            Logger.LogError("file is null.");
            return BadRequest();
        }
        if (file.Length > 0)
        {
            var name = Path.GetFileName(file.FileName);
            if (name != null)
            {
                using (var stream = new MemoryStream())
                {
                    await file.CopyToAsync(stream);
                    // Add watermark
                    var watermarkedStream = new MemoryStream();
                    using (var img = Image.FromStream(stream))
                    {
                        using (var graphic = Graphics.FromImage(img))
                        {
                            var font = new Font(FontFamily.GenericSansSerif, 20, FontStyle.Bold, GraphicsUnit.Pixel);
                            var color = Color.FromArgb(128, 255, 255, 255);
                            var brush = new SolidBrush(color);
                            var point = new Point(img.Width - 120, img.Height - 30);
                            graphic.DrawString("edi.wang", font, brush, point);
                            img.Save(watermarkedStream, ImageFormat.Png);
                        }
                    }
                    var response = await _imageStorageProvider.InsertAsync(name, watermarkedStream.ToArray());
                    Logger.LogInformation("Image Upload: " + JsonConvert.SerializeObject(response));
                    if (response.IsSuccess)
                    {
                        string refPath = "/uploads/" + response.Item;
                        return Json(new { location = refPath });
                    }
                    Logger.LogError(response.Message);
                    return StatusCode(StatusCodes.Status500InternalServerError);
                }
            }
        }
        return BadRequest();
    }
    catch (Exception e)
    {
        Logger.LogError(e, $"Error uploading image.");
        return StatusCode(StatusCodes.Status500InternalServerError);
    }
}

本文分享自微信公众号 - 汪宇杰博客(ediwangblog),作者:汪宇杰

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-10-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • .NET Core 如何生成信用卡卡号

    上个月我写了《.NET Core 如何验证信用卡卡号》,不少朋友表示挺有兴趣。在金融科技行业的实际工作中,通常还需要生成信用卡卡号用来测试,今天我就来教大家如何...

    Edi Wang
  • ASP.NET Core 生成验证码

    使用验证码保护网站免受垃圾信息的选择有很多,比如Google ReCaptcha和captcha.com。这两者都可以整合到ASP.NET Core应用中去。然...

    Edi Wang
  • 高级进阶:Azure DevOps搞定.NET Core编译版本号自增

    熟悉.NET Framework的人知道,我们可以通过指定AssemblyVersion为10.0.*来让编译器自增版本号。但是.NET Core和.NET S...

    Edi Wang
  • js倒计时,秒倒计时,天倒计时

    距某某开幕式还有 [<script language="JavaScript" type="text/javascript">djs()</script>] 天...

    用户3055976
  • Flash/Flex学习笔记(51):3维旋转与透视变换(PerspectiveProjection)

    Flash/Flex学习笔记(49):3D基础 里已经介绍了3D透视的基本原理,不过如果每次都要利用象该文中那样写一堆代码,估计很多人不喜欢,事实上AS3的Di...

    菩提树下的杨过
  • 一段时间里面的数据筛选

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    PHY_68
  • HTML5-本地存储与cookies

    一、H5的几种存储形式 1、本地存储(localstorage和sessionstorage) 存储形式:key-->value 过期策略:localstora...

    小古哥
  • asp.net产生客户端Cookie与js操作Cookie大全

    Js操作Cookie封装的代码[各个浏览器测试兼容]: 1 function SetCookie(name, value)//两个参数,一个是cookie的名...

    Java中文社群_老王
  • 一个进程有3个线程,如果一个线程抛出oom,其他两个线程还能运行么?

    jmap -dump:live,format=b,file=m.hprof <PID>

    王小明_HIT
  • win10 uwp 获得缩略图 文件缩略图视频小图

    有时候需要获得文件或视频的缩略图。 本文提供两个方法,用于获得文件的缩略图和截取视频指定时间的显示图片。

    林德熙

扫码关注云+社区

领取腾讯云代金券