Como processar imagens no Node.js com Sharp

O autor selecionou o Fundo de Diversidade em Tecnologia para receber uma doação como parte do programa Escreva para Doações.

Introdução

O processamento de imagem digital é um método de usar um computador para analisar e manipular imagens. O processo envolve a leitura de uma imagem, aplicação de métodos para alterar ou aprimorar a imagem e, em seguida, salvar a imagem processada. É comum em aplicativos que lidam com conteúdo carregado pelo usuário processar imagens. Por exemplo, se você está escrevendo um aplicativo web que permite aos usuários fazer upload de imagens, os usuários podem enviar imagens desnecessariamente grandes. Isso pode impactar negativamente a velocidade de carregamento do aplicativo e também desperdiçar o espaço do servidor. Com o processamento de imagem, seu aplicativo pode redimensionar e comprimir todas as imagens carregadas pelo usuário, o que pode melhorar significativamente o desempenho do seu aplicativo e economizar espaço em disco do seu servidor.

O Node.js tem um ecossistema de bibliotecas que você pode usar para processar imagens, como o sharp, jimp e o módulo gm. Este artigo focará no módulo sharp. sharp é uma biblioteca popular de processamento de imagens para Node.js que suporta vários formatos de arquivo de imagem, como JPEG, PNG, GIF, WebP, AVIF, SVG e TIFF.

Neste tutorial, você usará o sharp para ler uma imagem e extrair seus metadados, redimensionar, alterar o formato de uma imagem e comprimir uma imagem. Você então irá recortar, converter para tons de cinza, rotacionar e desfocar uma imagem. Por fim, você irá compor imagens e adicionar texto em uma imagem. Ao final deste tutorial, você terá uma boa compreensão de como processar imagens no Node.js.

Pré-requisitos

Para completar este tutorial, você precisará:

Passo 1 — Configurando o Diretório do Projeto e Baixando Imagens

Antes de começar a escrever seu código, você precisa criar o diretório que conterá o código e as imagens que você usará neste artigo.

Abra seu terminal e crie o diretório para o projeto usando o comando mkdir:

  1. mkdir process_images

Mova-se para o diretório recém-criado usando o comando cd:

  1. cd process_images

Crie um arquivo package.json usando o comando npm init para manter o controle das dependências do projeto:

  1. npm init -y

A opção -y instrui o npm a criar o arquivo package.json padrão.

Em seguida, instale o sharp como uma dependência:

  1. npm install sharp

Você usará as seguintes três imagens neste tutorial:



Em seguida, faça o download das imagens no diretório do seu projeto usando o comando curl.

Use o seguinte comando para baixar a primeira imagem. Isso vai baixar a imagem como sammy.png:

  1. curl -O https://assets.digitalocean.com/how-to-process-images-in-node-js-with-sharp/sammy.png

Em seguida, faça o download da segunda imagem com o seguinte comando. Isso vai baixar a imagem como underwater.png:

  1. curl -O https://assets.digitalocean.com/how-to-process-images-in-node-js-with-sharp/underwater.png

Por fim, faça o download da terceira imagem usando o seguinte comando. Isso vai baixar a imagem como sammy-transparent.png:

  1. curl -O https://assets.digitalocean.com/how-to-process-images-in-node-js-with-sharp/sammy-transparent.png

Com o diretório do projeto e as dependências configuradas, você está agora pronto para começar a processar imagens.

Passo 2 — Lendo Imagens e Extraindo Metadados

Nesta seção, você escreverá código para ler uma imagem e extrair seus metadados. Metadados de imagem são textos incorporados em uma imagem, que incluem informações sobre a imagem, como seu tipo, largura e altura.

Para extrair os metadados, primeiro você importará o módulo sharp, criará uma instância de sharp e passará o caminho da imagem como argumento. Depois disso, encadeará o método metadata() na instância para extrair os metadados e registrá-los no console.

Para fazer isso, crie e abra o arquivo readImage.js no seu editor de texto preferido. Este tutorial utiliza um editor de texto de terminal chamado nano:

  1. nano readImage.js

