javascript - Pixel perfect scaling of images while zooming the canvas with fabric.js -
my software kind of pixel art paint program brushes, fabric.js heavily modified in order have pixel rounded translation (the position integer) fabric.js objects, resizing images , making pixels fit canvas in 1:1 ratio still issue.
right now, fabric.js zoomtopoint
function used able zoom on canvas mouse wheel, when images aren't scaled, pixels fit canvas when scale objects down (or up), pixels not fit anymore canvas pixels of object smaller or bigger canvas pixel.
screenshots of problem zoom level of 8 :
original image dimensions (no problems, each pixels fit canvas pixels)
resized image, pixels of image not fit canvas pixels anymore
how can pixels of images fit canvas pixels in 1:1 ratio when scaling them?
by nature, resizing involves resampling original image , interpolating/convoluting existing pixels resized space. resulting image meant visually appealing @ new size. image resized x
, resulting pixels not have x:1 relationship anymore.
to zoom-in need "projection" each single 1x1 pixel expanded 2x2 pixel group (or 3x3 pixel group, etc).
to zoom-out need "projection" each 2x2 pixel group condensed single 1x1 pixel set.
to zoom-out, source (before scaling) must made of pixel groups. means cannot zoom-out image below original size without using resampling. there no projection available zoom-out below 1x. workaround have user draw @ 2x (or 3x or 4x) projection can zoom-out.
fabricjs not projections natively...you'll have use temporary canvas element projections.
here's example code zoom using projections:
var zoom=2; var img=new image(); img.crossorigin='anonymous'; img.onload=start; //img.src="sun.png"; img.src="https://dl.dropboxusercontent.com/u/139992952/multple/sun.png"; function start(){ var iw=img.width; var ih=img.height; img.width=iw; img.height=ih; // set "current zoom factor" on original image 1x img.zoom=1; // test: resize 4x var zoom4x=resize(img,4,'canvas4x'); document.body.appendchild(zoom4x); // test: resize 4x down 2x var zoom2x=resize(zoom4x,0.50,'canvas2x'); document.body.appendchild(zoom2x); // test: resize 2x down 1x var zoom1x=resize(zoom2x,0.50,'canvas1x'); document.body.appendchild(zoom1x); // test: resize 1x down half-size var zoomhx=resize(zoom1x,0.50,'canvas1x'); if(zoomhx){document.body.appendchild(zoomhx)}; // display original image document.body.appendchild(img); } var resize = function(img,scale,id){ var zoom=parseint(img.zoom*scale); if(zoom<1){ console.log('cannot recale image less original size'); return; } // pixels original img using canvas var c1=document.createelement('canvas'); var cw1=c1.width=img.width; var ch1=c1.height=img.height; var ctx1=c1.getcontext('2d'); ctx1.drawimage(img,0,0); var imgdata1=ctx1.getimagedata(0,0,cw1,ch1); var data1=imgdata1.data; // create canvas hold resized pixels var c2=document.createelement('canvas'); c2.id=id; c2.zoom=zoom; var cw2=c2.width=cw1*scale; var ch2=c2.height=ch1*scale; var ctx2=c2.getcontext('2d'); var imgdata2=ctx2.getimagedata(0,0,cw2,ch2); var data2=imgdata2.data; // copy each source pixel c1's data1 c2's data2 for(var y=0; y<ch2; y++) { for(var x=0; x<cw2; x++) { var i1=(math.floor(y/scale)*cw1+math.floor(x/scale))*4; var i2 =(y*cw2+x)*4; data2[i2] = data1[i1]; data2[i2+1] = data1[i1+1]; data2[i2+2] = data1[i1+2]; data2[i2+3] = data1[i1+3]; } } // put modified pixels onto c2 ctx2.putimagedata(imgdata2,0,0); // return canvas zoomed pixels return(c2); }
body{ background-color: ivory; } canvas{border:1px solid red;}
<h4>left: 4x, 2x, 1x projections, right:original image</h4>
Comments
Post a Comment