From 50cad5b2c16395939b211aff75550d705d83bc07 Mon Sep 17 00:00:00 2001 From: icydoge Date: Sat, 8 Jun 2019 19:12:26 +0100 Subject: [PATCH] Fix encoding of thumbnails --- thumbnail/thumbnail.go | 53 +++++++++++++++++++-------------- web/yronwood/static/yronwood.js | 34 +++++++++++++++++++-- 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/thumbnail/thumbnail.go b/thumbnail/thumbnail.go index 9ca305b..2bec9b6 100644 --- a/thumbnail/thumbnail.go +++ b/thumbnail/thumbnail.go @@ -1,7 +1,6 @@ package thumbnail import ( - "bufio" "bytes" "context" "fmt" @@ -13,6 +12,7 @@ import ( "os" "path" "strings" + "sync" "github.com/monzo/slog" "github.com/nfnt/resize" @@ -20,18 +20,23 @@ import ( "github.com/icydoge/yronwood/config" ) -const thumbnailWidth = 200 +const thumbnailWidth = 800 + +var thumbnailPathMutex = sync.Mutex{} func GetThumbnailForImage(ctx context.Context, fileName, storagePath, accessType string) ([]byte, error) { thumbnailPath := config.ConfigStorageDirectoryThumbnail + thumbnailPathMutex.Lock() if _, err := os.Stat(thumbnailPath); os.IsNotExist(err) { slog.Info(ctx, "Thumbnail directory %s does not exist, attempting to create it", thumbnailPath) mkdirErr := os.Mkdir(config.ConfigStorageDirectoryThumbnail, 0755) if mkdirErr != nil { slog.Error(ctx, "Could not create non-existing storage directory %s: %v", thumbnailPath, err) + thumbnailPathMutex.Unlock() return nil, mkdirErr } } + thumbnailPathMutex.Unlock() thumbnailFilePath := path.Join(thumbnailPath, getThumbnailFileName(fileName, accessType)) if _, err := os.Stat(thumbnailFilePath); err == nil { @@ -71,19 +76,23 @@ func GetThumbnailForImage(ctx context.Context, fileName, storagePath, accessType return nil, err } - thumbnail := resize.Thumbnail(thumbnailWidth, 0, img, resize.Lanczos3) - encodedThumbnail, err := encodeImage(fileName, thumbnail) + thumbnail := resize.Resize(thumbnailWidth, 0, img, resize.Lanczos3) + thumbnailFilePath, err = encodeImageToFile(fileName, thumbnailPath, accessType, thumbnail) if err != nil { slog.Debug(ctx, "Could not encode thumbnail of image %s: %v", filePath, err) return nil, err } - if err = ioutil.WriteFile(getThumbnailFileName(fileName, accessType), encodedThumbnail, 0644); err != nil { - slog.Debug(ctx, "Could not write thumbnail of image %s: %v", filePath, err) - return nil, err + if thumbnailFilePath != "" { + file, err := ioutil.ReadFile(thumbnailFilePath) + if err != nil { + slog.Debug(ctx, "Could not read thumnnail %s: %v", thumbnailFilePath, err) + return nil, err + } + return file, nil } - return encodedThumbnail, nil + return nil, nil } func getThumbnailFileName(fileName, accessType string) string { @@ -94,7 +103,7 @@ func getThumbnailFileName(fileName, accessType string) string { name := strings.Join(fileNameComponents[0:len(fileNameComponents)-1], ".") extension := fileNameComponents[len(fileNameComponents)-1] - thumbnailFileName := fmt.Sprintf("%s_%s.%s", name, "thumb", extension) + thumbnailFileName := fmt.Sprintf("%s_%s_%s.%s", name, accessType, "thumb", extension) return thumbnailFileName } @@ -118,31 +127,29 @@ func decodeImage(fileName string, filePayload []byte) (image.Image, error) { return nil, nil } -func encodeImage(fileName string, img image.Image) ([]byte, error) { +func encodeImageToFile(fileName, storagePath, accessType string, img image.Image) (string, error) { fileNameComponents := strings.Split(fileName, ".") if len(fileNameComponents) < 2 { - return nil, nil + return "", nil } extension := fileNameComponents[len(fileNameComponents)-1] - var buf = bytes.Buffer{} - imageWriter := bufio.NewWriter(&buf) + thumbnailPath := path.Join(storagePath, getThumbnailFileName(fileName, accessType)) + thumbnailFile, err := os.Create(thumbnailPath) + if err != nil { + return "", err + } + defer thumbnailFile.Close() var encodeErr error switch strings.ToLower(extension) { case "jpg", "jpeg": - encodeErr = jpeg.Encode(imageWriter, img, nil) + encodeErr = jpeg.Encode(thumbnailFile, img, nil) case "png": - encodeErr = png.Encode(imageWriter, img) + encodeErr = png.Encode(thumbnailFile, img) case "gif": - encodeErr = gif.Encode(imageWriter, img, nil) - } - - flushErr := imageWriter.Flush() - if encodeErr != nil || flushErr != nil { - return nil, encodeErr + encodeErr = gif.Encode(thumbnailFile, img, nil) } - imageReader := bufio.NewReader(&buf) - return ioutil.ReadAll(imageReader) + return thumbnailPath, encodeErr } diff --git a/web/yronwood/static/yronwood.js b/web/yronwood/static/yronwood.js index a8dd7ab..fc9cb94 100644 --- a/web/yronwood/static/yronwood.js +++ b/web/yronwood/static/yronwood.js @@ -46,12 +46,15 @@ function list_images(access_type, page) { $("#images-container").append(current_row); row_size = 0; } - var image_link = API_BASE + "/uploads/" + encodeURIComponent(image.access_path) + "/" + encodeURIComponent(image.file_name) + var image_link = API_BASE + "/uploads/" + encodeURIComponent(image.access_path) + "/" + encodeURIComponent(image.file_name) + '?' var secret = get_basic_auth_token(); if (secret != null && secret != "") { - image_link += "?token=" + encodeURIComponent(secret) + image_link = insertParam(image_link, "token", encodeURIComponent(secret)) } - $(current_row).append("
"); + + thumbnail_link = insertParam(image_link, "thumbnail", "yes") + $(current_row).append("
"); + row_size++; } } @@ -237,4 +240,29 @@ function randomFileName(length) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; +} + +// Adapted from https://stackoverflow.com/a/487049 +function insertParam(url, key, value) +{ + key = encodeURI(key); value = encodeURI(value); + + var kvp = url.split('&'); + var i=kvp.length; var x; while(i--) + { + x = kvp[i].split('='); + + if (x[0]==key) + { + x[1] = value; + kvp[i] = x.join('='); + break; + } + } + + if (i<0) { + kvp[kvp.length] = [key,value].join('='); + } + + return kvp.join('&'); } \ No newline at end of file