百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Golang:生成海报图

bigegpt 2025-01-09 10:43 5 浏览

为了传播拉新,需要海报图。一般情况下是前端生成:Canvas。但是,这次重担交给服务端了,能不能胜任?能,只要时间足够充裕,我可以慢慢学,调试(你看看,这工作态度。绝对的优秀员工)


相关库

  1. github.com/disintegration/imaging
  2. github.com/fogleman/gg
  3. golang.org/x/image/font
  4. golang.org/x/image/font/opentype
  5. image/color

github.com/disintegration/imaging

Imaging 是一个强大的图像处理库,提供了各种图像操作的功能,包括调整大小、裁剪、旋转、模糊、锐化、颜色调整等。

主要功能:

  • Resize: 调整图像大小。
  • Crop: 裁剪图像。
  • Rotate: 旋转图像。
  • Blur: 模糊图像。
  • Sharpen: 锐化图像。
  • Adjust: 调整亮度、对比度、饱和度等。

github.com/fogleman/gg

gg 是一个简单的 2D 绘图库,基于 cairo 提供了更方便的 API,用于生成和操作图形。它特别适合生成图表、图形叠加、文字和图形组合等任务。

主要功能:

  • 绘制基本形状: 线条、矩形、圆形、多边形等。
  • 文本处理: 设置字体、字号、颜色,并绘制文本。
  • 图像合成: 将多张图片进行组合。
  • 图像处理: 旋转、缩放、裁剪等。

golang.org/x/image/font

font 提供了与字体相关的功能,包括字体加载、字体渲染等。这个包定义了字体的基本接口和数据结构。

主要功能:

  • Font face: 定义和处理字体面。
  • Drawers: 用于在图像上绘制文本。
  • Glyph: 提供了处理字体字形的基本操作

golang.org/x/image/font/opentype

opentype 专门用于处理 OpenType 字体格式,提供了加载和渲染 OpenType 字体的功能。

主要功能:

  • Parse: 解析 OpenType 字体文件。
  • NewFace: 创建字体面,以便于字体渲染。
  • Font metrics: 提供字体的度量信息(如升部、降部、行高等)。

image/color

image/color 包定义了表示颜色的接口和类型。它提供了各种颜色模型和用于转换颜色的实用函数。

主要功能:

  • Color model: 提供 RGBA、NRGBA、YCbCr、Gray 等颜色模型。
  • 色彩转换: 在不同颜色模型之间进行转换。
  • 颜色定义: 定义基本颜色如黑色、白色、红色等。

实现个小小需求

实现一个按钮,要求是椭圆型,文字居中。

参数信息:
	boxW := 600
	boxH := 300
	boxColor := color.RGBA{R: 255, G: 255, B: 255, A: 1}

	buttonW := 200
	buttonH := 100
	ButtonColor := "#8650ac"

	fontSize := 48
	fontDpi := 96.0
	buttonText := "按钮"
	fontColor := "#ffffff"
	buttonImg := "./img/button.jpg"

物料:

下载字体资源文件:


技术方案

  1. 先拿一张宣纸(设定一个大的画布)
  2. 开始画椭圆(先画长方形,然后四个角加弧度,填充背景色)
  3. 拿个计算器,开始计算X,Y(计算文字行高)
  4. 拿起毛笔,开始在椭圆中心写字(加载字体,文字居中渲染)
  5. 按钮再覆盖到大的宣纸上(小画布和大画布相结合)
  6. 小demo实现

代码实现

package main

import (
	"context"
	"fmt"
	"github.com/disintegration/imaging"
	"github.com/fogleman/gg"
	"golang.org/x/image/font"
	"golang.org/x/image/font/opentype"
	"image/color"
	"os"
)

type DrawText struct {
}

type drawText interface {
	// DrawButton 绘制按钮
	DrawButton(ctx context.Context, w, y float64, color string, boxColor color.Color) (data *gg.Context, err error)
	// LoadFont 加载字体
	LoadFont(fontSize float64, dpi float64) (fontFace font.Face, err error)
	// PxToPt PxToPt
	PxToPt(px float64, dpi float64) float64
	// SaveImg 保存图片
	SaveImg(dc *gg.Context, fileName string) bool
}

