diff options
author | Chocobozzz <me@florianbigard.com> | 2021-11-16 15:59:56 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-11-16 15:59:56 +0100 |
commit | 7196a70b28e93ede11ccbfef7f1bc919c663b964 (patch) | |
tree | 517ddce0331fc602cd17ca3e829fbcee227dc25f /server | |
parent | b3ed044ded4ed3108a3ff459e6600b71fa53568a (diff) | |
download | PeerTube-7196a70b28e93ede11ccbfef7f1bc919c663b964.tar.gz PeerTube-7196a70b28e93ede11ccbfef7f1bc919c663b964.tar.zst PeerTube-7196a70b28e93ede11ccbfef7f1bc919c663b964.zip |
Fix thumbnails/previews for portrait videos
Diffstat (limited to 'server')
-rw-r--r-- | server/helpers/image-utils.ts | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/server/helpers/image-utils.ts b/server/helpers/image-utils.ts index 033be2c50..206cfa5bc 100644 --- a/server/helpers/image-utils.ts +++ b/server/helpers/image-utils.ts | |||
@@ -43,11 +43,11 @@ export { | |||
43 | // --------------------------------------------------------------------------- | 43 | // --------------------------------------------------------------------------- |
44 | 44 | ||
45 | async function jimpProcessor (path: string, destination: string, newSize: { width: number, height: number }, inputExt: string) { | 45 | async function jimpProcessor (path: string, destination: string, newSize: { width: number, height: number }, inputExt: string) { |
46 | let jimpInstance: Jimp | 46 | let sourceImage: Jimp |
47 | const inputBuffer = await readFile(path) | 47 | const inputBuffer = await readFile(path) |
48 | 48 | ||
49 | try { | 49 | try { |
50 | jimpInstance = await read(inputBuffer) | 50 | sourceImage = await read(inputBuffer) |
51 | } catch (err) { | 51 | } catch (err) { |
52 | logger.debug('Cannot read %s with jimp. Try to convert the image using ffmpeg first.', path, { err }) | 52 | logger.debug('Cannot read %s with jimp. Try to convert the image using ffmpeg first.', path, { err }) |
53 | 53 | ||
@@ -55,34 +55,55 @@ async function jimpProcessor (path: string, destination: string, newSize: { widt | |||
55 | await convertWebPToJPG(path, newName) | 55 | await convertWebPToJPG(path, newName) |
56 | await rename(newName, path) | 56 | await rename(newName, path) |
57 | 57 | ||
58 | jimpInstance = await read(path) | 58 | sourceImage = await read(path) |
59 | } | 59 | } |
60 | 60 | ||
61 | await remove(destination) | 61 | await remove(destination) |
62 | 62 | ||
63 | // Optimization if the source file has the appropriate size | 63 | // Optimization if the source file has the appropriate size |
64 | const outputExt = getLowercaseExtension(destination) | 64 | const outputExt = getLowercaseExtension(destination) |
65 | if (skipProcessing({ jimpInstance, newSize, imageBytes: inputBuffer.byteLength, inputExt, outputExt })) { | 65 | if (skipProcessing({ sourceImage, newSize, imageBytes: inputBuffer.byteLength, inputExt, outputExt })) { |
66 | return copy(path, destination) | 66 | return copy(path, destination) |
67 | } | 67 | } |
68 | 68 | ||
69 | await jimpInstance | 69 | await autoResize({ sourceImage, newSize, destination }) |
70 | .resize(newSize.width, newSize.height) | 70 | } |
71 | .quality(80) | 71 | |
72 | .writeAsync(destination) | 72 | async function autoResize (options: { |
73 | sourceImage: Jimp | ||
74 | newSize: { width: number, height: number } | ||
75 | destination: string | ||
76 | }) { | ||
77 | const { sourceImage, newSize, destination } = options | ||
78 | |||
79 | // Portrait mode, special handling | ||
80 | if (sourceImage.getWidth() < sourceImage.getHeight()) { | ||
81 | const baseImage = sourceImage.cloneQuiet().cover(newSize.width, newSize.height) | ||
82 | .color([ { apply: 'shade', params: [ 50 ] } ]) | ||
83 | |||
84 | const topImage = sourceImage.cloneQuiet().contain(newSize.width, newSize.height) | ||
85 | |||
86 | return write(baseImage.blit(topImage, 0, 0), destination) | ||
87 | } | ||
88 | |||
89 | return write(sourceImage.contain(newSize.width, newSize.height), destination) | ||
90 | } | ||
91 | |||
92 | function write (image: Jimp, destination: string) { | ||
93 | return image.quality(80).writeAsync(destination) | ||
73 | } | 94 | } |
74 | 95 | ||
75 | function skipProcessing (options: { | 96 | function skipProcessing (options: { |
76 | jimpInstance: Jimp | 97 | sourceImage: Jimp |
77 | newSize: { width: number, height: number } | 98 | newSize: { width: number, height: number } |
78 | imageBytes: number | 99 | imageBytes: number |
79 | inputExt: string | 100 | inputExt: string |
80 | outputExt: string | 101 | outputExt: string |
81 | }) { | 102 | }) { |
82 | const { jimpInstance, newSize, imageBytes, inputExt, outputExt } = options | 103 | const { sourceImage, newSize, imageBytes, inputExt, outputExt } = options |
83 | const { width, height } = newSize | 104 | const { width, height } = newSize |
84 | 105 | ||
85 | if (jimpInstance.getWidth() > width || jimpInstance.getHeight() > height) return false | 106 | if (sourceImage.getWidth() > width || sourceImage.getHeight() > height) return false |
86 | if (inputExt !== outputExt) return false | 107 | if (inputExt !== outputExt) return false |
87 | 108 | ||
88 | const kB = 1000 | 109 | const kB = 1000 |