img/effect.go
2025-07-29 16:59:49 +08:00

320 lines
7.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}