Em seguida, exija o sharp no topo do arquivo:

process_images/readImage.js
const sharp = require("sharp");

Sharp é um módulo de processamento de imagens baseado em promessas. Quando você cria uma instância de sharp, ela retorna uma promessa. Você pode resolver a promessa usando o método then ou usar async/await, que possui uma sintaxe mais limpa.

Para usar a sintaxe async/await, você precisará criar uma função assíncrona colocando a palavra-chave async no início da função. Isso permitirá que você use a palavra-chave await dentro da função para resolver a promessa retornada quando você lê uma imagem.

No seu arquivo readImage.js, defina uma função assíncrona, getMetadata(), para ler a imagem, extrair seus metadados e registrá-los no console:

process_images/readImage.js
const sharp = require("sharp");

async function getMetadata() {
  const metadata = await sharp("sammy.png").metadata();
  console.log(metadata);
}

A função getMetadata() é assíncrona, dado o uso da palavra-chave async que você definiu antes do rótulo function. Isso permite o uso da sintaxe await dentro da função. A função getMetadata() irá ler uma imagem e retornar um objeto com seus metadados.

No corpo da função, você lê a imagem chamando sharp(), que recebe o caminho da imagem como argumento, aqui com sammy.png.

Além de receber o caminho da imagem, sharp() também pode ler dados da imagem armazenados em um Buffer, Uint8Array, ou Uint8ClampedArray, desde que a imagem seja JPEG, PNG, GIF, WebP, AVIF, SVG ou TIFF.

Agora, quando você usa sharp() para ler a imagem, ele cria uma instância sharp. Você então encadeia o método metadata() do módulo sharp à instância. O método retorna um objeto contendo os metadados da imagem, que você armazena na variável metadata e registra seu conteúdo usando console.log().

Seu programa agora pode ler uma imagem e retornar seus metadados. No entanto, se o programa lançar um erro durante a execução, ele irá falhar. Para contornar isso, você precisa capturar os erros quando eles ocorrem.

Para fazer isso, envolva o código dentro do bloco try...catch dentro de uma função getMetadata():

process_images/readImage.js
const sharp = require("sharp");

async function getMetadata() {
  try {
    const metadata = await sharp("sammy.png").metadata();
    console.log(metadata);
  } catch (error) {
    console.log(`An error occurred during processing: ${error}`);
  }
}

Dentro do bloco try, você lê uma imagem, extrai e registra seus metadados. Quando ocorre um erro durante esse processo, a execução passa para a seção catch e registra o erro, impedindo que o programa trave.

Por fim, chame a função getMetadata() adicionando a linha destacada:

process_images/readImage.js

const sharp = require("sharp");

async function getMetadata() {
  try {
    const metadata = await sharp("sammy.png").metadata();
    console.log(metadata);
  } catch (error) {
    console.log(`An error occurred during processing: ${error}`);
  }
}

getMetadata();

Agora, salve e saia do arquivo. Digite y para salvar as alterações feitas no arquivo e confirme o nome do arquivo pressionando a tecla ENTER ou RETURN.

Execute o arquivo usando o comando node:

  1. node readImage.js

Você deve ver uma saída semelhante a esta:

Output
{ format: 'png', width: 750, height: 483, space: 'srgb', channels: 3, depth: 'uchar', density: 72, isProgressive: false, hasProfile: false, hasAlpha: false }

Agora que você leu uma imagem e extraiu seus metadados, agora redimensionará uma imagem, mudará seu formato e a comprimirá.

Etapa 3 — Redimensionando, Alterando Formato de Imagem e Comprimindo Imagens

Redimensionar é o processo de alterar as dimensões de uma imagem sem cortar nada dela, o que afeta o tamanho do arquivo de imagem. Nesta seção, você redimensionará uma imagem, mudará seu tipo de imagem e comprimirá a imagem. A compressão de imagem é o processo de reduzir o tamanho de um arquivo de imagem sem perder qualidade.

