Предоставление оттенка изображения canvas2d для шрифтов Sprite

Я делаю Spritefonts и в настоящее время реализовал для него оттенок на WebGL!

Но на canvas2d я пытался сделать это через ctx.globalCompositeOperation, но он показывает следующее

Как видите, черные пиксели тоже заполнены...

Вот мой код...

var size = 32;
var x = 200;
var y = 200;
var spacing = 0;
for (var i = 0; i < txt.length; i++) {
    var q = fonts[0].info[txt[i]];
    ctx.save();
    if (q) ctx.drawImage(fonts[0].src, q.x, q.y, q.w, q.h, x + (spacing || 0) + (i * size), y, size, size);
    ctx.globalCompositeOperation = "source-in";
    ctx.fillStyle = "green";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.restore();
}

При попытке вместо этого использовать режим «затемнения» он заполняется правильно, но также заполняет фон (чего я не хочу ...)

Я также пробовал с ctx.getImageData() и ctx.putImageData(), но буквы не отображаются

var size = 32;
var x = 200;
var y = 200;
var spacing = 0;
for (var i = 0; i < txt.length; i++) {
    var q = fonts[0].info[txt[i]];
    if (q) {
        ctx.drawImage(fonts[0].src, q.x, q.y, q.w, q.h, x + (spacing || 0) + (i * size), y, size, size);
        f = ctx.getImageData(x + (spacing || 0) + (i * size), y, size, size);
        for (var i = 0; i < f.data.length; i += 4) {
            f.data[i + 0] = 100;
            f.data[i + 1] = 100;
            f.data[i + 2] = 255;
            f.data[i + 3] = 255;
        }
        ctx.putImageData(f, x + (spacing || 0) + (i * size), y, 0, 0, size, size);
    }
}               

Изображение, которое я использую, взято из здесь

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
103
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Исправлено с помощью режима «осветления» для черных пикселей с заливкой фона, затем применен режим «затемнения» вместо «исходный» и все готово!

var size = 32;
var x = 200;
var y = 200;
var spacing = 0;
for (var i = 0; i < txt.length; i++) {
    var q = fonts[0].info[txt[i]];
    ctx.save();
    ctx.globalCompositeOperation = "lighten";
    ctx.fillStyle = ctx.canvas.style.backgroundColor;
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    if (q) ctx.drawImage(fonts[0].src, q.x, q.y, q.w, q.h, x + (spacing || 0) + (i * size), y, size, size);
    ctx.globalCompositeOperation = "darken";
    ctx.fillStyle = "green";
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.restore();
}
Ответ принят как подходящий

Это лучший способ, который я нашел:

  1. Создайте холст с размерами, соответствующими размерам изображения спрайта.
  2. Сохранить состояние контекста в созданном холсте
  3. Установите fillStyle созданного контекста холста с цветом текста спрайта (Tint)
  4. Установите globalAlpha созданного контекста холста на непрозрачность
  5. Залейте созданный фон холста цветом текста спрайта (Tint)
  6. Применить композитный режим «назначение поверх» в созданном контексте холста
  7. Сбросить globalAlpha созданного контекста холста до 1 (по умолчанию)
  8. Нарисуйте изображение спрайта на созданном холсте
  9. Восстановить состояние контекста в созданном холсте
  10. Затем пусть контекст холста по умолчанию (не созданный) рисует символы из изображения спрайтового шрифта, поэтому мы позволяем ему рисовать часть созданного нами холста (обратите внимание, что изображение спрайтового шрифта заполняет весь созданный холст)
  11. Сделанный!
var size = 32;
var x = 200;
var y = 200;
var spacing = 0;
var opacity = 0.8;
var color = "green";
for (var i = 0; i < txt.length; i++) {
    var q = fonts[0].info[txt[i]];
    var c = document.createElement("canvas").getContext("2d");
    c.canvas.width = fonts[0].src.width;
    c.canvas.height = fonts[0].src.height;
    c.save();
    c.fillStyle = color;
    c.globalAlpha = opacity || 0.8;
    c.fillRect(0, 0, c.canvas.width, c.canvas.height);
    c.globalCompositeOperation = "destination-atop";
    c.globalAlpha = 1;
    c.drawImage(fonts[0].src, 0, 0);
    c.restore();
    if (q) ctx.drawImage(c.canvas, q.x, q.y, q.w, q.h, x + (i * (size + spacing)), y, size, size);
}

Другие вопросы по теме