diff --git a/api4/file_test.go b/api4/file_test.go index 9cb271aaa0..19423351d4 100644 --- a/api4/file_test.go +++ b/api4/file_test.go @@ -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, diff --git a/app/file.go b/app/file.go index 98c45df7c0..87c439e45e 100644 --- a/app/file.go +++ b/app/file.go @@ -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) diff --git a/app/image.go b/app/image.go new file mode 100644 index 0000000000..a2f8ea10b2 --- /dev/null +++ b/app/image.go @@ -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 +} diff --git a/tests/10000x1.png b/tests/10000x1.png new file mode 100644 index 0000000000..2f02142202 Binary files /dev/null and b/tests/10000x1.png differ diff --git a/tests/10000x1_expected_preview.jpeg b/tests/10000x1_expected_preview.jpeg new file mode 100644 index 0000000000..c547e21eef Binary files /dev/null and b/tests/10000x1_expected_preview.jpeg differ diff --git a/tests/10000x1_expected_thumb.jpeg b/tests/10000x1_expected_thumb.jpeg new file mode 100644 index 0000000000..90f2925324 Binary files /dev/null and b/tests/10000x1_expected_thumb.jpeg differ diff --git a/tests/1x10000.png b/tests/1x10000.png new file mode 100644 index 0000000000..0a3fab5044 Binary files /dev/null and b/tests/1x10000.png differ diff --git a/tests/1x10000_expected_preview.jpeg b/tests/1x10000_expected_preview.jpeg new file mode 100644 index 0000000000..e2511cb26f Binary files /dev/null and b/tests/1x10000_expected_preview.jpeg differ diff --git a/tests/1x10000_expected_thumb.jpeg b/tests/1x10000_expected_thumb.jpeg new file mode 100644 index 0000000000..4845434877 Binary files /dev/null and b/tests/1x10000_expected_thumb.jpeg differ