Primeiro, você encadeará o método resize() da instância sharp para redimensionar a imagem e salvá-la no diretório do projeto. Em segundo lugar, você encadeará o método format() para a imagem redimensionada para alterar seu formato de png para jpeg. Além disso, você passará uma opção para o método format() para comprimir a imagem e salvá-la no diretório.

Crie e abra o arquivo resizeImage.js em seu editor de texto:

  1. nano resizeImage.js

Adicione o seguinte código para redimensionar a imagem para largura de 150px e altura de 97px:

process_images/resizeImage.js
const sharp = require("sharp");

async function resizeImage() {
  try {
    await sharp("sammy.png")
      .resize({
        width: 150,
        height: 97
      })
      .toFile("sammy-resized.png");
  } catch (error) {
    console.log(error);
  }
}

resizeImage();

A função resizeImage() encadeia o método resize() do módulo sharp à instância sharp. O método recebe um objeto como argumento. No objeto, você define as dimensões da imagem desejadas usando as propriedades width e height. Definir a width como 150 e a height como 97 fará com que a imagem tenha 150px de largura e 97px de altura.

Após redimensionar a imagem, você encadeia o método toFile() do módulo sharp, que recebe o caminho da imagem como argumento. Passar sammy-resized.png como argumento salvará o arquivo de imagem com esse nome no diretório de trabalho do seu programa.

Agora, salve e saia do arquivo. Execute seu programa no terminal:

  1. node resizeImage.js

Você não verá nenhuma saída, mas deverá ver um novo arquivo de imagem criado com o nome sammy-resized.png no diretório do projeto.

Abra a imagem no seu computador local. Você deverá ver uma imagem de Sammy 150px de largura e 97px de altura:

Agora que você pode redimensionar uma imagem, em seguida, você vai converter o formato da imagem redimensionada de png para jpeg, comprimir a imagem e salvá-la no diretório de trabalho. Para fazer isso, você usará o método toFormat(), que você encadeará após o método resize().

Adicione o código destacado para alterar o formato da imagem para jpeg e comprimi-la:

process_images/resizeImage.js
const sharp = require("sharp");

async function resizeImage() {
  try {
    await sharp("sammy.png")
      .resize({
        width: 150,
        height: 97
      })
      .toFormat("jpeg", { mozjpeg: true })
      .toFile("sammy-resized-compressed.jpeg");
  } catch (error) {
    console.log(error);
  }
}

resizeImage();

Dentro da função resizeImage(), você usa o método toFormat() do módulo sharp para alterar o formato da imagem e comprimi-la. O primeiro argumento do método toFormat() é uma string contendo o formato de imagem para o qual você deseja converter sua imagem. O segundo argumento é um objeto opcional contendo opções de saída que melhoram e comprimem a imagem.

Para comprimir a imagem, você passa a ela uma propriedade mozjpeg que contém um valor booleano. Quando você o define como true, sharp usa os padrões de mozjpeg para comprimir a imagem sem sacrificar qualidade. O objeto também pode aceitar mais opções; consulte a documentação do sharp para mais detalhes.

Nota: Em relação ao segundo argumento do método toFormat(), cada formato de imagem aceita um objeto com diferentes propriedades. Por exemplo, a propriedade mozjpeg é aceita apenas em imagens JPEG.

No entanto, outros formatos de imagem têm opções equivalentes como qualidade, compressão e sem perdas. Certifique-se de consultar a documentação para saber que tipo de opções são aceitáveis para o formato de imagem que está comprimindo.

Em seguida, passe o método toFile() um nome de arquivo diferente para salvar a imagem comprimida como sammy-redimensionada-comprimida.jpeg.

Agora, salve e saia do arquivo, e execute seu código com o seguinte comando:

  1. node resizeImage.js

Você não receberá nenhuma saída, mas um arquivo de imagem sammy-redimensionada-comprimida.jpeg será salvo no diretório do seu projeto.

Abra a imagem em sua máquina local e você verá a seguinte imagem:

Com sua imagem agora comprimida, verifique o tamanho do arquivo para confirmar que sua compressão foi bem-sucedida. No seu terminal, execute o comando du para verificar o tamanho do arquivo para sammy.png:

  1. du -h sammy.png

A opção -h produz uma saída legível para humanos mostrando o tamanho do arquivo em quilobytes, megabytes e muitos mais.

Após executar o comando, você deverá ver uma saída semelhante a esta:

Output
120K sammy.png

A saída mostra que a imagem original tem 120 quilobytes.

Em seguida, verifique o tamanho do arquivo para sammy-redimensionada.png:

  1. du -h sammy-resized.png

Após executar o comando, você verá a seguinte saída:

Output
8.0K sammy-resized.png

O arquivo sammy-resized.png agora tem 8 kilobytes, reduzido de 120 kilobytes. Isso mostra que a operação de redimensionamento afeta o tamanho do arquivo.

Agora, verifique o tamanho do arquivo para sammy-resized-compressed.jpeg:

  1. du -h sammy-resized-compressed.jpeg

Após executar o comando, você verá a seguinte saída:

Output
4.0K sammy-resized-compressed.jpeg

O sammy-resized-compressed.jpeg agora tem 4 kilobytes, reduzido de 8 kilobytes, economizando 4 kilobytes, mostrando que a compressão funcionou.

Agora que você redimensionou uma imagem, alterou seu formato e a comprimiu, você vai recortar e converter a imagem para tons de cinza.

Passo 4 — Recortar e Converter Imagens para Tons de Cinza

Neste passo, você vai recortar uma imagem e convertê-la para tons de cinza. Recortar é o processo de remover áreas indesejadas de uma imagem. Você usará o método extend() para recortar a imagem sammy.png. Depois disso, encadeará o método grayscale() à instância da imagem recortada e convertê-la para tons de cinza.

Crie e abra o arquivo cropImage.js no seu editor de texto:

  1. nano cropImage.js

No seu arquivo cropImage.js, adicione o seguinte código para recortar a imagem:

process_images/cropImage.js
const sharp = require("sharp");

async function cropImage() {
  try {
    await sharp("sammy.png")
      .extract({ width: 500, height: 330, left: 120, top: 70  })
      .toFile("sammy-cropped.png");
  } catch (error) {
    console.log(error);
  }
}

cropImage();

A função cropImage() é uma função assíncrona que lê uma imagem e retorna sua imagem cortada. Dentro do bloco try, uma instância de sharp irá ler a imagem. Em seguida, o método extract() do módulo sharp encadeado na instância recebe um objeto com as seguintes propriedades:

  • width: a largura da área que você deseja cortar.
  • height: a altura da área que você deseja cortar.
  • top: a posição vertical da área que você deseja cortar.
  • left: a posição horizontal da área que você deseja cortar.

Ao definir a width para 500 e a height para 330, imagine que sharp cria uma caixa transparente sobre a imagem que você deseja cortar. Qualquer parte da imagem que se encaixe na caixa permanecerá, e o restante será cortado:

As propriedades top e left controlam a posição da caixa. Ao definir left para 120, a caixa é posicionada a 120px da borda esquerda da imagem, e definir top para 70 posiciona a caixa a 70px da borda superior da imagem.

A área da imagem que se encaixa na caixa será extraída e salva em sammy-cropped.png como uma imagem separada.

Salve e saia do arquivo. Execute o programa no terminal:

  1. node cropImage.js

A saída não será mostrada, mas a imagem sammy-cropped.png será salva no diretório do seu projeto.

Abra a imagem em sua máquina local. Você deverá ver a imagem cortada:

Agora que você recortou uma imagem, você irá convertê-la para escala de cinza. Para fazer isso, você encadeará o método grayscale à instância sharp. Adicione o código destacado para converter a imagem para escala de cinza:

process_images/cropImage.js
const sharp = require("sharp");