func NewDrawText(ctx context.Context) drawText {
	return &DrawText{}
}

func main() {

	boxW := 600
	boxH := 300
	boxColor := color.RGBA{R: 255, G: 255, B: 255, A: 1}

	buttonW := 200
	buttonH := 100
	ButtonColor := "#8650ac"

	fontSize := 48
	fontDpi := 96.0
	buttonText := "按钮"
	fontColor := "#ffffff"
	buttonImg := "./img/button.jpg"

	d := NewDrawText(context.Background())
	// 创建一个大的画布
	dc := gg.NewContext(boxW, boxH)
	dc.SetColor(boxColor) // Set background color
	dc.Clear()

	// 绘制色块
	dcButton, err := d.DrawButton(context.Background(), float64(buttonW), float64(buttonH), ButtonColor, boxColor)
	if err != nil {
		panic(err)
		return
	}

	// 加载字体
	fontFace, err := d.LoadFont(d.PxToPt(float64(fontSize), fontDpi), fontDpi)
	if err != nil {
		panic(err)
		return
	}
	defer fontFace.Close()

	// 设置字体参数、颜色
	dcButton.SetFontFace(fontFace)
	dcButton.SetHexColor(fontColor)

	// 字体文案,计算x,y 居中位置
	buttonTextW, buttonTextH := dcButton.MeasureString(buttonText)
	dcButton.DrawString(buttonText, (float64(buttonW)-buttonTextW)/2, (float64(buttonH)+buttonTextH)*2/5)

	// 按钮绘制到画布上
	dc.DrawImage(dcButton.Image(), (boxW-buttonW)/2, (boxH-buttonH)/2)

	if d.SaveImg(dc, buttonImg) {
		return
	}

	fmt.Println("done")
	return
}

func (d *DrawText) SaveImg(dc *gg.Context, fileName string) bool {
	if err := imaging.Save(dc.Image(), fileName); err != nil {
		panic(err)
		return true
	}
	fmt.Printf("保持为jpg图片:%s\n", fileName)

	return false
}

