Мозаїка зображення на Canvas

Публікації

Мозаїка зображення - це малювання квадратами зображення тобто розбиття зображення на маленькі шматочки (прямокутники) та відображення їх у відповідних позиціях. Певний поділ зображення на частини і малювання цих частин на полотні canvas. Звісно щоб візуально побачити ці частини необхідно малювати їх з відступом одне від одного або малювати кожен квадрат у рамку щоб візуально відділити.

Звичайно можна просто намалювати "сітку" за допомогою lineTo() і отримати "просту мозаїку зображення".

Малювання квадратів частинами дає змогу виконати ефекти до кожного квадрата, такі як зміщення, обертання, зміна кольорів, замальовувати квадрат в "спільний" колір і т.п..

Малювати квадрати (частини) зображення можна методом drawImage() - вказавши координати на зображенні і координати на полотні. Також можна наприклад створити масив даних в якому буде зберігатися інформація про квадрат і навіть містити дані зображення - пікселі у форматі ImageData. Все залежить від того які ефекти Ви хочете застосувати для квадрата в подальшому.

Зверніть увагу що виконуючи нижче написаний код використовується зображення яке уже завантажено на даній веб-сторінці. Тому якщо використовувати цей код Вам доведеться використовувати подію Image.onload.

Намалюємо квадрами зображення з використання drawImage().

var img=document.getElementById('image'); var canvas=document.getElementById('test'); var ctx=canvas.getContext('2d'); canvas.width=img.width; canvas.height=img.height; //ширина квадрата var cellWidth=canvas.width/30; //висота квадрата var cellHeight=canvas.height/30; //замальовуємо полотно на чорний фон ctx.fillStyle='black'; ctx.fillRect(0,0,canvas.width,canvas.height); for(let y=0;y<canvas.height;y+=cellHeight) for(let x=0;x<canvas.width;x+=cellWidth){ ctx.drawImage(img, x, y, cellWidth, cellHeight, x, y, cellWidth, cellHeight); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(x, y, cellWidth, cellHeight); }

Намалюємо квадрами зображення з використання ImageData та метода putImageData().

var img=document.getElementById('image'); var canvas=document.getElementById('test1'); var ctx=canvas.getContext('2d'); var cells=[]; canvas.width=img.width; canvas.height=img.height; var cellWidth=canvas.width/30; var cellHeight=canvas.height/30; //малюємо зображення на полотні ctx.drawImage(img,0,0); //створюємо масив квадратів for(let j=0;j<canvas.height;j+=cellHeight) for(let i=0;i<canvas.width;i+=cellWidth){ cells.push({x:i, y:j, w:cellWidth, h:cellHeight, data:ctx.getImageData(i, j, cellWidth, cellHeight)}); } //очищаємо canvas - замальовуємо полотно на чорний фон ctx.fillStyle='black'; ctx.fillRect(0, 0, canvas.width, canvas.height); //малюємо кожний квадрат for(let i=0;i<cells.length;i++){ ctx.putImageData(cells[i].data, cells[i].x, cells[i].y); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(cells[i].x, cells[i].y, cells[i].w, cells[i].h); }

Створимо найпростіший ефект намалювавши квадратну мозаїку з зміщенням по координатах x і y.

var img=document.getElementById('image'); var canvas=document.getElementById('test2'); var ctx=canvas.getContext('2d'); var cells=[]; canvas.width=img.width; canvas.height=img.height; var cellWidth=canvas.width/30; var cellHeight=canvas.height/30; ctx.drawImage(img,0,0); for(let j=0;j<canvas.height;j+=cellHeight) for(let i=0;i<canvas.width;i+=cellWidth){ cells.push({x:i, y:j, w:cellWidth, h:cellHeight, data:ctx.getImageData(i, j, cellWidth, cellHeight)}); } //замальовуємо полотно на чорний фон ctx.fillStyle='black'; ctx.fillRect(0,0,canvas.width,canvas.height); //малюємо кожний квадрат з зміщенням for(let i=0;i<cells.length;i++){ //визначаємо випадкове зміщення let x=cells[i].x+parseInt(Math.random()*15); //від 0 до 15 let y=cells[i].y+parseInt(Math.random()*15); ctx.putImageData(cells[i].data, x, y); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(x, y, cells[i].w, cells[i].h); }

Додаємо до ефекту нахил під певним кутом.

var img=document.getElementById('image'); var canvas=document.getElementById('test3'); var ctx=canvas.getContext('2d'); canvas.width=img.width; canvas.height=img.height; //ширина квадрата var cellWidth=canvas.width/30; //висота квадрата var cellHeight=canvas.height/30; //замальовуємо полотно на чорний фон ctx.fillStyle='black'; ctx.fillRect(0,0,canvas.width,canvas.height); for(let j=0;j<canvas.height;j+=cellHeight) for(let i=0;i<canvas.width;i+=cellWidth){ if(Math.random()>0.75)continue; let x=i, y=j, w=cellWidth, h=cellHeight; let angle = 0; if(Math.random()>0.5)angle=(Math.random()*10) * Math.PI / 180; //визначаємо випадкове зміщення let px=x+parseInt(Math.random()*15); //від 0 до 15 let py=y+parseInt(Math.random()*15); ctx.save(); ctx.translate(px + w / 2, py + h / 2); // Переміщаємо контекст в центр квадрата ctx.rotate(angle); // Обертання ctx.translate(-w / 2, -h / 2); // Повертаємо контекст назад ctx.drawImage(img, x, y, w, h, 0, 0, w, h); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(0, 0, w, h); ctx.restore(); }

