@@ -78,20 +78,30 @@ function sharpFrom(inputBuffer: ArrayBufferLike | Buffer, options?: sharp.SharpO
78
78
return sharp ( new Uint8Array ( inputBuffer ) , options ) . rotate ( ) ;
79
79
}
80
80
81
+ function metadataToFrameHeight ( metadata : sharp . Metadata ) {
82
+ const frameCount = Math . max ( metadata . pages || 0 , 1 ) ;
83
+ const frameHeight =
84
+ metadata . height && frameCount ? metadata . height / frameCount : metadata . height ;
85
+ return frameHeight ;
86
+ }
87
+
81
88
/**
82
89
* Wrapper around `sharp.metadata` as it throws if not a valid image, and we usually
83
90
* want to just return null.
84
91
*
85
92
* Note: this will also orient a jpeg if needed. (i.e. calls rotate() through sharpFrom)
93
+ * Note: metadata height will be set to the frame height, not the full height
94
+ * of the canvas (as sharp.metadata does with animated webps)
86
95
*/
87
96
async function metadataFromBuffer (
88
97
inputBuffer : ArrayBufferLike | Buffer ,
89
98
options ?: sharp . SharpOptions
90
99
) {
91
100
try {
92
101
const metadata = await sharpFrom ( inputBuffer , options ) . metadata ( ) ;
102
+ const frameHeight = metadataToFrameHeight ( metadata ) ;
93
103
// we do need the await above so the try/catch does its job
94
- return metadata ;
104
+ return { ... metadata , height : frameHeight } ;
95
105
} catch ( e ) {
96
106
console . info ( 'metadataFromBuffer failed with' , e . message ) ;
97
107
return null ;
@@ -131,7 +141,7 @@ const workerActions: ImageProcessorWorkerActions = {
131
141
return {
132
142
outputBuffer : outputBuffer . buffer ,
133
143
width : outputMetadata . width ,
134
- height : outputMetadata . height ,
144
+ height : outputMetadata . height , // this one is only the frame height already, no need for `metadataToFrameHeight`
135
145
size : outputMetadataSize ,
136
146
format : 'jpeg' as const ,
137
147
contentType : 'image/jpeg' as const ,
@@ -231,7 +241,7 @@ const workerActions: ImageProcessorWorkerActions = {
231
241
232
242
avatarFallback = {
233
243
outputBuffer : firstFrameJpeg . outputBuffer ,
234
- height : firstFrameJpeg . height ,
244
+ height : firstFrameJpeg . height , // this one is only the frame height already. No need for `metadataToFrameHeight`
235
245
width : firstFrameJpeg . width ,
236
246
format : fallbackFormat ,
237
247
contentType : `image/${ fallbackFormat } ` as const ,
@@ -272,7 +282,7 @@ const workerActions: ImageProcessorWorkerActions = {
272
282
const format = 'jpeg' as const ;
273
283
return {
274
284
outputBuffer : createdBuffer . buffer ,
275
- height : createdMetadata . height ,
285
+ height : createdMetadata . height , // this one is only the frame height already, no need for `metadataToFrameHeight`
276
286
width : createdMetadata . width ,
277
287
isAnimated : false ,
278
288
format,
@@ -390,7 +400,7 @@ const workerActions: ImageProcessorWorkerActions = {
390
400
outputBuffer : inputBuffer ,
391
401
size,
392
402
width : metadata . width ,
393
- height : metadata . height ,
403
+ height : metadata . height , // this one is only the frame height already, no need for `metadataToFrameHeight`
394
404
isAnimated : isAnimated ( metadata ) ,
395
405
} ;
396
406
}
@@ -414,7 +424,7 @@ const workerActions: ImageProcessorWorkerActions = {
414
424
outputBuffer : inputBuffer ,
415
425
size,
416
426
width : metadata . width ,
417
- height : metadata . height ,
427
+ height : metadata . height , // this one is only the frame height already, no need for `metadataToFrameHeight`
418
428
isAnimated : isAnimated ( metadata ) ,
419
429
} ;
420
430
}
@@ -481,7 +491,7 @@ const workerActions: ImageProcessorWorkerActions = {
481
491
outputBuffer : buffer . buffer ,
482
492
size,
483
493
width : outputMetadata . width ,
484
- height : outputMetadata . height ,
494
+ height : outputMetadata . height , // this one is only the frame height already, no need for `metadataToFrameHeight`
485
495
isAnimated : isAnimated ( outputMetadata ) ,
486
496
} ;
487
497
}
0 commit comments