mark2web/helper/template_filters.go
Sebastian Frank 3a467134b3
All checks were successful
continuous-integration/drone/push Build is passing
image_resize filter
2019-03-03 13:25:00 +01:00

188 lines
4.7 KiB
Go

package helper
import (
"errors"
"fmt"
"io/ioutil"
"path"
"strconv"
"strings"
"github.com/ddliu/motto"
"github.com/disintegration/imaging"
"github.com/flosch/pongo2"
_ "github.com/flosch/pongo2-addons"
_ "github.com/robertkrimen/otto/underscore"
)
func init() {
err := pongo2.ReplaceFilter("markdown", MarkdownFilter)
if err != nil {
panic(err)
}
newFilters := map[string]pongo2.FilterFunction{
"image_resize": ImageResizeFilter,
"relative_path": RelativePathFilter,
}
for name, fn := range newFilters {
err := pongo2.RegisterFilter(name, fn)
if err != nil {
panic(err)
}
}
}
// MarkdownFilter is a pongo2 filter, which converts markdown to html
func MarkdownFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
return pongo2.AsSafeValue(
string(
renderMarkdown(
[]byte(in.String()),
currentPathConfig.Markdown,
))),
nil
}
type imageParams struct {
width int
height int
filename string
}
func parseImageParams(str string) (*imageParams, error) {
if str == "" {
return nil, errors.New("missing image parameters")
}
p := imageParams{}
for _, s := range strings.Split(str, ",") {
e := strings.Split(s, "=")
if len(e) < 2 {
return nil, fmt.Errorf("invalid image parameter: %s", s)
}
var err error
switch e[0] {
case "w":
p.width, err = strconv.Atoi(e[1])
case "h":
p.height, err = strconv.Atoi(e[1])
case "f":
p.filename = e[1]
default:
return nil, fmt.Errorf("invalid image parameter: %s", s)
}
if err != nil {
return nil, fmt.Errorf("could not convert image parameter to correct value type for '%s': %s", s, err)
}
}
return &p, nil
}
// ImageResizeFilter read the image url and resize parameters and saves the resized image
// param: w=WITDH,h=HEIGHT
func ImageResizeFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
imgSource := in.String()
p, err := parseImageParams(param.String())
if err != nil {
return nil, &pongo2.Error{
Sender: "filter:image_resize",
OrigError: err,
}
}
imgSource = ResolveInputPath(imgSource)
if p.filename == "" {
p.filename = fmt.Sprintf("%dx%d_%s", p.width, p.height, path.Base(imgSource))
}
imgTarget := ResolveOutputPath(p.filename)
Log.Noticef("resizing image from %s to %s", imgSource, imgTarget)
img, err := imaging.Open(imgSource, imaging.AutoOrientation(true))
if err != nil {
return nil, &pongo2.Error{
Sender: "filter:image_resize",
OrigError: fmt.Errorf("could not open image '%s': %s", imgSource, err),
}
}
img = imaging.Resize(img, p.width, p.height, imaging.Lanczos)
err = imaging.Save(img, imgTarget)
if err != nil {
return nil, &pongo2.Error{
Sender: "filter:image_resize",
OrigError: fmt.Errorf("could save image '%s': %s", imgTarget, err),
}
}
return pongo2.AsValue(ResolveNavPath(p.filename)), nil
}
// RelativePathFilter returns the relative path to navpoint based on current nav
func RelativePathFilter(in, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
return pongo2.AsValue(
ResolveNavPath(
in.String(),
),
), nil
}
// RegisterFilters reads a directory and register filters from files within it
func RegisterFilters(dir string) {
files, err := ioutil.ReadDir(dir)
if err != nil {
Log.Panicf("could not read from template filters dir '%s': %s", dir, err)
}
for _, f := range files {
if !f.IsDir() {
switch path.Ext(f.Name()) {
case ".js":
fileBase := strings.TrimSuffix(f.Name(), ".js")
jsFile := dir + "/" + f.Name()
Log.Debugf("trying to register filter from: %s", jsFile)
/*
jsStr, err := ioutil.ReadFile(jsFile)
if err != nil {
Log.Panicf("could not read '%s': %s", jsFile, err)
}
*/
vm := motto.New()
fn, err := vm.Run(jsFile)
if err != nil {
Log.Panicf("error in javascript vm for '%s': %s", jsFile, err)
}
if !fn.IsFunction() {
Log.Panicf("%s does not contain a function code", jsFile)
}
err = pongo2.RegisterFilter(
fileBase,
func(in, param *pongo2.Value) (out *pongo2.Value, erro *pongo2.Error) {
thisObj, _ := vm.Object("({})")
if currentContext != nil {
thisObj.Set("context", *currentContext)
}
if err != nil {
Log.Panicf("could not set context as in '%s': %s", jsFile, err)
}
ret, err := fn.Call(thisObj.Value(), in.Interface(), param.Interface())
if err != nil {
Log.Panicf("error in javascript file '%s' while calling returned function: %s", jsFile, err)
}
retGo, err := ret.Export()
if err != nil {
Log.Panicf("export error for '%s': %s", jsFile, err)
}
return pongo2.AsValue(retGo), nil
},
)
if err != nil {
Log.Panicf("could not register filter from '%s': %s", jsFile, err)
}
}
}
}
}