diff --git a/services/webdav/MIGRATION.md b/services/webdav/MIGRATION.md index 35d1879575..05dd70a34e 100644 --- a/services/webdav/MIGRATION.md +++ b/services/webdav/MIGRATION.md @@ -86,7 +86,11 @@ thumbnails: The resolutions are edge lengths now, and each axis of a request is rounded up on its own, so a preview is no longer returned in a different orientation than it was asked for. The default ladder ends at 2048, where it used to reach 8K, so a client -that asks for more gets 2048. +that asks for more gets 2048. A legacy `WidthxHeight` entry still counts with both +of its sides, each capped at 2048, which is the largest box the built-in generator +accepts by default. A larger length has to be written as a plain length, and the +generator's `THUMBNAILS_MAX_OUTPUT_WIDTH` and `THUMBNAILS_MAX_OUTPUT_HEIGHT` +raised to match it. A source smaller than the box is enlarged to fill it for the cropping operations, the way imagor's default resize does, where the previous service returned the diff --git a/services/webdav/README.md b/services/webdav/README.md index cfd83ac6f7..24e14c2c09 100644 --- a/services/webdav/README.md +++ b/services/webdav/README.md @@ -37,7 +37,7 @@ Example with the default ladder (16, 32, 64, 128, 192, 256, 320, 384, 448, 512, Requested: 18x12\ Returned: 32x16 -Entries written as `WidthxHeight` are still accepted and contribute both of their sides to the ladder, so a configuration written for the old box list keeps working. +Entries written as `WidthxHeight` are still accepted and contribute both of their sides to the ladder, each capped at 2048, the largest box the built-in generator accepts by default. A configuration written for the old box list, which reached 7680x4320, keeps working that way. A larger length has to be a plain one, with the generator's `THUMBNAILS_MAX_OUTPUT_WIDTH` and `THUMBNAILS_MAX_OUTPUT_HEIGHT` raised to match. Rounding onto the ladder is also what the cache is keyed on, so requests that produce the same image share one entry. diff --git a/services/webdav/pkg/config/config.go b/services/webdav/pkg/config/config.go index dffe3ebd4b..43eabeeddb 100644 --- a/services/webdav/pkg/config/config.go +++ b/services/webdav/pkg/config/config.go @@ -44,7 +44,7 @@ type Thumbnails struct { CacheDir string `yaml:"cache_dir" env:"WEBDAV_THUMBNAILS_CACHE_DIR" desc:"Directory for file-based thumbnail cache (Default: $OC_BASE_DATA_PATH/thumbnails/files). Only used when WEBDAV_THUMBNAILS_CACHE_BACKEND is 'file'." introductionVersion:"%%NEXT%%"` // kept so a deployment that configured the thumbnails service keeps its cache FilesystemStorageRoot string `yaml:"filesystemstorage_root" env:"THUMBNAILS_FILESYSTEMSTORAGE_ROOT" desc:"Directory the thumbnails service stored its files in. Read as a fallback for WEBDAV_THUMBNAILS_CACHE_DIR." introductionVersion:"1.0.0" deprecationVersion:"%%NEXT%%" removalVersion:"%%NEXT_PRODUCTION_VERSION%%" deprecationInfo:"THUMBNAILS_FILESYSTEMSTORAGE_ROOT is deprecated. The webdav service owns the thumbnail cache now, so use WEBDAV_THUMBNAILS_CACHE_DIR instead." deprecationReplacement:"WEBDAV_THUMBNAILS_CACHE_DIR"` - Resolutions []string `yaml:"resolutions" env:"THUMBNAILS_RESOLUTIONS;WEBDAV_THUMBNAILS_RESOLUTIONS" desc:"Allowed thumbnail edge lengths, like 512. Each axis of a requested size is rounded up to the next one of these before the box is sent to the generator. Legacy WidthxHeight entries are still accepted and contribute both of their sides." introductionVersion:"%%NEXT%%"` + Resolutions []string `yaml:"resolutions" env:"THUMBNAILS_RESOLUTIONS;WEBDAV_THUMBNAILS_RESOLUTIONS" desc:"Allowed thumbnail edge lengths, like 512. Each axis of a requested size is rounded up to the next one of these before the box is sent to the generator. Legacy WidthxHeight entries are still accepted and contribute both of their sides, each capped at 2048, the largest box the built-in generator accepts by default." introductionVersion:"%%NEXT%%"` CacheS3Bucket string `yaml:"cache_s3_bucket" env:"WEBDAV_THUMBNAILS_CACHE_S3_BUCKET" desc:"S3 bucket name for thumbnail cache when WEBDAV_THUMBNAILS_CACHE_BACKEND is 's3'." introductionVersion:"%%NEXT%%"` CacheS3Region string `yaml:"cache_s3_region" env:"WEBDAV_THUMBNAILS_CACHE_S3_REGION" desc:"S3 region for thumbnail cache when WEBDAV_THUMBNAILS_CACHE_BACKEND is 's3'." introductionVersion:"%%NEXT%%"` CacheS3Endpoint string `yaml:"cache_s3_endpoint" env:"WEBDAV_THUMBNAILS_CACHE_S3_ENDPOINT" desc:"S3 endpoint URL (for MinIO or compatible services) when WEBDAV_THUMBNAILS_CACHE_BACKEND is 's3'." introductionVersion:"%%NEXT%%"` diff --git a/services/webdav/pkg/thumbnail/resolutions.go b/services/webdav/pkg/thumbnail/resolutions.go index d284831ea9..493c33f3c1 100644 --- a/services/webdav/pkg/thumbnail/resolutions.go +++ b/services/webdav/pkg/thumbnail/resolutions.go @@ -12,6 +12,12 @@ import ( const ( _resolutionSeparator = "x" + + // legacyMaxEdge caps a side a legacy resolution contributes. Those boxes were + // written for the old service, which had no ceiling and listed boxes up to + // 7680x4320 by default, and 2048 is the largest box the built-in generator + // accepts by default (THUMBNAILS_MAX_OUTPUT_WIDTH and _HEIGHT). + legacyMaxEdge = 2048 ) // ParseResolution returns an image.Rectangle representing the resolution given as a string @@ -40,7 +46,8 @@ type Sizes struct { // ParseSizes builds the ladder from configuration. An entry is either a plain // edge length ("512") or a legacy resolution ("500x280"), which contributes both -// of its sides, so an existing box configuration keeps working. +// of its sides, capped at legacyMaxEdge, so an existing box configuration keeps +// working against the default generator. func ParseSizes(strs []string) (*Sizes, error) { seen := map[int]struct{}{} for _, s := range strs { @@ -53,8 +60,8 @@ func ParseSizes(strs []string) (*Sizes, error) { if err != nil { return nil, errors.Wrap(err, "could not parse thumbnail sizes") } - seen[r.Dx()] = struct{}{} - seen[r.Dy()] = struct{}{} + seen[min(r.Dx(), legacyMaxEdge)] = struct{}{} + seen[min(r.Dy(), legacyMaxEdge)] = struct{}{} continue } v, err := strconv.Atoi(s) diff --git a/services/webdav/pkg/thumbnail/sizes_test.go b/services/webdav/pkg/thumbnail/sizes_test.go index e168d3f29e..57e937e251 100644 --- a/services/webdav/pkg/thumbnail/sizes_test.go +++ b/services/webdav/pkg/thumbnail/sizes_test.go @@ -29,6 +29,16 @@ var _ = Describe("Sizes", func() { Expect(s.Snap(box(100, 100))).To(Equal(box(280, 280))) }) + It("caps the sides of a legacy resolution at what the default generator accepts", func() { + s := sizes("16x16", "1920x1080", "3840x2160", "7680x4320") + Expect(s.Max()).To(Equal(2048)) + Expect(s.Snap(box(0, 1000))).To(Equal(box(2048, 1080))) + }) + + It("takes a plain length above that as it is", func() { + Expect(sizes("16", "4096").Max()).To(Equal(4096)) + }) + It("rejects an entry that is not a number", func() { _, err := thumbnail.ParseSizes([]string{"large"}) Expect(err).To(HaveOccurred())