Add post target to create collage

fixes #1
This commit is contained in:
Balakrishnan Balasubramanian 2023-08-28 23:35:32 -04:00
parent cd7c27460f
commit e1e6e3650a
3 changed files with 111 additions and 85 deletions

145
main.go
View File

@ -1,99 +1,86 @@
package main package main
import ( import (
"crypto/rand"
"encoding/json"
"flag"
"fmt" "fmt"
"image" "io"
"image/draw" "net/http"
"image/jpeg"
"os" "os"
"path"
"sync/atomic"
"time"
"github.com/oliamb/cutter" "log/slog"
"go.oneofone.dev/resize"
"go.balki.me/collage-maker/collage"
) )
/** var (
"431" imagesDir string
"697" collageDir string
"2514" )
"2047"
zoom: 0.392
816
528
-------------
"153"
"9"
"1331"
"772"
zoom: 0.6949
816
528
*/
func main() { func main() {
const width = 816 * 4 flag.StringVar(&imagesDir, "images-dir", "images", "Sets the images dir")
const height = 528 * 4 flag.StringVar(&collageDir, "collages-dir", "collages", "Sets the collages dir")
imgFile1, err := os.Open("img1.jpg") flag.Parse()
if err != nil { nameGen := NewNameGen()
fmt.Println(err) imagesDirFs := os.DirFS(imagesDir)
}
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)
}
img1, err = cutter.Crop(img1, cutter.Config{ http.HandleFunc("/make-collage", func(w http.ResponseWriter, r *http.Request) {
Width: 2514 - 431, collageReq := collage.Request{}
Height: 2047 - 697, body, err := io.ReadAll(r.Body)
Anchor: image.Point{431, 697}, if err != nil {
Mode: cutter.TopLeft, // optional, default value 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 := http.ListenAndServe(":8767", nil); err != nil {
slog.Error("http ListenAndServe failed", "error", err)
}
}
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 { if err != nil {
panic(err) panic(err)
} }
alpha := []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
img1 = resize.Resize(width, height, img1, resize.Lanczos3) uniqRunID := ""
for _, b := range randBytes {
img2, err = cutter.Crop(img2, cutter.Config{ uniqRunID += string(alpha[int(b)%len(alpha)])
Width: 1331 - 153, }
Height: 772 - 9, return &nameGen{
Anchor: image.Point{153, 9}, prefix: fmt.Sprintf("%d-%s", currentTime, uniqRunID),
Mode: cutter.TopLeft, // optional, default value counter: atomic.Uint64{},
}) }
if err != nil {
panic(err)
} }
img2 = resize.Resize(width, height, img2, resize.Lanczos3) func (n *nameGen) Next() string {
return fmt.Sprintf("%s-%d", n.prefix, n.counter.Add(1))
//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 // curl -D - --json @req.json http://localhost:8767/make-collage
opt.Quality = 80
jpeg.Encode(out, rgba, &opt)
}

10
main_test.go Normal file
View File

@ -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()
}

29
req.json Normal file
View File

@ -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 }
}
}
]
}