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)

original image

resized image, pixels of image not fit canvas pixels anymore

resized image

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:

enter image description here

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

Popular posts from this blog

css - SVG using textPath a symbol not rendering in Firefox -

Java 8 + Maven Javadoc plugin: Error fetching URL -

node.js - How to abort query on demand using Neo4j drivers -