Its alivegit status
This commit is contained in:
parent
e2b5936197
commit
42bf437f07
|
@ -14,3 +14,9 @@
|
||||||
|
|
||||||
# Binary from `go build`
|
# Binary from `go build`
|
||||||
filtress
|
filtress
|
||||||
|
|
||||||
|
# Test images
|
||||||
|
*.jpeg
|
||||||
|
*.jpg
|
||||||
|
*.png
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"image"
|
||||||
|
"image/draw"
|
||||||
|
"image/jpeg"
|
||||||
|
"image/png"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func avgColor(orig, upd int) int {
|
||||||
|
a := float64(orig * orig)
|
||||||
|
b := float64(upd * upd)
|
||||||
|
return int(math.Sqrt(float64((a + b)/2)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadImage(path string) (*image.RGBA, string) {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
defer f.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("File access error: Unable to open image at path %q", path))
|
||||||
|
}
|
||||||
|
img, format, err := image.Decode(f)
|
||||||
|
rect := img.Bounds()
|
||||||
|
rgba := image.NewRGBA(rect)
|
||||||
|
draw.Draw(rgba, rect, img, rect.Min, draw.Src)
|
||||||
|
|
||||||
|
return rgba, format
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveImage(iPath, filterName, encodeType string, img *image.RGBA) {
|
||||||
|
ext := filepath.Ext(iPath)
|
||||||
|
name := strings.TrimSuffix(filepath.Base(iPath), ext)
|
||||||
|
newImagePath := fmt.Sprintf("%s/%s_%s%s", filepath.Dir(iPath), name, filterName, ext)
|
||||||
|
fg, err := os.Create(newImagePath)
|
||||||
|
defer fg.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("File access error: Unable to save image to path %q", newImagePath))
|
||||||
|
}
|
||||||
|
|
||||||
|
if encodeType == "jpeg" {
|
||||||
|
err = jpeg.Encode(fg, img, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic("Encode error: Unable to encode output as jpeg")
|
||||||
|
}
|
||||||
|
} else if encodeType == "png" {
|
||||||
|
err = png.Encode(fg, img)
|
||||||
|
if err != nil {
|
||||||
|
panic("Encode error: Unable to encode output as png")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("Encode error: Unable to encode output to unsupported format %q", encodeType))
|
||||||
|
}
|
||||||
|
}
|
219
main.go
219
main.go
|
@ -4,6 +4,8 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"tildegit.org/sloum/filtress/parser"
|
"tildegit.org/sloum/filtress/parser"
|
||||||
|
@ -30,8 +32,11 @@ type filterState struct {
|
||||||
location point
|
location point
|
||||||
mode filter
|
mode filter
|
||||||
}
|
}
|
||||||
|
|
||||||
var variables = map[string]int{}
|
var variables = map[string]int{}
|
||||||
|
var tree parser.AST
|
||||||
|
var fil filterState
|
||||||
|
var im *image.RGBA
|
||||||
|
var imFormat string
|
||||||
|
|
||||||
func openFileFromPath(path string) *os.File {
|
func openFileFromPath(path string) *os.File {
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
|
@ -42,8 +47,192 @@ func openFileFromPath(path string) *os.File {
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateAST(path string) {
|
||||||
|
filterFile := openFileFromPath(path)
|
||||||
|
defer filterFile.Close()
|
||||||
|
parser := parser.NewParser(filterFile)
|
||||||
|
tree = parser.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateInput(path string) {
|
||||||
|
generateAST(path)
|
||||||
|
if len(tree.Loops) > 0 {
|
||||||
|
fmt.Printf("File has %d procedures\n", len(tree.Loops))
|
||||||
|
fmt.Println("File is valid")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Invalid or empty input file")
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterImage(path, fname string) {
|
||||||
|
fmt.Print("Loading image \r")
|
||||||
|
im, imFormat = loadImage(path)
|
||||||
|
imSize := im.Bounds().Size()
|
||||||
|
variables["WID"] = imSize.X
|
||||||
|
variables["HIG"] = imSize.Y
|
||||||
|
variables["REG"] = 0
|
||||||
|
fil = filterState{
|
||||||
|
filter{255, 255, 255},
|
||||||
|
filter{255,255,255},
|
||||||
|
filter{255,255,255},
|
||||||
|
filter{255,255,255},
|
||||||
|
point{0,0,imSize.X,imSize.Y},
|
||||||
|
filter{3,0,0},
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("Filtering image \r")
|
||||||
|
for _, loop := range tree.Loops {
|
||||||
|
for ;loop.Counter > 0; loop.Counter-- {
|
||||||
|
for _, proc := range loop.Procedures {
|
||||||
|
procedure(proc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Print("Saving image \n")
|
||||||
|
saveImage(path, fname, imFormat, im)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateRegister(exp parser.Expression) {
|
||||||
|
opand := exp.Opperand
|
||||||
|
if exp.Variable != "" {
|
||||||
|
opand = variables[exp.Variable]
|
||||||
|
}
|
||||||
|
switch exp.Opperator {
|
||||||
|
case '+':
|
||||||
|
variables["REG"] += opand
|
||||||
|
case '-':
|
||||||
|
variables["REG"] -= opand
|
||||||
|
case '*':
|
||||||
|
variables["REG"] *= opand
|
||||||
|
case '/':
|
||||||
|
if opand == 0 {
|
||||||
|
variables["REG"] = 1
|
||||||
|
} else {
|
||||||
|
variables["REG"] /= opand
|
||||||
|
}
|
||||||
|
case '=':
|
||||||
|
variables["REG"] = opand
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func procedure(p parser.Procedure) {
|
||||||
|
switch p.Kind {
|
||||||
|
case "LOC":
|
||||||
|
if len(p.Expressions) == 2 {
|
||||||
|
fil.location.update(p.Expressions)
|
||||||
|
}
|
||||||
|
case "MOD":
|
||||||
|
if len(p.Expressions) >= 1 {
|
||||||
|
fil.mode.update(p.Expressions[0])
|
||||||
|
}
|
||||||
|
case "REG":
|
||||||
|
if len(p.Expressions) >= 1 {
|
||||||
|
updateRegister(p.Expressions[0])
|
||||||
|
}
|
||||||
|
case "APY":
|
||||||
|
applyToImage(p.Expressions)
|
||||||
|
case "RED":
|
||||||
|
if len(p.Expressions) >= 1 {
|
||||||
|
fil.red.update(p.Expressions[0])
|
||||||
|
}
|
||||||
|
case "BLU":
|
||||||
|
if len(p.Expressions) >= 1 {
|
||||||
|
fil.blue.update(p.Expressions[0])
|
||||||
|
}
|
||||||
|
case "GRN":
|
||||||
|
if len(p.Expressions) >= 1 {
|
||||||
|
fil.green.update(p.Expressions[0])
|
||||||
|
}
|
||||||
|
case "APH":
|
||||||
|
if len(p.Expressions) >= 1 {
|
||||||
|
fil.alpha.update(p.Expressions[0])
|
||||||
|
}
|
||||||
|
case "COL":
|
||||||
|
if len(p.Expressions) == 4 {
|
||||||
|
fil.red.update(p.Expressions[0])
|
||||||
|
fil.green.update(p.Expressions[1])
|
||||||
|
fil.blue.update(p.Expressions[2])
|
||||||
|
fil.alpha.update(p.Expressions[3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyToImage(exps []parser.Expression) {
|
||||||
|
if len(exps) == 0 {
|
||||||
|
im.SetRGBA(
|
||||||
|
fil.location.x,
|
||||||
|
fil.location.y,
|
||||||
|
color.RGBA{
|
||||||
|
uint8(fil.red.val),
|
||||||
|
uint8(fil.green.val),
|
||||||
|
uint8(fil.blue.val),
|
||||||
|
uint8(fil.alpha.val),
|
||||||
|
})
|
||||||
|
} else if len(exps) == 2 {
|
||||||
|
endX := exps[0].Opperand
|
||||||
|
endY := exps[1].Opperand
|
||||||
|
if exps[0].Variable != "" {
|
||||||
|
endX = variables[exps[0].Variable]
|
||||||
|
}
|
||||||
|
if exps[1].Variable != "" {
|
||||||
|
endY = variables[exps[1].Variable]
|
||||||
|
}
|
||||||
|
endX = getBoxBound(fil.location.x, endX, variables["WID"], exps[0].Opperator)
|
||||||
|
endY = getBoxBound(fil.location.y, endY, variables["HIG"], exps[0].Opperator)
|
||||||
|
for y := fil.location.y; y <= endY; y++ {
|
||||||
|
for x := fil.location.x; x <= endX; x++ {
|
||||||
|
im.SetRGBA(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
color.RGBA{
|
||||||
|
uint8(fil.red.val),
|
||||||
|
uint8(fil.green.val),
|
||||||
|
uint8(fil.blue.val),
|
||||||
|
uint8(fil.alpha.val),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBoxBound(start, end, max int, op rune) int {
|
||||||
|
var out int
|
||||||
|
switch op {
|
||||||
|
case '+':
|
||||||
|
out = start + end
|
||||||
|
case '-':
|
||||||
|
out = start - end
|
||||||
|
case '*':
|
||||||
|
out = start * end
|
||||||
|
case '/':
|
||||||
|
if end == 0 {
|
||||||
|
out = 0
|
||||||
|
} else {
|
||||||
|
out = start / end
|
||||||
|
}
|
||||||
|
case '%':
|
||||||
|
if end == 0 {
|
||||||
|
out = 0
|
||||||
|
} else {
|
||||||
|
out = start % end
|
||||||
|
}
|
||||||
|
case '=':
|
||||||
|
out = start
|
||||||
|
}
|
||||||
|
if out > max {
|
||||||
|
out = max
|
||||||
|
} else if out < 0 {
|
||||||
|
out = 0
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Handle checking filter file argument
|
validateFlag := flag.Bool("v", false, "If present, will validate the provided frs file and exit")
|
||||||
|
inputFlag := flag.String("image", "", "Path to the image to be filtered")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
posArgs := flag.Args()
|
posArgs := flag.Args()
|
||||||
if len(posArgs) > 1 || len(posArgs) < 1 {
|
if len(posArgs) > 1 || len(posArgs) < 1 {
|
||||||
|
@ -57,20 +246,18 @@ func main() {
|
||||||
panic(fmt.Sprintf("Input error: Incorrect filetype. Expected .FRS, received \".%s\"", fext))
|
panic(fmt.Sprintf("Input error: Incorrect filetype. Expected .FRS, received \".%s\"", fext))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open file and parse
|
if *validateFlag {
|
||||||
fmt.Println("Filtress v0.2.0")
|
fmt.Printf("Validating file: %s ...\n", fname)
|
||||||
filterFile := openFileFromPath(fpath)
|
validateInput(fpath)
|
||||||
parser := parser.NewParser(filterFile)
|
}
|
||||||
fmt.Printf("Parsing file: %s ...\n", fname)
|
|
||||||
tree := parser.Parse()
|
|
||||||
if len(tree.Loops) > 0 {
|
|
||||||
fmt.Printf("File has %d procedures\n", len(tree.Loops))
|
|
||||||
fmt.Println("File is valid")
|
|
||||||
} else {
|
|
||||||
fmt.Println("Invalid input file")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Print(tree)
|
if *inputFlag == "" {
|
||||||
fmt.Println()
|
fmt.Println("Input error: No image file was provided to filtress")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Parsing file: %s ...\n", fname)
|
||||||
|
generateAST(fpath)
|
||||||
|
frsName := strings.Split(fname, ".")[0]
|
||||||
|
filterImage(*inputFlag, frsName)
|
||||||
}
|
}
|
||||||
|
|
20
receivers.go
20
receivers.go
|
@ -5,10 +5,10 @@ import (
|
||||||
"tildegit.org/sloum/filtress/parser"
|
"tildegit.org/sloum/filtress/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f *filter) update(change parser.Expression, vars map[string]int) {
|
func (f *filter) update(change parser.Expression) {
|
||||||
opand := change.Opperand
|
opand := change.Opperand
|
||||||
if change.Variable != "" {
|
if change.Variable != "" {
|
||||||
if val, ok := vars[change.Variable]; ok {
|
if val, ok := variables[change.Variable]; ok {
|
||||||
opand = val
|
opand = val
|
||||||
} else {
|
} else {
|
||||||
panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val))
|
panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val))
|
||||||
|
@ -28,6 +28,12 @@ func (f *filter) update(change parser.Expression, vars map[string]int) {
|
||||||
} else {
|
} else {
|
||||||
f.val /= opand
|
f.val /= opand
|
||||||
}
|
}
|
||||||
|
case '%':
|
||||||
|
if opand == 0 {
|
||||||
|
f.val = 1
|
||||||
|
} else {
|
||||||
|
f.val %= opand
|
||||||
|
}
|
||||||
case '=':
|
case '=':
|
||||||
f.val = opand
|
f.val = opand
|
||||||
}
|
}
|
||||||
|
@ -39,7 +45,7 @@ func (f *filter) update(change parser.Expression, vars map[string]int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *point) update(change []parser.Expression, vars map[string]int) {
|
func (p *point) update(change []parser.Expression) {
|
||||||
var totalX, totalY, val, opand, max int
|
var totalX, totalY, val, opand, max int
|
||||||
var target *int
|
var target *int
|
||||||
|
|
||||||
|
@ -57,7 +63,7 @@ func (p *point) update(change []parser.Expression, vars map[string]int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Variable != "" {
|
if e.Variable != "" {
|
||||||
if val, ok := vars[e.Variable]; ok {
|
if val, ok := variables[e.Variable]; ok {
|
||||||
opand = val
|
opand = val
|
||||||
} else {
|
} else {
|
||||||
panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val))
|
panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val))
|
||||||
|
@ -79,6 +85,12 @@ func (p *point) update(change []parser.Expression, vars map[string]int) {
|
||||||
} else {
|
} else {
|
||||||
*target = val / opand
|
*target = val / opand
|
||||||
}
|
}
|
||||||
|
case '%':
|
||||||
|
if opand == 0 {
|
||||||
|
*target = 1
|
||||||
|
} else {
|
||||||
|
*target = val % opand
|
||||||
|
}
|
||||||
case '=':
|
case '=':
|
||||||
*target = opand
|
*target = opand
|
||||||
}
|
}
|
||||||
|
|
22
test.frs
22
test.frs
|
@ -1,17 +1,17 @@
|
||||||
# First attempt at a filtress file!!
|
# First attempt at a filtress file!!
|
||||||
MOD 1
|
MOD 1
|
||||||
|
APH 255
|
||||||
RED 100
|
RED 100
|
||||||
|
BLU 100
|
||||||
BEG 10
|
GRN 100
|
||||||
LOC +100:WID
|
# This loop should create a bunch of vertical lines
|
||||||
BLU /300
|
BEG 50
|
||||||
|
RED +23
|
||||||
|
BLU -81
|
||||||
|
GRN *27
|
||||||
|
APH -5
|
||||||
|
APY +5:HIG
|
||||||
|
LOC +20:+0
|
||||||
END
|
END
|
||||||
|
|
||||||
#comment
|
|
||||||
APY +100:+100
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue