2 Commits
Author SHA1 Message Date
twocookedfaggots 329b115e69 Update .gitignore 2026-06-21 03:10:41 +04:00
twocookedfaggots 445a6aab94 go fmt 2026-06-21 01:18:50 +03:00
21 changed files with 13 additions and 336 deletions
-3
View File
@@ -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/
-25
View File
@@ -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
}
}
}
-2
View File
@@ -1,2 +0,0 @@
input: image with modifier options
output: png image
-3
View File
@@ -1,3 +0,0 @@
package main
}
-2
View File
@@ -1,3 +1 @@
package main package main
-91
View File
@@ -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))
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 MiB

+1 -2
View File
@@ -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
) )
-2
View File
@@ -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=
-7
View File
@@ -1,7 +0,0 @@
package http
type Modifyer interface {
image.Image
}
type Actions map[string]Modifyer
+4 -8
View File
@@ -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)
} }
+4 -47
View File
@@ -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)
}
}
}
-20
View File
@@ -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.
-20
View File
@@ -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)
}
}
-16
View File
@@ -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))
}
-5
View File
@@ -1,5 +0,0 @@
image modifyer consists of:
input image
options
output (modifyed image)
usually Encoder
-22
View File
@@ -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)
}
+4
View File
@@ -1 +1,5 @@
package imageutils package imageutils
type Transformer interface {
Transform(image.Image) image.Image
}
-61
View File
@@ -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
}