Отключить интерполяцию при масштабировании <canvas> - PullRequest
119 голосов
/ 30 сентября 2011

ПРИМЕЧАНИЕ : это связано с тем, как существующие элементы холста отображаются при увеличении , , а не в зависимости от того, как линииили графика выводится на поверхность холста .Другими словами, это имеет отношение к интерполяции из масштабированных элементов , и не имеет ничего общего с сглаживанием графики, рисуемой на холсте.Меня не интересует, как браузер рисует линии;Меня интересует, как браузер отображает элемент canvas сам при его увеличении.


Есть ли свойство canvas или настройка браузера, которые я могу изменить программно, чтобы отключить интерполяцию при масштабировании <canvas> элементов?Кросс-браузерное решение идеально, но не обязательно;Браузеры на основе Webkit - моя главная цель.Производительность очень важна.

Этот вопрос наиболее похож, но не достаточно иллюстрирует проблему.Что бы это ни стоило, я попытался image-rendering: -webkit-optimize-contrast безрезультатно.

Приложение будет «ретро» 8-битной игрой, написанной на HTML5 + JS, чтобы было понятно, что мне нужно.


Для иллюстрации приведу пример.( живая версия )

Предположим, у меня есть холст 21x21 ...

<canvas id='b' width='21' height='21'></canvas>

... с css, который увеличивает элемент в 5 раз (105x105):

