img/effect.go

320 lines
7.3 KiB
Go
Raw Normal View History

2025-07-29 16:59:49 +08:00
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)
}