diff --git a/.gitignore b/.gitignore index 65579bb..a3e1554 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ - +collage/test_data/ *jpg diff --git a/collage/collage.go b/collage/collage.go index 95e6018..61db586 100644 --- a/collage/collage.go +++ b/collage/collage.go @@ -2,6 +2,9 @@ package collage import ( + "errors" + "fmt" + "image" "io" "io/fs" ) @@ -21,6 +24,13 @@ type Rectangle struct { End Point `json:"end"` } +func (r Rectangle) ToImgRect() image.Rectangle { + return image.Rectangle{ + Min: image.Point{int(r.Start.X), int(r.Start.Y)}, + Max: image.Point{int(r.End.X), int(r.End.Y)}, + } +} + type Request struct { BackgroundImage string `json:"background_image"` Aspect Dimension `json:"aspect"` @@ -32,5 +42,31 @@ type Request struct { } `json:"photos"` } -func Make(request Request, source fs.FS, output io.Writer) { +func Make(req Request, source fs.FS, output io.Writer) { + rec := image.Rect(0, 0, int(req.Aspect.Width), int(req.Aspect.Height)) + canvas := image.NewRGBA64(rec) + for photo := range req.Photos { + fmt.Println(photo) + } + fmt.Println(canvas) +} + +type HasSubImage interface { + SubImage(r image.Rectangle) image.Image +} + +func Crop(img image.Image, r Rectangle) (image.Image, error) { + if imgHS, ok := img.(HasSubImage); ok { + return imgHS.SubImage(r.ToImgRect()), nil + } + return nil, errors.New("image does not support cropping") +} + +func GetImage(source fs.FS, imageName string) (image.Image, error) { + imgF, err := source.Open(imageName) + if err != nil { + return nil, err + } + img, _, err := image.Decode(imgF) + return img, err } diff --git a/collage/collage_test.go b/collage/collage_test.go index e9ba6a4..49fa31c 100644 --- a/collage/collage_test.go +++ b/collage/collage_test.go @@ -3,22 +3,95 @@ package collage import ( "embed" "fmt" + "image" + "image/jpeg" + "io" "io/fs" + "log" + "os" "testing" ) //go:embed test_data/* var testData embed.FS +var testDataFS fs.FS + +func init() { + var err error + testDataFS, err = fs.Sub(testData, "test_data") + if err != nil { + log.Panicf("getting test_data subdir failed %v", err) + } +} + func TestMake(t *testing.T) { t.Log("Test was run") - ifs, err := fs.Sub(testData, "test_data") - if err != nil { - t.Fatalf("getting test_data subdir failed %v", err) - } - img1f, err := ifs.Open("img1.jpg") + img1f, err := testDataFS.Open("img1.jpg") if err != nil { t.Fatalf("opening image failed %v", err) } fmt.Printf("%#v\n", img1f) } + +func TestCrop(t *testing.T) { + img, err := GetImage(testDataFS, "img1.jpg") + if err != nil { + t.Fatalf("failed to get image %v", err) + } + r := Rectangle{ + Start: Point{X: 431, Y: 697}, + End: Point{X: 2514, Y: 2047}, + } + cropped, err := Crop(img, r) + if err != nil { + t.Fatalf("failed to crop image %v", err) + } + + croppedImgPrefix := fmt.Sprint(cropped)[:1000] + + refPrefixf, err := testDataFS.Open("cropped_image_prefix.txt") + if err != nil { + t.Fatalf("failed to open ref prefix %v", err) + } + + refImgPrefix, err := io.ReadAll(refPrefixf) + + if err != nil { + t.Fatalf("failed to read ref prefix %v", err) + } + + if string(refImgPrefix) != croppedImgPrefix { + t.Fatalf("Cropped image is not the same as reference image") + } + // SavePrefix(cropped) + // expectedImage, err := GetImage(testDataFS, "test_output.jpg") + // if err != nil { + // t.Fatalf("failed to get reference crop image %v", err) + // } + // fmt.Printf("%v\n", cropped) + // fmt.Printf("%v\n", expectedImage) + // if fmt.Sprintf("%#v", cropped) != fmt.Sprintf("%#v", expectedImage) { + // t.Fatalf("Cropped image is not the same as reference image") + // } + // SaveImage(cropped) +} + +// Save first 1000 bytes of string representation to compare against reference +func SavePrefix(img image.Image) error { + imgStr := fmt.Sprint(img) + prefix := imgStr[:1000] + return os.WriteFile("./test_data_prefix.txt", []byte(prefix), 0644) +} + +func SaveImage(img image.Image) { + out, err := os.Create("./test_output.jpg") + if err != nil { + fmt.Println(err) + } + + var opt jpeg.Options + opt.Quality = 100 + + jpeg.Encode(out, img, &opt) +}