PLT-173 Changed thumbnails and previews to generate correctly for images with a non-standard orientation
Этот коммит содержится в:
73
api/file.go
73
api/file.go
@@ -5,6 +5,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"code.google.com/p/graphics-go/graphics"
|
||||||
l4g "code.google.com/p/log4go"
|
l4g "code.google.com/p/log4go"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/goamz/goamz/aws"
|
"github.com/goamz/goamz/aws"
|
||||||
@@ -13,6 +14,7 @@ import (
|
|||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
"github.com/nfnt/resize"
|
"github.com/nfnt/resize"
|
||||||
|
"github.com/rwcarlsen/goexif/exif"
|
||||||
_ "golang.org/x/image/bmp"
|
_ "golang.org/x/image/bmp"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
@@ -21,6 +23,7 @@ import (
|
|||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -143,25 +146,58 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode image config
|
width := img.Bounds().Dx()
|
||||||
imgConfig, _, err := image.DecodeConfig(bytes.NewReader(fileData[i]))
|
height := img.Bounds().Dy()
|
||||||
if err != nil {
|
|
||||||
l4g.Error("Unable to decode image config channelId=%v userId=%v filename=%v err=%v", channelId, userId, filename, err)
|
// Get the image's orientation and ignore any errors since not all images will have orientation data
|
||||||
return
|
orientation, _ := getImageOrientation(fileData[i])
|
||||||
|
|
||||||
|
// Create a temporary image that will be manipulated and then used to make the thumbnail and preview image
|
||||||
|
var temp *image.RGBA
|
||||||
|
if orientation >= 1 && orientation <= 4 {
|
||||||
|
temp = image.NewRGBA(img.Bounds())
|
||||||
|
} else {
|
||||||
|
bounds := img.Bounds()
|
||||||
|
temp = image.NewRGBA(image.Rect(bounds.Min.Y, bounds.Min.X, bounds.Max.Y, bounds.Max.X))
|
||||||
|
|
||||||
|
width, height = height, width
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove transparency due to JPEG's lack of support of it
|
// Draw a white background since JPEGs lack transparency
|
||||||
temp := image.NewRGBA(img.Bounds())
|
|
||||||
draw.Draw(temp, temp.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src)
|
draw.Draw(temp, temp.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src)
|
||||||
|
|
||||||
|
// Copy the original image onto the temporary one while rotating it as necessary
|
||||||
|
switch orientation {
|
||||||
|
case 3, 4:
|
||||||
|
// rotate 180 degrees
|
||||||
|
err := graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: math.Pi})
|
||||||
|
if err != nil {
|
||||||
|
l4g.Error("Unable to rotate image")
|
||||||
|
}
|
||||||
|
case 5, 8:
|
||||||
|
// rotate 90 degrees CCW
|
||||||
|
graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: 3 * math.Pi / 2})
|
||||||
|
if err != nil {
|
||||||
|
l4g.Error("Unable to rotate image")
|
||||||
|
}
|
||||||
|
case 6, 7:
|
||||||
|
// rotate 90 degrees CW
|
||||||
|
graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: math.Pi / 2})
|
||||||
|
if err != nil {
|
||||||
|
l4g.Error("Unable to rotate image")
|
||||||
|
}
|
||||||
|
case 1, 2:
|
||||||
draw.Draw(temp, temp.Bounds(), img, img.Bounds().Min, draw.Over)
|
draw.Draw(temp, temp.Bounds(), img, img.Bounds().Min, draw.Over)
|
||||||
|
}
|
||||||
|
|
||||||
img = temp
|
img = temp
|
||||||
|
|
||||||
// Create thumbnail
|
// Create thumbnail
|
||||||
go func() {
|
go func() {
|
||||||
thumbWidth := float64(utils.Cfg.ImageSettings.ThumbnailWidth)
|
thumbWidth := float64(utils.Cfg.ImageSettings.ThumbnailWidth)
|
||||||
thumbHeight := float64(utils.Cfg.ImageSettings.ThumbnailHeight)
|
thumbHeight := float64(utils.Cfg.ImageSettings.ThumbnailHeight)
|
||||||
imgWidth := float64(imgConfig.Width)
|
imgWidth := float64(width)
|
||||||
imgHeight := float64(imgConfig.Height)
|
imgHeight := float64(height)
|
||||||
|
|
||||||
var thumbnail image.Image
|
var thumbnail image.Image
|
||||||
if imgHeight < thumbHeight && imgWidth < thumbWidth {
|
if imgHeight < thumbHeight && imgWidth < thumbWidth {
|
||||||
@@ -188,7 +224,7 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
|
|||||||
// Create preview
|
// Create preview
|
||||||
go func() {
|
go func() {
|
||||||
var preview image.Image
|
var preview image.Image
|
||||||
if imgConfig.Width > int(utils.Cfg.ImageSettings.PreviewWidth) {
|
if width > int(utils.Cfg.ImageSettings.PreviewWidth) {
|
||||||
preview = resize.Resize(utils.Cfg.ImageSettings.PreviewWidth, utils.Cfg.ImageSettings.PreviewHeight, img, resize.Lanczos3)
|
preview = resize.Resize(utils.Cfg.ImageSettings.PreviewWidth, utils.Cfg.ImageSettings.PreviewHeight, img, resize.Lanczos3)
|
||||||
} else {
|
} else {
|
||||||
preview = img
|
preview = img
|
||||||
@@ -212,6 +248,23 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getImageOrientation(imageData []byte) (int, error) {
|
||||||
|
if exifData, err := exif.Decode(bytes.NewReader(imageData)); err != nil {
|
||||||
|
return 1, err
|
||||||
|
} else {
|
||||||
|
if tag, err := exifData.Get("Orientation"); err != nil {
|
||||||
|
return 1, err
|
||||||
|
} else {
|
||||||
|
orientation, err := tag.Int(0)
|
||||||
|
if err != nil {
|
||||||
|
return 1, err
|
||||||
|
} else {
|
||||||
|
return orientation, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ImageGetResult struct {
|
type ImageGetResult struct {
|
||||||
Error error
|
Error error
|
||||||
ImageData []byte
|
ImageData []byte
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user