正如标题所述,使用
golang
对上传图片添加水印,以及将图片上传到阿里云OSS
,网上一搜索,便有你想要的结果了,可是,他们却先将上传图片添加水印后保存在本地,而后再将添加了水印的图片上传到阿里云OSS
。这无疑是暂时占用了你电脑的磁盘空间(这里说是暂时,因为你可以通过程序对上传到
阿里云OSS
成功的图片进行删除),即便是这样,它也是消耗了磁盘
读写操作,虽然人类是察觉不到这么细微的变化。然而,作为
技术人员
的我们(不介意我这么称呼自己吧!),使能够Review
出这段程序的问题。很显然,本地图片是要通过程序处理,添加水印,而后最终储存到阿里云OSS
中,而不是又要在本地多存了一张比原图
多了些水印的图片。
图像处理库
既然我们的目的明确了,那么就卷起柚子加油干吧!
虽然,使用golang
对上传图片添加水印,以及如何将图片上传到阿里云OSS
中,是两个独立分开的。但是,这两步看似分而食之
的程序,其实是可以合二为一
的!(我想,正在浏览本文的你,也是这么想的!)
这是可行的方案,毕竟先前的秋码记录 就是这么做的(那是使用Java
构建的那些年!当然现在的 秋码记录 改用 ```Hugo·``搭建了)。
既然,java
能实现对上传图片添加水印,而不暂时保存在本地,立马即可上传到阿里云OSS
中。想必,golang
也是可以完成的!
然而,网上相关的资料有限,才能铸就本文的诞生!
首先,我是用golang
的版本是1.19
,虽然不是最新的,但却不妨碍我们继续对本文的讲解。
虽然,人类总是对新鲜事物充满好奇,从而萌生了猎奇心。但也只有在旧事物的烘衬下,人们才能对新事物寄以最大的希望!这就好比,老婆总是别人的好看(当然,别人的老婆也有没有自己老婆好看的),这才造就了黄脸婆
这一全国男人在没有老婆在身旁统一叹息声!
你得在你电脑任一磁盘下,新建一空文件夹,随后打开黑窗口
(Terminal),输入以下命令,说明是modules
进行管理的(毕竟我使用的是golang 1.19
):
go mod init qiucode.cn/uploadImage
对于以上这行命令,就是初始化golang
模块(module),在golang
的世界是```万物皆可模块``(我说的如果不对,那么说出你的想法)。
初始化项目后,我们会发现文件夹下多了个go.mod
文件(这个就是用来管理第三方依赖库的管理文件,不需要操作!),在该同级目录下新建main.go
文件。
既然本文是探讨如何实现图片添加水印的,那么引入图像库
那是必不可少的!
go get github.com/fogleman/gg
本文不会对这个图像库
进行深层次的讲解!毕竟本文的核心内容是介绍如何对图片添加水印,而不是避重就轻
、本末倒置
讲起了本该一笔带过的东西,却花了浓墨重彩
去着重的描绘刻画它,到头来,却失了初心
,乱了本文的主旨,实属不该。(实在不清楚的,可以去查看其文档)
很显然,将图片上传到阿里云OSS
上,引入其SDK
,那是必不可少的(关于这一点,应该不需要我多费口舌了吧)
go get github.com/aliyun/aliyun-oss-go-sdk/oss
接下来的这个依赖库,并不是必须的(那就是可选的),毕竟,有它没有它,本文都可以实现!
go get github.com/gin-gonic/gin
是啊!都说了,不引入它,本文也可以实现,那么我为什么还引入了呢?(关于这一点,欢迎你能在评论中留下你的只言片语
,请不要吝啬你的文字!)
用代码实现标题的需求
前提准备工作就绪,我们该正式进入编码环节了。到了这里,正处于屏幕前的你,想必早就迫不及待了吧!毕竟,你就是与我有同样的需求,才会浏览本文的(当然也有那种,鼠标不小心点到了,但那种几率是很小的,我相信你不是属于那一类的)
首先,我们使用VS Code
(你也可以使用其他你平时常用的IDE
,不必非要使用与我一样的VS Code
,然而,作为一款开源免费的IDE
,你还有什么理由不去使用它呢?哦,差点忘记了,都说了,使用IDE
是个人的自由,可我这么一说,倒有了让你使用VS Code
之嫌。虽然,或许你比较喜欢使用收费软件
,但你都是找的破解方法来破解软件,从而使用它们)
打开刚刚新建的main.go
文件,开始逐步实现标题的需求。
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
函数中实现标题中的需求。
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
实现了公司的需求)
差点忘记了,还用静态资源,使用了开源的 editormd
。https://github.com/pandao/editor.md 。
以及 index.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>
最后,还是贴出效果图。