ikuaitu / vue-fabric-editor

快图设计-基于fabric.js和Vue的开源图片编辑器,可自定义字体、素材、设计模板。fabric.js and Vue based image editor, can customize fonts, materials, design templates.
https://ikuaitu.github.io/doc/#/
MIT License
4.87k stars 911 forks source link

剪裁:添加自定义图片裁剪功能 #482

Open momo2019 opened 2 months ago

momo2019 commented 2 months ago

修改SimpleClipImagePlugin.ts代码 增加自定义图片裁剪方法

const createCustomClip = (activeObject: fabric.Object, inverted: boolean, url: string) => {
  const { width = 0, height = 0, left = 0, top = 0 } = getBounds(activeObject);
  return new Promise<{ clipPath: fabric.Object; shell: fabric.Object }>((resolve) => {
    const shell = new fabric.Rect({
      fill: 'rgba(0,0,0,0)',
      originX: 'center',
      originY: 'center',
      width,
      height,
      left,
      top,
    });
    bindInfo(shell, activeObject);
    fabric.Image.fromURL(
      url,
      (clipPath) => {
        resolve({ clipPath, shell });
        clipPath.scaleX = width / (clipPath.width || width);
        clipPath.scaleY = height / (clipPath.height || height);
        shell.set({
          width: clipPath.width,
          height: clipPath.height,
          left,
          top,
          scaleX: clipPath.scaleX,
          scaleY: clipPath.scaleY,
        });
      },
      {
        absolutePositioned: true,
        originY: 'center',
        originX: 'center',
        left,
        top,
        inverted,
      }
    );
  });
};

添加switch中添加default

switch (name) {
  case 'polygon':
    clip = createPolygonClip(activeObject, isInverted);
    break;
  case 'rect':
    clip = createRectClip(activeObject, isInverted);
    break;
  case 'circle':
    clip = createCircleClip(activeObject, isInverted);
    break;
  case 'triangle':
    clip = createTriClip(activeObject, isInverted);
    break;
  default:
    clip = await createCustomClip(activeObject, isInverted, name);
    break;
}

取消选择的事件注册中将自定义图片的裁剪的处理方式和Polygon一致

shell.on('deselected', () => {
    if (clipPath instanceof fabric.Ellipse && shell instanceof fabric.Ellipse) {
      clipPath.set({ rx: shell.getRx(), ry: shell.getRy() });
      this.correctPosition(activeObject, shell, clipPath);
    } else if (shell instanceof fabric.Polygon || clipPath instanceof fabric.Image) {
      this.correctPosition(activeObject, shell, clipPath);
      const { scaleX: cSx = 1, scaleY: cSy = 1 } = clipPath;
      const { scaleX: sSx = 1, scaleY: sSy = 1 } = shell;
      clipPath.set('scaleX', cSx * sSx);
      clipPath.set('scaleY', cSy * sSy);
    } else {
      this.correctPosition(activeObject, shell, clipPath);
      clipPath.set('width', shell.getScaledWidth());
      clipPath.set('height', shell.getScaledHeight());
    }
    activeObject.set('dirty', true);
    this.canvas.remove(shell);
    this.canvas.requestRenderAll();
  });

效果视频

自定义图片规则,rgba图,透明值0和透明值大于0的为显示和非显示区域,例如 clip

AliceLanniste commented 1 month ago

要不要提个pr呢