320 lines
7.3 KiB
Go
320 lines
7.3 KiB
Go
package img
|
||
|
||
import (
|
||
"errors"
|
||
"image"
|
||
"image/color"
|
||
"image/draw"
|
||
"math"
|
||
|
||
"github.com/disintegration/imaging"
|
||
"github.com/fogleman/gg"
|
||
"github.com/ssgo/u"
|
||
)
|
||
|
||
// Crop 裁剪图像
|
||
func (g *Graphics) Crop(x, y, w, h int) {
|
||
rect := image.Rect(x, y, x+w, y+h)
|
||
newImg := imaging.Crop(g.dc.Image(), rect)
|
||
g.dc = gg.NewContextForImage(newImg)
|
||
}
|
||
|
||
// Contain 改变图片尺寸,保持图片比例,图片居中
|
||
func (g *Graphics) Contain(width, height int) {
|
||
bounds := g.dc.Image().Bounds()
|
||
srcW := bounds.Dx()
|
||
srcH := bounds.Dy()
|
||
ratio := math.Min(float64(width)/float64(srcW), float64(height)/float64(srcH))
|
||
dstW := int(float64(srcW) * ratio)
|
||
dstH := int(float64(srcH) * ratio)
|
||
|
||
// 创建透明背景画布
|
||
newImg := image.NewRGBA(image.Rect(0, 0, width, height))
|
||
|
||
// 居中放置缩放后的图像
|
||
offsetX := (width - dstW) / 2
|
||
offsetY := (height - dstH) / 2
|
||
resized := imaging.Resize(g.dc.Image(), dstW, dstH, imaging.Lanczos)
|
||
draw.Draw(newImg,
|
||
image.Rect(offsetX, offsetY, offsetX+dstW, offsetY+dstH),
|
||
resized, image.Point{}, draw.Over)
|
||
|
||
g.dc = gg.NewContextForImage(newImg)
|
||
}
|
||
|
||
// Cover 改变图片尺寸,保持图片比例,图片居中裁剪
|
||
func (g *Graphics) Cover(width, height int) {
|
||
bounds := g.dc.Image().Bounds()
|
||
srcW := bounds.Dx()
|
||
srcH := bounds.Dy()
|
||
ratio := math.Max(float64(width)/float64(srcW), float64(height)/float64(srcH))
|
||
dstW := int(float64(srcW) * ratio)
|
||
dstH := int(float64(srcH) * ratio)
|
||
|
||
resized := imaging.Resize(g.dc.Image(), dstW, dstH, imaging.Lanczos)
|
||
|
||
// 从中心裁剪
|
||
cropX := max(0, (dstW-width)/2)
|
||
cropY := max(0, (dstH-height)/2)
|
||
cropped := imaging.Crop(resized,
|
||
image.Rect(cropX, cropY, cropX+width, cropY+height))
|
||
|
||
g.dc = gg.NewContextForImage(cropped)
|
||
}
|
||
|
||
// Resize 改变图片尺寸,拉伸
|
||
func (g *Graphics) Resize(width, height int, resampleMode *string) {
|
||
resample := imaging.Lanczos
|
||
if resampleMode != nil {
|
||
switch *resampleMode {
|
||
case "nearest":
|
||
resample = imaging.NearestNeighbor
|
||
case "catmullrom":
|
||
resample = imaging.CatmullRom
|
||
case "box":
|
||
resample = imaging.Box
|
||
case "linear":
|
||
resample = imaging.Linear
|
||
case "hermite":
|
||
resample = imaging.Hermite
|
||
case "mitchellnetravali":
|
||
resample = imaging.MitchellNetravali
|
||
case "bspline":
|
||
resample = imaging.BSpline
|
||
case "gaussian":
|
||
resample = imaging.Gaussian
|
||
case "bartlett":
|
||
resample = imaging.Bartlett
|
||
case "hann":
|
||
resample = imaging.Hann
|
||
case "hamming":
|
||
resample = imaging.Hamming
|
||
case "blackman":
|
||
resample = imaging.Blackman
|
||
case "welch":
|
||
resample = imaging.Welch
|
||
case "cosine":
|
||
resample = imaging.Cosine
|
||
default:
|
||
resample = imaging.Lanczos
|
||
}
|
||
}
|
||
resized := imaging.Resize(g.dc.Image(), width, height, resample)
|
||
g.dc = gg.NewContextForImage(resized)
|
||
}
|
||
|
||
// Rotate 旋转图像
|
||
func (g *Graphics) Rotate(angle float64) {
|
||
rotated := imaging.Rotate(g.dc.Image(), angle, color.Transparent)
|
||
g.dc = gg.NewContextForImage(rotated)
|
||
}
|
||
|
||
// Blur 模糊图像
|
||
func (g *Graphics) Blur(sigma float64) {
|
||
blurred := imaging.Blur(g.dc.Image(), sigma)
|
||
g.dc = gg.NewContextForImage(blurred)
|
||
}
|
||
|
||
// Sharpen 锐化图像
|
||
func (g *Graphics) Sharpen(sigma float64) {
|
||
sharpened := imaging.Sharpen(g.dc.Image(), sigma)
|
||
g.dc = gg.NewContextForImage(sharpened)
|
||
}
|
||
|
||
// Grayscale 转为灰度图
|
||
func (g *Graphics) Grayscale() {
|
||
gray := imaging.Grayscale(g.dc.Image())
|
||
g.dc = gg.NewContextForImage(gray)
|
||
}
|
||
|
||
// AdjustBrightness 调整亮度
|
||
func (g *Graphics) AdjustBrightness(percent float64) {
|
||
adjusted := imaging.AdjustBrightness(g.dc.Image(), percent)
|
||
g.dc = gg.NewContextForImage(adjusted)
|
||
}
|
||
|
||
// AdjustContrast 调整对比度
|
||
func (g *Graphics) AdjustContrast(percent float64) {
|
||
adjusted := imaging.AdjustContrast(g.dc.Image(), percent)
|
||
g.dc = gg.NewContextForImage(adjusted)
|
||
}
|
||
|
||
// GammaCorrection Gamma校正
|
||
func (g *Graphics) GammaCorrection(gamma float64) {
|
||
adjusted := imaging.AdjustGamma(g.dc.Image(), gamma)
|
||
g.dc = gg.NewContextForImage(adjusted)
|
||
}
|
||
|
||
// FlipH 水平翻转
|
||
func (g *Graphics) FlipH() {
|
||
flipped := imaging.FlipH(g.dc.Image())
|
||
g.dc = gg.NewContextForImage(flipped)
|
||
}
|
||
|
||
// FlipV 垂直翻转
|
||
func (g *Graphics) FlipV() {
|
||
flipped := imaging.FlipV(g.dc.Image())
|
||
g.dc = gg.NewContextForImage(flipped)
|
||
}
|
||
|
||
// AdjustSaturation 调整饱和度
|
||
func (g *Graphics) AdjustSaturation(percent float64) {
|
||
adjusted := imaging.AdjustSaturation(g.dc.Image(), percent)
|
||
g.dc = gg.NewContextForImage(adjusted)
|
||
}
|
||
|
||
// func min(a, b int) int {
|
||
// if a < b {
|
||
// return a
|
||
// }
|
||
// return b
|
||
// }
|
||
|
||
// func max(a, b int) int {
|
||
// if a > b {
|
||
// return a
|
||
// }
|
||
// return b
|
||
// }
|
||
|
||
// Convolve3x3 应用3x3卷积核
|
||
func (g *Graphics) Convolve3x3(kernel []float64) error {
|
||
if len(kernel) != 9 {
|
||
return errors.New("kernel " + u.String(len(kernel)) + " must be 3x3")
|
||
}
|
||
|
||
// 获取图像大小
|
||
bounds := g.dc.Image().Bounds()
|
||
width, height := bounds.Dx(), bounds.Dy()
|
||
|
||
// 创建新图像
|
||
result := image.NewRGBA(bounds)
|
||
|
||
// 卷积核权重和
|
||
var sum float64
|
||
for _, v := range kernel {
|
||
sum += v
|
||
}
|
||
|
||
// 如果权重和不是0,则使用归一化因子
|
||
scale := 1.0
|
||
if sum != 0 {
|
||
scale = 1.0 / sum
|
||
}
|
||
|
||
// 处理每个像素
|
||
for y := 1; y < height-1; y++ {
|
||
for x := 1; x < width-1; x++ {
|
||
var r, g1, b, a float64
|
||
|
||
// 应用卷积核
|
||
for ky := -1; ky <= 1; ky++ {
|
||
for kx := -1; kx <= 1; kx++ {
|
||
k := kernel[(ky+1)*3+(kx+1)]
|
||
px := g.dc.Image().At(x+kx, y+ky)
|
||
pr, pg, pb, pa := px.RGBA()
|
||
|
||
r += float64(pr>>8) * k
|
||
g1 += float64(pg>>8) * k
|
||
b += float64(pb>>8) * k
|
||
a += float64(pa>>8) * k
|
||
}
|
||
}
|
||
|
||
// 应用比例因子并限制范围
|
||
r = math.Max(0, math.Min(255, r*scale))
|
||
g1 = math.Max(0, math.Min(255, g1*scale))
|
||
b = math.Max(0, math.Min(255, b*scale))
|
||
a = math.Max(0, math.Min(255, a*scale))
|
||
|
||
// 设置结果像素
|
||
result.SetRGBA(x, y, color.RGBA{
|
||
R: uint8(r),
|
||
G: uint8(g1),
|
||
B: uint8(b),
|
||
A: uint8(a),
|
||
})
|
||
}
|
||
}
|
||
|
||
// 复制边界像素
|
||
for y := 0; y < height; y++ {
|
||
for x := 0; x < width; x++ {
|
||
if y == 0 || y == height-1 || x == 0 || x == width-1 {
|
||
result.Set(x, y, g.dc.Image().At(x, y))
|
||
}
|
||
}
|
||
}
|
||
|
||
g.dc = gg.NewContextForImage(result)
|
||
return nil
|
||
}
|
||
|
||
// 带强度参数的滤镜应用
|
||
func (g *Graphics) ApplyFilter(kernel []float64, strength *float64) error {
|
||
if len(kernel) != 9 {
|
||
return errors.New("kernel " + u.String(len(kernel)) + " must be 3x3")
|
||
}
|
||
|
||
// 创建加权核
|
||
weightedKernel := make([]float64, len(kernel))
|
||
if strength == nil {
|
||
copy(weightedKernel, kernel)
|
||
} else {
|
||
centerIdx := 4 // 3x3核心中心索引
|
||
for i, v := range kernel {
|
||
if i == centerIdx {
|
||
weightedKernel[i] = 1 + *strength*(v-1)
|
||
} else {
|
||
weightedKernel[i] = *strength * v
|
||
}
|
||
}
|
||
}
|
||
return g.Convolve3x3(weightedKernel)
|
||
}
|
||
|
||
// 边缘检测
|
||
func (g *Graphics) EdgeDetectionFilter(strength *float64) {
|
||
g.ApplyFilter([]float64{
|
||
-1, -1, -1,
|
||
-1, 8, -1,
|
||
-1, -1, -1,
|
||
}, strength)
|
||
}
|
||
|
||
// 高斯模糊
|
||
func (g *Graphics) GaussianBlurFilter(strength *float64) {
|
||
g.ApplyFilter([]float64{
|
||
1, 2, 1,
|
||
2, 4, 2,
|
||
1, 2, 1,
|
||
}, strength)
|
||
}
|
||
|
||
// 锐化
|
||
func (g *Graphics) SharpenFilter(strength *float64) {
|
||
g.ApplyFilter([]float64{
|
||
-1, -1, -1,
|
||
-1, 9, -1,
|
||
-1, -1, -1,
|
||
}, strength)
|
||
}
|
||
|
||
// 浮雕
|
||
func (g *Graphics) EmbossFilter(strength *float64) {
|
||
g.ApplyFilter([]float64{
|
||
-2, -1, 0,
|
||
-1, 1, 1,
|
||
0, 1, 2,
|
||
}, strength)
|
||
}
|
||
|
||
// 散景模糊
|
||
func (g *Graphics) BokehFilter(strength *float64) {
|
||
g.ApplyFilter([]float64{
|
||
0, 0.1, 0,
|
||
0.1, 0.6, 0.1,
|
||
0, 0.1, 0,
|
||
}, strength)
|
||
}
|