Ефект падаюча мозаїка створюється при створені координат y з від'ємним значенням - піднімаємо вище 0 на випадкове значення формулою Math.random()*200-300.

Кожен квадрат має параметри точки py - початкове знаходження квадрата по осі Y і y - кінцеве знаходження квадрата по осі Y.

Для малювання виконується функція draw() яка викликається циклічно за допомогою requestAnimationFrame() коли хочаб один квадрат потрібно опускати нижче.

Висоту квадрата робимо меншою якщо квадрат високо і збільшуємо по зближені до точки де має знаходитися квадрат.

var img=document.getElementById('image'); var canvas=document.getElementById('test4'); var ctx=canvas.getContext('2d'); var cells=[]; canvas.width=img.width; canvas.height=img.height; //ширина квадрата var cellWidth=canvas.width/30; //висота квадрата var cellHeight=canvas.height/30; for(let j=0;j<canvas.height;j+=cellHeight) for(let i=0;i<canvas.width;i+=cellWidth){ cells.push({x:i, y:j, w:cellWidth, h:cellHeight, py: parseInt(Math.random()*200-300)}); } function draw(){ //замальовуємо полотно на чорний фон ctx.fillStyle='black'; ctx.fillRect(0,0,canvas.width,canvas.height); let c=0; for(let i=0, ph;i<cells.length;i++){ if(cells[i].y!==cells[i].py)c++; cells[i].py+=15; if(cells[i].py>cells[i].y)cells[i].py=cells[i].y; if(cells[i].y==0) ph=cells[i].h; else ph=cells[i].h*(cells[i].py/cells[i].y); ctx.drawImage(img, cells[i].x, cells[i].y, cells[i].w, cells[i].h, cells[i].x, cells[i].py, cells[i].w, ph); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(cells[i].x, cells[i].py, cells[i].w, cells[i].h); } if(c>0)requestAnimationFrame(draw); } draw();

Випадкові злітаючі квадрати мозаїки - полягає у зміненні координат Y у меншу сторону. Що створює ефект злітаючого квадрата.

У змінну drawAnime присвоюємо масив в який додоється індекс комірки до якого необхідно застосувати ефект.

countAnime - кількість комірок до яких одночасно застосовується змінна координат.

Якщо квадрат піднято на висоту вище 0 тоді індекс квадрата додоється до масиву noDrawCells.

При малюванні квадратів якщо в масиві noDrawCells є індекс квадрату то він не малюється, так як він вище 0 позиції Y.

var img=document.getElementById('image'); var canvas=document.getElementById('test5'); var ctx=canvas.getContext('2d'); var cells=[]; canvas.width=img.width; canvas.height=img.height; //ширина квадрата var count=30; //кількість одночасних квадратів для анімацій var countAnime=15; var cellWidth=canvas.width/count; //висота квадрата var cellHeight=canvas.height/count; for(let j=0;j<canvas.height;j+=cellHeight){ //cells.push([]); for(let i=0;i<canvas.width;i+=cellWidth){ cells.push({x:i, y:j, w:cellWidth, h:cellHeight, px:i, py:j}); } } var drawAnime=[parseInt(cells.length*Math.random())]; var noDrawCells=[]; function draw(){ //замальовуємо полотно на чорний фон ctx.fillStyle='black'; ctx.fillRect(0,0,canvas.width,canvas.height); for(let i=0, ph;i<cells.length;i++){ if(noDrawCells.indexOf(i)>-1)continue; ctx.drawImage(img, cells[i].x, cells[i].y, cells[i].w, cells[i].h, cells[i].px, cells[i].py, cells[i].w, cells[i].h); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(cells[i].px, cells[i].py, cells[i].w, cells[i].h); } if(drawAnime.length>0){ for(let i=0;i<drawAnime.length;i++){ cells[drawAnime[i]].px=(Math.random()>0.5 ? cells[drawAnime[i]].px+1 : cells[drawAnime[i]].px-1); cells[drawAnime[i]].py-=5; if(cells[drawAnime[i]].py<0-cellHeight){ drawAnime.splice(i,1); noDrawCells.push(i); } } //setTimeout(draw,25); requestAnimationFrame(draw); } if(drawAnime.length<countAnime){ drawAnime.push(parseInt(cells.length*Math.random())); } } draw();

Ефект при наведені курсора на квадрат мозаїки - робимо квадрат сірим.

