Можно ли отключить сглаживание для элемента HTML <canvas>? - PullRequest
74 голосов
/ 12 октября 2008

Я играю с элементом <canvas>, рисуем линии и тому подобное.

Я заметил, что мои диагональные линии сглажены. Я бы предпочел зазубренный взгляд на то, что я делаю - есть ли способ отключить эту функцию?

Ответы [ 9 ]

58 голосов
/ 19 июля 2010

Нарисуйте 1-pixel линии по координатам, как ctx.lineTo(10.5, 10.5). Рисование однопиксельной линии над точкой (10, 10) означает, что этот 1 пиксель в этой позиции достигает значения от 9.5 до 10.5, что приводит к двум линиям, нарисованным на холсте.

Хорошая уловка - не всегда нужно добавлять 0.5 к фактической координате, которую вы хотите нарисовать, если у вас много однопиксельных линий, это ctx.translate(0.5, 0.5) весь ваш холст в начале.

47 голосов
/ 12 октября 2008

Для изображений теперь есть context.imageSmoothingEnabled= false.

Однако нет ничего, что явно контролирует рисование линий. Возможно, вам понадобится нарисовать ваши собственные линии ( трудный путь ), используя getImageData и putImageData.

24 голосов
/ 15 апреля 2011

Это можно сделать в Mozilla Firefox. Добавьте это к своему коду:

contextXYZ.mozImageSmoothingEnabled = false;

В Opera в настоящее время это запрос функции, но, надеюсь, он будет добавлен в ближайшее время.

9 голосов
/ 10 января 2017

Это должно сглаживать векторную графику

Сглаживание требуется для правильного построения векторной графики, которая включает нецелые координаты (0,4, 0,4), что будут делать все, кроме очень немногих клиентов.

Когда заданы нецелые координаты, холст имеет две опции:

  • Antialias - закрасить пиксели вокруг координаты относительно расстояния от целочисленной координаты до нецелой (ошибка округления).
  • Round - применить некоторую функцию округления к нецелочисленной координате (например, 1,4 станет 1).

Более поздняя стратегия будет работать для статической графики, хотя для небольшой графики (круг с радиусом 2) кривые будут показывать четкие шаги, а не плавную кривую.

Настоящая проблема заключается в том, что графика переводится (перемещается) - скачки между одним пикселем и другим (1.6 => 2, 1.4 => 1) означают, что начало фигуры может перескакивать относительно родительского контейнера. (постоянно смещается на 1 пиксель вверх / вниз и влево / вправо).

Некоторые советы

Совет № 1 : Вы можете смягчить (или укрепить) сглаживание, масштабируя холст (скажем, по x), а затем примените обратную шкалу (1 / x) к геометрии самостоятельно (не используя холст). .

Сравнить (без масштабирования):

A few rectangles

с (масштаб холста: 0,75; ручная шкала: 1,33):

Same rectangles with softer edges

и (масштаб холста: 1,33; ручной масштаб: 0,75):

Same rectangles with darker edges

Совет № 2 : Если неровный вид действительно то, что вам нужно, попробуйте нарисовать каждую фигуру несколько раз (без стирания). С каждым рисованием пиксели сглаживания становятся темнее.

Сравнить. После рисования один раз:

A few paths

После рисования трижды:

Same paths but darker and no visible antialiasing.

8 голосов
/ 21 марта 2014

Я бы нарисовал все, используя собственный алгоритм линий, такой как алгоритм линий Брезенхэма. Проверьте эту реализацию JavaScript: http://members.chello.at/easyfilter/canvas.html

Я думаю, это определенно решит твои проблемы.

6 голосов
/ 26 сентября 2015

Хочу добавить, что у меня возникли проблемы при уменьшении размера изображения и рисовании на холсте, он все еще использовал сглаживание, хотя и не использовал его при увеличении масштаба.

Я решил использовать это:

function setpixelated(context){
    context['imageSmoothingEnabled'] = false;       /* standard */
    context['mozImageSmoothingEnabled'] = false;    /* Firefox */
    context['oImageSmoothingEnabled'] = false;      /* Opera */
    context['webkitImageSmoothingEnabled'] = false; /* Safari */
    context['msImageSmoothingEnabled'] = false;     /* IE */
}

Вы можете использовать эту функцию следующим образом:

var canvas = document.getElementById('mycanvas')
setpixelated(canvas.getContext('2d'))

Может быть, это кому-нибудь пригодится.

5 голосов
/ 30 марта 2014
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5;

С помощью этого комбо я могу рисовать тонкие линии размером 1 пиксель.

4 голосов
/ 02 октября 2017

Обратите внимание на очень ограниченный трюк. Если вы хотите создать изображение в 2 цвета, вы можете нарисовать любую фигуру с цветом # 010101 на фоне с цветом # 000000. Как только это будет сделано, вы можете протестировать каждый пиксель в imageData.data [] и установить 0xFF независимо от значения 0x00:

imageData = context2d.getImageData (0, 0, g.width, g.height);
for (i = 0; i != imageData.data.length; i ++) {
    if (imageData.data[i] != 0x00)
        imageData.data[i] = 0xFF;
}
context2d.putImageData (imageData, 0, 0);

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

0 голосов
/ 22 октября 2018

Всего два примечания к ответу StashOfCode:

  1. Работает только для непрозрачного холста в оттенках серого (fillRect белым, затем рисование черным или наоборот)
  2. Это может произойти сбой, если линии тонкие (ширина линии ~ 1px)

Лучше сделать это вместо:

Ударьте и заполните #FFFFFF, затем сделайте следующее:

imageData.data[i] = (imageData.data[i] >> 7) * 0xFF

Это решает проблему для линий шириной 1px.

Помимо этого, решение StashOfCode является идеальным, поскольку не требует написания собственных функций растеризации (например, не только линий, но и безеров, дуг окружностей, заполненных многоугольников с отверстиями и т. Д.)

...