使用 golang 以及 Gin 框架,将上传的图片在不保存至本地的情况下添加水印,并上传至阿里云 OSS

正如标题所述,使用golang对上传图片添加水印,以及将图片上传到阿里云OSS,网上一搜索,便有你想要的结果了,可是,他们却先将上传图片添加水印后保存在本地,而后再将添加了水印的图片上传到阿里云OSS

这无疑是暂时占用了你电脑的磁盘空间(这里说是暂时,因为你可以通过程序对上传到阿里云OSS成功的图片进行删除),即便是这样,它也是消耗了磁盘读写操作,虽然人类是察觉不到这么细微的变化。

然而,作为技术人员的我们(不介意我这么称呼自己吧!),使能够Review出这段程序的问题。很显然,本地图片是要通过程序处理,添加水印,而后最终储存到阿里云OSS中,而不是又要在本地多存了一张比原图多了些水印的图片。

图像处理库

既然我们的目的明确了,那么就卷起柚子加油干吧!

虽然,使用golang对上传图片添加水印,以及如何将图片上传到阿里云OSS中,是两个独立分开的。但是,这两步看似分而食之的程序,其实是可以合二为一的!(我想,正在浏览本文的你,也是这么想的!)

这是可行的方案,毕竟先前的秋码记录 就是这么做的(那是使用Java构建的那些年!当然现在的 秋码记录 改用 ```Hugo·``搭建了)。

既然,java能实现对上传图片添加水印,而不暂时保存在本地,立马即可上传到阿里云OSS中。想必,golang也是可以完成的!

然而,网上相关的资料有限,才能铸就本文的诞生!

首先,我是用golang的版本是1.19,虽然不是最新的,但却不妨碍我们继续对本文的讲解。

虽然,人类总是对新鲜事物充满好奇,从而萌生了猎奇心。但也只有在旧事物的烘衬下,人们才能对新事物寄以最大的希望!这就好比,老婆总是别人的好看(当然,别人的老婆也有没有自己老婆好看的),这才造就了黄脸婆这一全国男人在没有老婆在身旁统一叹息声!

你得在你电脑任一磁盘下,新建一空文件夹,随后打开黑窗口(Terminal),输入以下命令,说明是modules进行管理的(毕竟我使用的是golang 1.19):

shell 复制代码
go mod init qiucode.cn/uploadImage

对于以上这行命令,就是初始化golang模块(module),在golang的世界是```万物皆可模块``(我说的如果不对,那么说出你的想法)。

初始化项目后,我们会发现文件夹下多了个go.mod文件(这个就是用来管理第三方依赖库的管理文件,不需要操作!),在该同级目录下新建main.go文件。

既然本文是探讨如何实现图片添加水印的,那么引入图像库那是必不可少的!

shell 复制代码
go get github.com/fogleman/gg

本文不会对这个图像库进行深层次的讲解!毕竟本文的核心内容是介绍如何对图片添加水印,而不是避重就轻本末倒置讲起了本该一笔带过的东西,却花了浓墨重彩去着重的描绘刻画它,到头来,却失了初心,乱了本文的主旨,实属不该。(实在不清楚的,可以去查看其文档)

很显然,将图片上传到阿里云OSS上,引入其SDK,那是必不可少的(关于这一点,应该不需要我多费口舌了吧)

shell 复制代码
go get github.com/aliyun/aliyun-oss-go-sdk/oss

接下来的这个依赖库,并不是必须的(那就是可选的),毕竟,有它没有它,本文都可以实现!

shell 复制代码
go get github.com/gin-gonic/gin

是啊!都说了,不引入它,本文也可以实现,那么我为什么还引入了呢?(关于这一点,欢迎你能在评论中留下你的只言片语,请不要吝啬你的文字!)

用代码实现标题的需求

前提准备工作就绪,我们该正式进入编码环节了。到了这里,正处于屏幕前的你,想必早就迫不及待了吧!毕竟,你就是与我有同样的需求,才会浏览本文的(当然也有那种,鼠标不小心点到了,但那种几率是很小的,我相信你不是属于那一类的)

首先,我们使用VS Code(你也可以使用其他你平时常用的IDE,不必非要使用与我一样的VS Code,然而,作为一款开源免费的IDE,你还有什么理由不去使用它呢?哦,差点忘记了,都说了,使用IDE是个人的自由,可我这么一说,倒有了让你使用VS Code之嫌。虽然,或许你比较喜欢使用收费软件,但你都是找的破解方法来破解软件,从而使用它们)

打开刚刚新建的main.go文件,开始逐步实现标题的需求。

golang 复制代码
package main

import (
    "bytes"
    "image"
    "image/png" 
    // "image/jepg"  //用于对 jpg 格式的图片进行处理 本文暂时不对 jpg 图片做处理

    "github.com/gin-gonic/gin"  //web 框架
    "github.com/fogleman/gg"  // 图像处理哭
    "github.com/aliyun/aliyun-oss-go-sdk/oss" //阿里云OSS SDK
)

随后,我们在main函数中实现标题中的需求。

golang 复制代码
func main() {
    r := gin.Default()

    r.MaxMultipartMemory = 8 << 20 // 8 MiB
	r.Static("/", "./public")
    
    r.POST("/upload", func(c *gin.Context) {
        // 获取用户上传文件
        file, err := c.FormFile("editormd-image-file")
        if err != nil {
          c.JSON(500, gin.H{"message":  "err:"+ err.Error()})
          return
        }

        // file.Filename 就是原始的文件名
        originalFilename := file.Filename
        
        // 做一些处理,例如打印文件名
        println("Uploaded file: " + originalFilename)
        
        src, err2 := file.Open()
        if err2 != nil {
          c.JSON(500, gin.H{"message":  "err2:"+ err2.Error()})
          return
        }
        defer src.Close()

        // 将文件转化为image.Image,添加水印
        img, _, err3 := image.Decode(src)
        if err3 != nil {
          c.JSON(500, gin.H{"message":  "err3:"+ err3.Error()})
          return
        }

        println("%d | %T",img.Bounds().Dx(),img.Bounds().Dx())

        imgWidth := img.Bounds().Dx()
        imgHeight := img.Bounds().Dy()

      
        dc := gg.NewContext(imgWidth, imgHeight)
        dc.DrawImage(img, 0, 0)
        dc.SetRGB(118,104,104)
        err4 := dc.LoadFontFace("aparaj.ttf", 48)
        if err4 != nil {
          c.JSON(500, gin.H{"message": "err4:"+ err4.Error()})
          return
        }
        

         // 旋转文本 以图像正中为中心旋转
        dc.RotateAbout(gg.Radians(-40), float64(imgWidth/2), float64(imgHeight/2)) 


      W := int(imgWidth)
      H := int(imgHeight)

      text := "https:;//qiucode.cn" //水印文字
         // 计算水印文本的尺寸
      textWidth := float64(len(text)) * 20 // 20 是字体大小  可自行修改
      const S = 60 // 水印文本的大小
        
        for y := -H; y < H; y += S {
           for x := -H; x < W*2; x += int(textWidth) { // 根据文本尺寸调整x轴的绘制间距
                dc.DrawStringAnchored(text, float64(x), float64(y), 0.5, 0.5)
            }
        }
      //循环添加水印 end

        dc.SetLineWidth(2)
        dc.Stroke()
     
        // 创建字节缓冲区并将图像编码为PNG
        buf := new(bytes.Buffer)
        err5 :=png.Encode(buf, dc.Image())
        if err5 != nil {
          c.JSON(500, gin.H{"message":  "err5:"+ err5.Error()})
          return
       }

        endpoint := "这里是您的 endpoint "  // 这里的是广州区,
        accessKeyID := "您阿里云的 accessKeyID "   
        accessKeySecret := "您阿里云 accessKeySecret"   

        bucketName := "qiucodeimg";
        //文件存储目录
        filedir := "golang-test/";

        // 创建OSS client
        client, err6 := oss.New(endpoint, accessKeyID, accessKeySecret)
        if err6 != nil {
          c.JSON(500, gin.H{"message":  "err6:"+ err6.Error()})
          return
      }
        // 获取存储空间
        bucket, err7 := client.Bucket(bucketName)

        if err7 != nil {
          c.JSON(500, gin.H{"message":  "err7:"+ err7.Error()})
          return
        }

        objectKey := filedir + originalFilename

        // 上传文件流
        bucket.PutObject(objectKey, bytes.NewReader(buf.Bytes()))

         // 生成签名的 URL
         signedURL, err8 := bucket.SignURL(objectKey, oss.HTTPGet, 600)
         if err8 != nil {
          c.JSON(500, gin.H{"message":  "err8 :"+ err8.Error()})
          return
        }

        c.JSON(200, gin.H{
          "success": 1,
          "message": "上传成功",
          "url": signedURL, //将成功上传到阿里云OSS的图片 URL 返回给页面
        })
    })
    // 使用  8080 端口进行监听
	r.Run(":8080")
}

对于以上代码,你看完后,想必有很多话要说吧!没错,可以将图片添加水印的抽取成一个函数,还有的是就是需要判断上传的图片格式,是PNG还是JPEG等格式......

然而,你似乎忘记了,本文已经将原本两个各自独立的,合二为一而且还实现了,至于抽取成函数,上传图片格式判别,就让正在浏览本文的您,或还苦苦找寻怎么使用golang实现对上传图片添加水印并上传到阿里云OSS挠头托腮的!本文的实现将你们的福音,也将是你们的一剂强心针(总算是找到了一篇关于怎么使用golang实现了公司的需求)

差点忘记了,还用静态资源,使用了开源的 editormdhttps://github.com/pandao/editor.md

以及 index.html文件内容。

html 复制代码
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link href="/static/editormd/css/editormd.css" type="text/css" rel="stylesheet">
</head>
<body>


<div id="test-editor">
    <textarea style="display: none;" name="context"></textarea>
</div>

</body>

<script src="./static/jquery-3.4.1/jquery-3.4.1.min.js"></script>
<script type="text/javascript" charset="utf-8"  src="./static/editormd/editormd.min.js"></script>


<script>
    var editor;
    $(function () {
        editor = editormd("test-editor", { //注意1:这里的就是上面的DIV的id属性值
            width: "90%",
            height: 750,
            syncScrolling: "single",
            path: "/static/editormd/lib/", //注意2:你的路径
            saveHTMLToTextarea: true ,//注意3:这个配置,方便post提交表单

            imageUpload : true,
            imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
            imageUploadURL : "/upload",
        });
    });
</script>

</html>

最后,还是贴出效果图。

相关推荐
禁默9 小时前
2024年图像处理、多媒体技术与机器学习
图像处理·人工智能·microsoft
发呆小天才O.oᯅ14 小时前
YOLOv8目标检测——详细记录使用OpenCV的DNN模块进行推理部署C++实现
c++·图像处理·人工智能·opencv·yolo·目标检测·dnn
hkNaruto14 小时前
【P2P】【Go】采用go语言实现udp hole punching 打洞 传输速度测试 ping测试
golang·udp·p2p
入 梦皆星河14 小时前
go中常用的处理json的库
golang
桃园码工17 小时前
2-Gin 框架中的路由 --[Gin 框架入门精讲与实战案例]
gin·路由·实战案例
海绵波波10717 小时前
Gin-vue-admin(2):项目初始化
vue.js·golang·gin
海绵波波10717 小时前
Gin-vue-admin(4):项目创建前端一级页面和二级页面
前端·vue.js·gin
每天写点bug17 小时前
【go每日一题】:并发任务调度器
开发语言·后端·golang
一个不秃头的 程序员17 小时前
代码加入SFTP Go ---(小白篇5)
开发语言·后端·golang
liuming199217 小时前
Halcon中histo_2dim(Operator)算子原理及应用详解
图像处理·人工智能·深度学习·算法·机器学习·计算机视觉·视觉检测