Dither

by nynexman4464

HTML

<canvas id=canvas>you don't have canvas?</canvas>
<div id="controls">
  <label><select id="algo" name="algo">
      <option value="">color</option>
      <option value="greyscale">greyscale</option>
      <option value="avg">greyscale (avg)</option>
      <option value="threshold">threshold</option>
      <option value="ordered">dither (ordered)</option>
      <option value="random">dither (random)</option>
      <option value="floyd">dither (Floyd–Steinberg)</option>
      <option value="error">dither (error diffusion 1)</option>
      <option value="minAvg">dither (min average error)</option>
      <option value="halftone">halftone</option>
    </select></label>
  <input type="range" id="level" />
  <label>image: <input type="file" id=file accept="image/*"></label>
</div>

CSS

html,body{margin: 0}

@media (prefers-color-scheme: dark) {
  body {
    background: black;
    color: white;
  }
}

JavaScript

const meta = document.createElement('meta');
meta.name = "color-scheme";
meta.content = "light dark";
document.head.appendChild(meta);

const controls = document.getElementById('controls');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
canvas.width = window.innerWidth;
// size canvas to make room for file input
canvas.height = window.innerHeight - controls.scrollHeight - 10;

// Create gradient
var grd = context.createLinearGradient(20, 0, canvas.width - 20, 0);
grd.addColorStop(0, "black");
grd.addColorStop(1, "white");

// Fill with gradient
context.fillStyle = grd;
context.fillRect(0, 0, canvas.width, canvas.height);
let currImgData = context.getImageData(0, 0, canvas.width, canvas.height);
setTimeout(drawImg);

//attach image uploader
document.getElementById('file').addEventListener('change', e => {
  const reader = new FileReader();
  const file = e.target.files[0];
  // load to image to get it's width/height
  const img = new Image();
  img.onload = () => {
    const imgRatio = img.width / img.height;
    const canvasRatio = canvas.width / canvas.height;
    let width, height;
    if (imgRatio < canvasRatio) {
      // image is narrower than us
      height = canvas.height;
      width = canvas.height * imgRatio;
    } else {
      // image is wider than us
      width = canvas.width;
      height = canvas.width / imgRatio;
    }
    // draw image
    context.drawImage(img, 0, 0, width, height);
    currImgData = context.getImageData(0, 0, width, height);
    drawImg();
  }
  // this is to setup loading the image
  reader.onloadend = () => img.src = reader.result
  // this is to read the file
  reader.readAsDataURL(file);
});
document.getElementById('algo').addEventListener('change', () => drawImg());
document.getElementById('level').addEventListener('change', () => drawImg());

function drawImg() {
  if (currImgData == null) return;
  const algo = document.getElementById('algo').value;
  const level =...