Какой алгоритм используется в context.drawImage() в Chrome/Firefox?

Вопрос или проблема

Спецификация говорит:

При масштабировании вверх, если атрибут imageSmoothingEnabled установлен в значение false, то изображение должно быть отрисовано с использованием интерполяции ближайшего соседа.

Таким образом, когда imageSmoothingEnabled равно false и процесс масштабирования происходит вверх, используется следующий ближайший сосед, что мне и нужно. Но я также хочу использовать ближайший сосед для масштабирования вниз (и если это считается другим случаем, когда масштабирование одно и то же), в основном всегда.

Спецификация также говорит следующее:

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

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

imageSmoothingEnabled равно false и если это не увеличение, не гарантируется использование ближайшего соседа.

Я не знаю никакого способа протестировать это правильно и окончательно. Chrome (Chromium) и Firefox являются открытым исходным кодом. Я проверил их репозитории, но не смог найти ничего полезного. Все, что я смог найти, это тестовый код.

Есть ли способ убедиться, что drawImage использует ближайшего соседа? Если да, то как?

Я так не думаю, но если это важно, я использую версию с 9 параметрами и делаю все масштабирования вверх/вниз/одно от случая к случаю. Также это проект расширения для браузера. Так что без фреймворков и OffscreenCanvas.

Я видел этот вопрос, но он довольно старый, и ответ меня не удовлетворил. Предпочтительно пример кода для выполнения или ссылка на исходный код.

Спасибо заранее.

Я пытался искать в репозиториях, но не смог найти связанные функции. Я не мог придумать никакого другого способа.

Я нашел несколько файлов в исходном коде Firefox, которые вам могут быть интересны. Я также прикрепил ссылку на область поиска, которую я использовал, так что вы можете искать более глубоко, если хотите. Я не смог найти ничего о реализации drawImage() от Google, так что вам, возможно, нужно будет искать это самостоятельно. Также, если вы не знали, context является экземпляром CanvasRenderingContext2D

Фактическое определение функции

Файл определения (.h)

Мой поиск в коде Firefox

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

  if (CurrentState().imageSmoothingEnabled || isDownScale) {
    samplingFilter = gfx::SamplingFilter::LINEAR;
    antialiasMode = AntialiasMode::DEFAULT;
  } else {
    samplingFilter = gfx::SamplingFilter::POINT;
    antialiasMode = AntialiasMode::NONE;
  }

Ответ или решение

При использовании метода context.drawImage() в браузерах Chrome и Firefox важно понимать, какие алгоритмы интерполяции применяются при изменении размеров изображений. Документация спецификаций HTML и практическое поведение браузеров подсказывают, что выбор алгоритма зависит от состояния атрибута imageSmoothingEnabled и того, увеличивается или уменьшается изображение.

Алгоритмы интерполяции в drawImage()

  1. При увеличении изображения:

    • Если imageSmoothingEnabled установлен в значение false, применяется интерполяция ближайшего соседа (nearest-neighbor interpolation). Это означает, что пиксели «растягиваются» на соответствующее новое разрешение, сохраняя оригинальные краевые значения, что может привести к блочным артефактам, но сохраняет четкость.
    • Если imageSmoothingEnabled установлен в true, браузер может применять более сложные алгоритмы сглаживания (например, билинейное или бикубическое сглаживание), что приведет к более мягкому и менее пикселизированному виду.
  2. При уменьшении изображения:

    • В спецификациях не указано, какой именно алгоритм должен использоваться при уменьшении. Однако, как указано в вашем примере кода из исходного кода Firefox, при уменьшении графика (isDownScale) используется интерполяция с применением линейного фильтра (linear filtering). Этот алгоритм обеспечивает более плавный и сглаженный результат по сравнению с ближайшим соседом.
  3. При отсутствии изменения размера (одинаковые размеры): Поведение в этом случае также не прописано четко. Без несовпадения с кодом вы можете обнаружить, что результат может варьироваться в зависимости от реализации браузера. Обычно он будет исходить из используемого фильтра при установленных параметрах и не всегда гарантирует использование ближайшего соседа.

Возможности тестирования

Чтобы убедиться, что метод drawImage использует именно алгоритм ближайшего соседа, можно выполнить следующие действия:

  • Создайте тестовый проект: Вы можете использовать JavaScript для генерации тестового изображения с различными размерами на холсте. Установите imageSmoothingEnabled в false и выполните масштабирование, сравните результаты с ожиданиями.
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

// Включаем режим ближайшего соседа
ctx.imageSmoothingEnabled = false;

const img = new Image();
img.src = 'path_to_your_image.png';
img.onload = () => {
    ctx.drawImage(img, 0, 0, img.width * 2, img.height * 2); // Увеличение
    ctx.drawImage(img, 0, 0, img.width / 2, img.height / 2); // Уменьшение
    // Проанализируйте получившееся изображение
};
  • Используйте инструменты для визуального тестирования: Исследуйте созданные изображения, чтобы выявить артефакты от изображения при различных операциях.

Заключение

В конечном итоге, поведение drawImage в контексте imageSmoothingEnabled является определяющим для выбора алгоритма интерполяции. Храните это в своем рабочем процессе, чтобы обеспечить соответствие вашим требованиям. Для более глубокой информации о промежуточных алгоритмах в реализации Chrome, рекомендуется изучить исходный код Chromium, хотя это может потребовать значительных усилий по поиску и анализу.

Если у вас остались вопросы или вы хотите обсудить конкретные случаи использования, не стесняйтесь задавать их.

Оцените материал
Добавить комментарий

Капча загружается...