async function cropImage() {
  try {
    await sharp("sammy.png")
      .extract({ width: 500, height: 330, left: 120, top: 70 })
      .grayscale()
      .toFile("sammy-cropped-grayscale.png");
  } catch (error) {
    console.log(error);
  }
}

cropImage();

A função cropImage() converte a imagem recortada para escala de cinza encadeando o método grayscale() do módulo sharp à instância sharp. Em seguida, salva a imagem no diretório do projeto como sammy-cropped-grayscale.png.

Pressione CTRL+X para salvar e sair do arquivo.

Execute seu código no terminal:

  1. node cropImage.js

Abra sammy-cropped-grayscale.png em sua máquina local. Agora você deverá ver a imagem em escala de cinza:

Agora que você recortou e extraiu a imagem, trabalhará com rotação e desfoque nela.

Passo 5 — Rotacionando e Desfocando Imagens

Neste passo, você irá rotacionar a imagem sammy.png em um ângulo de 33 graus. Também aplicará um desfoque gaussiano na imagem rotacionada. Um desfoque gaussiano é uma técnica de desfoque de uma imagem usando a função Gaussiana, que reduz o nível de ruído e detalhes em uma imagem.

Crie um arquivo rotateImage.js no seu editor de texto:

  1. nano rotateImage.js

No seu arquivo rotateImage.js, escreva o seguinte bloco de código para criar uma função que rotaciona sammy.png para um ângulo de 33 graus:

process_images/rotateImage.js
const sharp = require("sharp");

async function rotateImage() {
  try {
    await sharp("sammy.png")
      .rotate(33, { background: { r: 0, g: 0, b: 0, alpha: 0 } })
      .toFile("sammy-rotated.png");
  } catch (error) {
    console.log(error);
  }
}

rotateImage();

A função rotateImage() é uma função assíncrona que lê uma imagem e retornará a imagem rotacionada para um ângulo de 33 graus. Dentro da função, o método rotate() do módulo sharp recebe dois argumentos. O primeiro argumento é o ângulo de rotação de 33 graus. Por padrão, o sharp faz o fundo da imagem rotacionada preto. Para remover o fundo preto, você passa um objeto como segundo argumento para tornar o fundo transparente.

O objeto tem uma propriedade background que contém um objeto definindo o modelo de cor RGBA. RGBA significa vermelho, verde, azul e alfa.

  • r: controla a intensidade da cor vermelha. Aceita um valor inteiro de 0 a 255. 0 significa que a cor não está sendo usada, e 255 é vermelho no máximo.

  • g: controla a intensidade da cor verde. Aceita um valor inteiro de 0-255. 0 significa que a cor verde não está sendo usada, e 255 é verde no máximo.

  • b: controla a intensidade do azul. Também aceita um valor inteiro entre 0 e 255. 0 significa que a cor azul não está sendo usada, e 255 é azul no máximo.

  • alfa: controla a opacidade da cor definida pelas propriedades r, g e b. 0 ou 0.0 torna a cor transparente e 1 ou 1.1 torna a cor opaca.

Para que a propriedade alfa funcione, você deve garantir que defina e ajuste os valores para r, g e b. Definir os valores de r, g e b como 0 cria uma cor preta. Para criar um fundo transparente, você deve definir uma cor primeiro e, em seguida, pode definir alfa como 0 para torná-lo transparente.

Agora, salve e saia do arquivo. Execute seu script no terminal:

  1. node rotateImage.js

Verifique a existência de sammy-rotated.png no diretório do seu projeto. Abra-o em sua máquina local.

Você deve ver a imagem rotacionada a um ângulo de 33 graus:

Em seguida, você irá desfocar a imagem rotacionada. Você conseguirá isso encadeando o método blur() à instância sharp.

Insira o código destacado abaixo para desfocar a imagem:

process_images/rotateImage.js
const sharp = require("sharp");

async function rotateImage() {
  try {
    await sharp("sammy.png")
      .rotate(33, { background: { r: 0, g: 0, b: 0, alpha: 0 } })
      .blur(4)
      .toFile("sammy-rotated-blurred.png");
  } catch (error) {
    console.log(error);
  }
}

