Задача: сделать инструмент, с помощью которого юзер может обрезать свое изображение по определнной маске.
Например, есть вот такая рамка:

Юзер может перетягивать свое изображение под этой маской, менять его размер и по нажатии на кнопку, все, что внутри фигуры сохраняется в .png файл.

Я буду использовать библиотеку для работы с html5 canvas fabric.js. Ничего более простого я придумать не смог.
Маска должна быть в .svg, вот, например, моя.
Создаем два canvas: один статичный (маска то не изменяемая), второй нет (на нем будет фото). Pointer-events мы используем для того, что статичный canvas будет находится над другим (фото должно быть под маской), но pointer-events должны быть только у нижнего.

1
2
3
4
5
6
<div class="photo-canvas">
    <canvas id="photo-canvas"></canvas>
</div>
<div class="photo-canvas" style="pointer-events: none;">
    <canvas id="static-photo-canvas"></canvas>
</div>

1
2
3
4
5
.photo-canvas {
  width: 500px;
  height: 500px;
  position: absolute;
}

Подключаем fabric.js и пишем js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Создаем холсты
photoCanvas = new fabric.Canvas('photo-canvas');
staticPhotoCanvas = new fabric.StaticCanvas('static-photo-canvas');

// Задаем их размеры
photoCanvas.setHeight($('.photo-canvas').height());
photoCanvas.setWidth($('.photo-canvas').width());
staticPhotoCanvas.setHeight($('.photo-canvas').height());
staticPhotoCanvas.setWidth($('.photo-canvas').width());

// Загружаем маску на статичный холст и устанавливаем ее по центру холста
fabric.loadSVGFromURL('/assets/first.svg', function(objects, options) {
  var mask = fabric.util.groupSVGElements(objects, options);
  staticPhotoCanvas.add(mask);
  mask.center().setCoords();
  staticPhotoCanvas.renderAll();
});

// Загружаем изображение на динамический холст, задаем высота и устанавливаем ее по центру
fabric.Image.fromURL('/assets/Cat.jpg', function(img) {
  img.scaleToHeight(500);
  photoCanvas.add(img);
  img.center().setCoords();
  photoCanvas.renderAll();
});

Мы добавили нашу маску на статичный canvas, и изображение – на динамический. Теперь код кнопки “Обрезать”:

1
2
3
4
5
6
7
8
9
10
$('#crop-button').click(function(event) {
  // Обрезаем холст
  photoCanvas.clipTo = function (ctx) {
           staticPhotoCanvas.item(0).render(ctx);
  };
  photoCanvas.renderAll();

  // Сохраняем .png файл в переменную
  var dataUrl = photoCanvas.toDataURL('png');
});

То есть мы обрезали наш canvas с фотографией по контору векторной маски и сохранили его в png файл, который хранится в переменной dataUrl.
Результат работ:

P.S. Если нужно создать canvas в модальном окне Bootstrap 3, то лучше создавать холст на событии ‘shown.bs.modal’. Иначе он не будет принимать pointer events.

Комментарии