Demo different sampling options
Requested by blink team
Change-Id: I5b93c330341e8582bfc479bd830bb6dfa3489847
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/396198
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
diff --git a/demos.skia.org/demos/sampling_types/index.html b/demos.skia.org/demos/sampling_types/index.html
new file mode 100644
index 0000000..c9f35c7
--- /dev/null
+++ b/demos.skia.org/demos/sampling_types/index.html
@@ -0,0 +1,195 @@
+<!DOCTYPE html>
+<title>Image sampling techniques</title>
+<meta charset="utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<script type="text/javascript" src="https://unpkg.com/canvaskit-wasm@0.25.0/bin/full/canvaskit.js"></script>
+
+<style>
+ figcaption {
+ max-width: 800px;
+ }
+</style>
+
+<body>
+ <h1>Image sampling techniques</h1>
+
+ <div class="slidecontainer">
+ <input style="width:400px;" type="range" min="-10" max="10" value="0" step="0.01"
+ class="slider" id="scale_slider" title="Scale">
+ </div>
+
+ <figure>
+ <div ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
+ <canvas id="draw" width=2048 height=1600></canvas>
+ </div>
+ <figcaption>
+ Drop an Image onto the page (above)
+ </figcaption>
+ </figure>
+
+</body>
+
+<script type="text/javascript" charset="utf-8">
+ function preventScrolling(elem) {
+ elem.addEventListener('touchmove', (e) => {
+ // Prevents touch events in the element from scrolling.
+ e.preventDefault();
+ e.stopPropagation();
+ });
+ }
+
+ function dragOverHandler(ev) { ev.preventDefault(); }
+
+ // these can be changed with click/drag on the primary rectangle
+ let cell_width = 256,
+ cell_height = 256;
+
+ let image = null;
+ let CK = null;
+ let surface = null;
+ let drawFrame = null;
+
+ function dropHandler(ev) {
+ ev.preventDefault();
+
+ let file = null;
+ if (ev.dataTransfer.items) {
+ // Use DataTransferItemList interface to access the file(s)
+ for (item of ev.dataTransfer.items) {
+ // If dropped items aren't files, reject them
+ if (item.kind === 'file') {
+ file = item.getAsFile();
+ break;
+ }
+ }
+ } else {
+ // Use DataTransfer interface to access the file(s)
+ for (f of ev.dataTransfer.files) {
+ file = f;
+ break;
+ }
+ }
+ if (file) {
+ file.arrayBuffer().then(buffer => {
+ image = CK.MakeImageFromEncoded(buffer);
+ surface.requestAnimationFrame(drawFrame);
+ });
+ }
+ }
+
+ const ckLoaded = CanvasKitInit({ locateFile: (file) => 'https://unpkg.com/canvaskit-wasm@0.25.0/bin/full/' + file });
+
+ ckLoaded.then((_CK) => {
+ CK = _CK;
+ surface = CK.MakeCanvasSurface('draw');
+ if (!surface) {
+ throw 'Could not make surface';
+ }
+
+ const font = new CK.Font(null, 15);
+ const paint = new CK.Paint();
+ const textPaint = new CK.Paint();
+ const TX = 20,
+ TY = 30; // where we start the first rectangle
+
+ scale_slider.oninput = () => { surface.requestAnimationFrame(drawFrame); };
+
+ m33_scaled = function(sx, sy) {
+ if (!sy) sy = sx;
+ let m = new Float32Array(9);
+ m[0] = sx; m[4] = sy; m[8] = 1;
+ return m;
+ }
+
+ drawFrame = function(canvas) {
+ if (!image) return;
+
+ const scale = scale_slider.valueAsNumber < 0 ? 1 / (1 - scale_slider.valueAsNumber)
+ : (1 + scale_slider.valueAsNumber);
+
+ const bounds = [0, 0, cell_width, cell_height];
+
+ const lm = m33_scaled(scale, scale);
+
+ const samplings = [
+ [CK.FilterMode.Nearest, CK.MipmapMode.None, 0, 0, "Nearest"],
+ [CK.FilterMode.Linear, CK.MipmapMode.None, 0, 0, "Bilerp"],
+ [CK.FilterMode.Linear, CK.MipmapMode.Linear, 0, 0, "Trilerp"],
+ [null, null, 0, 0.5, "CatmullRom"],
+ [null, null, 1/3.0, 1/3.0, "Mitchell"],
+ ];
+
+ const tile = CK.TileMode.Repeat;
+
+ canvas.save();
+ canvas.translate(TX, TY);
+ canvas.save();
+ for (i in samplings) {
+ if (i == 3) {
+ canvas.restore();
+ canvas.translate(0, bounds[3] - bounds[1] + 30);
+ canvas.save();
+ }
+
+ const s = samplings[i];
+ const shader = s[0] ? image.makeShaderOptions(tile, tile, s[0], s[1], lm)
+ : image.makeShaderCubic( tile, tile, s[2], s[3], lm);
+ paint.setShader(shader);
+ canvas.drawRect(bounds, paint);
+ shader.delete();
+
+ canvas.drawText(s[4], 20, -8, textPaint, font);
+
+ canvas.translate(bounds[2] - bounds[0] + 30, 0);
+ }
+ canvas.restore();
+ canvas.restore();
+ // draw the drag handle
+ if (true) {
+ canvas.save();
+ paint.setShader(null);
+ paint.setColor(CK.Color4f(1, 0, 0));
+ paint.setStrokeWidth(2);
+ canvas.translate(TX + cell_width + 4, TY + cell_height + 4);
+ canvas.drawLine(-12, 0, 0, 0, paint);
+ canvas.drawLine( 0, -12, 0, 0, paint);
+ canvas.restore()
+ }
+ };
+
+ // register our mouse handler
+ {
+ function len2(x, y) {
+ return x*x + y*y;
+ }
+ function hit_test(x,y, x1,y1) {
+ return len2(x-x1, y-y1) <= 10*10;
+ }
+
+ let do_drag = false;
+ function pointer_up(e) {
+ do_drag = false;
+ }
+ function pointer_down(e) {
+ do_drag = hit_test(TX+cell_width, TY+cell_height, e.offsetX, e.offsetY);
+ }
+ function pointer_move(e) {
+ if (e.pressure && do_drag) {
+ cell_width = Math.max(e.offsetX - TX, 32);
+ cell_height = Math.max(e.offsetY - TY, 32);
+ surface.requestAnimationFrame(drawFrame);
+ }
+ }
+
+ const elem = document.getElementById('draw');
+ elem.addEventListener('pointermove', pointer_move);
+ elem.addEventListener('pointerdown', pointer_down);
+ elem.addEventListener('pointerup', pointer_up);
+ preventScrolling(elem);
+ }
+
+ surface.requestAnimationFrame(drawFrame);
+ });
+
+</script>