Compare commits
2
Commits
master
..
329b115e69
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
329b115e69 | ||
|
|
445a6aab94 |
@@ -1,12 +1,9 @@
|
|||||||
# imageutils
|
# imageutils
|
||||||
## that is exactly image utilities, what i made for myself
|
## that is exactly image utilities, what i made for myself
|
||||||
|
|
||||||
all the 2d graphics related stuff now moves there
|
|
||||||
|
|
||||||
||(with a dummy as fuck image rescaling)||
|
||(with a dummy as fuck image rescaling)||
|
||||||
utilities work in theory, but doing everything very slow.
|
utilities work in theory, but doing everything very slow.
|
||||||
i really love Go's image.Image interface type, but its really hard to do something with it well.
|
i really love Go's image.Image interface type, but its really hard to do something with it well.
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
- create main binary that give access to all implemented things in cmd/
|
- create main binary that give access to all implemented things in cmd/
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
type FileWithOptions struct {
|
|
||||||
Options map[string]string
|
|
||||||
io.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
func mapToStruct[T any](m map[string]string, a T) T {
|
|
||||||
t := reflect.TypeOf(a)
|
|
||||||
for _, v := range reflect.VisibleFields(t) {
|
|
||||||
v.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Handle(img image.Image) http.Handler {
|
|
||||||
func(w http.ResponseWriter,
|
|
||||||
r *http.Request) {
|
|
||||||
err := png.Encode(w, img)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
input: image with modifier options
|
|
||||||
output: png image
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,3 +1 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
func parseMap(fields []string) (map[string]string, error) {
|
|
||||||
m := map[string]string{}
|
|
||||||
var k, v string
|
|
||||||
|
|
||||||
for i, v := range fields {
|
|
||||||
if v == "=" {
|
|
||||||
return nil, errors.New("bad field")
|
|
||||||
}
|
|
||||||
if len(v) > 1 {
|
|
||||||
// check if "=" is the last or first character
|
|
||||||
if "=" == v[0] {
|
|
||||||
return nil, errors.New("no key")
|
|
||||||
}
|
|
||||||
if "=" == v[len(v)-1] {
|
|
||||||
return nil, errors.New("no value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.Contains(v, "=") {
|
|
||||||
splitted := strings.Split(v, "=")
|
|
||||||
k, v = splitted[0], splitted[1]
|
|
||||||
m[k] = v
|
|
||||||
if i == len(fields)-1 {
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return nil, errors.New("no equality sign in field")
|
|
||||||
}
|
|
||||||
return nil, errors.New("everything is wrong!")
|
|
||||||
}
|
|
||||||
|
|
||||||
type Map map[color.Color]color.Color
|
|
||||||
type repalette struct {
|
|
||||||
image.Image
|
|
||||||
Map
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r repalette) ColorModel() color.Model {
|
|
||||||
return r.Image.ColorModel()
|
|
||||||
}
|
|
||||||
func (r repalette) Bounds() image.Rectangle {
|
|
||||||
return r.Image.Bounds()
|
|
||||||
}
|
|
||||||
func (r repalette) At(x, y int) color.Color {
|
|
||||||
v := r.Image.At(x, y)
|
|
||||||
newColor, ok := r.Map[v]
|
|
||||||
if !ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return newColor
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fields := os.Args[1:]
|
|
||||||
m, err := parseMap(fields)
|
|
||||||
if err != nil {
|
|
||||||
panic("parseMap:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
errParseHexColor := errors.New("parse hex color:")
|
|
||||||
newPalette, err :=
|
|
||||||
func(m map[string]string) (newMap map[color.Color]color.Color, err error) {
|
|
||||||
for k, v := range m {
|
|
||||||
newKey, err := util.ParseHexColor(k)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Join(
|
|
||||||
errors.New("bad key hex value."),
|
|
||||||
errors.Join(errParseHexColor, err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
newValue, err := util.ParseHexColor(v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Join(
|
|
||||||
errors.New("bad value hex value."),
|
|
||||||
errors.Join(errParseHexColor, err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
newMap[newKey] = newValue
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}(fields)
|
|
||||||
if err != nil {
|
|
||||||
panic(errors.Join(errors.New("palette parsing:"), err))
|
|
||||||
}
|
|
||||||
err = util.ProcessStdio(func(img image.Image) image.Image { return repalette{img, newPalette} })
|
|
||||||
if err != nil {
|
|
||||||
panic(errors.Join(errors.New("process stdio:"), err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 9.5 MiB |
@@ -1,6 +1,6 @@
|
|||||||
module git.nkpl.cc/twocookedfaggots/imageutils
|
module git.nkpl.cc/twocookedfaggots/imageutils
|
||||||
|
|
||||||
go 1.26.4
|
go 1.25.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
@@ -8,7 +8,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Shopify/go-lua v0.0.0-20250718183320-1e37f32ad7d0 // indirect
|
|
||||||
github.com/dbriemann/pixel v0.5.1 // indirect
|
github.com/dbriemann/pixel v0.5.1 // indirect
|
||||||
github.com/go-gl/mathgl v1.2.0 // indirect
|
github.com/go-gl/mathgl v1.2.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
github.com/Shopify/go-lua v0.0.0-20250718183320-1e37f32ad7d0 h1:oGlw/+ndlFMn8KWLjEX5nULcDwOC4tJy3Kk1Pm84Cys=
|
|
||||||
github.com/Shopify/go-lua v0.0.0-20250718183320-1e37f32ad7d0/go.mod h1:M4CxjVc/1Nwka5atBv7G/sb7Ac2BDe3+FxbiT9iVNIQ=
|
|
||||||
github.com/dbriemann/pixel v0.5.1 h1:9iPqkfolOW2VRu8IzEbUBii9/S5ubMwPTQP7xBGkNX8=
|
github.com/dbriemann/pixel v0.5.1 h1:9iPqkfolOW2VRu8IzEbUBii9/S5ubMwPTQP7xBGkNX8=
|
||||||
github.com/dbriemann/pixel v0.5.1/go.mod h1:iWjzS4T3euA4FW04ULyz3SCkZB5LyK7pwTR1vyZFv0E=
|
github.com/dbriemann/pixel v0.5.1/go.mod h1:iWjzS4T3euA4FW04ULyz3SCkZB5LyK7pwTR1vyZFv0E=
|
||||||
github.com/go-gl/mathgl v1.2.0 h1:v2eOj/y1B2afDxF6URV1qCYmo1KW08lAMtTbOn3KXCY=
|
github.com/go-gl/mathgl v1.2.0 h1:v2eOj/y1B2afDxF6URV1qCYmo1KW08lAMtTbOn3KXCY=
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
type Modifyer interface {
|
|
||||||
image.Image
|
|
||||||
}
|
|
||||||
|
|
||||||
type Actions map[string]Modifyer
|
|
||||||
@@ -7,14 +7,10 @@ import (
|
|||||||
|
|
||||||
const side = 16
|
const side = 16
|
||||||
|
|
||||||
type Options struct {
|
|
||||||
Factor float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// tile
|
// tile
|
||||||
type grid struct {
|
type grid struct {
|
||||||
color.Gray
|
color.Gray
|
||||||
Options
|
Factor float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ grid) ColorModel() color.Model {
|
func (_ grid) ColorModel() color.Model {
|
||||||
@@ -26,7 +22,7 @@ func (_ grid) Bounds() image.Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g grid) At(x, y int) color.Color {
|
func (g grid) At(x, y int) color.Color {
|
||||||
n := uint8(float64(g.Gray.Y) * g.Options.Factor)
|
n := uint8(float64(g.Gray.Y) * g.Factor)
|
||||||
|
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return color.Black
|
return color.Black
|
||||||
@@ -58,13 +54,13 @@ func (g uniformGrid) At(x, y int) color.Color {
|
|||||||
|
|
||||||
type Dithering struct {
|
type Dithering struct {
|
||||||
image.Image
|
image.Image
|
||||||
Options
|
Factor float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Dithering) ColorModel() color.Model { return color.GrayModel }
|
func (d Dithering) ColorModel() color.Model { return color.GrayModel }
|
||||||
func (d Dithering) Bounds() image.Rectangle { return d.Image.Bounds() }
|
func (d Dithering) Bounds() image.Rectangle { return d.Image.Bounds() }
|
||||||
func (d Dithering) At(x, y int) color.Color {
|
func (d Dithering) At(x, y int) color.Color {
|
||||||
c := color.GrayModel.Convert(d.Image.At(x, y))
|
c := color.GrayModel.Convert(d.Image.At(x, y))
|
||||||
return uniformGrid{grid{c.(color.Gray), d.Options.Factor}}.
|
return uniformGrid{grid{c.(color.Gray), d.Factor}}.
|
||||||
At(x, y)
|
At(x, y)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"git.nkpl.cc/twocookedfaggots/imageutils"
|
"git.nkpl.cc/twocookedfaggots/imageutils"
|
||||||
)
|
)
|
||||||
@@ -18,8 +17,6 @@ func init() {
|
|||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
}
|
}
|
||||||
|
|
||||||
const factor = 0.75
|
|
||||||
|
|
||||||
func callImage(img image.Image) {
|
func callImage(img image.Image) {
|
||||||
for y := 0; y < img.Bounds().Dy(); y++ {
|
for y := 0; y < img.Bounds().Dy(); y++ {
|
||||||
for x := 0; x < img.Bounds().Dx(); x++ {
|
for x := 0; x < img.Bounds().Dx(); x++ {
|
||||||
@@ -41,14 +38,14 @@ func TestGrid(t *testing.T) {
|
|||||||
|
|
||||||
n := uint8(rand.Int() % 256)
|
n := uint8(rand.Int() % 256)
|
||||||
t.Log(n)
|
t.Log(n)
|
||||||
img := imageutils.Scale(grid{color.Gray{n}, factor}, 1<<6)
|
img := imageutils.Scale(1<<6, grid{color.Gray{n}})
|
||||||
err = png.Encode(w, img)
|
err = png.Encode(w, img)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
callImage(grid{color.Gray{4}, factor})
|
callImage(grid{color.Gray{4}})
|
||||||
callImage(grid{color.Gray{0}, factor})
|
callImage(grid{color.Gray{0}})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDithering(t *testing.T) {
|
func TestDithering(t *testing.T) {
|
||||||
@@ -69,48 +66,8 @@ func TestDithering(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = png.Encode(w, Dithering{img, factor})
|
err = png.Encode(w, Dithering{img})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRangeStruct(t *testing.T){
|
|
||||||
s := Dithering{image.Rectangle{},0}
|
|
||||||
value := reflect.ValueOf(s)
|
|
||||||
if value.Kind() == reflect.Ptr {
|
|
||||||
value = value.Elem()
|
|
||||||
}
|
|
||||||
if value.Kind() != reflect.Struct {
|
|
||||||
t.Log("Provided value is not a struct")
|
|
||||||
}
|
|
||||||
tp := value.Type()
|
|
||||||
for i := 0; i < value.NumField(); i++ {
|
|
||||||
fieldName := tp.Field(i).Name
|
|
||||||
fieldValue := value.Field(i)
|
|
||||||
|
|
||||||
if !fieldValue.CanInterface() {
|
|
||||||
t.Logf("Field %s is unexported\n", fieldName)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if fieldValue.Kind() == reflect.Ptr {
|
|
||||||
fieldValue = fieldValue.Elem()
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if fieldValue.Kind() == reflect.Interface {
|
|
||||||
fieldValue = fieldValue.Elem()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
actualValue := fieldValue.Interface()
|
|
||||||
switch v := actualValue.(type) {
|
|
||||||
case float64:
|
|
||||||
t.Logf("Field '%s' is a float64.\n", fieldName)
|
|
||||||
case image.Image:
|
|
||||||
t.Logf("Field '%s' is a image.Image. Value: %q\n", fieldName, v)
|
|
||||||
default:
|
|
||||||
t.Logf("Field '%s' has an unhandled type: %T\n", fieldName, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
//go:build ignore
|
|
||||||
package dithering
|
|
||||||
|
|
||||||
func valueOfType(a any) reflect.Value {
|
|
||||||
return reflect.TypeOf(a).Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
func ServeHTTP(w http.ResponseWriter, req* http.Request) {
|
|
||||||
instance := new(Dithering{})
|
|
||||||
value := reflect.ValueOf(instance).Elem()
|
|
||||||
imageType := valueOfType(new(image.Image))
|
|
||||||
floatType := valueOfType
|
|
||||||
|
|
||||||
for i := 0; i < value.NumField(); i++ {
|
|
||||||
v := value.Field(i)
|
|
||||||
switch v.Type() {
|
|
||||||
case imageType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 249 KiB |
Binary file not shown.
@@ -1,20 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"git.nkpl.cc/twocookedfaggots/imageutils/pkg/mirror"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cmp := func(v reflect.Value) {
|
|
||||||
switch v := reflect.f {
|
|
||||||
case
|
|
||||||
}
|
|
||||||
}
|
|
||||||
instance := &mirror.Mirror{}
|
|
||||||
value := reflect.ValueOf(instance).Elem()
|
|
||||||
for i := 0; i < value.NumField(); i++ {
|
|
||||||
value.Type().Field(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
addr := ":8080"
|
|
||||||
http.HandleFunc("/",
|
|
||||||
func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
log.Println(req.URL.Query())
|
|
||||||
})
|
|
||||||
log.Println("listening on", addr)
|
|
||||||
log.Fatal(http.ListenAndServe(addr, nil))
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
image modifyer consists of:
|
|
||||||
input image
|
|
||||||
options
|
|
||||||
output (modifyed image)
|
|
||||||
usually Encoder
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package mirror
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Mirror struct {
|
|
||||||
image.Image
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Mirror) ColorModel() color.Model {
|
|
||||||
return m.Image.ColorModel()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Mirror) Bounds() image.Rectangle {
|
|
||||||
return m.Image.Bounds()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Mirror) At(x, y int) color.Color {
|
|
||||||
return m.Image.At(m.Bounds().Dx()-x, y)
|
|
||||||
}
|
|
||||||
@@ -1 +1,5 @@
|
|||||||
package imageutils
|
package imageutils
|
||||||
|
|
||||||
|
type Transformer interface {
|
||||||
|
Transform(image.Image) image.Image
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
package fb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Resolution() (w int, h int) {
|
|
||||||
resFile, err := os.Open("/sys/class/graphics/fb0/virtual_size")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r := bufio.NewReader(resFile)
|
|
||||||
s, err := r.ReadString('\n')
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Sscanf(s, "%d,%d", &w, &h)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var devfb *os.File
|
|
||||||
var width, height = Resolution()
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var err error
|
|
||||||
devfb, err = os.OpenFile("/dev/fb0", os.O_WRONLY, os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Bytes(c color.Color) []byte {
|
|
||||||
r, g, b, a := c.RGBA()
|
|
||||||
return []byte{byte(b), byte(g), byte(r), byte(a)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Draw(img image.Image) error {
|
|
||||||
buf := bufio.NewWriterSize(devfb, 1<<16)
|
|
||||||
for h := 0; h < height; h++ {
|
|
||||||
for w := 0; w < width; w++ {
|
|
||||||
_, err := buf.Write(Bytes(img.At(w, h)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := buf.Flush()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err := devfb.Seek(0,0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user