У змінну drawEffect присвоюємо масив в який будемо записувати індекс масиву квадратів cells які уже були намальовані сірим кольором - наведено було курсор миші. Це для того щоб не перемальовувати зайвий раз ціле полотно.

При події onmousemove вираховуємо над яким квадратом мозаїки є полотно і застосовуємо сірий ефект за допомогою функції drawGray.

var img=document.getElementById('image'); var canvas=document.getElementById('test6'); var ctx=canvas.getContext('2d'); var cells=[]; canvas.width=img.width; canvas.height=img.height; canvas.onmousemove=function(e){ for(let i=0;i<cells.length;i++){ if(e.offsetY>=cells[i].y && e.offsetY<=cells[i].y+cellHeight){ if(e.offsetX>=cells[i].x && e.offsetX<=cells[i].x+cellWidth){ if( drawEffect.indexOf(i)<0){ drawEffect.push(i); drawGray(i); } break; } } } } //ширина квадрата var count=30; var drawEffect=[]; var cellWidth=canvas.width/count; //висота квадрата var cellHeight=canvas.height/count; ctx.drawImage(img,0,0); for(let j=0;j<canvas.height;j+=cellHeight) for(let i=0;i<canvas.width;i+=cellWidth){ cells.push({x:i, y:j, w:cellWidth, h:cellHeight, imageData:ctx.getImageData(i, j, cellWidth, cellHeight)}); } //замальовуємо полотно на чорний фон ctx.fillStyle='black'; ctx.fillRect(0,0,canvas.width,canvas.height); for(let i=0, ph;i<cells.length;i++){ ctx.putImageData(cells[i].imageData, cells[i].x, cells[i].y); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(cells[i].x, cells[i].y, cells[i].w, cells[i].h); } function drawGray(index){ for(let j=0, r,g,b;j<cells[index].imageData.data.length;j+=4){ r = cells[index].imageData.data[j]; g = cells[index].imageData.data[j+1]; b = cells[index].imageData.data[j+2]; r=g=b=(r+g+b)/3; cells[index].imageData.data[j]=r; cells[index].imageData.data[j+1]=g; cells[index].imageData.data[j+2]=b; } ctx.putImageData(cells[index].imageData, cells[index].x, cells[index].y); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(cells[index].x, cells[index].y, cells[index].w, cells[index].h); }

Випадковий ефект для кожного квадрата мозаїки.

Визначаємо R G B для кожного пікселя і застосовуємо ефекти до пікселя: сірий, noise, сепія, інверсія.

var img=document.getElementById('image'); var canvas=document.getElementById('test7'); var ctx=canvas.getContext('2d'); var cells=[]; canvas.width=img.width; canvas.height=img.height; var cellWidth=canvas.width/30; var cellHeight=canvas.height/30; //малюємо зображення на полотні ctx.drawImage(img,0,0); //створюємо масив квадратів for(let j=0;j<canvas.height;j+=cellHeight) for(let i=0;i<canvas.width;i+=cellWidth){ cells.push({x:i, y:j, w:cellWidth, h:cellHeight, imageData:ctx.getImageData(i, j, cellWidth, cellHeight)}); } //очищаємо canvas - замальовуємо полотно на чорний фон ctx.fillStyle='black'; ctx.fillRect(0, 0, canvas.width, canvas.height); //малюємо кожний квадрат for(let i=0, ef;i<cells.length;i++){ efect=parseInt(Math.random()*5); for(let j=0, r,g,b;j<cells[i].imageData.data.length;j+=4){ r = cells[i].imageData.data[j]; g = cells[i].imageData.data[j+1]; b = cells[i].imageData.data[j+2]; //вибір ефекту switch(efect){ case 0: //сірий r=g=b=(r+g+b)/3; break; case 1: //noise (шум) const noise = (Math.random() - 0.5) * 0.2; r += noise * 255; // Red g += noise * 255; // Green b += noise * 255; // Blue // Затримуємо значення в межах [0, 255] r = Math.max(0, Math.min(255, r)); g = Math.max(0, Math.min(255, g)); b = Math.max(0, Math.min(255, b)); break; case 2: //Сепія r = Math.min(255, 0.393 * r + 0.769 * g + 0.189 * b); // Red g = Math.min(255, 0.349 * r + 0.686 * g + 0.168 * b); // Green b = Math.min(255, 0.272 * r + 0.534 * g + 0.131 * b); // Blue break; case 3: //Інверсія r=255-r; g=255-g; b=255-b; break; default: break; } cells[i].imageData.data[j]=r; cells[i].imageData.data[j+1]=g; cells[i].imageData.data[j+2]=b; } ctx.putImageData(cells[i].imageData, cells[i].x, cells[i].y); //обводимо контур квадрата чорним кольором ctx.strokeStyle='black'; ctx.strokeRect(cells[i].x, cells[i].y, cells[i].w, cells[i].h); }
Адмін 2025-02-21 21:59:26

Тільки зареєстровані користувачі можуть писати коментарі.