parent
cd7c27460f
commit
e1e6e3650a
157
main.go
157
main.go
@ -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 {
|
||||||
if err != nil {
|
slog.Error("http ListenAndServe failed", "error", err)
|
||||||
panic(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
|
||||||
|
10
main_test.go
Normal file
10
main_test.go
Normal 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
29
req.json
Normal 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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user