mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-21 19:26:40 +00:00
[chore] Only call imaging.Resize when necessary
, use even tinier blurhashes (#3247)
* [chore] Use `imaging.Fit`, use even tinier blurhashes * avoid calling resize if not necessary * update blurhashes + thumb
This commit is contained in:
parent
277b043633
commit
e10aa76612
|
@ -858,7 +858,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() {
|
||||||
"static_url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/attachment/small/`+instanceAccount.AvatarMediaAttachment.ID+`.webp",`+`
|
"static_url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/attachment/small/`+instanceAccount.AvatarMediaAttachment.ID+`.webp",`+`
|
||||||
"thumbnail_static_type": "image/webp",
|
"thumbnail_static_type": "image/webp",
|
||||||
"thumbnail_description": "A bouncing little green peglin.",
|
"thumbnail_description": "A bouncing little green peglin.",
|
||||||
"blurhash": "LE9as6M}4YtO%dRlWEt6Dmoxx?WC"
|
"blurhash": "LF9kG$RR4YtP%dR+V^t5D,oxx?WC"
|
||||||
}`, string(instanceV2ThumbnailJson))
|
}`, string(instanceV2ThumbnailJson))
|
||||||
|
|
||||||
// double extra special bonus: now update the image description without changing the image
|
// double extra special bonus: now update the image description without changing the image
|
||||||
|
|
|
@ -206,7 +206,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateSuccessful() {
|
||||||
Y: 0.5,
|
Y: 0.5,
|
||||||
},
|
},
|
||||||
}, *attachmentReply.Meta)
|
}, *attachmentReply.Meta)
|
||||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", *attachmentReply.Blurhash)
|
suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", *attachmentReply.Blurhash)
|
||||||
suite.NotEmpty(attachmentReply.ID)
|
suite.NotEmpty(attachmentReply.ID)
|
||||||
suite.NotEmpty(attachmentReply.URL)
|
suite.NotEmpty(attachmentReply.URL)
|
||||||
suite.NotEmpty(attachmentReply.PreviewURL)
|
suite.NotEmpty(attachmentReply.PreviewURL)
|
||||||
|
@ -291,7 +291,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateSuccessfulV2() {
|
||||||
Y: 0.5,
|
Y: 0.5,
|
||||||
},
|
},
|
||||||
}, *attachmentReply.Meta)
|
}, *attachmentReply.Meta)
|
||||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", *attachmentReply.Blurhash)
|
suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", *attachmentReply.Blurhash)
|
||||||
suite.NotEmpty(attachmentReply.ID)
|
suite.NotEmpty(attachmentReply.ID)
|
||||||
suite.Nil(attachmentReply.URL)
|
suite.Nil(attachmentReply.URL)
|
||||||
suite.NotEmpty(attachmentReply.PreviewURL)
|
suite.NotEmpty(attachmentReply.PreviewURL)
|
||||||
|
|
|
@ -276,7 +276,7 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcess() {
|
||||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||||
suite.Equal(269739, attachment.File.FileSize)
|
suite.Equal(269739, attachment.File.FileSize)
|
||||||
suite.Equal(22858, attachment.Thumbnail.FileSize)
|
suite.Equal(22858, attachment.Thumbnail.FileSize)
|
||||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", attachment.Blurhash)
|
suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash)
|
||||||
|
|
||||||
// now make sure the attachment is in the database
|
// now make sure the attachment is in the database
|
||||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||||
|
@ -429,7 +429,7 @@ func (suite *ManagerTestSuite) TestSlothVineProcess() {
|
||||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||||
suite.Equal(312453, attachment.File.FileSize)
|
suite.Equal(312453, attachment.File.FileSize)
|
||||||
suite.Equal(5648, attachment.Thumbnail.FileSize)
|
suite.Equal(5648, attachment.Thumbnail.FileSize)
|
||||||
suite.Equal("LhIrNMt6Nsj[t7ayW.j[_4WBsWkB", attachment.Blurhash)
|
suite.Equal("LfIYH~xtNskCxtfPW.kB_4aespof", attachment.Blurhash)
|
||||||
|
|
||||||
// now make sure the attachment is in the database
|
// now make sure the attachment is in the database
|
||||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||||
|
@ -489,7 +489,7 @@ func (suite *ManagerTestSuite) TestLongerMp4Process() {
|
||||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||||
suite.Equal(109569, attachment.File.FileSize)
|
suite.Equal(109569, attachment.File.FileSize)
|
||||||
suite.Equal(2976, attachment.Thumbnail.FileSize)
|
suite.Equal(2976, attachment.Thumbnail.FileSize)
|
||||||
suite.Equal("L8QJfm~qD%_3_3D%t7RjM{j[ofRj", attachment.Blurhash)
|
suite.Equal("LJQJfm?bM{?b~qRjt7WBayWBofWB", attachment.Blurhash)
|
||||||
|
|
||||||
// now make sure the attachment is in the database
|
// now make sure the attachment is in the database
|
||||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||||
|
@ -549,7 +549,7 @@ func (suite *ManagerTestSuite) TestBirdnestMp4Process() {
|
||||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||||
suite.Equal(1409625, attachment.File.FileSize)
|
suite.Equal(1409625, attachment.File.FileSize)
|
||||||
suite.Equal(14478, attachment.Thumbnail.FileSize)
|
suite.Equal(14478, attachment.Thumbnail.FileSize)
|
||||||
suite.Equal("LKF~w1RjRO.99DM_RPaetkV?WCMw", attachment.Blurhash)
|
suite.Equal("LJF?FZV@RO.99DM_RPWAx]V?ayMw", attachment.Blurhash)
|
||||||
|
|
||||||
// now make sure the attachment is in the database
|
// now make sure the attachment is in the database
|
||||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||||
|
@ -657,7 +657,7 @@ func (suite *ManagerTestSuite) TestPngNoAlphaChannelProcess() {
|
||||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||||
suite.Equal(17471, attachment.File.FileSize)
|
suite.Equal(17471, attachment.File.FileSize)
|
||||||
suite.Equal(6446, attachment.Thumbnail.FileSize)
|
suite.Equal(6446, attachment.Thumbnail.FileSize)
|
||||||
suite.Equal("LDQcrD%i-?aj%ho#M~RP~nf3~nt2", attachment.Blurhash)
|
suite.Equal("LFQT7e.A%O%4?co$M}M{_1W9~TxV", attachment.Blurhash)
|
||||||
|
|
||||||
// now make sure the attachment is in the database
|
// now make sure the attachment is in the database
|
||||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||||
|
@ -713,7 +713,7 @@ func (suite *ManagerTestSuite) TestPngAlphaChannelProcess() {
|
||||||
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
suite.Equal("image/webp", attachment.Thumbnail.ContentType)
|
||||||
suite.Equal(18832, attachment.File.FileSize)
|
suite.Equal(18832, attachment.File.FileSize)
|
||||||
suite.Equal(3592, attachment.Thumbnail.FileSize)
|
suite.Equal(3592, attachment.Thumbnail.FileSize)
|
||||||
suite.Equal("LBOW$@%i-rak%go#RSRP_1av~Ts+", attachment.Blurhash)
|
suite.Equal("LCONII.A%Oxw?co#M}M{_1ac~TxV", attachment.Blurhash)
|
||||||
|
|
||||||
// now make sure the attachment is in the database
|
// now make sure the attachment is in the database
|
||||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||||
|
@ -769,7 +769,7 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcessWithCallback() {
|
||||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||||
suite.Equal(269739, attachment.File.FileSize)
|
suite.Equal(269739, attachment.File.FileSize)
|
||||||
suite.Equal(22858, attachment.Thumbnail.FileSize)
|
suite.Equal(22858, attachment.Thumbnail.FileSize)
|
||||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", attachment.Blurhash)
|
suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash)
|
||||||
|
|
||||||
// now make sure the attachment is in the database
|
// now make sure the attachment is in the database
|
||||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||||
|
@ -847,7 +847,7 @@ func (suite *ManagerTestSuite) TestSimpleJpegProcessWithDiskStorage() {
|
||||||
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
suite.Equal("image/jpeg", attachment.Thumbnail.ContentType)
|
||||||
suite.Equal(269739, attachment.File.FileSize)
|
suite.Equal(269739, attachment.File.FileSize)
|
||||||
suite.Equal(22858, attachment.Thumbnail.FileSize)
|
suite.Equal(22858, attachment.Thumbnail.FileSize)
|
||||||
suite.Equal("LjCGfG#6RkRn_NvzRjWF?urqV@a$", attachment.Blurhash)
|
suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash)
|
||||||
|
|
||||||
// now make sure the attachment is in the database
|
// now make sure the attachment is in the database
|
||||||
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachment.ID)
|
||||||
|
|
|
@ -34,6 +34,40 @@
|
||||||
"golang.org/x/image/webp"
|
"golang.org/x/image/webp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxThumbWidth = 512
|
||||||
|
maxThumbHeight = 512
|
||||||
|
)
|
||||||
|
|
||||||
|
// thumbSize returns the dimensions to use for an input
|
||||||
|
// image of given width / height, for its outgoing thumbnail.
|
||||||
|
// This attempts to maintains the original image aspect ratio.
|
||||||
|
func thumbSize(width, height int, aspect float32) (int, int) {
|
||||||
|
|
||||||
|
switch {
|
||||||
|
// Simplest case, within bounds!
|
||||||
|
case width < maxThumbWidth &&
|
||||||
|
height < maxThumbHeight:
|
||||||
|
return width, height
|
||||||
|
|
||||||
|
// Width is larger side.
|
||||||
|
case width > height:
|
||||||
|
// i.e. height = newWidth * (height / width)
|
||||||
|
height = int(float32(maxThumbWidth) / aspect)
|
||||||
|
return maxThumbWidth, height
|
||||||
|
|
||||||
|
// Height is larger side.
|
||||||
|
case height > width:
|
||||||
|
// i.e. width = newHeight * (width / height)
|
||||||
|
width = int(float32(maxThumbHeight) * aspect)
|
||||||
|
return width, maxThumbHeight
|
||||||
|
|
||||||
|
// Square.
|
||||||
|
default:
|
||||||
|
return maxThumbWidth, maxThumbHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// generateThumb generates a thumbnail for the
|
// generateThumb generates a thumbnail for the
|
||||||
// input file at path, resizing it to the given
|
// input file at path, resizing it to the given
|
||||||
// dimensions and generating a blurhash if needed.
|
// dimensions and generating a blurhash if needed.
|
||||||
|
@ -229,11 +263,17 @@ func generateNativeThumb(
|
||||||
img = imaging.Transverse(img)
|
img = imaging.Transverse(img)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize image to dimens.
|
// Resize image to dimens only if necessary.
|
||||||
img = imaging.Resize(img,
|
if img.Bounds().Dx() > maxThumbWidth ||
|
||||||
width, height,
|
img.Bounds().Dy() > maxThumbHeight {
|
||||||
imaging.Linear,
|
// Note: We could call "imaging.Fit" here
|
||||||
)
|
// but there's no point, as we've already
|
||||||
|
// calculated target dimensions beforehand.
|
||||||
|
img = imaging.Resize(img,
|
||||||
|
width, height,
|
||||||
|
imaging.Linear,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Open output file at given path.
|
// Open output file at given path.
|
||||||
outfile, err := os.Create(outpath)
|
outfile, err := os.Create(outpath)
|
||||||
|
@ -255,7 +295,7 @@ func generateNativeThumb(
|
||||||
if needBlurhash {
|
if needBlurhash {
|
||||||
// for generating blurhashes, it's more cost effective to
|
// for generating blurhashes, it's more cost effective to
|
||||||
// lose detail since it's blurry, so make a tiny version.
|
// lose detail since it's blurry, so make a tiny version.
|
||||||
tiny := imaging.Resize(img, 64, 64, imaging.NearestNeighbor)
|
tiny := imaging.Resize(img, 32, 0, imaging.NearestNeighbor)
|
||||||
|
|
||||||
// Drop the larger image
|
// Drop the larger image
|
||||||
// ref as soon as possible
|
// ref as soon as possible
|
||||||
|
@ -294,7 +334,7 @@ func generateWebpBlurhash(filepath string) (string, error) {
|
||||||
|
|
||||||
// for generating blurhashes, it's more cost effective to
|
// for generating blurhashes, it's more cost effective to
|
||||||
// lose detail since it's blurry, so make a tiny version.
|
// lose detail since it's blurry, so make a tiny version.
|
||||||
tiny := imaging.Resize(img, 64, 64, imaging.NearestNeighbor)
|
tiny := imaging.Resize(img, 32, 0, imaging.NearestNeighbor)
|
||||||
|
|
||||||
// Drop the larger image
|
// Drop the larger image
|
||||||
// ref as soon as possible
|
// ref as soon as possible
|
||||||
|
|
|
@ -39,39 +39,6 @@ func getExtension(path string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// thumbSize returns the dimensions to use for an input
|
|
||||||
// image of given width / height, for its outgoing thumbnail.
|
|
||||||
// This attempts to maintains the original image aspect ratio.
|
|
||||||
func thumbSize(width, height int, aspect float32) (int, int) {
|
|
||||||
const (
|
|
||||||
maxThumbWidth = 512
|
|
||||||
maxThumbHeight = 512
|
|
||||||
)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
// Simplest case, within bounds!
|
|
||||||
case width < maxThumbWidth &&
|
|
||||||
height < maxThumbHeight:
|
|
||||||
return width, height
|
|
||||||
|
|
||||||
// Width is larger side.
|
|
||||||
case width > height:
|
|
||||||
// i.e. height = newWidth * (height / width)
|
|
||||||
height = int(float32(maxThumbWidth) / aspect)
|
|
||||||
return maxThumbWidth, height
|
|
||||||
|
|
||||||
// Height is larger side.
|
|
||||||
case height > width:
|
|
||||||
// i.e. width = newHeight * (width / height)
|
|
||||||
width = int(float32(maxThumbHeight) * aspect)
|
|
||||||
return width, maxThumbHeight
|
|
||||||
|
|
||||||
// Square.
|
|
||||||
default:
|
|
||||||
return maxThumbWidth, maxThumbHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getMimeType returns a suitable mimetype for file extension.
|
// getMimeType returns a suitable mimetype for file extension.
|
||||||
func getMimeType(ext string) string {
|
func getMimeType(ext string) string {
|
||||||
const defaultType = "application/octet-stream"
|
const defaultType = "application/octet-stream"
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
@ -1078,7 +1078,7 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
|
||||||
Thumbnail: gtsmodel.Thumbnail{
|
Thumbnail: gtsmodel.Thumbnail{
|
||||||
Path: "01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpeg",
|
Path: "01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpeg",
|
||||||
ContentType: "image/jpeg",
|
ContentType: "image/jpeg",
|
||||||
FileSize: 20394,
|
FileSize: 20395,
|
||||||
URL: "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.webp",
|
URL: "http://localhost:8080/fileserver/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.webp",
|
||||||
},
|
},
|
||||||
Avatar: util.Ptr(false),
|
Avatar: util.Ptr(false),
|
||||||
|
@ -1124,7 +1124,7 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
|
||||||
Thumbnail: gtsmodel.Thumbnail{
|
Thumbnail: gtsmodel.Thumbnail{
|
||||||
Path: "062G5WYKY35KKD12EMSM3F8PJ8/attachment/small/01PFPMWK2FF0D9WMHEJHR07C3R.jpeg",
|
Path: "062G5WYKY35KKD12EMSM3F8PJ8/attachment/small/01PFPMWK2FF0D9WMHEJHR07C3R.jpeg",
|
||||||
ContentType: "image/webp",
|
ContentType: "image/webp",
|
||||||
FileSize: 20394,
|
FileSize: 20395,
|
||||||
URL: "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/small/01PFPMWK2FF0D9WMHEJHR07C3R.webp",
|
URL: "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/small/01PFPMWK2FF0D9WMHEJHR07C3R.webp",
|
||||||
},
|
},
|
||||||
Avatar: util.Ptr(false),
|
Avatar: util.Ptr(false),
|
||||||
|
|
Loading…
Reference in a new issue