Вимкнути інтерполяцію, коли масштабувати <canvas>


126

ПРИМІТКА . Це пов'язано з тим, як відображаються наявні елементи полотна при масштабуванні , а не з тим, як лінії чи графіки відображаються на поверхні полотна . Іншими словами, це є всещоб зробити з інтерполяцією з масштабованих елементів , і нічого спільного з згладжуванням графічної втягується на полотні. Мене не хвилює те, як браузер малює лінії; Мене хвилює те, як браузер відображає сам елемент полотна , коли його масштабують.


Чи є властивість полотна чи налаштування браузера, який я можу змінити програмно, щоб відключити інтерполяцію при масштабуванні <canvas>елементів? Рішення крос-браузера ідеально, але не є істотним; Мої основні цілі - веб-браузери. Продуктивність дуже важлива.

Це питання є найбільш подібним, але недостатньо ілюструє проблему. Що варто, я намагався 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 */

Я малюю простий X на полотні так:

$('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). Зображення праворуч - це те, що я хочу (намальовано вручну для ілюстративних цілей).

Хром інтерполює масштабовані елементи полотна Неінтерпольована версія


1
Кілька пов'язаних, хоча і не ідентичні: stackoverflow.com/questions/195262 / ...
HostileFork говорить не довіряю SE

1
Я вважаю, що питання стосується функцій малювання ліній, що малюють антиалійні лінії. Я маю на увазі те, як розміри елементів полотна відображаються за допомогою інтерполяції за замовчуванням.
namuol

Так, вибачте ... Спочатку я подумав, що питання те саме, а потім відразу помітив мою помилку. : - / Що робити, якщо ви спробували використати піксельний фільтр jsmanipulate? joelb.me/jsmanipulate
HostileFork каже, що не довіряти SE

1
Це більше фільтра зображень, призначеного для фотографій.
namuol

Так, але якщо воно перетворить ваше ліве зображення на достатньо хороший варіант правого зображення, щоб зробити вас щасливими, то це може забезпечити крос-браузерне рішення (враховуючи, що це не дуже перспективно знайти прапор для цього режиму малювання, універсальний чи іншим способом , у WebKit). Чи це життєздатний замінник, залежить від проблеми, яку ви намагаєтеся вирішити ... якщо вам дійсно потрібен дискретний малюнок пікселів або ви просто намагаєтеся переконатися, що результат пікселюється з певною детальністю.
HostileFork каже, що не довіряти SE

Відповіді:


126

Останнє оновлення: 12.09.2014

Чи є властивість полотна чи налаштування браузера, який я можу змінити програмно, щоб відключити інтерполяцію при масштабуванні елементів?

Відповідь, можливо, якийсь день . Поки що вам доведеться вдаватися до хак-аренду, щоб отримати те, що ви хочете.


image-rendering

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

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

Специфікація описує одне з наступних значень: auto, crisp-edges, і pixelated.

пікселізований:

Під час масштабування зображення вгору необхідно використовувати "найближчий сусід" або подібний алгоритм, щоб зображення було просто складено з дуже великих пікселів. Якщо зменшити масштаб, це те саме, що і авто.

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

Оскільки це лише робочий проект , немає гарантії, що це стане стандартним. Підтримка веб-переглядача наразі плямиста, в кращому випадку.

Мережа розробників Mozilla має досить ретельну сторінку, присвячену сучасній сучасності, яку я дуже рекомендую прочитати.

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

Оновлення: 2014-09-12

Зараз підтримується Chrome 38image-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властивість (недоступно у старих браузерах, але простіше, ніж попереднє масштабування та досить широко підтримується).

Демонстраційна демонстрація

Якщо ви хочете перевірити властивості CSS, обговорені в статті MDN щодо canvasелементів, я зробив цю загадку, яка повинна відображати щось подібне, розмите чи ні, залежно від вашого браузера: зображення 4: 1 (64x64 до 256x256) ізометричного телевізора в стилі пікселя


Відображення зображень, здається, працює і в інших місцях, але веб-браузери. Я дуже сподіваюся, що персонал Chrome / Chromium / Safari добре читає, що означає «перехід на інтерполяцію EPX у ситуаціях з низьким навантаженням». Коли я вперше прочитав речення, я подумав, що оптимізація-контраст дозволяє створювати нові кольори з низьким навантаженням, але НІ: en.wikipedia.org/wiki/…
Тимо Кяхьонен

2
Opera 12.02 на Mac і Windows підтримує візуалізацію зображень: -o-crisp- edge ( jsfiddle.net/VAXrL/21 ), щоб ви могли додати це у своїй відповіді.
Тімо Кехьонен

Це повинно працювати, коли я збільшую масштаб браузера? Я протестував малюнок за допомогою FF 22, Chrome 27 та IE 10 для Windows 7, коли масштаб браузера становить 150%, а результат розмитий у всіх браузерах. Коли я подвоюю ширину та висоту полотна та повертаю його до початкової ширини та висоти за допомогою CSS, він малює гострі лінії.
пабло

Це гарне запитання. Я не впевнений, чи є специфікація для визначеної користувачем поведінки масштабування.
namuol

1
Я (з теперішнього майбутнього!) На Chrome 78. Я бачу "рендеринг зображень: пікселізований"; робочий. Схоже, це було додано у 2015 році до Chrome 41: developers.google.com/web/updates/2015/01/pixelated
MrColes

61

Нова відповідь 31.07.2012

Це нарешті в полотні специфікації!

Нещодавно у специфікацію додано властивість під назвою imageSmoothingEnabled, яка за замовчуванням trueвизначає, чи використовуватимуться зображення, намальовані на нецілочисельних координатах або намальовані масштабовані, використовувати більш плавний алгоритм. Якщо він встановлений на falseнайближчий сусід, то використовується менш гладке зображення і замість того, щоб просто зробити більш пікселі більшого розміру.

Згладжування зображень лише нещодавно було додано до специфікації полотна і підтримується не всіма браузерами, проте деякі браузери реалізували версії цієї властивості, встановлені для постачальників. У контексті існує mozImageSmoothingEnabledFirefox, webkitImageSmoothingEnabledChrome і Safari, і якщо встановити їх на значення false, це не призведе до появи антиалізингу. На жаль, під час написання IE9 та Opera не реалізували цю властивість, префікс постачальника чи іншим способом.


Попередній перегляд: JSFiddle

Результат:

введіть тут опис зображення


1
На жаль, схоже, що це ще не працює. Можливо, мені чогось не вистачає? Ось тест: jsfiddle.net/VAXrL/187
namuol

12
вам потрібно масштабувати, використовуючи API canvas, щоб він працював, ви не можете коли-небудь масштабувати з CSS, і API-інтерфейс на нього впливає! Тож щось подібне: jsfiddle.net/VAXrL/190
Саймон Сарріс

1
Але природа цієї проблеми насправді не стосується полотна. Йдеться про те, як браузер видає масштабовані зображення, включаючи елементи <canvas>.
namuol

4
Якщо масштабувати за допомогою CSS, рішення намuol буде працювати. Якщо масштабувати зображення вручну на полотні, рішення Сімона працює. Акуратно, що в обох випадках є рішення, тому дякую вам обом!
Шон Леброн

Для IE 11: msImageSmoothingEnabled працює для мене! msdn.microsoft.com/en-us/library/dn265062(v=vs.85).aspx
steve

11

Редагувати 31.07.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/

Що створює це:

введіть тут опис зображення

Напевно, не те, що ти хочеш. Але якщо ви просто хотіли мати нульове розмиття, то це був би квиток, тому я пропоную це на всякий випадок.

Більш складним варіантом є використання піксельної маніпуляції та написання алгоритму для роботи. Кожен піксель першого зображення стає блоком 5x5 пікселів на новому зображенні. З іміджетатами було б не надто важко.

Але Canvas і CSS не допоможуть вам тут змінити масштаб одне до іншого з точним ефектом, який ви хочете.


Так, я цього боявся. Мабуть, image-rendering: -webkit-optimize-contrastслід робити трюк, але, схоже, нічого не робити. Я можу розглянути можливість прокрутки функції масштабування вмісту полотна за допомогою інтерполяції найближчого сусіда.
namuol

Я спочатку прийняв вашу відповідь; Я відкликав це поки, тому що, здається, виникає плутанина в тому, чи це дублікат чи ні.
namuol

У мене є більш повна відповідь після проведення деяких досліджень, і я хотів би знову відкрити питання, щоб надати свою відповідь.
namuol

3

У хроні Google, картини полотна не інтерполюються.

Ось робочий приклад, відредагований із відповіді на namuol http://jsfiddle.net/pGs4f/

ctx.scale(4, 4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, 64, 64);

Це найпривабливіший спосіб, який я бачив досі. Ще не впевнений у продуктивності, але все-таки варто заглянути. Я спробую це.
namuol

використання повтору замість не повторення швидше. Не знаю чому. Також досить швидко, три.js використовують це в CanvasRenderer
saviski

6
оновлення: більше не працює з chrome 21 (через підтримку дисплея сітківки додано?) нова версія jsfiddle.net/saviski/pGs4f/12 за допомогою imageSmoothingEnabled, вказаний Simon
saviski

Коли резолюція Retina стає загальною, все сильно змінюється. Якщо дисплей Retina стилю 326dpi (128dpcm) із сіткою відображається на 24-дюймових (52x32см) моніторах, розмір екрана складе 6656 x 4096 пікселів. Тоді антиаліазінг поганий, і всі постачальники браузерів (навіть на базі Webkit) змушені дозволити вимкнути антиаліазінг. Антиаліазінг - це дуже інтенсивний процессорний процес, а антиаліанізація зображення 6656 x 4096 пікселів буде надто повільною, але, на щастя, не потрібною.
Тімо Кахьонен

1
Як бічна примітка, ось хороший орієнтир щодо викрійок проти зображень: jsperf.com/drawimage-vs-canvaspattern/9
yckart

1

Обійти Saviski в розгорнутому тут є перспективним, так як він працює на:

  • 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-чіткі краї працюють у цьому )
  • Opera 12.02 Mac OS X 10.6.8 (візуалізація зображень: -o-чіткі краї працюють у цьому )
  • Opera 12.02 Windows 7 (візуалізація зображень: -o-чіткі краї працюють у цьому )

Проблемні ці проблеми, тому що ctx.XXXImageSmoothingEnabled не працює, а візуалізація не працює:

  • Safari 5.1.7 Mac OS X 10.6.8. (візуалізація зображень: -webkit-оптимізація-контраст НЕ працює)
  • Safari 5.1.7 Windows 7 (візуалізація зображень: -webkit-оптимізація-контраст НЕ працює)
  • IE 9 Windows 7 (-ms-інтерполяція-режим: найближчий сусід НЕ працює)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.