image to pixel art converter
A Pen by Gregor Adams on CodePen.
image to pixel art converter
A Pen by Gregor Adams on CodePen.
"use strict"; | |
// requestAnimationFrame() shim by Paul Irish | |
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ | |
window.requestAnimFrame = function () { | |
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function ( /* function */callback, /* DOMElement */element) { | |
window.setTimeout(callback, 1000 / 60); | |
}; | |
}(); | |
/** | |
* Behaves the same as setInterval except uses requestAnimationFrame() where possible for better performance | |
* @param {function} fn The callback function | |
* @param {int} delay The delay in milliseconds | |
*/ | |
window.requestInterval = function (fn, delay) { | |
if (!window.requestAnimationFrame && !window.webkitRequestAnimationFrame && !(window.mozRequestAnimationFrame && window.mozCancelRequestAnimationFrame) && // Firefox 5 ships without cancel support | |
!window.oRequestAnimationFrame && !window.msRequestAnimationFrame) return window.setInterval(fn, delay); | |
var start = new Date().getTime(), | |
handle = new Object(); | |
function loop() { | |
var current = new Date().getTime(), | |
delta = current - start; | |
if (delta >= delay) { | |
fn.call(); | |
start = new Date().getTime(); | |
} | |
handle.value = requestAnimFrame(loop); | |
}; | |
handle.value = requestAnimFrame(loop); | |
return handle; | |
}; | |
/** | |
* Behaves the same as clearInterval except uses cancelRequestAnimationFrame() where possible for better performance | |
* @param {int|object} fn The callback function | |
*/ | |
window.clearRequestInterval = function (handle) { | |
window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) : window.webkitCancelAnimationFrame ? window.webkitCancelAnimationFrame(handle.value) : window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) : /* Support for legacy API */ | |
window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) : window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) : window.msCancelRequestAnimationFrame ? window.msCancelRequestAnimationFrame(handle.value) : clearInterval(handle); | |
}; | |
class Pixel { | |
constructor(props,target){ | |
this.props = props; | |
this.target = target; | |
this.createReader(); | |
this.createInput(); | |
this.generateType = props.type || 'canvas'; | |
this.downScale = props.scale || 32; | |
this.pixelSize = (props.pixel || 1); | |
this.pixelShape = (props.shape || 'square'); | |
this.src(props.src); | |
} | |
createReader(){ | |
this.Reader = document.createElement('canvas'); | |
this.reader = this.Reader.getContext('2d'); | |
} | |
updateReader(){ | |
if (!this.loaded) return; | |
this.Reader.height = this.height; | |
this.Reader.width = this.width; | |
this.reader.drawImage(this.Input,0,0,this.width,this.height); | |
this.getColorArray(); | |
this.draw(); | |
} | |
draw(){ | |
let drawing = this.generateByType(this.generateType); | |
this.target.innerHTML = ''; | |
this.target.appendChild(drawing); | |
} | |
onLoad(e){ | |
this.loaded = true; | |
this.setSize(); | |
this.updateReader(); | |
} | |
createInput(){ | |
this.Input = document.createElement('img'); | |
this.Input.crossOrigin = 'Anonymous'; | |
this.Input.onload = this.onLoad.bind(this); | |
} | |
src(src){ | |
this.loaded = false; | |
this.Input.src = src; | |
} | |
pixel(size){ | |
this.pixelSize = size; | |
this.updateReader(); | |
} | |
type(type){ | |
this.generateType = type; | |
this.updateReader(); | |
} | |
scale(scale){ | |
this.downScale = scale; | |
this.setSize(); | |
this.updateReader(); | |
} | |
shape(shape){ | |
this.pixelShape = shape; | |
this.updateReader(); | |
} | |
resize(scale, pixel) { | |
this.downScale = scale; | |
this.pixelSize = pixel; | |
this.setSize(); | |
this.updateReader(); | |
} | |
setSize(){ | |
this.height = this.Input.height/this.Input.width*this.downScale; | |
this.width = this.downScale; | |
this.Input.height = this.height; | |
this.Input.width = this.width; | |
} | |
getColorArray(){ | |
let data = []; | |
if (this.Reader.height > 0) { | |
data = this.reader.getImageData(0,0,this.width,this.height).data; | |
} | |
let colorArray = []; | |
for (let i = 0; i < data.length; i += 4) { | |
let r = data[i]; | |
let g = data[i + 1]; | |
let b = data[i + 2]; | |
let a = data[i + 3]/255; | |
let rgba = [r,g,b,a].join(','); | |
if (a === 0) { | |
colorArray.push('transparent'); | |
} else { | |
colorArray.push(`rgba(${rgba})`); | |
} | |
} | |
this.colorArray = colorArray; | |
this.generateByType(this.generateType); | |
} | |
drawCanvas(){ | |
let C = document.createElement('canvas'); | |
let $ = C.getContext('2d'); | |
C.height = this.height*this.pixelSize; | |
C.width = this.width*this.pixelSize; | |
let n = -1; | |
for (let i = 0; i < this.colorArray.length; i++ ) { | |
$.fillStyle = this.colorArray[i]; | |
let x = i%this.width; | |
if (x === 0) { | |
++n; | |
} | |
if (this.colorArray[i] !== 'transparent') { | |
let y = n; | |
if (this.pixelShape === 'circle') { | |
$.beginPath(); | |
$.arc((x + .5)*this.pixelSize, (y + .5)*this.pixelSize, this.pixelSize/2, 0, 2 * Math.PI); | |
$.closePath(); | |
$.fill(); | |
} else { | |
$.fillRect(x*this.pixelSize,y*this.pixelSize,this.pixelSize,this.pixelSize); | |
} | |
} | |
} | |
return C; | |
} | |
drawSVG(){ | |
let xmlns = 'http://www.w3.org/2000/svg'; | |
let SVG = document.createElementNS(xmlns,'svg'); | |
SVG.setAttributeNS (null, 'viewBox', `0 0 ${[this.width, this.height].join(' ')}`); | |
SVG.setAttributeNS (null, 'height', this.height*this.pixelSize); | |
SVG.setAttributeNS (null, 'width', this.width*this.pixelSize); | |
let n = -1; | |
for (let i = 0; i < this.colorArray.length; i++ ) { | |
let x = i%this.width; | |
if (x === 0) { | |
++n; | |
} | |
if (this.colorArray[i] !== 'transparent') { | |
let y = n; | |
if (this.pixelShape === 'circle') { | |
let circle = document.createElementNS(xmlns,'circle'); | |
circle.setAttributeNS (null, 'fill', this.colorArray[i]); | |
circle.setAttributeNS (null, 'cx', (x + .5)); | |
circle.setAttributeNS (null, 'cy', (y + .5)); | |
circle.setAttributeNS (null, 'r', .5); | |
SVG.appendChild(circle); | |
} else { | |
let rect = document.createElementNS(xmlns,'rect'); | |
rect.setAttributeNS (null, 'fill', this.colorArray[i]); | |
rect.setAttributeNS (null, 'x', x); | |
rect.setAttributeNS (null, 'y', y); | |
rect.setAttributeNS (null, 'width', 1); | |
rect.setAttributeNS (null, 'height', 1); | |
SVG.appendChild(rect); | |
} | |
} | |
} | |
return SVG; | |
} | |
drawShadow(){ | |
let shadow = []; | |
let S = document.createElement('div'); | |
S.style.margin = `${-1*this.pixelSize}px ${this.width*this.pixelSize}px ${this.height*this.pixelSize}px ${-1*this.pixelSize}px`; | |
S.style.width = `${this.pixelSize}px`; | |
S.style.height = `${this.pixelSize}px`; | |
if (this.pixelShape === 'circle') { | |
S.style.borderRadius = '100%'; | |
} | |
let n = 0; | |
for (let i = 0; i < this.colorArray.length; i++ ) { | |
let x = (i%this.width + 1)*this.pixelSize; | |
if (i%this.width === 0) { | |
++n; | |
} | |
if (this.colorArray[i] !== 'transparent') { | |
let y = n*this.pixelSize; | |
shadow.push(`${x}px ${y}px 0 ${this.colorArray[i]}`) | |
} | |
} | |
S.style.boxShadow = shadow.join(',').replace(/"/g,''); | |
return S; | |
} | |
drawIMG(){ | |
let C = this.drawCanvas(); | |
let I = document.createElement('img'); | |
let dataURL = C.toDataURL('image/png');; | |
I.src = dataURL; | |
return I; | |
} | |
generateByType(type){ | |
if (type === 'canvas') { | |
return this.drawCanvas(); | |
} else if (type === 'svg') { | |
return this.drawSVG(); | |
} else if (type === 'img') { | |
return this.drawIMG(); | |
} else if (type === 'shadow') { | |
return this.drawShadow(); | |
} | |
} | |
} |