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

news2024/11/26 12:25:58

正如标题所述,使用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>

最后,还是贴出效果图。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1557249.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SRS OBS利用RTMP协议实现音视频推拉流

参考&#xff1a;https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started 1&#xff09;docker直接运行SRS服务&#xff1a; docker run --rm -it -p 1935:1935 -p 1985:1985 -p 8080:8080 registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5运行起来后可以http://localho…

学习笔记——C语言基本概念指针(上)——(7)

今天学习了指针&#xff0c;指针吧理解有点小难&#xff0c;慢慢分析就懂。 在开始学指针之前先回顾一下C语言的数据类型如下图所示: 按照分类分别为&#xff1a; 1->基础数据类型&#xff1a;char &#xff1b;short&#xff1b; int&#xff1b; long&#xff1b; float&…

Platypus 一种集中式的央行数字货币方案

集中式的CBDC&#xff0c;混合使用账户模型和UTXO模型。 角色分类 中央银行&#xff1a;发行货币&#xff0c;交易验证&#xff0c;公开交易日志&#xff0c;防止双花。 不是完全受信任的&#xff0c;假定为会遵守监管要求&#xff0c;但可能会破坏交易隐私&#xff0c;即获…

瑞吉外卖实战学习--5、新增员工功能

新增员工功能 效果图1、开发流程2、页面发送ajax请求,将新增员工的信息以json的形式提交给服务器2.1、在填写信息的时候会发现身份校验比较麻烦,可以在validate中将全局的校验方式去掉,方便填写2.3、看到接口未employee2.4、前端代码分析3、服务器接收到提交的数据并调用ser…

无论PC还是Mac,都能畅快地使用移动硬盘 Mac使用NTFS移动硬盘不能读写

如果你拥有一台Mac设备&#xff0c;总会遇到尴尬的那一刻——你在Mac上用得好好的移动硬盘怎么都不能被PC识别到。又或者你朋友在PC上用得好好的移动硬盘&#xff0c;连上你的Mac后&#xff0c;Mac里的文件死活就是拷贝不进移动硬盘里。这种坑&#xff0c;相信大多数使用Mac的小…

Linux 基于chrony进行时钟同步方案验证

Linux 基于chrony进行时钟同步方案验证 1. 背景介绍2. 验证过程2.1 追踪配置2.2 追平记录2.2 追平时间换算 3. 疑问和思考3.1 如何统计追踪1s需要花费多长时间&#xff1f; 4. 参考文档 chrony是一个Linux系统中用于时钟同步的工具。它使用NTP&#xff08;网络时间协议&#xf…

【Java常用的API】JDK8相关时间类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

Delphi 12 安卓 部署文件,不支持中文文件名

procedure TForm3.Button1Click(Sender: TObject); var sFileName:string; begin sFileName:TPath.Combine(TPath.GetDocumentsPath,禁止吸烟.wav); showmessage(sFileName); MediaPlayer1.Stop ; MediaPlayer1.FileName: sFileName; MediaPlayer1.Play; end;

c语言:vs2022写一个一元二次方程(包含虚根)

求一元二次方程 的根&#xff0c;通过键盘输入a、b、c&#xff0c;根据△的值输出对应x1和x2的值(保留一位小数)(用if语句完成)。 //一元二次方程的实现 #include <stdio.h> #include <math.h> #include <stdlib.h> int main() {double a, b, c, delta, x1…

商品说明书的制作工具来啦,用这几个就够了!

商品说明书是用户了解产品特性、性能、使用方法的重要途径。一个明确、易懂的商品说明书&#xff0c;可以显著提升用户体验&#xff0c;进而提升产品的销量。但我们都知道&#xff0c;制作一份高质量的说明书并不容易&#xff0c;需要仔细设计、计划和撰写。幸运的是&#xff0…

Python模块与包管理使用pip与virtualenv【第151篇—模块与包管理】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python模块与包管理&#xff1a;使用pip与virtualenv 在Python开发中&#xff0c;模块和包…

【Linux系列】tree和find命令

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

网络性能提升10%,ZStack Edge 云原生超融合基于第四代英特尔®至强®可扩展处理器解决方案发布

随着业务模式的逐渐转变、业务架构逐渐变得复杂&#xff0c;同时容器技术的兴起和逐渐成熟&#xff0c;使得Kubernetes、微服务等新潮技术逐步应用于业务应用系统上。 为了充分释放性能、为业务系统提供更高效的运行环境&#xff0c;ZStack Edge 云原生超融合采用了第四代英特尔…

c语言例题,逐个打印数字

今天来分享个比较简单的程序例题&#xff0c;也是比较经典的一个新手例题&#xff0c;逐个打印输入的数字。我们直接从主函数看起&#xff0c;先定义一个num变量&#xff0c;同时变量的类型是unsigned int&#xff0c;这个类型的意思是无符号的整型变量&#xff0c;unsigned&am…

单链表求集合的交集

#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef struct LinkNode {ElemType data;LinkNode* next; }LinkNode, * LinkList; //尾插法建立单链表 void creatLinkList(LinkList& L) {L (LinkNode*)mallo…

嵌入式数据库-Sqlite3

阅读引言&#xff1a; 本文将会从环境sqlite3的安装、数据库的基础知识、sqlite3命令、以及sqlite的sql语句最后还有一个完整的代码实例&#xff0c; 相信仔细学习完这篇内容之后大家一定能有所收获。 目录 一、数据库的基础知识 1.数据库的基本概念 2.常用数据库 3.嵌入式…

2、Cocos Creator 下载安装

Cocos Creator 从 v2.3.2 开始接入了全新的 Dashboard 系统&#xff0c;能够同时对多版本引擎和项目进行统一升级和管理&#xff01;Cocos Dashboard 将做为 Creator 各引擎统一的下载器和启动入口&#xff0c;方便升级和管理多个版本的 Creator。还集成了统一的项目管理及创建…

习题2-5 求平方根序列前N项和

本题要求编写程序&#xff0c;计算平方根序列 的前N项之和。可包含头文件math.h&#xff0c;并调用sqrt函数求平方根。 输入格式: 输入在一行中给出一个正整数N。 输出格式: 在一行中按照“sum S”的格式输出部分和的值S&#xff0c;精确到小数点后两位。题目保证计算结果不…

SD-WAN网络构建要点简述

近年来&#xff0c;SD-WAN已成为企业网络优化的热门选择。SD-WAN代表软件定义广域网&#xff0c;是一种基于软件的网络解决方案&#xff0c;旨在提高企业网络连接的可靠性、安全性和性能。相比传统网络架构&#xff0c;SD-WAN技术通过虚拟化网络通信&#xff0c;利用智能软件和…

ubuntu20.04安装截图工具flameshot

ubuntu20.04 自带的截图工具&#xff0c;可以使用快捷键“shift printScreen” ,但是它不能对截图进行编辑。 现在安装截图工具 flameshot&#xff0c;使用以下命令&#xff1a; sudo apt install flameshot 安装完成后&#xff0c;使用以下命令打开&#xff1a; flamesho…