diff options
author | George Goldberg <george@gberg.me> | 2016-11-22 15:14:25 +0000 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2016-11-22 10:14:25 -0500 |
commit | e1fca412fc9c1f98f1682052fa8ce52166181a44 (patch) | |
tree | 19bb89069088c829cb87f9eafb806f92ef4849dd /api | |
parent | 3c65a20f4587da6315d47222b5d9852d7e5ad66f (diff) | |
download | chat-e1fca412fc9c1f98f1682052fa8ce52166181a44.tar.gz chat-e1fca412fc9c1f98f1682052fa8ce52166181a44.tar.bz2 chat-e1fca412fc9c1f98f1682052fa8ce52166181a44.zip |
PLT-4442 Generate preview images sequentially in Slack importer (#4617)
* Break out image preparation to its own function.
This is preparatory work to make it easier to handle the thumbnail image
generation in a non-racy way in the Slack command line importer.
* Build preview images sequentially in Slack import.
This removes the use of goroutines from the image preview generation
code run when importing Slack attachments. This slows things down, but
it has important benefits:
1) Avoids a race condition with the goroutines and the command line
exiting.
2) Avoids the problem of massive memory consumption when importing a
Slack channel with a lot of large images attached in quick succession.
Fixes PLT-4442.
* Use mutliple return values instead of struct.
Diffstat (limited to 'api')
-rw-r--r-- | api/file.go | 85 | ||||
-rw-r--r-- | api/import.go | 14 |
2 files changed, 50 insertions, 49 deletions
diff --git a/api/file.go b/api/file.go index dd075d3e0..8de69937a 100644 --- a/api/file.go +++ b/api/file.go @@ -195,50 +195,57 @@ func doUploadFile(teamId string, channelId string, userId string, rawFilename st func handleImages(previewPathList []string, thumbnailPathList []string, fileData [][]byte) { for i, data := range fileData { go func(i int, data []byte) { - // Decode image bytes into Image object - img, imgType, err := image.Decode(bytes.NewReader(fileData[i])) - if err != nil { - l4g.Error(utils.T("api.file.handle_images_forget.decode.error"), err) - return - } - - width := img.Bounds().Dx() - height := img.Bounds().Dy() - - // Fill in the background of a potentially-transparent png file as white - if imgType == "png" { - dst := image.NewRGBA(img.Bounds()) - draw.Draw(dst, dst.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src) - draw.Draw(dst, dst.Bounds(), img, img.Bounds().Min, draw.Over) - img = dst - } - - // Flip the image to be upright - orientation, _ := getImageOrientation(fileData[i]) - - switch orientation { - case UprightMirrored: - img = imaging.FlipH(img) - case UpsideDown: - img = imaging.Rotate180(img) - case UpsideDownMirrored: - img = imaging.FlipV(img) - case RotatedCWMirrored: - img = imaging.Transpose(img) - case RotatedCCW: - img = imaging.Rotate270(img) - case RotatedCCWMirrored: - img = imaging.Transverse(img) - case RotatedCW: - img = imaging.Rotate90(img) + img, width, height := prepareImage(fileData[i]) + if img != nil { + go generateThumbnailImage(*img, thumbnailPathList[i], width, height) + go generatePreviewImage(*img, previewPathList[i], width) } - - go generateThumbnailImage(img, thumbnailPathList[i], width, height) - go generatePreviewImage(img, previewPathList[i], width) }(i, data) } } +func prepareImage(fileData []byte) (*image.Image, int, int) { + // Decode image bytes into Image object + img, imgType, err := image.Decode(bytes.NewReader(fileData)) + if err != nil { + l4g.Error(utils.T("api.file.handle_images_forget.decode.error"), err) + return nil, 0, 0 + } + + width := img.Bounds().Dx() + height := img.Bounds().Dy() + + // Fill in the background of a potentially-transparent png file as white + if imgType == "png" { + dst := image.NewRGBA(img.Bounds()) + draw.Draw(dst, dst.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src) + draw.Draw(dst, dst.Bounds(), img, img.Bounds().Min, draw.Over) + img = dst + } + + // Flip the image to be upright + orientation, _ := getImageOrientation(fileData) + + switch orientation { + case UprightMirrored: + img = imaging.FlipH(img) + case UpsideDown: + img = imaging.Rotate180(img) + case UpsideDownMirrored: + img = imaging.FlipV(img) + case RotatedCWMirrored: + img = imaging.Transpose(img) + case RotatedCCW: + img = imaging.Rotate270(img) + case RotatedCCWMirrored: + img = imaging.Transverse(img) + case RotatedCW: + img = imaging.Rotate90(img) + } + + return &img, width, height +} + func getImageOrientation(imageData []byte) (int, error) { if exifData, err := exif.Decode(bytes.NewReader(imageData)); err != nil { return Upright, err diff --git a/api/import.go b/api/import.go index 3ac6a9ce9..570444464 100644 --- a/api/import.go +++ b/api/import.go @@ -62,23 +62,17 @@ func ImportFile(file io.Reader, teamId string, channelId string, userId string, io.Copy(buf, file) data := buf.Bytes() - previewPathList := []string{} - thumbnailPathList := []string{} - imageDataList := [][]byte{} - fileInfo, err := doUploadFile(teamId, channelId, userId, fileName, data) if err != nil { return nil, err } - if fileInfo.PreviewPath != "" || fileInfo.ThumbnailPath != "" { - previewPathList = append(previewPathList, fileInfo.PreviewPath) - thumbnailPathList = append(thumbnailPathList, fileInfo.ThumbnailPath) - imageDataList = append(imageDataList, data) + img, width, height := prepareImage(data) + if img != nil { + generateThumbnailImage(*img, fileInfo.ThumbnailPath, width, height) + generatePreviewImage(*img, fileInfo.PreviewPath, width) } - go handleImages(previewPathList, thumbnailPathList, imageDataList) - return fileInfo, nil } |