问题
My software is a kind of pixel art paint program with brushes, fabric.js was heavily modified in order to have pixel rounded translation (the position is always an integer) for the fabric.js objects, however resizing images and making their pixels fit the canvas in a 1:1 ratio is still an issue.
Right now, the fabric.js zoomToPoint
function is used to be able to zoom on the canvas with the mouse wheel, when images aren't scaled, their pixels fit with the canvas but when i scale any objects down (or up), pixels does not fit anymore with the canvas so the pixels of the object are actually smaller or bigger than the canvas pixel.
Screenshots of the problem with a zoom level of 8 :
Original image dimensions (no problems, each pixels fit the canvas pixels)

Resized image, pixels of the image does not fit the canvas pixels anymore

How can the pixels of the images fit the canvas pixels in a 1:1 ratio when scaling them?
回答1:
By its nature, resizing involves resampling the original image and interpolating/convoluting the existing pixels into the resized space. The resulting image is meant to be visually appealing at its new size. But for an image resized by X
, the resulting pixels certainly do not have an X:1 relationship anymore.
To zoom-in you need a "projection" where each single 1x1 pixel is expanded into a 2x2 pixel group (or a 3x3 pixel group, etc).
To zoom-out you need a "projection" where each 2x2 pixel group is condensed into a single 1x1 pixel set.
To zoom-out, the source (before scaling) must be made up of pixel groups. This means that you cannot zoom-out an image below its original size without using resampling. There is no projection available to zoom-out below 1X. A workaround is to have the user draw at 2X (or 3X or 4X) projection so you can zoom-out.
FabricJS does not do projections natively...You'll have to use a temporary canvas element to do projections.
Here's example code to 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 the "current zoom factor" on the original image to 1x
img.zoom=1;
// test: resize by 4X
var zoom4x=resize(img,4,'canvas4x');
document.body.appendChild(zoom4x);
// test: resize the 4X back down to 2X
var zoom2x=resize(zoom4x,0.50,'canvas2x');
document.body.appendChild(zoom2x);
// test: resize the 2X back down to 1X
var zoom1x=resize(zoom2x,0.50,'canvas1x');
document.body.appendChild(zoom1x);
// test: resize the 1X down to half-size
var zoomHx=resize(zoom1x,0.50,'canvas1x');
if(zoomHx){document.body.appendChild(zoomHx)};
// display the 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 to less than original size');
return;
}
// get the pixels from the original img using a 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 a canvas to hold the 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 from c1's data1 into the 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 the modified pixels back onto c2
ctx2.putImageData(imgData2,0,0);
// return the canvas with the zoomed pixels
return(c2);
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>Left: 4X, 2X, 1X projections, Right:Original Image</h4>
来源:https://stackoverflow.com/questions/29633200/pixel-perfect-scaling-of-images-while-zooming-the-canvas-with-fabric-js