rotateImage();

A função rotateImage() agora lê a imagem, a rotaciona e aplica um desfoque gaussiano à imagem. Ela aplica um desfoque gaussiano à imagem usando o método blur() do módulo sharp. O método aceita um único argumento contendo um valor sigma entre 0.3 e 1000. Passar 4 aplicará um desfoque gaussiano com um valor sigma de 4. Após a imagem ser borrada, você define um caminho para salvar a imagem borrada.

Seu script agora borrará a imagem rotacionada com um valor sigma de 4. Salve e saia do arquivo e, em seguida, execute o script em seu terminal:

  1. node rotateImage.js

Depois de executar o script, abra o arquivo sammy-rotated-blurred.png em seu computador local. Você deverá ver a imagem rotacionada borrada agora:

Agora que você rotacionou e borrou uma imagem, você vai compor uma imagem sobre outra.

Passo 6 — Compondo Imagens Usando composite()

A composição de imagens é um processo de combinar duas ou mais imagens separadas para criar uma única imagem. Isso é feito para criar efeitos que aproveitam os melhores elementos das diferentes fotos. Outro caso de uso comum é adicionar uma marca d’água a uma imagem com um logotipo.

Nesta seção, você vai compor sammy-transparent.png sobre o underwater.png. Isso criará a ilusão de que o Sammy está nadando nas profundezas do oceano. Para compor as imagens, você encadeará o método composite() à instância sharp.

Crie e abra o arquivo compositeImage.js no seu editor de texto:

  1. nano compositeImages.js

Agora, crie uma função para compor as duas imagens adicionando o seguinte código no arquivo compositeImages.js:

process_images/compositeImages.js
const sharp = require("sharp");

async function compositeImages() {
  try {
    await sharp("underwater.png")
      .composite([
        {
          input: "sammy-transparent.png",
          top: 50,
          left: 50,
        },
      ])
      .toFile("sammy-underwater.png");
  } catch (error) {
    console.log(error);
  }
}

compositeImages()

A função compositeImages() lê primeiro a imagem underwater.png. Em seguida, você encadeia o método composite() do módulo sharp, que recebe um array como argumento. O array contém um único objeto que lê a imagem sammy-transparent.png. O objeto tem as seguintes propriedades:

  • input: recebe o caminho da imagem que você deseja compor sobre a imagem processada. Também aceita um Buffer, Uint8Array ou Uint8ClampedArray como entrada.
  • top: controla a posição vertical da imagem que você deseja compor. Configurando top como 50, você desloca a imagem sammy-transparent.png 50px a partir da borda superior da imagem underwater.png.
  • left: controla a posição horizontal da imagem que você deseja compor sobre outra. Definir left para 50 desloca o sammy-transparent.png 50px a partir da borda esquerda da imagem underwater.png.

O método composite() requer uma imagem de tamanho semelhante ou menor que a imagem processada.

Para visualizar o que o método composite() está fazendo, pense nele como se estivesse criando uma pilha de imagens. A imagem sammy-transparent.png é colocada sobre a imagem underwater.png:

Os valores de top e left posicionam a imagem sammy-transparent.png em relação à imagem underwater.png.

Salve seu script e saia do arquivo. Execute seu script para criar uma composição de imagem:

node compositeImages.js

Abra o sammy-underwater.png em sua máquina local. Agora você deve ver o sammy-transparent.png compostado sobre a imagem underwater.png:

Agora você compôs imagens usando o método composite(). No próximo passo, você usará o método composite() para adicionar texto a uma imagem.

Passo 7 — Adicionando Texto em uma Imagem

Nesta etapa, você escreverá texto em uma imagem. No momento da escrita, o sharp não possui uma maneira nativa de adicionar texto a uma imagem. Para adicionar texto, primeiro, você escreverá código para desenhar texto usando Gráficos Vetoriais Escaláveis (SVG). Depois de criar a imagem SVG, você escreverá código para compor a imagem com a imagem sammy.png usando o método composite.

