2024-04-11 15:51:56 +02:00
|
|
|
package goeffects
|
|
|
|
|
|
|
|
// goeffects.go provides functions to interface with go-effects
|
|
|
|
// Package copied from https://github.com/markdaws/go-effects/
|
|
|
|
|
|
|
|
import "seekia/internal/helpers"
|
|
|
|
import "seekia/internal/imagery"
|
|
|
|
|
|
|
|
import "image"
|
|
|
|
import "image/draw"
|
|
|
|
import "errors"
|
|
|
|
|
|
|
|
|
|
|
|
func ApplyCartoonEffect(inputImage image.Image, effectStrength int)(image.Image, error){
|
|
|
|
|
|
|
|
if (inputImage == nil){
|
|
|
|
return nil, errors.New("ApplyCartoonEffect called with nil image.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectStrength < 0 || effectStrength > 100){
|
|
|
|
return nil, errors.New("ApplyCartoonEffect called with invalid effectStrength.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectStrength == 0) {
|
|
|
|
return inputImage, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-08-07 09:45:31 +02:00
|
|
|
blurKernelSize, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 1, 3)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
if (blurKernelSize % 2 == 0){
|
|
|
|
blurKernelSize += 1
|
|
|
|
}
|
|
|
|
|
2024-08-07 09:45:31 +02:00
|
|
|
edgeThreshold, err := helpers.ScaleIntProportionally(false, effectStrength, 0, 100, 5, 200)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
2024-08-07 09:45:31 +02:00
|
|
|
oilFilterSize, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 5, 20)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
2024-08-07 09:45:31 +02:00
|
|
|
oilLevels, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 1, 3)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
options := CTOpts{
|
|
|
|
BlurKernelSize : blurKernelSize,
|
|
|
|
EdgeThreshold : edgeThreshold,
|
|
|
|
OilFilterSize : oilFilterSize,
|
|
|
|
OilLevels : oilLevels,
|
|
|
|
}
|
|
|
|
|
|
|
|
cartoonEffectObject := NewCartoon(options)
|
|
|
|
|
|
|
|
goeffectsImageObject, err := convertGolangImageObjectToGoeffectsImageObject(inputImage)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
resultGoeffectsImage, err := cartoonEffectObject.Apply(&goeffectsImageObject, 8)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
result := convertGoeffectsImageObjectToGolangImageObject(*resultGoeffectsImage)
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ApplyPencilEffect(inputImage image.Image, effectStrength int)(image.Image, error){
|
|
|
|
|
|
|
|
if (inputImage == nil){
|
|
|
|
return nil, errors.New("ApplyPencilEffect called with nil image.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectStrength < 0 || effectStrength > 100){
|
|
|
|
return nil, errors.New("ApplyPencilEffect called with invalid effectStrength.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectStrength == 0) {
|
|
|
|
return inputImage, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
goeffectsImageObject, err := convertGolangImageObjectToGoeffectsImageObject(inputImage)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
2024-08-07 09:45:31 +02:00
|
|
|
blurAmount, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 1, 20)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
if (blurAmount % 2 == 0) {
|
|
|
|
blurAmount += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
pencilEffectObject := NewPencil(blurAmount)
|
|
|
|
|
|
|
|
resultGoeffectsImage, err := pencilEffectObject.Apply(&goeffectsImageObject, 5)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
result := convertGoeffectsImageObjectToGolangImageObject(*resultGoeffectsImage)
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ApplyWireframeEffect(inputImage image.Image, effectStrength int, lightMode bool)(image.Image, error){
|
|
|
|
|
|
|
|
if (inputImage == nil){
|
|
|
|
return nil, errors.New("ApplyWireframeEffect called with nil image.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectStrength < 0 || effectStrength > 100){
|
|
|
|
return nil, errors.New("ApplyWireframeEffect called with invalid effectStrength.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectStrength == 0) {
|
|
|
|
return inputImage, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
goeffectsImageObject, err := convertGolangImageObjectToGoeffectsImageObject(inputImage)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
const algorithm GSAlgo = 3
|
|
|
|
|
|
|
|
grayscaleEffectObject := NewGrayscale(algorithm)
|
|
|
|
|
|
|
|
grayscaleGoeffectsImage, err := grayscaleEffectObject.Apply(&goeffectsImageObject, 5)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
2024-08-07 09:45:31 +02:00
|
|
|
threshold, err := helpers.ScaleIntProportionally(false, effectStrength, 0, 100, 10, 100)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
sobelEffectObject := NewSobel(threshold, lightMode)
|
|
|
|
|
|
|
|
resultGoeffectsImage, err := sobelEffectObject.Apply(grayscaleGoeffectsImage, 5)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
result := convertGoeffectsImageObjectToGolangImageObject(*resultGoeffectsImage)
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ApplyOilPaintingEffect(inputImage image.Image, effectStrength int)(image.Image, error){
|
|
|
|
|
|
|
|
if (inputImage == nil){
|
|
|
|
return nil, errors.New("ApplyOilPaintingEffect called with nil image.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectStrength < 0 || effectStrength > 100){
|
|
|
|
return nil, errors.New("ApplyOilPaintingEffect called with invalid effectStrength.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (effectStrength == 0) {
|
|
|
|
return inputImage, nil
|
|
|
|
}
|
|
|
|
|
2024-08-07 09:45:31 +02:00
|
|
|
filterSize, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 10, 30)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
2024-08-07 09:45:31 +02:00
|
|
|
levels, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 10, 70)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
oilPaintingEffectObject := NewOilPainting(filterSize, levels)
|
|
|
|
|
|
|
|
goeffectsImageObject, err := convertGolangImageObjectToGoeffectsImageObject(inputImage)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
resultGoeffectsImage, err := oilPaintingEffectObject.Apply(&goeffectsImageObject, 5)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
result := convertGoeffectsImageObjectToGolangImageObject(*resultGoeffectsImage)
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func convertGolangImageObjectToGoeffectsImageObject(inputImage image.Image)(Image, error){
|
|
|
|
|
|
|
|
newImageRGBA := image.NewRGBA(inputImage.Bounds())
|
|
|
|
draw.Draw(newImageRGBA, inputImage.Bounds(), inputImage, image.Point{}, draw.Over)
|
|
|
|
|
|
|
|
width, height, err := imagery.GetImageWidthAndHeightPixels(inputImage)
|
|
|
|
if (err != nil) {
|
|
|
|
var failedImage Image
|
|
|
|
return failedImage, err
|
|
|
|
}
|
|
|
|
|
|
|
|
goeffectsImage := Image{
|
|
|
|
img: newImageRGBA,
|
|
|
|
Width: width,
|
|
|
|
Height: height,
|
|
|
|
Bounds: Rect{X: 0, Y: 0, Width: width, Height: height},
|
|
|
|
}
|
|
|
|
|
|
|
|
return goeffectsImage, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func convertGoeffectsImageObjectToGolangImageObject(inputImage Image) image.Image {
|
|
|
|
|
|
|
|
imageRGBA := inputImage.img
|
|
|
|
|
|
|
|
imageWidth := inputImage.Width
|
|
|
|
imageHeight := inputImage.Height
|
|
|
|
|
|
|
|
newRectangle := image.Rect(0, 0, imageWidth, imageHeight)
|
|
|
|
|
|
|
|
newImage := image.NewRGBA(newRectangle)
|
|
|
|
|
|
|
|
draw.Draw(newImage, newImage.Bounds(), imageRGBA, image.Point{}, draw.Over)
|
|
|
|
|
|
|
|
return newImage
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|