canvas { border: 5px solid #ddd; }
canvas#b { width: 105px; height: 105px; } /* 5 * 21 = 105 */

Я рисую простой крестик на холсте следующим образом:

$('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

Изображение слева - это то, что отображает Chromium (14.0).Изображение справа - это то, что я хочу (нарисовано от руки для иллюстративных целей).

Chrome interpolates scaled canvas elements A non-interpolated version

Ответы [ 5 ]

117 голосов
/ 05 октября 2011

Последнее обновление: 2014-09-12

Есть ли свойство canvas или настройка браузера, которые я могу программно изменить, чтобы отключить интерполяцию при масштабировании элементов?

Ответ может быть, когда-нибудь . Пока вам придется прибегать к хакерским атакам, чтобы получить то, что вы хотите.


image-rendering

Рабочий проект CSS3 обрисовывает в общих чертах новое свойство, image-rendering, которое должно делать то, что я хочу:

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

В спецификации указаны три допустимых значения: auto, crisp-edges и pixelated.

некачественно:

При увеличении изображения необходимо использовать «ближайший сосед» или аналогичный алгоритм, чтобы изображение казалось просто составленным из очень больших пикселей. При уменьшении это то же самое, что и auto.

Стандартный? Кросс-браузер?

Поскольку это всего лишь рабочий проект , нет гарантии, что это станет стандартом. В настоящее время поддержка браузеров в лучшем случае ненадежная.

Mozilla Developer Network имеет довольно подробную страницу, посвященную современному состоянию , которую я настоятельно рекомендую прочитать.

Разработчики Webkit изначально решили предварительно реализовать это как -webkit-optimize-contrast, но Chromium / Chrome, похоже, не использует версию Webkit, которая реализует это.

Обновление: 2014-09-12

Chrome 38 теперь поддерживает image-rendering: pixelated!

У Firefox есть отчет об ошибках , открытый для реализации image-rendering: pixelated, но -moz-crisp-edges пока работает.

Решение

Самое кроссплатформенное решение, предназначенное только для CSS, пока таково:

canvas {
  image-rendering: optimizeSpeed;             /* Older versions of FF          */
  image-rendering: -moz-crisp-edges;          /* FF 6.0+                       */
  image-rendering: -webkit-optimize-contrast; /* Safari                        */
  image-rendering: -o-crisp-edges;            /* OS X & Windows Opera (12.02+) */
  image-rendering: pixelated;                 /* Awesome future-browsers       */
  -ms-interpolation-mode: nearest-neighbor;   /* IE                            */
}

К сожалению, это пока не работает на всех основных платформах HTML5 (в частности, в Chrome).

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

ImpactJS использует технику предварительного масштабирования текстуры, чтобы обойти весь этот FUD. Разработчик Impact, Доминик Сзаблевски, написал очень подробную статью об этом (он даже закончил ссылаться на этот вопрос в своем исследовании).

См. ответ Саймона о решении на основе холста, которое опирается на свойство imageSmoothingEnabled (недоступно в старых браузерах, но проще, чем предварительное масштабирование и довольно широко поддерживается).

Live Demo

Если вы хотите протестировать свойства CSS, обсуждаемые в статье MDN для canvas элементов, я сделал эту скрипку , которая должна отображать что-то вроде этого, размытое или нет, в зависимости от вашего браузер: a 4:1 (64x64 to 256x256) image of an isometric pixel-art style TV

58 голосов
/ 01 августа 2012

Новый ответ 7/31/2012

Это, наконец, в спецификации canvas!

В спецификации недавно добавлено свойство с именем imageSmoothingEnabled, по умолчаниюна true и определяет, будут ли изображения, нарисованные по нецелым координатам или масштабированные, будут использовать более плавный алгоритм.Если он установлен на false, то используется ближайший сосед, создавая менее гладкое изображение и вместо этого просто делая пиксели большего размера.

Сглаживание изображения было добавлено только недавно в спецификацию холста и не поддерживаетсявсеми браузерами, но некоторые браузеры реализовали версии этого свойства с префиксом поставщика.В контексте существует mozImageSmoothingEnabled в Firefox и webkitImageSmoothingEnabled в Chrome и Safari, и установка их в значение false остановит сглаживание.К сожалению, на момент написания статьи IE9 и Opera не реализовали это свойство, с префиксом поставщика или иным образом.


Предварительный просмотр: JSFiddle

Результат:

enter image description here

11 голосов
/ 30 сентября 2011

Изменить 31/31/2012 - эта функциональность теперь в спецификации холста!См. Отдельный ответ здесь:

https://stackoverflow.com/a/11751817/154112

Старый ответ ниже для потомков.


В зависимости от желаемого эффекта, у вас это как единое целоеопция:

var can = document.getElementById('b');
var ctx = can.getContext('2d');
ctx.scale(5,5);
$('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

http://jsfiddle.net/wa95p/

Что создает это:

enter image description here

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

Более сложный вариант - использовать манипуляции с пикселями и самостоятельно написать алгоритм для работы.Каждый пиксель первого изображения становится блоком пикселей 5x5 на новом изображении.Это не будет слишком сложно сделать с imagedata.

Но Canvas и CSS сами по себе не помогут вам масштабировать одно с другим с желаемым эффектом.

4 голосов
/ 03 мая 2012

В Google Chrome шаблоны изображений на холсте не интерполируются.

Вот рабочий пример, отредактированный из ответа namuol http://jsfiddle.net/pGs4f/

ctx.scale(4, 4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, 64, 64);
1 голос
/ 08 октября 2012

Обходной путь Сависки объяснил здесь перспективен, потому что он работает на:

  • Chrome 22.0.1229.79 Mac OS X 10.6.8
  • Chrome 22.0.1229.79 м Windows 7
  • Chromium 18.0.1025.168 (Developer Build 134367 Linux) Ubuntu 11.10
  • Firefox 3.6.25 Windows 7

Но неработает в следующем, но тот же эффект может быть достигнут с помощью CSS-рендеринга:

  • Firefox 15.0.1 Mac OS X 10.6.8 (рендеринг изображения: -moz-crisp -dge работает в this )
  • Opera 12.02 Mac OS X 10.6.8 (рендеринг изображений: -o-crisp-edge работает в this )
  • Opera12.02 Windows 7 (рендеринг изображений: -o-crisp-edge работает в this )

Проблема в том, что ctx.XXXImageSmoothingEnabled не работает, а рендеринг изображений -не работает:

  • Safari 5.1.7 Mac OS X 10.6.8.(рендеринг изображений: -webkit-optimize-контраст НЕ работает)
  • Safari 5.1.7 Windows 7 (рендеринг изображений: -webkit-optimize-контраст НЕ работает)
  • IE 9 Windows 7(-ms-interpolation-mode: ближайший сосед НЕ работает)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...