clli-mdcv-png.html (5060B)
1 <!DOCTYPE HTML> 2 <script src="/resources/testharness.js"></script> 3 <script src="/resources/testharnessreport.js"></script> 4 <script> 5 // Render serveral equivalent ISO 21496-1 gainmap images with various values for 6 // globalHdrHeadroom. 7 // The test images used by this test have an SDR representation (at headroom 0) 8 // with pixel values in sRGB of: 9 // #C08040, #8040C0, #40C080, #FFFFFF 10 // They have an HDR representation (at headroom 1) with pixel values in sRGB of 11 // #40C080, #C08040, #8040C0 color(srgb 0x17F/0xFF, 0x17F/0xFF, 0x17F/0xFF) 12 // The test images vary in: 13 // * Some have SDR as the base image (encoded as sRGB) and some have HDR as the 14 // base image (encoded as Rec2100 PQ or Rec2100 HLG). 15 // * Some use sRGB as the gain application primaries, others use Rec2020 16 // The tests that use a Rec2100 PQ or HLG base are allowed a higher amount of 17 // error because of the brutal quantization error in those spaces. 18 const tests = [ 19 { 20 filename:'pq-clli_none-mdcv_none.png', 21 desc:'No CLLI or MDCV', 22 max_linear_value:1000/203, 23 }, 24 { 25 filename:'pq-clli_100-mdcv_p3_5000.png', 26 desc:'CLLI 100, MDCV 5000', 27 max_linear_value:203/203, 28 }, 29 { 30 filename:'pq-clli_500-mdcv_none.png', 31 desc:'CLLI 500', 32 max_linear_value:500/203, 33 }, 34 { 35 filename:'pq-clli_none-mdcv_rec2020_5000.png', 36 desc:'MDCV 5000', 37 max_linear_value:5000/203, 38 }, 39 ]; 40 for (const test of tests) { 41 promise_test(async () => { 42 filename = test.filename; 43 const canvas = new OffscreenCanvas(40, 40); 44 const ctx = canvas.getContext('2d', {colorType:'float16'}); 45 if (ctx.globalHDRHeadroom === undefined) { 46 return; 47 } 48 49 const pixelLinearValues = [ 50 100/203, 51 500/203, 52 1000/203, 53 5000/203, 54 ]; 55 const globalHDRHeadroomValues = [ 56 0, // log2(1) 57 1.3045, // log2(500/203) 58 4.6224, // log2(5000/203) 59 Infinity, 60 ]; 61 const globalHDRHeadroomLinear = [ 62 203/203, 63 500/203, 64 5000/203, 65 Infinity, 66 ]; 67 68 // Draw the image at the specified headrooms. 69 const image = new Image; 70 image.src = 'resources/' + filename; 71 await new Promise(resolve => image.onload = resolve); 72 for (let hdrHeadroomIndex = 0; hdrHeadroomIndex < 4; ++hdrHeadroomIndex) { 73 ctx.globalHDRHeadroom = globalHDRHeadroomValues[hdrHeadroomIndex]; 74 ctx.drawImage(image, 0, 10*hdrHeadroomIndex); 75 } 76 77 // Read back a pixel in each solid color region. 78 for (let hdrHeadroomIndex = 0; hdrHeadroomIndex < 4; ++hdrHeadroomIndex) { 79 for (let pixelIndex = 0; pixelIndex < 4; ++pixelIndex) { 80 const name = 'globalHDRHeadroom: ' + 81 globalHDRHeadroomValues[hdrHeadroomIndex] + 82 ', hdrHeadroomIndex:' + 83 hdrHeadroomIndex; 84 const data = ctx.getImageData( 85 5 + 10*pixelIndex, 5 + 10*hdrHeadroomIndex, 1, 1, 86 {colorSpace:'rec2100-linear', pixelFormat:'rgba-float16'}); 87 if (test.max_linear_value <= globalHDRHeadroomLinear[hdrHeadroomIndex]) { 88 // If the test image's (max nits)/203 is <= exp2(globalHDRHeadroom), 89 // then no tone mapping is performed. 90 if (pixelLinearValues[pixelIndex] <= 91 globalHDRHeadroomLinear[hdrHeadroomIndex]) { 92 // Values below the target will be unchanged. 93 const kEps = 0.15; 94 assert_approx_equals( 95 data.data[0], pixelLinearValues[pixelIndex], kEps, 96 'No tone mapping'); 97 } else { 98 // Values above the target may be clamped. 99 const kEps = 0.05; 100 assert_greater_than( 101 data.data[0], globalHDRHeadroomLinear[hdrHeadroomIndex] - kEps, 102 'Tone map to or above target max'); 103 } 104 } else { 105 // If the test image doesn't fit in targeted headroom, then tone 106 // mapping will happen. 107 if (pixelLinearValues[pixelIndex] == test.max_linear_value) { 108 // Pixels equal to the content maximum will map to the target 109 // maximum. 110 const kEps = 0.05; 111 assert_approx_equals( 112 data.data[0], globalHDRHeadroomLinear[hdrHeadroomIndex], kEps, 113 'Tone map to target max'); 114 } else if (pixelLinearValues[pixelIndex] > test.max_linear_value) { 115 // Pixels greater than content maximum will map to be greater or 116 // equal to the target maximum. 117 const kEps = 0.05; 118 assert_greater_than( 119 data.data[0], globalHDRHeadroomLinear[hdrHeadroomIndex] - kEps, 120 'Tone map to or above target max'); 121 } else { 122 // Pixels less than the content maximum will map to a value less 123 // than the target maximum. 124 const kEps = 0.05; 125 assert_less_than( 126 data.data[0], globalHDRHeadroomLinear[hdrHeadroomIndex], 127 'Tone map below target max'); 128 } 129 } 130 } 131 } 132 }, test.desc); 133 } 134 </script>