@@ -364,26 +364,43 @@ class PaletteColorLookupTable {
364364 ]
365365 const maxInput = Math . max ( ...maxValues )
366366 const maxOutput = 255
367+
368+ // Apply gamma correction to compensate for display gamma (brightens mid-tones)
369+ // When a linear intensity value i (0 to 1) is looked up, we actually want to look up
370+ // the color at position i^gamma where gamma = 1/2.2 ≈ 0.4545
371+ // This pre-brightens the colors for mid-tones
372+ const gammaInverse = 1.0 / 2.2 // ≈ 0.4545
373+
367374 if ( this [ _attrs ] . bitsPerEntry === 16 && maxInput > 255 ) {
368375 /*
369376 * Only palettes with 256 entries and 8 bit per entry are supported for
370377 * display. Therefore, data need to rescaled and resampled.
371378 */
372379 const n = 256
373- const step = this [ _attrs ] . numberOfEntries / n
374380 this [ _attrs ] . data = new Array ( n )
375381 for ( let i = 0 ; i < n ; i ++ ) {
376- const j = i * step
382+ // Apply gamma correction: for palette position i, look up the color
383+ // that would be at the gamma-corrected position
384+ const normalizedPos = i / ( n - 1 )
385+ const gammaCorrectedPos = Math . pow ( normalizedPos , gammaInverse )
386+ const lutIndex = Math . round ( gammaCorrectedPos * ( this [ _attrs ] . numberOfEntries - 1 ) )
387+
377388 this [ _attrs ] . data [ i ] = [
378- Math . round ( rescale ( redLUT [ j ] , 0 , maxInput , 0 , maxOutput ) ) ,
379- Math . round ( rescale ( greenLUT [ j ] , 0 , maxInput , 0 , maxOutput ) ) ,
380- Math . round ( rescale ( blueLUT [ j ] , 0 , maxInput , 0 , maxOutput ) )
389+ Math . round ( rescale ( redLUT [ lutIndex ] , 0 , maxInput , 0 , maxOutput ) ) ,
390+ Math . round ( rescale ( greenLUT [ lutIndex ] , 0 , maxInput , 0 , maxOutput ) ) ,
391+ Math . round ( rescale ( blueLUT [ lutIndex ] , 0 , maxInput , 0 , maxOutput ) )
381392 ]
382393 }
383394 } else {
384395 this [ _attrs ] . data = new Array ( this [ _attrs ] . numberOfEntries )
385396 for ( let i = 0 ; i < this [ _attrs ] . numberOfEntries ; i ++ ) {
386- this [ _attrs ] . data [ i ] = [ redLUT [ i ] , greenLUT [ i ] , blueLUT [ i ] ]
397+ // Apply gamma correction: for palette position i, look up the color
398+ // that would be at the gamma-corrected position
399+ const normalizedPos = i / ( this [ _attrs ] . numberOfEntries - 1 )
400+ const gammaCorrectedPos = Math . pow ( normalizedPos , gammaInverse )
401+ const lutIndex = Math . round ( gammaCorrectedPos * ( this [ _attrs ] . numberOfEntries - 1 ) )
402+
403+ this [ _attrs ] . data [ i ] = [ redLUT [ lutIndex ] , greenLUT [ lutIndex ] , blueLUT [ lutIndex ] ]
387404 }
388405 }
389406 }
0 commit comments