SVG é uma linguagem de marcação baseada em XML para criar gráficos vetoriais para a web. Você pode desenhar texto ou formas como círculos, triângulos e também desenhar formas complexas como ilustrações, logotipos, etc. As formas complexas são criadas com uma ferramenta gráfica como Inkscape que gera o código SVG. As formas SVG podem ser renderizadas e escaladas para qualquer tamanho sem perder qualidade.

Crie e abra o arquivo addTextOnImage.js no seu editor de texto.

  1. nano addTextOnImage.js

No seu arquivo addTextOnImage.js, adicione o seguinte código para criar um contêiner SVG:

process_images/addTextOnImage.js
const sharp = require("sharp");

async function addTextOnImage() {
  try {
    const width = 750;
    const height = 483;
    const text = "Sammy the Shark";

    const svgImage = `
    <svg width="${width}" height="${height}">
    </svg>
    `;
  } catch (error) {
    console.log(error);
  }
}

addTextOnImage();

A função addTextOnImage() define quatro variáveis: width, height, text e svgImage. width contém o inteiro 750, e height contém o inteiro 483. text contém a string Sammy the Shark. Este é o texto que você desenhará usando SVG.

A variável svgImage contém o elemento svg. O elemento svg possui dois atributos: width e height que interpolam as variáveis width e height que você definiu anteriormente. O elemento svg cria um recipiente transparente de acordo com a largura e altura fornecidas.

Você deu ao elemento svg uma width de 750 e height de 483 para que a imagem SVG tenha o mesmo tamanho que sammy.png. Isso ajudará a centralizar o texto na imagem sammy.png.

Em seguida, você irá desenhar os gráficos de texto. Adicione o código destacado para desenhar Sammy the Shark no contêiner SVG:

process_images/addTextOnImage.js
async function addTextOnImage() {
    ...
    const svg = `
    <svg width="${width}" height="${height}">
    <text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
    </svg>
    `;
  ....
}

O elemento text SVG possui quatro atributos: x, y, text-anchor e class. x e y definem a posição para o texto que você está desenhando no contêiner SVG. O atributo x posiciona o texto horizontalmente, e o atributo y posiciona o texto verticalmente.

Definir x como 50% desenha o texto no meio do contêiner no eixo x, e definir y como 50% posiciona o texto no meio no eixo y da imagem SVG.

O text-anchor alinha o texto horizontalmente. Definir text-anchor como middle alinhará o texto no centro na coordenada x especificada.

A class define um nome de classe no elemento text. Você usará o nome da classe para aplicar estilos CSS ao elemento text.

${text} interpola a string Sammy the Shark armazenada na variável text. Este é o texto que será desenhado na imagem SVG.

Em seguida, adicione o código destacado para estilizar o texto usando CSS:

process_images/addTextOnImage.js
    const svg = `
    <svg width="${width}" height="${height}">
      <style>
      .title { fill: #001; font-size: 70px; font-weight: bold;}
      </style>
      <text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
    </svg>
    `;

Neste código, fill altera a cor do texto para preto, font-size altera o tamanho da fonte, e font-weight altera o peso da fonte.

Neste ponto, você escreveu o código necessário para desenhar o texto Sammy the Shark com SVG. Em seguida, você salvará a imagem SVG como um png com sharp para que possa ver como o SVG está desenhando o texto. Uma vez feito isso, você comporá a imagem SVG com sammy.png.

Adicione o código destacado para salvar a imagem SVG como um png com sharp:

process_images/addTextOnImage.js
    ....
    const svgImage = `
    <svg width="${width}" height="${height}">
    ...
    </svg>
    `;
    const svgBuffer = Buffer.from(svgImage);
    const image = await sharp(svgBuffer).toFile("svg-image.png");
  } catch (error) {
    console.log(error);
  }
}

addTextOnImage();

Buffer.from() cria um objeto Buffer a partir da imagem SVG. Um buffer é um espaço temporário na memória que armazena dados binários.

