实现一个阿里云oss图片处理库

在这里插入图片描述

0.概述

在web开发中我们页面需要对图片做各种处理,如图片缩放自定义裁剪质量变换格式转换等。

而且长期以来,加载速度一直是优化网站最重要的因素之一,访问者和搜索引擎都将调用页面所需的时间作为重要的评价标准。精简的代码或使用缓存机制是解决网站快速加载方案的一部分,而网页中展示的图片大小也影响着加载速度。因此我们不能仅仅通过前端处理,而是在返回图片的时间就要减少大小。

如果是国内用户使用阿里云oss,里面的图片处理使用起来就很方便。但是你如果使用s3或自己搭建得文件服务系统的话,你就得自己实现了。以往我们对于这种得话,我们需要提取准备很多规格得图片上传到文件系统,然后再不同场景使用,但是使用场景会随时变化。那电商来说上传到不同平台得图片尺寸要求不尽相同,这是就得准备大量不同规格得图片了。

因此我们可以自己设计一个类似oss图片处理系统,让以前不支持图片处理得文件系统拥有动态处理图片得能力。

imageprocess库可以帮助我们非常简单实现。

Imageprocess是一个简单的Go图像处理包。支持 WEBP,JPG,JPEG,PNG,BMP,TIFF,GIF。提供了类似阿里云oss的图片处理能力。 包括:

图片缩放

图片水印

自定义裁剪

质量变换

格式转换

模糊效果

旋转

亮度

锐化

对比度

参数兼容阿里云oss图片处理参数,可以用于搭建本地文件oss图片处理系统。

1.安装

go get github.com/AndsGo/imageprocess

2.api调用

import (
	"image/color"
	"os"
	"testing"
    "github.com/AndsGo/imageprocess"
)

func Test_Process(t *testing.T) {
	img, f, err := imageprocess.LoadImage("examples/example.jpg")
	if err != nil {
		t.Error(err)
	}
	file, _ := os.Create("examples/out.jpg")
	options := make([]Option, 0)
	// 格式转换为PNG
	options = append(options, Option{FormatType, FormatOption{Format: PNG}})
	//  改变大小
	options = append(options, Option{Resize, ResizeOption{ResizeMode: Pad, Width: 300, Height: 300, Color: &color.RGBA{R: 255, G: 255, B: 0, A: 255}}})
	// 裁剪
	options = append(options, Option{Crop, CropOption{Width: 200, Height: 200, X: 0, Y: 0, Position: Center}})
	// 水印
	options = append(options, Option{Watermark, TextWatermarkOption{WatermarkOption: WatermarkOption{
		Opacity: 100, Position: South, X: 10, Y: 10,
	}, Color: &color.RGBA{111, 222, 111, 1}, Size: 40, Text: "hello watermark"}})
	// 模糊
	options = append(options, Option{Blur, GammaOption{Value: 5}})
	// 质量
	options = append(options, Option{Quality, QualityOption{Quality: 500}})
	err = imageprocess.Process(img, file, f, options)
	if err != nil {
		t.Error(err)
	}
}

func Test_ProcessGif(t *testing.T) {
	img, err := imageprocess.LoadGif("examples/example.gif")
	if err != nil {
		t.Error(err)
	}
	file, _ := os.Create("examples/out.gif")
	options := make([]Option, 0)
	// 格式转换为GIF
	options = append(options, Option{FormatType, FormatOption{Format: GIF}})
	options = append(options, Option{Gamma, GammaOption{Value: 500}})
	options = append(options, Option{Resize, ResizeOption{ResizeMode: Pad, Width: 300, Height: 300, Color: &color.RGBA{R: 255, G: 255, B: 255, A: 1}}})
	options = append(options, Option{Crop, CropOption{Width: 200, Height: 200, X: 0, Y: 0, Position: Center}})
	options = append(options, Option{Watermark, TextWatermarkOption{WatermarkOption: WatermarkOption{
		Opacity: 20, Position: Center, X: 10, Y: 10,
	}, Color: &color.RGBA{0, 0, 0, 1}, Size: 40, Text: "hello watermark"}})
	err = imageprocess.ProcessGif(img, file, options)
	if err != nil {
		t.Error(err)
	}
}

func Test_UrlOptions(t *testing.T) {
	img, f, err := imageprocess.LoadImage("examples/example.jpg")
	if err != nil {
		t.Error(err)
	}
	file, _ := os.Create("examples/out.jpg")
	// 增加水印,然后修改大小
	options, err := imageprocess.ParseOptions("image/watermark,t_30,g_center,x_10,y_10,text_hello watermark,color_1366ec,size_200/resize,m_pad,h_100,w_100,color_FF0000")
	if err != nil {
		t.Error(err)
	}
	err = imageprocess.Process(img, file, f, options)
	if err != nil {
		t.Error(err)
	}

}

更多api查看 doc

3.Url参数调用

在源码 examples 目录里面实现了一个简单得文件服务器。我们可以轻松实现图片得动态处理。

cd examples
go run example.go

我们可以启动后进行测试。下面我们进行测试

