Its alivegit status

This commit is contained in:
Brian Evans 2019-07-18 16:49:04 -07:00
parent e2b5936197
commit 42bf437f07
5 changed files with 294 additions and 31 deletions

6
.gitignore vendored
View File

@ -14,3 +14,9 @@
# Binary from `go build`
filtress
# Test images
*.jpeg
*.jpg
*.png

58
imageHandler.go Normal file
View File

@ -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
View File

@ -4,6 +4,8 @@ import (
"flag"
"fmt"
"os"
"image"
"image/color"
"path/filepath"
"strings"
"tildegit.org/sloum/filtress/parser"
@ -30,8 +32,11 @@ type filterState struct {
location point
mode filter
}
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 {
file, err := os.Open(path)
@ -42,8 +47,192 @@ func openFileFromPath(path string) *os.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() {
// 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()
posArgs := flag.Args()
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))
}
// Open file and parse
fmt.Println("Filtress v0.2.0")
filterFile := openFileFromPath(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")
}
if *validateFlag {
fmt.Printf("Validating file: %s ...\n", fname)
validateInput(fpath)
}
fmt.Print(tree)
fmt.Println()
if *inputFlag == "" {
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)
}

View File

@ -5,10 +5,10 @@ import (
"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
if change.Variable != "" {
if val, ok := vars[change.Variable]; ok {
if val, ok := variables[change.Variable]; ok {
opand = val
} else {
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 {
f.val /= opand
}
case '%':
if opand == 0 {
f.val = 1
} else {
f.val %= opand
}
case '=':
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 target *int
@ -57,7 +63,7 @@ func (p *point) update(change []parser.Expression, vars map[string]int) {
}
if e.Variable != "" {
if val, ok := vars[e.Variable]; ok {
if val, ok := variables[e.Variable]; ok {
opand = val
} else {
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 {
*target = val / opand
}
case '%':
if opand == 0 {
*target = 1
} else {
*target = val % opand
}
case '=':
*target = opand
}

View File

@ -1,17 +1,17 @@
# First attempt at a filtress file!!
MOD 1
APH 255
RED 100
BEG 10
LOC +100:WID
BLU /300
BLU 100
GRN 100
# This loop should create a bunch of vertical lines
BEG 50
RED +23
BLU -81
GRN *27
APH -5
APY +5:HIG
LOC +20:+0
END
#comment
APY +100:+100