Golang Gin Practice Serialization 15 to Generate Two-dimensional Codes and Merge Posters
Original address:Golang Gin Practice Serialization 15 to Generate Two-dimensional Codes and Merge Posters
Project address:https://github.com/EDDYCJY/go …
If it is helpful to you, welcome to Star.
Preface
In this chapter, the following functional details will be implemented:
1, generating a two-dimensional code
2. Merge Posters (Background Map+Two-dimensional Code)
Realization
First of all, you need to add the storage path of the two-dimensional code and its poster to the App configuration item. We agree that the configuration item name isQrCodeSavePath
, the value isqrcode/
You should be able to finish the serial after many sections, if you don’t understand it, you can refer to it.go-gin-example
Generate two-dimensional code
Installation
$ go get -u github.com/boombuler/barcode
Tool kit
Considering that the action of generating two-dimensional codes conforms to the definition of the toolkit and has the possibility of common use, create a new pkg/qrcode/qrcode.go file and write the contents:
package qrcode
import (
"image/jpeg"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
"github.com/EDDYCJY/go-gin-example/pkg/file"
"github.com/EDDYCJY/go-gin-example/pkg/setting"
"github.com/EDDYCJY/go-gin-example/pkg/util"
)
type QrCode struct {
URL string
Width int
Height int
Ext string
Level qr.ErrorCorrectionLevel
Mode qr.Encoding
}
const (
EXT_JPG = ".jpg"
)
func NewQrCode(url string, width, height int, level qr.ErrorCorrectionLevel, mode qr.Encoding) *QrCode {
return &QrCode{
URL: url,
Width: width,
Height: height,
Level: level,
Mode: mode,
Ext: EXT_JPG,
}
}
func GetQrCodePath() string {
return setting.AppSetting.QrCodeSavePath
}
func GetQrCodeFullPath() string {
return setting.AppSetting.RuntimeRootPath + setting.AppSetting.QrCodeSavePath
}
func GetQrCodeFullUrl(name string) string {
return setting.AppSetting.PrefixUrl + "/" + GetQrCodePath() + name
}
func GetQrCodeFileName(value string) string {
return util.EncodeMD5(value)
}
func (q *QrCode) GetQrCodeExt() string {
return q.Ext
}
func (q *QrCode) CheckEncode(path string) bool {
src := path + GetQrCodeFileName(q.URL) + q.GetQrCodeExt()
if file.CheckNotExist(src) == true {
return false
}
return true
}
func (q *QrCode) Encode(path string) (string, string, error) {
name := GetQrCodeFileName(q.URL) + q.GetQrCodeExt()
src := path + name
if file.CheckNotExist(src) == true {
code, err := qr.Encode(q.URL, q.Level, q.Mode)
if err != nil {
return "", "", err
}
code, err = barcode.Scale(code, q.Width, q.Height)
if err != nil {
return "", "", err
}
f, err := file.MustOpen(name, path)
if err != nil {
return "", "", err
}
defer f.Close()
err = jpeg.Encode(f, code, nil)
if err != nil {
return "", "", err
}
}
return name, path, nil
}
The main focus here isfunc (q *QrCode) Encode
Methods, did the following things:
- Acquiring a two-dimensional code generation path
- Create two-dimensional code
- Scales the QR code to the specified size
- Create a new file for storing two-dimensional code pictures.
- Write the image (two-dimensional code) into the file in JPEG 4: 2: 0 baseline format
Also injpeg.Encode(f, code, nil)
, the third parameter can set its image quality, the default value is 75
// DefaultQuality is the default quality encoding parameter.
const DefaultQuality = 75
// Options are the encoding parameters.
// Quality ranges from 1 to 100 inclusive, higher is better.
type Options struct {
Quality int
}
Routing method
1. The first step
Add the GenerateArticlePoster method to routers/api/v1/article.go for interface development.
2. Step 2
Add to apiv1 of routers/router.goapiv1.POST("/articles/poster/generate", v1.GenerateArticlePoster)
Routing
3. Step 3
Modify the GenerateArticlePoster method and write the corresponding generation logic as follows:
const (
QRCODE_URL = "https://github.com/EDDYCJY/blog#gin%E7%B3%BB%E5%88%97%E7%9B%AE%E5%BD%95"
)
func GenerateArticlePoster(c *gin.Context) {
appG := app.Gin{c}
qrc := qrcode.NewQrCode(QRCODE_URL, 300, 300, qr.M, qr.Auto)
path := qrcode.GetQrCodeFullPath()
_, _, err := qrc.Encode(path)
if err != nil {
appG.Response(http.StatusOK, e.ERROR, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
Verification
Access via POST methodhttp://127.0.0.1:8000/api/v1/articles/poster/generate? token=$token
(note $token)
Determine whether the function is normal by checking two points, as follows:
1. Whether the visit result is 200
2. Whether the local directory successfully generated the two-dimensional code picture
Merge posters
In this section, the two-dimensional code picture and the background picture are combined into a new picture, which can be used in common business scenes such as publicity posters.
Background map
Save the background map as runtime/qrcode/bg.jpg (for practical application, OSS or other places may exist)
Service method
Open the service/article_service directory, create a new article_poster.go file, and write:
package article_service
import (
"image"
"image/draw"
"image/jpeg"
"os"
"github.com/EDDYCJY/go-gin-example/pkg/file"
"github.com/EDDYCJY/go-gin-example/pkg/qrcode"
)
type ArticlePoster struct {
PosterName string
*Article
Qr *qrcode.QrCode
}
func NewArticlePoster(posterName string, article *Article, qr *qrcode.QrCode) *ArticlePoster {
return &ArticlePoster{
PosterName: posterName,
Article: article,
Qr: qr,
}
}
func GetPosterFlag() string {
return "poster"
}
func (a *ArticlePoster) CheckMergedImage(path string) bool {
if file.CheckNotExist(path+a.PosterName) == true {
return false
}
return true
}
func (a *ArticlePoster) OpenMergedImage(path string) (*os.File, error) {
f, err := file.MustOpen(a.PosterName, path)
if err != nil {
return nil, err
}
return f, nil
}
type ArticlePosterBg struct {
Name string
*ArticlePoster
*Rect
*Pt
}
type Rect struct {
Name string
X0 int
Y0 int
X1 int
Y1 int
}
type Pt struct {
X int
Y int
}
func NewArticlePosterBg(name string, ap *ArticlePoster, rect *Rect, pt *Pt) *ArticlePosterBg {
return &ArticlePosterBg{
Name: name,
ArticlePoster: ap,
Rect: rect,
Pt: pt,
}
}
func (a *ArticlePosterBg) Generate() (string, string, error) {
fullPath := qrcode.GetQrCodeFullPath()
fileName, path, err := a.Qr.Encode(fullPath)
if err != nil {
return "", "", err
}
if !a.CheckMergedImage(path) {
mergedF, err := a.OpenMergedImage(path)
if err != nil {
return "", "", err
}
defer mergedF.Close()
bgF, err := file.MustOpen(a.Name, path)
if err != nil {
return "", "", err
}
defer bgF.Close()
qrF, err := file.MustOpen(fileName, path)
if err != nil {
return "", "", err
}
defer qrF.Close()
bgImage, err := jpeg.Decode(bgF)
if err != nil {
return "", "", err
}
qrImage, err := jpeg.Decode(qrF)
if err != nil {
return "", "", err
}
jpg := image.NewRGBA(image.Rect(a.Rect.X0, a.Rect.Y0, a.Rect.X1, a.Rect.Y1))
draw.Draw(jpg, jpg.Bounds(), bgImage, bgImage.Bounds().Min, draw.Over)
draw.Draw(jpg, jpg.Bounds(), qrImage, qrImage.Bounds().Min.Sub(image.Pt(a.Pt.X, a.Pt.Y)), draw.Over)
jpeg.Encode(mergedF, jpg, nil)
}
return fileName, path, nil
}
The focus here is onfunc (a *ArticlePosterBg) Generate()
Methods, did the following things:
- Acquiring a two-dimensional code storage path
- Generating two-dimensional code image
- Check whether the merged image (referring to storing the merged poster) exists
- If it does not exist, generating an image mergedF to be merged
- Open the background map bgF stored in advance
- Open the generated two-dimensional code image qrF
- Decoding bgF and qrF returns image.Image
- Create a new RGBA image
- Draw a background map (bgF) on the RGBA image
- Drawing a two-dimensional code image (qrF) on the designated Point on the RGBA image on which the background map has been drawn
- Writing the drawn RGBA image into the merged image file (mergedF) in JPEG 4: 2: 0 baseline format
Error code
Routing method
Open the routers/api/v1/article.go file, modify the GenerateArticlePoster method, and write the final business logic (including generating two-dimensional codes and merging posters), as follows:
const (
QRCODE_URL = "https://github.com/EDDYCJY/blog#gin%E7%B3%BB%E5%88%97%E7%9B%AE%E5%BD%95"
)
func GenerateArticlePoster(c *gin.Context) {
appG := app.Gin{c}
article := &article_service.Article{}
qr := qrcode.NewQrCode(QRCODE_URL, 300, 300, qr.M, qr.Auto) // 目前写死 gin 系列路径,可自行增加业务逻辑
posterName := article_service.GetPosterFlag() + "-" + qrcode.GetQrCodeFileName(qr.URL) + qr.GetQrCodeExt()
articlePoster := article_service.NewArticlePoster(posterName, article, qr)
articlePosterBgService := article_service.NewArticlePosterBg(
"bg.jpg",
articlePoster,
&article_service.Rect{
X0: 0,
Y0: 0,
X1: 550,
Y1: 700,
},
&article_service.Pt{
X: 125,
Y: 298,
},
)
_, filePath, err := articlePosterBgService.Generate()
if err != nil {
appG.Response(http.StatusOK, e.ERROR_GEN_ARTICLE_POSTER_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, map[string]string{
"poster_url": qrcode.GetQrCodeFullUrl(posterName),
"poster_save_url": filePath + posterName,
})
}
This piece involves a great deal of knowledge. It is strongly recommended to read it as follows:
It is suggested to study all the related libraries involved in it.
StaticFS
In the routers/router.go file, add the following code:
r.StaticFS("/qrcode", http.Dir(qrcode.GetQrCodeFullPath()))
Verification
Visit the complete URL path, return the synthesized poster and wipe out the two-dimensional code. Success is correct.
Summary
In this chapter, two common business functions are realized, namely, generating two-dimensional codes and merging posters. I hope you can read the links I have given carefully. There is a lot of knowledge in this area. If you want to use the image processing function well, you must understand the corresponding ideas and draw a analogy from one another.
Finally, I hope it will be helpful to you.
References
This series of sample codes
This series of catalogues
- Serial One Golang Introduction and Environmental Installation
- Serialized 2 to build Blog API’s (1)
- Serial 3 to build Blog API’s (2)
- Serial 4 to build Blog API’s (3)
- Serial 5 Use JWT for Identity Verification
- Serial 6 Write a Simple File Log
- Serial Seven Golang Gracefully Restart HTTP Service
- Serial 8 Add Swagger to It
- Serial 9 Deploying Golang Applications to Docker
- Serial Ten Customized GORM Callbacks
- Serial Eleven Cron Scheduled Tasks
- Serial 12 Optimizing Configuration Structure and Realizing Picture Upload
- Serialization 13 Optimize Your Application Structure and Implement Redis Cache
- Serial 14 Realize Export and Import into Excel
- Serial 15 Generate Two-dimensional Code and Merge Posters
- Serial 16 Draw Text on Pictures
- Serial 17 Deploying Go Applications with Nginx
- Cross-compilation of safari Golang
- Please get started with Makefile