Depois de criar o objeto de buffer, você cria uma instância sharp com o objeto de buffer como entrada. Além de um caminho de imagem, sharp também aceita um buffer, Uint9Array, ou Uint8ClampedArray.

Finalmente, você salva a imagem SVG no diretório do projeto como svg-image.png.

Aqui está o código completo:

process_images/addTextOnImage.js
const sharp = require("sharp");

async function addTextOnImage() {
  try {
    const width = 750;
    const height = 483;
    const text = "Sammy the Shark";

    const svgImage = `
    <svg width="${width}" height="${height}">
      <style>
      .title { fill: #001; font-size: 70px; font-weight: bold;}
      </style>
      <text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
    </svg>
    `;
    const svgBuffer = Buffer.from(svgImage);
    const image = await sharp(svgBuffer).toFile("svg-image.png");
  } catch (error) {
    console.log(error);
  }
}

addTextOnImage()

Salve e saia do arquivo e, em seguida, execute seu script com o seguinte comando:

node addTextOnImage.js

Observação: Se você instalou o Node.js usando Opção 2 — Instalando o Node.js com Apt Usando um PPA do NodeSource ou Opção 3 — Instalando o Node Usando o Gerenciador de Versões do Node e está recebendo o erro fontconfig error: cannot load default config file: no such file: (null), instale o fontconfig para gerar o arquivo de configuração de fonte.

Atualize o índice de pacotes do seu servidor e, depois disso, use apt install para instalar fontconfig.

  1. sudo apt update
  2. sudo apt install fontconfig

Abra svg-image.png em seu computador local. Agora você deverá ver o texto Sammy the Shark renderizado com um fundo transparente:

Agora que você confirmou que o código SVG desenha o texto, você irá compor os gráficos de texto em sammy.png.

Adicione o seguinte código destacado para compor a imagem dos gráficos de texto SVG sobre a imagem sammy.png.

process_images/addTextOnImage.js
const sharp = require("sharp");

async function addTextOnImage() {
  try {
    const width = 750;
    const height = 483;
    const text = "Sammy the Shark";

    const svgImage = `
    <svg width="${width}" height="${height}">
      <style>
      .title { fill: #001; font-size: 70px; font-weight: bold;}
      </style>
      <text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
    </svg>
    `;
    const svgBuffer = Buffer.from(svgImage);
    const image = await sharp("sammy.png")
      .composite([
        {
          input: svgBuffer,
          top: 0,
          left: 0,
        },
      ])
      .toFile("sammy-text-overlay.png");
  } catch (error) {
    console.log(error);
  }
}

addTextOnImage();

O método composite() lê a imagem SVG da variável svgBuffer e a posiciona a 0 pixels do topo e 0 pixels da borda esquerda do sammy.png. Em seguida, você salva a imagem composta como sammy-text-overlay.png.

Salve e feche seu arquivo, e então execute seu programa usando o seguinte comando:

  1. node addTextOnImage.js

Abra sammy-text-overlay.png em seu computador local. Você deverá ver o texto adicionado sobre a imagem:

Você agora utilizou o método composite() para adicionar texto criado com SVG em outra imagem.

Conclusão

Neste artigo, você aprendeu como usar métodos afiados para processar imagens no Node.js. Primeiro, você criou uma instância para ler uma imagem e usou o método metadata() para extrair os metadados da imagem. Em seguida, você usou o método resize() para redimensionar uma imagem. Depois, você usou o método format() para alterar o tipo de imagem e comprimir a imagem. Em seguida, você prosseguiu usando vários métodos afiados para cortar, transformar em escala de cinza, girar e desfocar uma imagem. Por fim, você usou o método composite() para compor uma imagem e adicionar texto a uma imagem.

Para obter mais informações sobre métodos afiados adicionais, visite a documentação do sharp. Se você quiser continuar aprendendo Node.js, veja a série Como Codificar em Node.js.

Source:
https://www.digitalocean.com/community/tutorials/how-to-process-images-in-node-js-with-sharp