Self-Eroding Image
Loads your image URL first; if saving is blocked by CORS, use Upload.
const canvas = document.getElementById('serode-canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const statusEl = document.getElementById('serode-status');
const warnEl = document.getElementById('serode-warn');
const STEP = { blurPx: 0.4, noiseStd: 3, contrastDrop: 0.02, dropoutProb: 0.002 };
function clamp(x){ return x<0?0:(x>255?255:x); }
function saveState(dataUrl, level){
localStorage.setItem('erodedDataUrl', dataUrl);
localStorage.setItem('erodeLevel', String(level));
}
function clearState(){
localStorage.removeItem('erodedDataUrl');
localStorage.removeItem('erodeLevel');
}
function updateStatus(level){ statusEl.textContent = `Degradation level: ${level}`; }
function warn(msg){ warnEl.style.display='block'; warnEl.textContent = msg; }
function drawImageElement(img){
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(img, 0, 0);
}
function drawFromDataUrl(dataUrl){
return new Promise((resolve, reject) => {
if (!dataUrl) { resolve(false); return; }
const img = new Image();
img.onload = () => { drawImageElement(img); resolve(true); };
img.onerror = () => reject(new Error('Failed to load embedded/stored image.'));
img.src = dataUrl;
});
}
function drawFromUrl(url){
return new Promise((resolve, reject) => {
const img = new Image();
// same-origin image on your site: crossOrigin not needed, but harmless if present
img.crossOrigin = 'anonymous';
img.onload = () => { drawImageElement(