原图:

原图

我们可以和阿里oss一样进行调用了,参数放在url上,固定参数x-oss-process=image/后面接你需要进行逻辑。

调用测试:

http://127.0.0.1:8080/file/example.jpg?x-oss-process=image/resize,w_500,h_300/watermark,t_80,g_se,x_10,y_10,text_hello,color_FFFFFF,size_40/format,webp

在这里插入图片描述

http://127.0.0.1:8080/file/example.gif?x-oss-process=image/resize,w_500,h_300/watermark,t_80,g_se,x_10,y_10,text_hello,color_FF00FF,size_40/format,gif

在这里插入图片描述

更多参数测试如下:

OptionsMeaningImage
resize,h_100,w_300,m_lfit改变大小,高100px,宽300px,模式等比缩放匹配最大边break
resize,m_fill,h_100,w_100将原图缩放成宽高100 px:resize,h_100,w_100 缩放模式fill:m_fill自动裁剪
resize,m_pad,h_100,w_100,color_FF0000将原图缩放成宽高100 px:resize,h_100,w_100 缩放模式pad:m_pad。 以红色填充:color_FF0000填充红色
resize,w_300,h_300/watermark,size_30,text_Hello World,color_FFFFFF,g_se,x_10,y_10将example.jpg缩略为宽高300:resize,w_300,h_300 水印内容为“Hello World”:text_Hello%20World 水印文字颜色为白色、字体大小为30:color_FFFFFF,size_30 水印文字位置是右下、水平边距10、中线垂直偏移10:g_se,x_10,y_10图片处理1
crop,x_800,y_500,w_300,h_300裁剪起点为(800,500):crop,x_800,y_500 裁减范围300 px*300 px:w_300,h_300裁剪2
crop,w_900,h_900,g_se裁剪起点为原图右下角:crop,g_se 裁减范围900 px*900 px:w_900,h_900裁剪3
resize,w_100/quality,q_80原图缩放为宽100 px:resize,w_100 图片相对质量设置为80%:quality,q_80变换1
format,png将原图转换为PNG格式png
rotate,90将原图按顺时针旋转90°旋转1
bright,50将图片亮度提高50亮度1
sharpen,100对原图进行锐化处理,锐化参数为100锐化1
contrast,-50对比度提高50外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下面是文件服务器测试代码,可以在源码examples文件夹中找到。

package main

import (
	"fmt"
	"image/gif"
	"io"
	"net/http"
	"os"
	"strings"

	"github.com/AndsGo/imageprocess"
)

// 文件夹,you need change it
var fileFolders = "./"

func main() {
	http.HandleFunc("/file/", fileHandler)

	fmt.Println("Starting server on :8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Println("Server failed:", err)
	}
}

func fileHandler(w http.ResponseWriter, r *http.Request) {
	// 获取文件名称
	fileName := strings.TrimPrefix(r.URL.Path, "/file/")
	// 打开文件
	file, err := os.Open(fmt.Sprintf("%s%s", fileFolders, fileName))
	if err != nil {
		http.Error(w, "File not found", http.StatusNotFound)
		return
	}
	defer file.Close()
	// 获取参数
	// 获取文件后缀
	f, err := imageprocess.FormatFromExtension(fileName)
	if err != nil {
		// 将处理后的文件内容写入响应
		if _, err := io.Copy(w, file); err != nil {
			http.Error(w, "Failed to send file", http.StatusInternalServerError)
		}
		return
	}
	//处理处理参数
	ossParams := r.URL.Query().Get("x-oss-process")
	if ossParams == "" {
		//无需处理
		if _, err := io.Copy(w, file); err != nil {
			http.Error(w, "Failed to send file", http.StatusInternalServerError)
		}
		return
	}
	options, err := imageprocess.ParseOptions(ossParams)
	if err != nil {
		http.Error(w, fmt.Sprintf("ParseOptions %s", err.Error()), http.StatusInternalServerError)
		return
	}
	if len(options) == 0 {
		//无需处理
		if _, err := io.Copy(w, file); err != nil {
			http.Error(w, "Failed to send file", http.StatusInternalServerError)
		}
		return
	}
	//处理图片
	err = processImg(file, w, f, options)
	if err != nil {
		http.Error(w, fmt.Sprintf("processFile %s", err.Error()), http.StatusInternalServerError)
	}
}

// 进行转换
func processImg(file io.Reader, w io.Writer, f imageprocess.Format, options []imageprocess.Option) error {
	if f == imageprocess.GIF {
		imgGif, err := gif.DecodeAll(file)
		if err != nil {
			return err
		}
		return imageprocess.ProcessGif(imgGif, w, options)
	} else {
		img, err := imageprocess.DecodeImage(file, f)
		if err != nil {
			return err
		}
		return imageprocess.Process(img, w, f, options)
	}
}

原文地址:
https://mp.weixin.qq.com/s/AG2_fJPCSkKlkPeZV5olRQ?token=573702923&lang=zh_CN
源码地址:

https://github.com/AndsGo/imageprocess

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值