使用fabric.js缩放画布时,像素完美缩放图像

时间:2015-04-14 16:58:15

标签: javascript html5 fabricjs

我的软件是一种带有画笔的像素艺术绘画程序,fabric.js经过大量修改,以便为fabric.js对象进行像素舍入平移(位置始终为整数),但是调整图像大小并使其成为可能。像素以1:1的比例适合画布仍然是一个问题。

现在,fabric.js zoomToPoint函数用于能够使用鼠标滚轮在画布上放大,当图像没有缩放时,它们的像素与画布匹配但是当我缩放任何对象时向下(或向上),像素不再适合画布,因此对象的像素实际上小于或大于画布像素。

缩放级别为8的问题的屏幕截图:

原始图像尺寸(没有问题,每个像素都适合画布像素)

Original Image

调整大小的图像,图像的像素不再适合画布像素

Resized Image

当缩放它们时,图像的像素如何以1:1的比例拟合画布像素?

1 个答案:

答案 0 :(得分:2)

就其本质而言,调整大小涉及重新采样原始图像并将现有像素插值/卷积到调整大小的空间中。生成的图像在其新尺寸上具有视觉吸引力。但对于X调整大小的图像,结果像素肯定不再具有X:1关系。

要放大,您需要一个“投影”,其中每个单个1x1像素扩展为2x2像素组(或3x3像素组等)。

要缩小,您需要一个“投影”,其中每个2x2像素组会聚为一个1x1像素集。

要缩小,源(缩放前)必须由像素组组成。这意味着您无法在不使用重新取样的情况下将图像缩小到原始尺寸以下。没有可用于缩小1X以下的投影。解决方法是让用户以2X(或3X或4X)投影进行绘制,以便缩小。

FabricJS本身不进行投影...您必须使用临时画布元素进行投影。

以下是使用投影进行缩放的示例代码:

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 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>