diff --git a/main.go b/main.go index 6460673..bf42e95 100644 --- a/main.go +++ b/main.go @@ -1,99 +1,86 @@ package main import ( + "crypto/rand" + "encoding/json" + "flag" "fmt" - "image" - "image/draw" - "image/jpeg" + "io" + "net/http" "os" + "path" + "sync/atomic" + "time" - "github.com/oliamb/cutter" - "go.oneofone.dev/resize" + "log/slog" + + "go.balki.me/collage-maker/collage" ) -/** -"431" -"697" -"2514" -"2047" -zoom: 0.392 -816 -528 -------------- -"153" -"9" -"1331" -"772" -zoom: 0.6949 -816 -528 -*/ +var ( + imagesDir string + collageDir string +) func main() { - const width = 816 * 4 - const height = 528 * 4 - imgFile1, err := os.Open("img1.jpg") - if err != nil { - fmt.Println(err) - } - imgFile2, err := os.Open("img2.jpg") - if err != nil { - fmt.Println(err) - } - img1, _, err := image.Decode(imgFile1) - if err != nil { - fmt.Println(err) - } - img2, _, err := image.Decode(imgFile2) - if err != nil { - fmt.Println(err) - } + flag.StringVar(&imagesDir, "images-dir", "images", "Sets the images dir") + flag.StringVar(&collageDir, "collages-dir", "collages", "Sets the collages dir") + flag.Parse() + nameGen := NewNameGen() + imagesDirFs := os.DirFS(imagesDir) - img1, err = cutter.Crop(img1, cutter.Config{ - Width: 2514 - 431, - Height: 2047 - 697, - Anchor: image.Point{431, 697}, - Mode: cutter.TopLeft, // optional, default value + http.HandleFunc("/make-collage", func(w http.ResponseWriter, r *http.Request) { + collageReq := collage.Request{} + body, err := io.ReadAll(r.Body) + if err != nil { + slog.Error("failed to read request body", "error", err) + return + } + if err := json.Unmarshal(body, &collageReq); err != nil { + slog.Error("failed to unmarshal json request", "error", err) + return + } + collageFile := fmt.Sprintf("collage-%s.jpg", nameGen.Next()) + out, err := os.Create(path.Join(collageDir, collageFile)) + if err != nil { + slog.Error("failed to create collage output file", "error", err) + } + if err := collage.Make(collageReq, imagesDirFs, out); err != nil { + slog.Error("failed to make collage", "error", err) + return + } + w.Write([]byte(collageFile)) }) - - if err != nil { - panic(err) + if err := http.ListenAndServe(":8767", nil); err != nil { + slog.Error("http ListenAndServe failed", "error", err) } - - img1 = resize.Resize(width, height, img1, resize.Lanczos3) - - img2, err = cutter.Crop(img2, cutter.Config{ - Width: 1331 - 153, - Height: 772 - 9, - Anchor: image.Point{153, 9}, - Mode: cutter.TopLeft, // optional, default value - }) - - if err != nil { - panic(err) - } - - img2 = resize.Resize(width, height, img2, resize.Lanczos3) - - //starting position of the second image (bottom left) - //sp2 := image.Point{img1.Bounds().Dx(), 0} - //new rectangle for the second image - //r2 := image.Rectangle{sp2, sp2.Add(img2.Bounds().Size())} - //rectangle for the big image - r := image.Rectangle{image.Point{0, 0}, image.Point{width, height + height}} - r2 := image.Rectangle{image.Point{0, height + 1}, image.Point{width, height + height}} - rgba := image.NewRGBA(r) - - draw.Draw(rgba, img1.Bounds(), img1, image.Point{0, 0}, draw.Src) - draw.Draw(rgba, r2, img2, image.Point{0, 0}, draw.Src) - - out, err := os.Create("./output.jpg") - if err != nil { - fmt.Println(err) - } - - var opt jpeg.Options - opt.Quality = 80 - - jpeg.Encode(out, rgba, &opt) } + +type nameGen struct { + prefix string + counter atomic.Uint64 +} + +func NewNameGen() *nameGen { + currentTime := time.Now().Unix() + randBytes := make([]byte, 8) + _, err := rand.Read(randBytes) + if err != nil { + panic(err) + } + alpha := []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + uniqRunID := "" + for _, b := range randBytes { + uniqRunID += string(alpha[int(b)%len(alpha)]) + } + return &nameGen{ + prefix: fmt.Sprintf("%d-%s", currentTime, uniqRunID), + counter: atomic.Uint64{}, + } +} + +func (n *nameGen) Next() string { + return fmt.Sprintf("%s-%d", n.prefix, n.counter.Add(1)) +} + +// curl -D - --json @req.json http://localhost:8767/make-collage diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..34e9f73 --- /dev/null +++ b/main_test.go @@ -0,0 +1,10 @@ +package main + +import "testing" + +func TestNameGen(t *testing.T) { + g := NewNameGen() + t.Logf("next id: %s", g.Next()) + t.Logf("next id: %s", g.Next()) + t.Fail() +} diff --git a/req.json b/req.json new file mode 100644 index 0000000..e7f3a57 --- /dev/null +++ b/req.json @@ -0,0 +1,29 @@ +{ + "background_image": "", + "aspect": { "width": 4224, "height": 3264 }, + "dimension": { "width": 1187, "height": 848 }, + "photos": [ + { + "image": "img1.jpg", + "crop": { + "start": { "x": 419, "y": 667 }, + "end": { "x": 2707, "y": 3389 } + }, + "frame": { + "start": { "x": 0, "y": 0 }, + "end": { "x": 712, "y": 848 } + } + }, + { + "image": "img2.jpg", + "crop": { + "start": { "x": 331, "y": 44 }, + "end": { "x": 1132, "y": 1468 } + }, + "frame": { + "start": { "x": 712, "y": 0 }, + "end": { "x": 1187, "y": 848 } + } + } + ] +}