[MM-28638] Improve image thumbnail generation logic (#15534)
* Improve image thumbnail generation logic * Improve naming
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
0af0a4eff4
Коммит
73c41ef808
@@ -380,6 +380,30 @@ func TestUploadFiles(t *testing.T) {
|
|||||||
expectedImageMiniPreview: []bool{true},
|
expectedImageMiniPreview: []bool{true},
|
||||||
expectedCreatorId: th.BasicUser.Id,
|
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",
|
title: "Happy admin",
|
||||||
client: th.SystemAdminClient,
|
client: th.SystemAdminClient,
|
||||||
|
|||||||
43
app/file.go
43
app/file.go
@@ -838,31 +838,16 @@ func (t *UploadFileTask) postprocessImage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w := decoded.Bounds().Dx()
|
|
||||||
h := decoded.Bounds().Dy()
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(3)
|
wg.Add(3)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
thumb := decoded
|
writeJPEG(genThumbnail(decoded), t.fileinfo.ThumbnailPath)
|
||||||
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)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
preview := decoded
|
writeJPEG(genPreview(decoded), t.fileinfo.PreviewPath)
|
||||||
if w > ImagePreviewWidth {
|
|
||||||
preview = imaging.Resize(decoded, ImagePreviewWidth, 0, imaging.Lanczos)
|
|
||||||
}
|
|
||||||
writeJPEG(preview, t.fileinfo.PreviewPath)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
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) {
|
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)
|
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))
|
mlog.Error("Unable to encode image as jpeg", mlog.String("path", thumbnailPath), mlog.Err(err))
|
||||||
return
|
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) {
|
func (a *App) generatePreviewImage(img image.Image, previewPath string, width int) {
|
||||||
var preview image.Image
|
preview := genPreview(img)
|
||||||
|
|
||||||
if width > IMAGE_PREVIEW_PIXEL_WIDTH {
|
|
||||||
preview = imaging.Resize(img, IMAGE_PREVIEW_PIXEL_WIDTH, 0, imaging.Lanczos)
|
|
||||||
} else {
|
|
||||||
preview = img
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
|||||||
50
app/image.go
Обычный файл
50
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
|
||||||
|
}
|
||||||
Двоичные данные
tests/10000x1.png
Обычный файл
Двоичные данные
tests/10000x1.png
Обычный файл
Двоичный файл не отображается.
|
После Ширина: | Высота: | Размер: 283 B |
Двоичные данные
tests/10000x1_expected_preview.jpeg
Обычный файл
Двоичные данные
tests/10000x1_expected_preview.jpeg
Обычный файл
Двоичный файл не отображается.
|
После Ширина: | Высота: | Размер: 1.1 KiB |
Двоичные данные
tests/10000x1_expected_thumb.jpeg
Обычный файл
Двоичные данные
tests/10000x1_expected_thumb.jpeg
Обычный файл
Двоичный файл не отображается.
|
После Ширина: | Высота: | Размер: 628 B |
Двоичные данные
tests/1x10000.png
Обычный файл
Двоичные данные
tests/1x10000.png
Обычный файл
Двоичный файл не отображается.
|
После Ширина: | Высота: | Размер: 307 B |
Двоичные данные
tests/1x10000_expected_preview.jpeg
Обычный файл
Двоичные данные
tests/1x10000_expected_preview.jpeg
Обычный файл
Двоичный файл не отображается.
|
После Ширина: | Высота: | Размер: 3.0 KiB |
Двоичные данные
tests/1x10000_expected_thumb.jpeg
Обычный файл
Двоичные данные
tests/1x10000_expected_thumb.jpeg
Обычный файл
Двоичный файл не отображается.
|
После Ширина: | Высота: | Размер: 624 B |
Ссылка в новой задаче
Block a user