commit 870b440e87094d868d58007a66e14088ba07d6a1 Author: Marcus Noble Date: Tue Jul 27 05:50:37 2021 +0100 Initial commit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..84947c5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM jess/inkscape + +RUN apt-get update && apt-get install -y python-lxml python-numpy wget pstoedit unzip + +RUN wget https://golang.org/dl/go1.16.2.linux-amd64.tar.gz && rm -rf /usr/local/go && tar -C /usr/local -xzf go1.16.2.linux-amd64.tar.gz && ln -s /usr/local/go/bin/go /usr/local/bin/go && go version + +RUN wget "https://fonts.google.com/download?family=Fira%20Sans|Lobster|Pacifico|Permanent%20Marker|Roboto|Ceviche%20One|Press%20Start%202P|UnifrakturMaguntia|Zilla%20Slab%20Highlight|Londrina%20Shadow" -O /usr/share/fonts/fonts.zip +RUN cd /usr/share/fonts && unzip fonts.zip + +WORKDIR /app +ADD go.mod go.sum main.go index.html template.svg ./ +RUN go build -o main main.go + +ENTRYPOINT ["/app/main"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2955198 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +MIT License Copyright (c) 2020 - present Marcus Noble + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8eae275 --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +.DEFAULT_GOAL := default + +IMAGE ?= docker.cluster.fun/averagemarcus/text-to-dxf:latest + +.PHONY: test # Run all tests, linting and format checks +test: lint check-format run-tests + +.PHONY: lint # Perform lint checks against code +lint: + @echo "⚠️ 'lint' unimplemented" + +.PHONY: check-format # Checks code formatting and returns a non-zero exit code if formatting errors found +check-format: + @echo "⚠️ 'check-format' unimplemented" + +.PHONY: format # Performs automatic format fixes on all code +format: + @echo "⚠️ 'format' unimplemented" + +.PHONY: run-tests # Runs all tests +run-tests: + @echo "⚠️ 'run-tests' unimplemented" + +.PHONY: fetch-deps # Fetch all project dependencies +fetch-deps: + @echo "⚠️ 'fetch-deps' unimplemented" + +.PHONY: build # Build the project +build: lint check-format fetch-deps + @echo "⚠️ 'build' unimplemented" + +.PHONY: docker-build # Build the docker image +docker-build: + @docker build --tag $(IMAGE) . + +.PHONY: docker-publish # Push the docker image to the remote registry +docker-publish: + @docker push $(IMAGE) + +.PHONY: run # Run the application +run: docker-build + @docker run -it -p 8080:8080 $(IMAGE) + +.PHONY: ci # Perform CI specific tasks to perform on a pull request +ci: + @echo "⚠️ 'ci' unimplemented" + +.PHONY: release # Release the latest version of the application +release: + @kubectl --namespace text-to-dxf set image deployment text-to-dxf web=docker.cluster.fun/averagemarcus/text-to-dxf:$(SHA) + +.PHONY: help # Show this list of commands +help: + @echo "text-to-dxf" + @echo "Usage: make [target]" + @echo "" + @echo "target description" | expand -t20 + @echo "-----------------------------------" + @grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20 + +default: test build diff --git a/README.md b/README.md new file mode 100644 index 0000000..1da1cbd --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +![text-to-dxf](logo.png) + +> Create a .dxf file containing the provided text + +Available at https://text-to-dxf.cluster.fun/ + +## Features + +Runs a webserver that takes in an `?text=` query string and then returns it as a .dxf. + +Optionally a `?font=` can be provided, current available fonts are: + +* Roboto +* Fira Sans +* Lobster +* Pacifico +* Permanent Marker +* Ceviche One +* Londrina Shadow +* Press Start 2P +* UnifrakturMaguntia +* Zilla Slab Highlight + +## Usage + +```sh +docker run -it --rm -p 8080:8080 docker.cluster.fun/averagemarcus/text-to-dxf +``` + +## Building from source + +With Docker: + +```sh +make docker-build +``` + +## Resources + +* [inkscape](https://inkscape.org/) + +## Contributing + +If you find a bug or have an idea for a new feature please raise an issue to discuss it. + +Pull requests are welcomed but please try and follow similar code style as the rest of the project and ensure all tests and code checkers are passing. + +Thank you 💛 + +## License + +See [LICENSE](LICENSE) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..13fa0ee --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module text-to-dxf + +go 1.16 + +require github.com/spf13/afero v1.6.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..57c179b --- /dev/null +++ b/go.sum @@ -0,0 +1,20 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/index.html b/index.html new file mode 100644 index 0000000..40d4957 --- /dev/null +++ b/index.html @@ -0,0 +1,105 @@ + + + + + + + text-to-dxf + + + + + + + + + + + + + + + + + + + + + + +
+

