Вопрос или проблема
Спецификация говорит:
При масштабировании вверх, если атрибут imageSmoothingEnabled установлен в значение false, то изображение должно быть отрисовано с использованием интерполяции ближайшего соседа.
Таким образом, когда imageSmoothingEnabled
равно false и процесс масштабирования происходит вверх, используется следующий ближайший сосед, что мне и нужно. Но я также хочу использовать ближайший сосед для масштабирования вниз (и если это считается другим случаем, когда масштабирование одно и то же), в основном всегда.
Спецификация также говорит следующее:
При масштабировании вверх, если атрибут imageSmoothingEnabled установлен в значение true, пользовательский агент должен попытаться применить алгоритм сглаживания к данным изображения, когда оно масштабируется. Пользовательские агенты, которые поддерживают несколько алгоритмов фильтрации, могут использовать значение атрибута imageSmoothingQuality для выбора алгоритма фильтрации, когда атрибут imageSmoothingEnabled установлен в true. В противном случае изображение должно быть отрисовано с использованием интерполяции ближайшего соседа.
Эта спецификация не определяет точный алгоритм, который следует использовать при уменьшении изображения или при увеличении изображения, когда атрибут imageSmoothingEnabled установлен в true.
imageSmoothingEnabled равно false и если это не увеличение, не гарантируется использование ближайшего соседа.
Я не знаю никакого способа протестировать это правильно и окончательно. Chrome (Chromium) и Firefox являются открытым исходным кодом. Я проверил их репозитории, но не смог найти ничего полезного. Все, что я смог найти, это тестовый код.
Есть ли способ убедиться, что drawImage
использует ближайшего соседа? Если да, то как?
Я так не думаю, но если это важно, я использую версию с 9 параметрами и делаю все масштабирования вверх/вниз/одно от случая к случаю. Также это проект расширения для браузера. Так что без фреймворков и OffscreenCanvas.
Я видел этот вопрос, но он довольно старый, и ответ меня не удовлетворил. Предпочтительно пример кода для выполнения или ссылка на исходный код.
Спасибо заранее.
Я пытался искать в репозиториях, но не смог найти связанные функции. Я не мог придумать никакого другого способа.
Я нашел несколько файлов в исходном коде Firefox, которые вам могут быть интересны. Я также прикрепил ссылку на область поиска, которую я использовал, так что вы можете искать более глубоко, если хотите. Я не смог найти ничего о реализации drawImage() от Google, так что вам, возможно, нужно будет искать это самостоятельно. Также, если вы не знали, context
является экземпляром CanvasRenderingContext2D
Фактическое определение функции
Вот единственное использование 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()
-
При увеличении изображения:
- Если
imageSmoothingEnabled
установлен в значениеfalse
, применяется интерполяция ближайшего соседа (nearest-neighbor interpolation). Это означает, что пиксели «растягиваются» на соответствующее новое разрешение, сохраняя оригинальные краевые значения, что может привести к блочным артефактам, но сохраняет четкость. - Если
imageSmoothingEnabled
установлен вtrue
, браузер может применять более сложные алгоритмы сглаживания (например, билинейное или бикубическое сглаживание), что приведет к более мягкому и менее пикселизированному виду.
- Если
-
При уменьшении изображения:
- В спецификациях не указано, какой именно алгоритм должен использоваться при уменьшении. Однако, как указано в вашем примере кода из исходного кода Firefox, при уменьшении графика (
isDownScale
) используется интерполяция с применением линейного фильтра (linear filtering). Этот алгоритм обеспечивает более плавный и сглаженный результат по сравнению с ближайшим соседом.
- В спецификациях не указано, какой именно алгоритм должен использоваться при уменьшении. Однако, как указано в вашем примере кода из исходного кода Firefox, при уменьшении графика (
-
При отсутствии изменения размера (одинаковые размеры): Поведение в этом случае также не прописано четко. Без несовпадения с кодом вы можете обнаружить, что результат может варьироваться в зависимости от реализации браузера. Обычно он будет исходить из используемого фильтра при установленных параметрах и не всегда гарантирует использование ближайшего соседа.
Возможности тестирования
Чтобы убедиться, что метод 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, хотя это может потребовать значительных усилий по поиску и анализу.
Если у вас остались вопросы или вы хотите обсудить конкретные случаи использования, не стесняйтесь задавать их.