// LoadFont 加载字体
func (d *DrawText) LoadFont(fontSize float64, dpi float64) (fontFace font.Face, err error) {
	fontBytes, err := os.ReadFile("./assets/Source_Han_Sans_SC_Normal_Normal.otf")
	if err != nil {
		return nil, fmt.Errorf("failed to read font file: %w", err)
	}
	fontVal, err := opentype.Parse(fontBytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse font: %w", err)
	}
	fontFace, err = opentype.NewFace(fontVal, &opentype.FaceOptions{
		Size:    fontSize,
		DPI:     dpi,
		Hinting: font.HintingFull,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to create font face: %w", err)
	}

	return fontFace, nil
}

// DrawButton 绘制色块
func (d *DrawText) DrawButton(ctx context.Context, w, y float64, color string, boxColor color.Color) (data *gg.Context, err error) {
	// 创建一个上下文来绘制色块
	dc := gg.NewContext(int(w), int(y))
	// 设置背景颜色 同画布颜色
	dc.SetColor(boxColor)
	// 填充颜色
	dc.Clear()

	// 设置圆角
	dc.SetHexColor(color)
	dc.DrawRoundedRectangle(0, 0, w, y, 20)
	dc.Fill()

	return dc, nil
}

func (d *DrawText) PxToPt(px float64, dpi float64) float64 {
	return px * (72 / dpi)
}

效果图

麻雀虽小,五脏俱全。想实现其他功能,自由组合。


总结:

海报图生成,最麻烦的就是计算,从始至终,就是拿着计算器计算,调整X,Y坐标。还有一点就是,px和pt的转化,不同的设备,分辨率展示出的效果不同。前端可以获取到客户端的设备信息,服务端拿不到这些数据,只能按照经验值去设定。


轻松一刻


我为人人,人人为我。美美与共,天下大同。

相关推荐

5分钟搭建公网https网页文件服务器,免费权威TLS证书

请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习前言本文主要讲解如何快速搭建一个https网页文件服务器,并免费申请权威机构颁发的tls证...

nginx负载均衡配置(nginx负载均衡配置两个程序副本)

Nginx是什么没有听过Nginx?那么一定听过它的“同行”Apache吧!Nginx同Apache一样都是一种WEB服务器。基于REST架构风格,以统一资源描述符(UniformResources...

19《Nginx 入门教程》Nginx综合实践

今天我们将基于Nginx完成两个比较有用的场景,但是用到的Nginx的配置非常简单。内部Yum源搭建内部Pip源搭建1.实验环境ceph1centos7.6内网ip:172.16....

Nginx性能调优与优化指南(nginx优化配置大全)

Nginx性能调优需要结合服务器硬件资源、业务场景和负载特征进行针对性优化。以下是一些关键优化方向和具体配置示例:一、Nginx配置优化1.进程与连接数优化nginxworker_process...

C++后端开发必须彻底搞懂Nginx,从原理到实战(高级篇)

本文为Nginx实操高级篇。通过配置Nginx配置文件,实现正向代理、反向代理、负载均衡、Nginx缓存、动静分离和高可用Nginx6种功能,并对Nginx的原理作进一步的解析。当需...

【Nginx】史上最全的Nginx配置详解

Nginx服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里,http块又包括http全局块和server块。Nginx是非常重要的负载均衡中间件,被广泛应用于大型...

【Nginx】Nginx 4种常见配置实例(nginx基本配置与参数说明)

本文主要介绍nginx4种常见的配置实例。Nginx实现反向代理;Nginx实现负载均衡;Nginx实现动静分离;Nginx实现高可用集群;Nginx4种常见配置实例如下:一、Nginx反向代理配...

使用nginx+allure管理自动化测试报告

allure在自动化测试中经常用来生成漂亮的报告,但是网上及官网上给出的例子都仅仅是针对单个测试用例文件的形式介绍的,实际使用中,自动化测试往往需要包含不止一个产品或项目,本文介绍如何使用nginx+...

nginx配置文件详解(nginx配置文件详解高清版)

Nginx是一个强大的免费开源的HTTP服务器和反向代理服务器。在Web开发项目中,nginx常用作为静态文件服务器处理静态文件,并负责将动态请求转发至应用服务器(如Django,Flask,et...

SpringCloud Eureka-服务注册与发现

1.Eureka介绍1.1学习Eureka前的说明目前主流的服务注册&发现的组件是Nacos,但是Eureka作为老牌经典的服务注册&发现技术还是有必要学习一下,原因:(1)一些早期的分布式微服...

微服务 Spring Cloud 实战 Eureka+Gateway+Feign+Hystrix

前言我所在项目组刚接到一个微服务改造需求,技术选型为SpringCloud,具体需求是把部分项目使用SpringCloud技术进行重构。本篇文章中介绍了Eureka、Gateway、Fe...

深度剖析 Spring Cloud Eureka 底层实现原理

你作为一名互联网大厂后端技术开发人员,在构建分布式系统时,是不是常常为服务的注册与发现而头疼?你是否好奇,像SpringCloudEureka这样被广泛使用的组件,它的底层实现原理到底是怎样的...

热爱生活,喜欢折腾。(很热爱生活)

原文是stackoverflow的一则高票回答,原文链接可能之前也有人翻译过,但是刚好自己也有疑惑,所以搬运一下,个人水平有限所以可能翻译存在误差,欢迎指正(如侵删)。尽管classmethod和st...

GDB调试的高级技巧(详细描述gdb调试程序的全过程)

GDB是我们平时调试c/c++程序的利器,查起复杂的bug问题,比打印大法要好得多,但是也不得不说,gdb在默认情况下用起来并不是很好用,最近学习到几个高级点的技巧,分享下:一美化打印先上个例子...

Arduino 实例(二十三)Arduino 给Python 编译器发送信息

1首先Python需要安装Pyserial库,在命令提示符中输入pipintallpyserial若是遇到提示‘pip‘不是内部或外部命令,也不是可运行的程序或批处理文件,则需要设置环境变...