1cb93a386Sopenharmony_ci<!DOCTYPE html> 2cb93a386Sopenharmony_ci<title>Custom Image Upscaling</title> 3cb93a386Sopenharmony_ci<meta charset="utf-8" /> 4cb93a386Sopenharmony_ci<meta http-equiv="X-UA-Compatible" content="IE=edge"> 5cb93a386Sopenharmony_ci<meta name="viewport" content="width=device-width, initial-scale=1.0"> 6cb93a386Sopenharmony_ci<script type="text/javascript" src="https://unpkg.com/canvaskit-wasm@0.25.0/bin/full/canvaskit.js"></script> 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci<style> 9cb93a386Sopenharmony_ci figcaption { 10cb93a386Sopenharmony_ci max-width: 800px; 11cb93a386Sopenharmony_ci } 12cb93a386Sopenharmony_ci</style> 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci<body> 15cb93a386Sopenharmony_ci <h1>Custom Image Upscaling</h1> 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci <div class="slidecontainer"> 18cb93a386Sopenharmony_ci <input type="range" min="0" max="1" value="0" step="0.01" class="slider" id="sharpen" 19cb93a386Sopenharmony_ci title="sharpen coefficient: 0 means nearest neighbor."> 20cb93a386Sopenharmony_ci <input type="range" min="0" max="1" value="0.3" step="0.01" class="slider" id="cubic_B" 21cb93a386Sopenharmony_ci title="cubic B"> 22cb93a386Sopenharmony_ci <input type="range" min="0" max="1" value="0.3" step="0.01" class="slider" id="cubic_C" 23cb93a386Sopenharmony_ci title="cubic C"> 24cb93a386Sopenharmony_ci </div> 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci <figure> 27cb93a386Sopenharmony_ci <canvas id=draw width=820 height=820></canvas> 28cb93a386Sopenharmony_ci <figcaption> 29cb93a386Sopenharmony_ci This demo shows off a custom image upscaling algorithm written in SkSL. The algorithm 30cb93a386Sopenharmony_ci can be between nearest neighbor and linear interpolation, depending if the value of the 31cb93a386Sopenharmony_ci sharpen (i.e. the first) slider is 0 or 1, respectively. The upper left quadrant shows 32cb93a386Sopenharmony_ci the results of a 100x zoom in on a 4 pixel by 4 pixel image of random colors with this 33cb93a386Sopenharmony_ci algorithm. The lower left is the same algorithm with a smoothing curve applied. 34cb93a386Sopenharmony_ci <br> 35cb93a386Sopenharmony_ci For comparison, the upper right shows a stock linear interpolation and the lower right 36cb93a386Sopenharmony_ci shows a cubic interpolation with the B and C values controlled by the two remaining 37cb93a386Sopenharmony_ci sliders. 38cb93a386Sopenharmony_ci </figcaption> 39cb93a386Sopenharmony_ci </figure> 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci</body> 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci<script type="text/javascript" charset="utf-8"> 44cb93a386Sopenharmony_ci const ckLoaded = CanvasKitInit({ locateFile: (file) => 'https://unpkg.com/canvaskit-wasm@0.25.0/bin/full/' + file }); 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci ckLoaded.then((CanvasKit) => { 47cb93a386Sopenharmony_ci if (!CanvasKit.RuntimeEffect) { 48cb93a386Sopenharmony_ci throw 'Need RuntimeEffect'; 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci const surface = CanvasKit.MakeCanvasSurface('draw'); 51cb93a386Sopenharmony_ci if (!surface) { 52cb93a386Sopenharmony_ci throw 'Could not make surface'; 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci const prog = ` 56cb93a386Sopenharmony_ci uniform shader image; 57cb93a386Sopenharmony_ci uniform float sharp; // 1/m 0 --> NN, 1 --> Linear 58cb93a386Sopenharmony_ci uniform float do_smooth; // bool 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci float2 smooth(float2 t) { 61cb93a386Sopenharmony_ci return t * t * (3.0 - 2.0 * t); 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci float2 sharpen(float2 w) { 65cb93a386Sopenharmony_ci return saturate(sharp * (w - 0.5) + 0.5); 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci half4 main(float2 p) { 69cb93a386Sopenharmony_ci half4 pa = image.eval(float2(p.x-0.5, p.y-0.5)); 70cb93a386Sopenharmony_ci half4 pb = image.eval(float2(p.x+0.5, p.y-0.5)); 71cb93a386Sopenharmony_ci half4 pc = image.eval(float2(p.x-0.5, p.y+0.5)); 72cb93a386Sopenharmony_ci half4 pd = image.eval(float2(p.x+0.5, p.y+0.5)); 73cb93a386Sopenharmony_ci float2 w = sharpen(fract(p + 0.5)); 74cb93a386Sopenharmony_ci if (do_smooth > 0) { 75cb93a386Sopenharmony_ci w = smooth(w); 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci return mix(mix(pa, pb, w.x), mix(pc, pd, w.x), w.y); 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci `; 80cb93a386Sopenharmony_ci const effect = CanvasKit.RuntimeEffect.Make(prog); 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 83cb93a386Sopenharmony_ci // image is a 4x4 image of 16 random colors. This very small image will be upscaled 84cb93a386Sopenharmony_ci // through various techniques. 85cb93a386Sopenharmony_ci const image = function() { 86cb93a386Sopenharmony_ci const surf = CanvasKit.MakeSurface(4, 4); 87cb93a386Sopenharmony_ci const c = surf.getCanvas(); 88cb93a386Sopenharmony_ci for (let y = 0; y < 4; y++) { 89cb93a386Sopenharmony_ci for (let x = 0; x < 4; x++) { 90cb93a386Sopenharmony_ci paint.setColor([Math.random(), Math.random(), Math.random(), 1]); 91cb93a386Sopenharmony_ci c.drawRect(CanvasKit.LTRBRect(x, y, x+1, y+1), paint); 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci return surf.makeImageSnapshot(); 95cb93a386Sopenharmony_ci }(); 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci const imageShader = image.makeShaderOptions(CanvasKit.TileMode.Clamp, 98cb93a386Sopenharmony_ci CanvasKit.TileMode.Clamp, 99cb93a386Sopenharmony_ci CanvasKit.FilterMode.Nearest, 100cb93a386Sopenharmony_ci CanvasKit.MipmapMode.None); 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci sharpen.oninput = () => { surface.requestAnimationFrame(drawFrame); }; 103cb93a386Sopenharmony_ci cubic_B.oninput = () => { surface.requestAnimationFrame(drawFrame); }; 104cb93a386Sopenharmony_ci cubic_C.oninput = () => { surface.requestAnimationFrame(drawFrame); }; 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci const drawFrame = function(canvas) { 107cb93a386Sopenharmony_ci const v = sharpen.valueAsNumber; 108cb93a386Sopenharmony_ci const m = 1/Math.max(v, 0.00001); 109cb93a386Sopenharmony_ci const B = cubic_B.valueAsNumber; 110cb93a386Sopenharmony_ci const C = cubic_C.valueAsNumber; 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci canvas.save(); 113cb93a386Sopenharmony_ci // Upscale all drawing by 100x; This is big enough to make the differences in technique 114cb93a386Sopenharmony_ci // more obvious. 115cb93a386Sopenharmony_ci const scale = 100; 116cb93a386Sopenharmony_ci canvas.scale(scale, scale); 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci // Upper left, draw image using an algorithm (written in SkSL) between nearest neighbor and 119cb93a386Sopenharmony_ci // linear interpolation with no smoothing. 120cb93a386Sopenharmony_ci paint.setShader(effect.makeShaderWithChildren([m, 0], true, [imageShader], null)); 121cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(0, 0, 4, 4), paint); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci // Lower left, draw image using an algorithm (written in SkSL) between nearest neighbor and 124cb93a386Sopenharmony_ci // linear interpolation with smoothing enabled. 125cb93a386Sopenharmony_ci canvas.save(); 126cb93a386Sopenharmony_ci canvas.translate(0, 4.1); 127cb93a386Sopenharmony_ci paint.setShader(effect.makeShaderWithChildren([m, 1], true, [imageShader], null)); 128cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(0, 0, 4, 4), paint); 129cb93a386Sopenharmony_ci canvas.restore(); 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci // Upper right, draw image with built-in linear interpolation. 132cb93a386Sopenharmony_ci canvas.drawImageOptions(image, 4.1, 0, CanvasKit.FilterMode.Linear, CanvasKit.MipmapMode.None, null); 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci // Lower right, draw image with configurable cubic interpolation. 135cb93a386Sopenharmony_ci canvas.drawImageCubic(image, 4.1, 4.1, B, C, null); 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci canvas.restore(); 138cb93a386Sopenharmony_ci }; 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci surface.requestAnimationFrame(drawFrame); 141cb93a386Sopenharmony_ci }); 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci</script> 144