From f5a51b92e73a951c28a0136b6c37258911dd4e0c Mon Sep 17 00:00:00 2001 From: potassium Date: Mon, 2 Nov 2026 22:12:30 +0300 Subject: [PATCH] img2gif --- .gitignore | 3 +- cmd/httputil/type.go | 8 ++++- cmd/img2gif/img2gif.go | 22 ++++++++++++ http/url_values.go | 21 +++++++++++ pkg/rotate/gist.go | 79 +++++++++++++++++++++++++++++++++++++++++ pkg/rotate/pull.go | 19 ++++++++++ pkg/rotate/push.go | 23 ++++++++++++ pkg/rotate/push_test.go | 38 ++++++++++++++++++++ util/palette.go | 29 +++++++++++++++ 9 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 cmd/img2gif/img2gif.go create mode 100644 http/url_values.go create mode 100644 pkg/rotate/gist.go create mode 100644 pkg/rotate/pull.go create mode 100644 pkg/rotate/push.go create mode 100644 pkg/rotate/push_test.go create mode 100644 util/palette.go diff --git a/.gitignore b/.gitignore index 11b9b35..b69437d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ imageutils.test cpu.out profile.out *.png +*.gif *.jpg -*.jpeg \ No newline at end of file +*.jpeg diff --git a/cmd/httputil/type.go b/cmd/httputil/type.go index b418d7a..9392560 100644 --- a/cmd/httputil/type.go +++ b/cmd/httputil/type.go @@ -1,3 +1,9 @@ package main -} +import ( + "image" +) + +type Options any + +type Modifunc func(image.Image) image.Image diff --git a/cmd/img2gif/img2gif.go b/cmd/img2gif/img2gif.go new file mode 100644 index 0000000..cd35076 --- /dev/null +++ b/cmd/img2gif/img2gif.go @@ -0,0 +1,22 @@ +package main + +import ( + "image" + "image/gif" + _ "image/jpeg" + _ "image/png" + "os" +) + +func main() { + r, w := os.Stdin, os.Stdout + img, format, err := image.Decode(r) + println("registered format:", format) + if err != nil { + panic(err) + } + err = gif.Encode(w, img, &gif.Options{256, nil, nil}) + if err != nil { + panic(err) + } +} diff --git a/http/url_values.go b/http/url_values.go new file mode 100644 index 0000000..97a7c4b --- /dev/null +++ b/http/url_values.go @@ -0,0 +1,21 @@ +package url_values + +func UnmarshalURLValues(values url.Values) map[string]any { + +} + +var noSuchField = errors.New("no such field") + +func Pull(V any, m map[string]any) error { + v := reflect.ValueOf(V).Elem() + for i := 0; i < v.NumField(); i++ { + value, ok := m[strings.ToLower(v.Field(i).Name)] + if !ok { + return noSuchField + } + + } +} + +func Push(V any, m map[string]any) error { +} diff --git a/pkg/rotate/gist.go b/pkg/rotate/gist.go new file mode 100644 index 0000000..7b98db4 --- /dev/null +++ b/pkg/rotate/gist.go @@ -0,0 +1,79 @@ +//go:build gist + +package main + +import ( + "fmt" + "image" + "image/color" + "image/gif" + "math" + "os" +) + +type Circle struct { + X, Y, R float64 +} + +func (c *Circle) Brightness(x, y float64) uint8 { + var dx, dy float64 = c.X - x, c.Y - y + d := math.Sqrt(dx*dx+dy*dy) / c.R + if d > 1 { + return 0 + } else { + return 255 + } +} + +func main() { + var w, h int = 240, 240 + + var palette = []color.Color{ + color.RGBA{0x00, 0x00, 0x00, 0xff}, color.RGBA{0x00, 0x00, 0xff, 0xff}, + color.RGBA{0x00, 0xff, 0x00, 0xff}, color.RGBA{0x00, 0xff, 0xff, 0xff}, + color.RGBA{0xff, 0x00, 0x00, 0xff}, color.RGBA{0xff, 0x00, 0xff, 0xff}, + color.RGBA{0xff, 0xff, 0x00, 0xff}, color.RGBA{0xff, 0xff, 0xff, 0xff}, + } + var images []*image.Paletted + var delays []int + + var hw, hh float64 = float64(w / 2), float64(h / 2) + circles := []*Circle{&Circle{}, &Circle{}, &Circle{}} + steps := 20 + for step := 0; step < steps; step++ { + img := image.NewPaletted(image.Rect(0, 0, w, h), palette) + images = append(images, img) + delays = append(delays, 0) + + θ := 2.0 * math.Pi / float64(steps) * float64(step) + for i, circle := range circles { + θ0 := 2 * math.Pi / 3 * float64(i) + println(θ0) + circle.X = hw - math.Sin(θ0) - math.Sin(θ0+θ) + circle.Y = hh - math.Cos(θ0) - math.Cos(θ0+θ) + circle.R = 50 + } + + for x := 0; x < w; x++ { + for y := 0; y < h; y++ { + img.Set(x, y, color.RGBA{ + circles[0].Brightness(float64(x), float64(y)), + circles[1].Brightness(float64(x), float64(y)), + circles[2].Brightness(float64(x), float64(y)), + 255, + }) + } + } + } + + f, err := os.OpenFile("rgb.gif", os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + fmt.Println(err) + return + } + defer f.Close() + gif.EncodeAll(f, &gif.GIF{ + Image: images, + Delay: delays, + }) +} diff --git a/pkg/rotate/pull.go b/pkg/rotate/pull.go new file mode 100644 index 0000000..0638f59 --- /dev/null +++ b/pkg/rotate/pull.go @@ -0,0 +1,19 @@ +//go:build pull +package rotate + +import ( + "image" + "image/color" +) + +type Rotate struct { + image.Image + Angle float64 // math.Pi * n +} + +func (rot Rotate) Bounds() image.Rectangle { return rot.Image.Bounds() } +func (rot Rotate) ColorModel() color.Model { return rot.Image.ColorModel() } + +func (rot Rotate) At(x, y int) color.Color { + +} diff --git a/pkg/rotate/push.go b/pkg/rotate/push.go new file mode 100644 index 0000000..31656d7 --- /dev/null +++ b/pkg/rotate/push.go @@ -0,0 +1,23 @@ +package rotate + +import ( + "image" + "math" +) + +func Rotate(img image.Image, angle float64) image.Image { + newImg := image.NewRGBA(img.Bounds()) + w, h := img.Bounds().Dx(), img.Bounds().Dy() + hh, hw := float64(h/2), float64(w/2) + + for y := 0; y < w; y++ { + for x := 0; x < h; x++ { + newImg.Set( + int(hh-math.Cos(angle)), + int(hw-math.Sin(angle)), + img.At(x, y), + ) + } + } + return newImg +} diff --git a/pkg/rotate/push_test.go b/pkg/rotate/push_test.go new file mode 100644 index 0000000..053b995 --- /dev/null +++ b/pkg/rotate/push_test.go @@ -0,0 +1,38 @@ +package rotate + +import ( + "image" + "image/png" + "net/http" + "os" + "testing" + "math" +) + +func TestRender(t *testing.T) { + gopherImg, err := func() (image.Image, error) { + r, err := http.Get("https://go.dev/images/favicon-gopher.png") + defer r.Body.Close() + if err != nil { + return nil, err + } + img, err := png.Decode(r.Body) + if err != nil { + return nil, err + } + return img, nil + }() + if err != nil { + t.Fatal(err) + } + + f, err := os.Create("img.png") + if err != nil { + t.Fatal(err) + } + defer f.Close() + err = png.Encode(f, Rotate(gopherImg, math.Pi/6)) + if err != nil { + t.Fatal(err) + } +} diff --git a/util/palette.go b/util/palette.go new file mode 100644 index 0000000..8851438 --- /dev/null +++ b/util/palette.go @@ -0,0 +1,29 @@ +package util + +type Set map[color.Color]struct{} + +func PaletteFromImage(img image.Image) color.Palette { + m := Set{} + for y := 0; y < img.Bounds().Dy(); y++ { + for x := 0; x < img.Bounds().Dx(); x++ { + m[img.At] = struct{}{} + } + } + return func(m Set)(p color.Palette){ + for k := range m { + p = append(p, k) + } + }(m) +} + +func ImageToPaletted(img image.Image) (image.Paletted) { + p := image.NewPaletted(img.Bounds(), PaletteFromImage(img)) + + for y := 0; y < img.Bounds().Dy(); y++ { + for x := 0; x < img.Bounds().Dx(); x++ { + p.Set(x, y, img.At(x,y)) + } + } + return p +} +