blob: 6c94f3ee87f38552f007b58a0f7ef43129f32a76 [file] [log] [blame]
<!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>
#draw {
border: 1px dashed grey;
}
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>
<!-- width/height hard-coded for grid of 256px images. -->
<div ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
<canvas id="draw" width=868 height=592></canvas>
</div>
<figcaption>
Drop an Image onto the rectangle 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>