绘制Circle Jimp JavaScript

时间:2019-01-14 01:57:22

标签: javascript algorithm geometry

我正在尝试使用Jimp在JavaScript中使用以下代码绘制一个圆圈。

const Jimp = require("jimp");

const size = 500;
const black = [0, 0, 0, 255];
const white = [255, 255, 255, 255];
new Jimp(size, size, (err, image) => {
    for (let x = 0; x < size; x++) {
        for (let y = 0; y < size; y++) {
            const colorToUse = distanceFromCenter(size, x, y) > size / 2 ? black : white;
            const color = Jimp.rgbaToInt(...colorToUse);
            image.setPixelColor(color, x, y);
        }
    }
    image.write("circle.png");
});

它产生了这个。

Circle

问题是,当您放大时,它看起来非常不稳定。

Circle Zoomed

如何使圆更平滑,不那么起伏?

2 个答案:

答案 0 :(得分:1)

您需要创建anti-aliasing。通过简单地根据每个像素到中心的浮动距离来控制每个像素的灰度级别,即可轻松实现黑白效果。

例如,在您的设置中,距离为250的像素应为黑色,而距离为250.5的像素应为灰色(〜#808080)。 因此,您要做的就是考虑这些浮点数。

这里是使用Canvas2D API的示例,但核心逻辑直接适用于您的代码。

const size = 500;
const rad = size / 2;
const black = 0xFF000000; //[0, 0, 0, 255];
const white = 0xFFFFFFFF; //[255, 255, 255, 255];

const img = new ImageData(size, size);
const data = new Uint32Array(img.data.buffer);

for (let x = 0; x < size; x++) {
  for (let y = 0; y < size; y++) {
    const dist = distanceFromCenter(rad, x, y);
    let color;
    if (dist >= rad + 1) color = black;
    else if (dist <= rad) color = white;
    else {
      const mult = (255 - Math.floor((dist - rad) * 255)).toString(16).padStart(2, 0);
      color = '0xff' + mult.repeat(3); // grayscale 0xffnnnnnn
    }
    // image.setPixelColor(color, x, y);
    data[(y * size) + x] = Number(color);
  }
}
//image.write("circle.png");
c.getContext('2d').putImageData(img, 0, 0);


function distanceFromCenter(rad, x, y) {
  return Math.hypot(rad - x, rad - y);
}
<canvas id="c" width="500" height="500"></canvas>

答案 1 :(得分:0)

很抱歉,我这么说,但答案是您真的做不到。问题在于像素是可以绘制的最小单位,您必须绘制或不绘制。因此,只要使用一些raster image format(而不是vector graphics),就无法以大的缩放率绘制平滑的线条。

如果您考虑一下,则可能将问题归咎于不了解图像逻辑(圆圈)的缩放应用程序,并将每个像素映射到许多整个像素。换句话说,您的图像仅包含500x500像素的信息。您无法从中可靠地建立5,000x5,000像素的信息(实际上就是10倍缩放),因为原始图像中没有足够的信息。因此,您(或进行缩放的任何人)都必须猜测如何填充丢失的信息,而这种“斩波”是最简单(也是使用最广泛的)猜测算法的结果:只需将每个像素映射到{{1} }个像素,其中NxN是缩放因子。

有三种可能的解决方法:

  1. 绘制更大的图像,因此您无需首先缩放图像(但它到处都会占用更多空间)

  2. 使用一些矢量图形,例如SVG(但是您必须更改库,最终可能不是您想要的,因为这样做还有其他问题)

  3. 尝试使用anti-aliasing,这是一个巧妙的技巧,可以用来颠覆人类的视线:您在边缘周围绘制了一些像素,以灰色而不是黑白的方式绘制。在较小的变焦下看起来会更好,但在足够大的变焦下,您仍然会看到实际的细节,魔术将停止工作。