+ text-to-dxf + +

+ +
+ Create a .dxf file for the given text +
+ + +
+
+
+ + + +
+
+
+ +
+ +
+ Source code available on GitHub, GitLab, Bitbucket & my own Gitea server. +
+
+ +
+
+
+ +
+
+
+ + + + diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..108e157 Binary files /dev/null and b/logo.png differ diff --git a/main.go b/main.go new file mode 100644 index 0000000..dd37568 --- /dev/null +++ b/main.go @@ -0,0 +1,104 @@ +package main + +import ( + "embed" + "fmt" + "math/rand" + "net/http" + "os" + "os/exec" + "strings" + "text/template" + "time" + + "github.com/spf13/afero" +) + +//go:embed index.html template.svg +var content embed.FS + +var port = os.Getenv("PORT") + +func init() { + rand.Seed(time.Now().UTC().UnixNano()) +} + +func main() { + if port == "" { + port = "8080" + } + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + text := r.URL.Query().Get("text") + font := r.URL.Query().Get("font") + + if text == "" { + body, _ := content.ReadFile("index.html") + w.Write(body) + return + } + + dxf, err := createDXF(text, font) + if err != nil { + fmt.Fprintf(w, err.Error()) + return + } + fmt.Println("Converted to DXF") + + w.Header().Add("Content-Type", "application/octet-stream") + w.Header().Add("Content-Length", fmt.Sprint(len(dxf))) + w.Header().Add("Content-Disposition", fmt.Sprintf("inline; filename=%s.dxf", randomString(7))) + fmt.Fprintf(w, string(dxf)) + }) + + fmt.Println(http.ListenAndServe(":"+port, nil)) +} + +func createDXF(text, font string) ([]byte, error) { + fs := afero.NewOsFs() + afs := &afero.Afero{Fs: fs} + svgFile, _ := afs.TempFile(".", "*.svg") + epsFile, _ := afs.TempFile(".", "*.eps") + dxfFile, _ := afs.TempFile(".", "*.dxf") + + err := template. + Must( + template. + New("template.svg"). + Funcs(template.FuncMap{ + "offset": func(i int) int { + return i * 30 + }, + "font": func() string { + return font + }, + }). + ParseFS(content, "template.svg")). + Execute(svgFile, strings.Split(text, "\n")) + if err != nil { + fmt.Println(err) + return nil, err + } + + cmd := exec.Command("inkscape", "-E", epsFile.Name(), svgFile.Name()) + if err := cmd.Run(); err != nil { + fmt.Println(err) + return nil, err + } + cmd = exec.Command("pstoedit", "-q", "-dt", "-f", "dxf:-polyaslines -mm", epsFile.Name(), dxfFile.Name()) + if err := cmd.Run(); err != nil { + fmt.Println(err) + return nil, err + } + return afs.ReadFile(dxfFile.Name()) +} + +func randomString(n int) string { + var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + + s := make([]rune, n) + for i := range s { + s[i] = letters[rand.Intn(len(letters))] + } + return string(s) +} diff --git a/template.svg b/template.svg new file mode 100644 index 0000000..b4cada5 --- /dev/null +++ b/template.svg @@ -0,0 +1,7 @@ + + + +{{range $i, $val := .}} + {{ $val }} +{{end}} +