使用 fabricjs 创建重复图像模式

Create a repetitive image pattern using fabricjs

正如标题所说,我正在尝试通过在我的 canvas 元素中重复相同的图像来创建平铺图案。

这是我目前尝试过的方法:<canvas id='c' width='345' height='345'></canvas>

let canvas = new fabric.Canvas('c',{backgroundColor: "#fff"});
const logo = 'https://www.logomaker.com/wpstatic/uploads/2018/11/bakerylogo2.png';
canvas.add(
        new fabric.Line([7,10,17,10],{
            fill: "grey",
            stroke: "grey",
            strokeWidth: 3           
        }),
        new fabric.Line([10,10,10,150],{
            fill: "grey",
            stroke: "grey",
            strokeWidth: 3
        }),
        new fabric.IText("500mm",{
            left: 20,
            top: 152,
            fill: "grey",
            stroke: "grey",
            fontSize: 10,
            angle: 90
        }),
        new fabric.Line([10, 190, 10, 315], {
            fill: "grey",
            stroke: "grey",
            strokeWidth: 3
        }),
        new fabric.Line([7,315,17,315],{
            fill: "grey",
            stroke: "grey",
            strokeWidth: 3           
        }),
        new fabric.Line([30,333,30,320],{
            fill: "grey",
            stroke: "grey",
            strokeWidth: 3           
        }),
        new fabric.Line([30,325,150,325],{
            fill: "grey",
            stroke: "grey",
            strokeWidth: 3           
        }),
        new fabric.IText("380mm",{
            left: 152,
            top: 320,
            fill: "grey",
            stroke: "grey",
            fontSize: 10,
        }),
        new fabric.Line([187,325,310,325],{
            fill: "grey",
            stroke: "grey",
            strokeWidth: 3           
        }),
        new fabric.Line([310,333,310,320],{
            fill: "grey",
            stroke: "grey",
            strokeWidth: 3           
        }),
    )
    fabric.Image.fromURL(logo, function(img) {
        var oImg = img.set({
            left: 40,
            top: 40,
            angle: 310
        }).scale(0.1);
        canvas.add(oImg);
    })
    canvas.renderTop();

,但现在卡住了。

这里有一个 jsfiddle,如果它有助于更​​快地可视化问题:https://jsfiddle.net/1fevg8dc/3/

任何正确方向的帮助都会对我有很大帮助,因为我真的很难理解 fabricjs 的文档。

我的最终目标是在图像(声明为徽标)上应用灰度滤镜并将图像旋转 45 度,并在我

的线条内创建图案

作为 fabric.js 背景的平铺重复图案实际上并不难做到。但是,您的问题是您希望它成一定角度并应用灰度滤镜。

无论如何,首先我们需要创建一个 canvas.js Shape 对象 - 这将作为我们的背景,因此需要覆盖整个视口。

let shape = new fabric.Rect({
    width: canvas.width,
    height: canvas.height,
    left: 0,
    top: 0,
    selectable: false
});

不过我们还没有将它添加到舞台上。因为我们想用图像填充形状,所以我们需要先加载它。对于此任务,我们使用 Image 对象的 .fromURL() 方法。

fabric.Image.fromURL("https://corsanywhere.herokuapp.com/https://www.logomaker.com/wpstatic/uploads/2018/11/bakerylogo2.png", function(img) {}, {crossOrigin: 'anonymous'})

在空回调函数中 - function(img) {} - 必须发生以下情况:

  • 将图像转换为灰度
  • 使用此图像作为形状的填充
  • 旋转填充,例如45°

第一步是使用 fabric.js built-in 过滤器

img.filters.push(new fabric.Image.filters.Grayscale());
img.applyFilters();

第二步涉及创建一个 Pattern 对象,然后将其应用于 Shape 对象。

最后一步是棘手的​​部分。填充没有旋转 属性。相反,它使用 patternTransform 属性 通过变换矩阵进行变换。此 patternTransform 是一个包含 6 个值的数组,用于控制位置、缩放和倾斜。对于 45 度旋转,它必须是这样的:

let angle = -45 * Math.PI / 180;
let transformMatrix=[Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0, 0];

让我们详细说明一下变换矩阵。正如我所说,它包含六个值。如果我们给 那些有意义的名字看起来有点像这样:

matrix= [scaleX, skewY, skewX, scaleY, translateX, translateY];

我们可以看到没有控制旋转的值。那是因为在矩阵中,旋转 是倾斜和缩放的组合。如果我们回顾一下自己的转变:

let transformMatrix = [Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0, 0];

确实是 scaleXskewYskewXscaleY 属性被填充。

如果我们要改变矩阵的比例,我们需要改变的是 scaleXscaleY 特性。然而,在这种情况下,它有点不同,因为我们已经应用了旋转。幸运的是 这并不难。刻度本身是一个十进制数,其中1表示不变,2是双刻度 例如,0.5 是比例的一半。所以如果我们想把图案变成原来大小的一半,我们 需要将 scaleX、skewY、skewX 和 scaleY 乘以 0.5。

let angle = -45 * Math.PI / 180;
let scale = 0.5;
let transformMatrix = [Math.cos(angle) * scale, Math.sin(angle) * scale, -Math.sin(angle) * scale, Math.cos(angle) * scale, 0, 0];

现在,如果我们将所有内容放在一起,我们将得出以下结果:

let canvas = this.__canvas = new fabric.Canvas('c');

let shape = new fabric.Rect({
  width: canvas.width,
  height: canvas.height,
  left: 0,
  top: 0,
  selectable: false
});

fabric.Image.fromURL("https://corsanywhere.herokuapp.com/https://www.logomaker.com/wpstatic/uploads/2018/11/bakerylogo2.png", function(img) {
  img.filters.push(new fabric.Image.filters.Grayscale());
  img.applyFilters();

  let angle = -45 * Math.PI / 180;
  let scale = 0.5;
  shape.set('fill', new fabric.Pattern({
    source: img._element,
    repeat: 'repeat',
    patternTransform: [Math.cos(angle) * scale, Math.sin(angle) * scale, -Math.sin(angle) * scale, Math.cos(angle) * scale, 0, 0]
  }));

  canvas.add(shape);
  canvas.renderAll();

}, {
  crossOrigin: 'anonymous'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/500/fabric.min.js" integrity="sha512-ft2xOUYF7h2UeYQUbol4GJHrkGPVrgimINEYwLI23hyxN1JIy6EEj2vEc8RWWIIExvUKZvYq3oJTDrbif2oSVw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<canvas id="c" width="800" height="600" style="border:1px solid #ccc"></canvas>