[MM-28638] Improve image thumbnail generation logic (#15534)

* Improve image thumbnail generation logic

* Improve naming
This commit is contained in:
Claudio Costa 2020-10-09 08:47:20 +02:00 committed by GitHub
parent 0af0a4eff4
commit 73c41ef808
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 78 additions and 39 deletions

View file

@ -380,6 +380,30 @@ func TestUploadFiles(t *testing.T) {
expectedImageMiniPreview: []bool{true},
expectedCreatorId: th.BasicUser.Id,
},
// Extremely wide image test
{
title: "Happy image thumbnail/preview 10",
names: []string{"10000x1.png"},
expectedImageThumbnailNames: []string{"10000x1_expected_thumb.jpeg"},
expectedImagePreviewNames: []string{"10000x1_expected_preview.jpeg"},
expectImage: true,
expectedImageWidths: []int{10000},
expectedImageHeights: []int{1},
expectedImageHasPreview: []bool{true},
expectedCreatorId: th.BasicUser.Id,
},
// Extremely high image test
{
title: "Happy image thumbnail/preview 11",
names: []string{"1x10000.png"},
expectedImageThumbnailNames: []string{"1x10000_expected_thumb.jpeg"},
expectedImagePreviewNames: []string{"1x10000_expected_preview.jpeg"},
expectImage: true,
expectedImageWidths: []int{1},
expectedImageHeights: []int{10000},
expectedImageHasPreview: []bool{true},
expectedCreatorId: th.BasicUser.Id,
},
{
title: "Happy admin",
client: th.SystemAdminClient,

View file

@ -838,31 +838,16 @@ func (t *UploadFileTask) postprocessImage() {
}
}
w := decoded.Bounds().Dx()
h := decoded.Bounds().Dy()
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
thumb := decoded
if h > ImageThumbnailHeight || w > ImageThumbnailWidth {
if float64(h)/float64(w) < ImageThumbnailRatio {
thumb = imaging.Resize(decoded, 0, ImageThumbnailHeight, imaging.Lanczos)
} else {
thumb = imaging.Resize(decoded, ImageThumbnailWidth, 0, imaging.Lanczos)
}
}
writeJPEG(thumb, t.fileinfo.ThumbnailPath)
writeJPEG(genThumbnail(decoded), t.fileinfo.ThumbnailPath)
}()
go func() {
defer wg.Done()
preview := decoded
if w > ImagePreviewWidth {
preview = imaging.Resize(decoded, ImagePreviewWidth, 0, imaging.Lanczos)
}
writeJPEG(preview, t.fileinfo.PreviewPath)
writeJPEG(genPreview(decoded), t.fileinfo.PreviewPath)
}()
go func() {
@ -1083,22 +1068,8 @@ func getImageOrientation(input io.Reader) (int, error) {
}
func (a *App) generateThumbnailImage(img image.Image, thumbnailPath string, width int, height int) {
thumbWidth := float64(IMAGE_THUMBNAIL_PIXEL_WIDTH)
thumbHeight := float64(IMAGE_THUMBNAIL_PIXEL_HEIGHT)
imgWidth := float64(width)
imgHeight := float64(height)
var thumbnail image.Image
if imgHeight < IMAGE_THUMBNAIL_PIXEL_HEIGHT && imgWidth < thumbWidth {
thumbnail = img
} else if imgHeight/imgWidth < thumbHeight/thumbWidth {
thumbnail = imaging.Resize(img, 0, IMAGE_THUMBNAIL_PIXEL_HEIGHT, imaging.Lanczos)
} else {
thumbnail = imaging.Resize(img, IMAGE_THUMBNAIL_PIXEL_WIDTH, 0, imaging.Lanczos)
}
buf := new(bytes.Buffer)
if err := jpeg.Encode(buf, thumbnail, &jpeg.Options{Quality: 90}); err != nil {
if err := jpeg.Encode(buf, genThumbnail(img), &jpeg.Options{Quality: 90}); err != nil {
mlog.Error("Unable to encode image as jpeg", mlog.String("path", thumbnailPath), mlog.Err(err))
return
}
@ -1110,13 +1081,7 @@ func (a *App) generateThumbnailImage(img image.Image, thumbnailPath string, widt
}
func (a *App) generatePreviewImage(img image.Image, previewPath string, width int) {
var preview image.Image
if width > IMAGE_PREVIEW_PIXEL_WIDTH {
preview = imaging.Resize(img, IMAGE_PREVIEW_PIXEL_WIDTH, 0, imaging.Lanczos)
} else {
preview = img
}
preview := genPreview(img)
buf := new(bytes.Buffer)

50
app/image.go Normal file
View file

@ -0,0 +1,50 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package app
import (
"image"
"github.com/disintegration/imaging"
)
func genThumbnail(img image.Image) image.Image {
thumb := img
w := img.Bounds().Dx()
h := img.Bounds().Dy()
if h > ImageThumbnailHeight || w > ImageThumbnailWidth {
ratio := float64(h) / float64(w)
if ratio < ImageThumbnailRatio {
// we pre-calculate the thumbnail's width to make sure we are not upscaling.
targetWidth := int(float64(ImageThumbnailHeight) * float64(w) / float64(h))
if targetWidth <= w {
thumb = imaging.Resize(img, 0, ImageThumbnailHeight, imaging.Lanczos)
} else {
thumb = imaging.Resize(img, ImageThumbnailWidth, 0, imaging.Lanczos)
}
} else {
// we pre-calculate the thumbnail's height to make sure we are not upscaling.
targetHeight := int(float64(ImageThumbnailWidth) * float64(h) / float64(w))
if targetHeight <= h {
thumb = imaging.Resize(img, ImageThumbnailWidth, 0, imaging.Lanczos)
} else {
thumb = imaging.Resize(img, 0, ImageThumbnailHeight, imaging.Lanczos)
}
}
}
return thumb
}
func genPreview(img image.Image) image.Image {
preview := img
w := img.Bounds().Dx()
if w > ImagePreviewWidth {
preview = imaging.Resize(img, ImagePreviewWidth, 0, imaging.Lanczos)
}
return preview
}

BIN
tests/10000x1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

BIN
tests/1x10000.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B