Node.js
Как изменить цвет PNG на Node.js через sharp
Короткий ответ: для обработки PNG в Node.js чаще всего используют библиотеку sharp. Если PNG — это простая иконка с прозрачным фоном, ее можно перекрасить через tint. Если нужно заменить конкретный цвет внутри сложной картинки, задача становится не “поменять цвет”, а обработать пиксели по условию
Этот материал полезен, когда нужно автоматически готовить аватарки, иконки, бейджи, цветовые версии логотипа или изображения для карточек. Но важно сразу разделить два сценария: перекрасить одноцветную иконку легко, а аккуратно заменить один цвет на фотографии намного сложнее
Установите sharp
Создайте папку проекта
mkdir png-color-node
cd png-color-node
npm init -y
npm install sharp
Положите рядом файл icon.png. Лучше начать с простой PNG-иконки: темный силуэт на прозрачном фоне
Самый простой вариант: tint
Создайте index.js
const sharp = require("sharp");
async function recolorPng() {
await sharp("icon.png")
.tint("#1d4ed8")
.png()
.toFile("icon-blue.png");
console.log("Готово: icon-blue.png");
}
recolorPng().catch(console.error);
Запустите
node index.js
Метод tint хорошо подходит для одноцветных иконок. Он сохраняет прозрачность и меняет общий оттенок изображения
Если нужно сделать белую иконку
Для белого варианта
const sharp = require("sharp");
async function makeWhiteIcon() {
await sharp("icon.png")
.tint("#ffffff")
.png()
.toFile("icon-white.png");
}
makeWhiteIcon().catch(console.error);
Если исходная иконка уже цветная, результат может быть не таким чистым, как ожидалось. Для идеальной перекраски лучше иметь черную или однотонную маску с прозрачным фоном
Перекраска через наложение цвета и альфа-канал
Более контролируемый вариант — взять альфа-канал исходной PNG и наложить новый цвет как фон
const sharp = require("sharp");
async function recolorByAlpha() {
const image = sharp("icon.png");
const metadata = await image.metadata();
await sharp({
create: {
width: metadata.width,
height: metadata.height,
channels: 4,
background: "#ef4444"
}
})
.composite([
{
input: await sharp("icon.png").extractChannel("alpha").toBuffer(),
blend: "dest-in"
}
])
.png()
.toFile("icon-red.png");
console.log("Готово: icon-red.png");
}
recolorByAlpha().catch(console.error);
Этот подход полезен, если нужно получить ровно один цвет и сохранить форму и прозрачность исходной иконки
Как заменить конкретный цвет
Если задача звучит “все красное сделать синим”, придется работать с пикселями. Для простых изображений можно использовать raw
const sharp = require("sharp");
async function replaceRedWithBlue() {
const image = sharp("image.png").ensureAlpha();
const { data, info } = await image.raw().toBuffer({ resolveWithObject: true });
for (let i = 0; i < data.length; i += 4) {
const red = data[i];
const green = data[i + 1];
const blue = data[i + 2];
const isRed = red > 180 && green < 80 && blue < 80;
if (isRed) {
data[i] = 29;
data[i + 1] = 78;
data[i + 2] = 216;
}
}
await sharp(data, {
raw: {
width: info.width,
height: info.height,
channels: 4
}
})
.png()
.toFile("image-recolored.png");
}
replaceRedWithBlue().catch(console.error);
Этот код заменяет ярко-красные пиксели на синие. Для реальных фотографий границы цвета нужно подбирать аккуратнее, потому что тени, сглаживание и полутона редко имеют один точный RGB
Как сделать функцию для проекта
Вынесите обработку в отдельную функцию
const sharp = require("sharp");
async function recolorIcon(inputPath, outputPath, color) {
const image = sharp(inputPath);
const metadata = await image.metadata();
await sharp({
create: {
width: metadata.width,
height: metadata.height,
channels: 4,
background: color
}
})
.composite([
{
input: await sharp(inputPath).extractChannel("alpha").toBuffer(),
blend: "dest-in"
}
])
.png()
.toFile(outputPath);
}
module.exports = { recolorIcon };
Теперь функцию можно использовать в Express-роуте, скрипте генерации картинок или сборке ассетов
Мини-практика
Возьмите одну PNG-иконку с прозрачным фоном и сделайте три версии: синюю, красную и белую. После этого проверьте, что прозрачность сохранилась, а размер файла не стал неожиданно огромным
Дополнительное упражнение: добавьте массив цветов и сгенерируйте несколько файлов в цикле
const colors = ["#1d4ed8", "#ef4444", "#22c55e"];
Частые ошибки
Пытаются перекрасить сложную фотографию как иконку tint подходит не для всех изображений. Для фотографии нужна другая логика обработки цвета
Теряют прозрачность Следите за альфа-каналом. Для иконок с прозрачным фоном это ключевая часть результата
Не ждут завершения асинхронной операции sharp(...).toFile(...) возвращает promise. Используйте await или .then
Сохраняют результат поверх исходника На этапе экспериментов лучше писать в новый файл, чтобы не потерять оригинал
Что почитать дальше по Node.js
Если нужен общий маршрут по теме, откройте рубрику Node.js. Для соседних задач пригодятся эти разборы:
- Node.js + MongoDB: первая коллекция из приложения
- Node.js + MySQL: REST API для первых данных
- Node.js LTS: какую версию ставить новичку
- Node.js выводит странные имена файлов: как исправить кодировку и пути