From 02a5292f2fd9ec911914e628a4cd1fee454e5a99 Mon Sep 17 00:00:00 2001 From: Zach Fuller Date: Wed, 3 Apr 2024 17:53:56 -0700 Subject: [PATCH] Feat/13 create alt sizes for uploaded files (#15) * Logging with Slog + Fixed Get File (#8) * logging with slog * added path prefix to file being returned * Added default cors config (#14) * setup empty func 'createAltSizes' that will be called at the end of 'saveFile' * removed a couple comments * new file to house functions for resizing uploaded files * printing out dimensions of src file * creating new image with half-sized dimensions. wip: copying over image contents to resized img * successfully copied image using same dimensions * able to create image at 1/4 the og dimensions * renamed functions, now creates 2 alts sizes on file upload * fixed file prefix --- main.go | 10 +++------ resizer.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 resizer.go diff --git a/main.go b/main.go index 22c121e..b2db088 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ type UploadedFiles struct { } const FilePrefix = "/opt/picloud/uploads/" + // const FilePrefix = "uploads/" // localhost // global var initialized before API to store info on the server's uploaded files @@ -46,7 +47,6 @@ var uploadedFiles UploadedFiles func loadFileMetadata() UploadedFiles { var files UploadedFiles - // check if file exists if _, err := os.Stat("metadata.json"); err == nil { data, err := os.ReadFile("metadata.json") if err != nil { @@ -71,7 +71,6 @@ func loadFileMetadata() UploadedFiles { } func writeFileMetadata() { - // write file metadata to file data, err := json.Marshal(uploadedFiles) if err != nil { panic(err) @@ -82,7 +81,6 @@ func writeFileMetadata() { } } -// buildLink returns a link to be used in the FileMetadata struct on initialization func buildLink(rawFilename string) string { return fmt.Sprintf("http://pi.local:1234/file/%s", url.QueryEscape(rawFilename)) } @@ -120,6 +118,7 @@ func saveFile(c echo.Context) error { tags := form.Value["tags"] uploadedFiles.Files = append(uploadedFiles.Files, FileMetadata{Name: file.Filename, Tags: tags, Link: buildLink(file.Filename)}) go writeFileMetadata() + go createAltSizes(file.Filename) return c.String(http.StatusOK, fmt.Sprintf("File %s uploaded successfully!", file.Filename)) } @@ -206,7 +205,6 @@ func getAvif(c echo.Context) error { slog.Error("Error decoding image") return err } - slog.Debug("Image decoded successfully") // encode the img as avif file err = avif.Encode(dstFile, img, nil) @@ -222,14 +220,11 @@ func getAvif(c echo.Context) error { // e.GET("/files", listFiles) func listFiles(c echo.Context) error { - // list all available files return c.JSON(http.StatusOK, uploadedFiles) } // e.GET("/files/search", searchFiles) func searchFiles(c echo.Context) error { - // search for files by tag - // get the tag from the request tag := c.QueryParam("tag") // search for the tag in the uploadedFiles var foundFiles []FileMetadata @@ -274,6 +269,7 @@ func main() { return nil }, })) + e.Use(middleware.CORS()) e.GET("/", func(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!") }) diff --git a/resizer.go b/resizer.go new file mode 100644 index 0000000..6d17b19 --- /dev/null +++ b/resizer.go @@ -0,0 +1,64 @@ +package main + +import ( + "fmt" + "image" + "image/jpeg" + "log/slog" + "os" +) + +func writeNewImg(img *image.Image, scale int, filename string) error { + // create destination file + dstFile, err := os.Create(fmt.Sprintf("%s-%d.jpeg", filename, scale)) + if err != nil { + return err + } + defer dstFile.Close() + + // create new image + maxX := (*img).Bounds().Dx() / scale + maxY := (*img).Bounds().Dy() / scale + // newImg := image.NewRGBA((*img).Bounds()) + newImg := image.NewRGBA(image.Rect(0, 0, maxX, maxY)) + fmt.Printf("New image bounds: %v\n", newImg.Bounds()) + + for y := range (*newImg).Bounds().Dy() { + for x := range (*newImg).Bounds().Dx() { + newImg.Set(x, y, (*img).At(x*scale, y*scale)) + } + } + + err = jpeg.Encode(dstFile, newImg, nil) + if err != nil { + return err + } + return nil +} + +func createAltSizes(srcPath string) { + slog.Info(fmt.Sprintf("Creating alt sizes for %s", srcPath)) + srcFile, err := os.Open(srcPath) + if err != nil { + panic(err) + } + defer srcFile.Close() + + img, err := jpeg.Decode(srcFile) + if err != nil { + slog.Error("Error decoding image") + panic(err) + } + + filename := srcFile.Name() + // Create medium img at 1/4 size + err = writeNewImg(&img, 4, filename) + if err != nil { + panic(err) + } + // Create icon image at 1/10 size + err = writeNewImg(&img, 10, filename) + if err != nil { + panic(err) + } +}