Manipulation d’image avec des Nestjs et Sharp

Apprenez l’importance de l’optimisation de l’image et comment intégrer la bibliothèque Sharp aux NESTJ pour effectuer certaines techniques de manipulation d’images.
Dans cet article, nous créerons une application Web de manipulation d’image en utilisant Pointu bibliothèque et Faire. Nous apprendrons l’importance de l’optimisation de l’image et comment intégrer la bibliothèque Sharp avec les NESTJ pour effectuer des techniques de manipulation d’images comme le flou, le format d’image, la rotation, le retournement, etc.
Qu’est-ce que Sharp?
Sharp est facile à utiliser Node.js bibliothèque pour le traitement d’image. Il est largement utilisé en raison de sa vitesse, de sa qualité d’image de sortie et de ses besoins minimaux de code.
Par exemple, le code de redimensionnement d’une image ressemblerait à ceci:
async function resizeImage() {
try {
await sharp("house.jpg")
.resize({
width: 40,
height: 107,
})
.toFile("resized-house.jpg");
} catch (error) {
console.log(error);
}
}
Qu’est-ce que NESTJS?
NESTJS est un cadre backend Node.js largement aimé pour son architecture modulaire. Cette architecture favorise la séparation des préoccupations, permettant aux développeurs et aux équipes de créer rapidement des applications côté serveur évolutives et maintenables.
NESTJS dispose également de plusieurs modules intégrés pour gérer les tâches communes comme les téléchargements de fichiers et le service de fichiers statiques, que nous utiliserons pour intégrer Sharp dans notre application.
Importance de l’optimisation de l’image
Bien que les images améliorent les sites Web, les sites non optimisés peuvent les ralentir. Des images non optimisées entraînent des temps de chargement plus longs, une mauvaise expérience utilisateur et une augmentation des coûts de stockage du site Web. Cela peut être une différence significative entre un site étonnant et terrible.
L’optimisation de l’image signifie fournir des visuels de haute qualité dans un format et une taille efficaces. L’optimisation des images peut avoir un impact direct sur la rétention des utilisateurs et le classement des moteurs de recherche, donc l’optimisation des images est très importante.
Zones d’optimisation d’image
Certains domaines clés à considérer sont le format de fichier, la qualité et la taille de l’image.
Format de fichier
Lorsque vous choisissez un format de fichier, vous devez d’abord distinguer les formats plus anciens et plus largement pris en charge et les formats plus récents et plus performants.
Formats plus anciens:
- Jpeg – Une option populaire pour les photos et les images détaillées. Pensez aux images sur un site Web de portefeuille de photographie.
- PNG – Pensez aux graphiques, aux images avec des contrastes nets ou des arrière-plans transparents.
Formats plus récents:
- Webp – C’est un bon choix lors de la priorisation des performances. Il réduit considérablement la taille du fichier et est pris en charge par la plupart des navigateurs modernes.
- Avenues – C’est un autre bon choix pour les performances, offrant souvent une meilleure compression que WebP et production de fichiers plus petits au même niveau de qualité, bien qu’il ne soit pas aussi largement adopté que WebP.
Des formats plus récents comme WebP et AVIF sont de plus en plus préférés, et les images de secours peuvent être utilisées pour la compatibilité avec les navigateurs qui ne les soutiennent pas.
Qualité et taille
- Optimiser pour le contenu – Qualité d’image de tailleur basée sur le but. Les photos peuvent tolérer plus de compression avec une qualité inférieure, tandis que les images avec du texte, des ridules ou des logos devraient avoir une meilleure qualité pour préserver la netteté.
- Rédigez-vous toujours avant utilisation – Une astuce pro est de redimensionner les images aux dimensions exactes qu’elles seront utilisées. Cela évite les tailles de fichiers inutilement importantes, l’amélioration des vitesses de rendu et l’efficacité globale.
Configuration du projet
Pour commencer, vous devrez installer la CLI NESTJS si vous ne l’avez pas déjà fait. Exécutez la commande suivante pour l’installer:
npm i -g @nestjs/cli
Ensuite, utilisons la CLI NESTJS pour créer un nouveau projet en exécutant la commande suivante:
nest new sharp-demo
Vous serez invité à choisir un gestionnaire de packages. Pour cet article, nous utiliserons NPM (Node Package Manager).
Une fois l’installation terminée, vous aurez un nouveau dossier appelé sharp-demo
. Ce sera notre répertoire de projet, et vous pouvez y accéder en exécutant cette commande:
cd sharp-demo
Ensuite, exécutons la commande suivante pour échafaudager un module d’images:
nest g resource images
Sélectionnez ensuite l’API REST comme indiqué dans l’image ci-dessous.
Installer des dépendances
Exécutez la commande suivante pour installer les dépendances dont nous aurons besoin pour notre projet:
npm i sharp && npm i --save @nestjs/serve-static && npm i -D @types/multer
La commande ci-dessus installe le sharp
package, que nous utiliserons pour la manipulation d’images; les nestjs serve-static
package, que nous utiliserons pour servir notre index.html
; Et le Multer typings
Package, que nous utiliserons dans notre intercepteur de fichiers pour extraire notre image.
Servir la page HTML
Pour le frontend de notre application, nous créerons une page HTML et la servirons avec les NESTJS ServeStaticModule
.
Mettez à jour votre app.module.ts
dossier avec les éléments suivants:
import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { ImagesModule } from "./images/images.module";
import { ServeStaticModule } from "@nestjs/serve-static";
import { join } from "path";
@Module({
imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, "..", "public"),
}),
ImagesModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Dans le code ci-dessus, nous configurons notre application pour servir des fichiers statiques. Nous soulignons également le répertoire public situé à un niveau au-dessus du répertoire actuel en tant que répertoire contenant nos fichiers statiques.
Ensuite, créez un dossier appelé public
À la racine de votre projet, et dans l’informatique, créez deux fichiers nommés index.html
et script.js
.
Le répertoire du projet devrait maintenant ressembler à ceci:
Mettre à jour le index.html
dossier avec les éléments suivants:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Image Manipulation with NestJS and Sharp</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.form-group {
margin-bottom: 15px;
}
#output-container {
margin-top: 20px;
display: flex;
gap: 20px;
}
img {
max-width: 300px;
max-height: 300px;
object-fit: contain;
border: 1px solid #ddd;
padding: 5px;
}
</style>
</head>
<body>
<h1>Image Manipulation with NestJS and Sharp</h1>
<form id="imageForm">
<div class="form-group">
<label for="fileInput">Upload Image:</label>
<input
type="file"
id="fileInput"
name="file"
accept="image/*"
required
/>
</div>
<div class="form-group">
<label for="technique">Choose Manipulation Technique:</label>
<select id="technique" name="technique" required>
<option value="blur">Blur</option>
<option value="rotate">Rotate</option>
<option value="tint">Tint</option>
<option value="grayscale">Grayscale</option>
<option value="flip">Flip</option>
<option value="flop">Flop</option>
<option value="crop">Crop</option>
<option value="createComposite">Create Composite Image</option>
</select>
</div>
<div class="form-group">
<label for="format">Choose Output Format:</label>
<select id="format" name="format" required>
<option value="jpeg">JPEG</option>
<option value="png">PNG</option>
<option value="webp">WebP</option>
<option value="avif">AVIF</option>
</select>
</div>
<button type="submit">Submit</button>
</form>
<div id="output-container" style="display: none">
<div>
<h3>Original Image</h3>
<img
id="originalImage"
width="300"
height="300"
src="#"
alt="Original Image"
/>
</div>
<div>
<h3>Manipulated Image</h3>
<img id="manipulatedImage" src="#" alt="Manipulated Image" />
</div>
</div>
<script src="script.js"></script>
</body>
</html>
Mettre à jour également le script.js
dossier avec les éléments suivants:
document.addEventListener("DOMContentLoaded", () => {
const form = document.getElementById("imageForm");
const manipulatedImage = document.getElementById("manipulatedImage");
const outputContainer = document.getElementById("output-container");
const originalImage = document.getElementById("originalImage");
form.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(form);
const file = formData.get("file");
if (!file) return;
try {
const response = await fetch("http://localhost:3000/images/process", {
method: "POST",
body: formData,
});
const result = await response.json();
if (result.imageBase64) {
manipulatedImage.src = result.imageBase64;
const reader = new FileReader();
reader.onloadend = function () {
originalImage.src = reader.result;
};
reader.readAsDataURL(file);
outputContainer.style.display = "flex";
} else {
alert("File upload failed");
}
} catch (error) {
console.error("Error during upload:", error);
}
});
});
Dans le code ci-dessus, nous extraissons l’image traitée au format Base64 à partir de la réponse et la définissons comme source du manipulatedImage
élément, ce qui lui permet d’être affiché dynamiquement.
Configurer le contrôleur d’images
Ensuite, mettons à jour notre ImagesController
Pour gérer les téléchargements de fichiers et renvoyer l’image traitée au format Base64.
Mettre à jour le images.controller.ts
dossier avec les éléments suivants:
import {
Body,
Controller,
Post,
UploadedFile,
UseInterceptors,
} from "@nestjs/common";
import { ImagesService } from "./images.service";
import { FileInterceptor } from "@nestjs/platform-express";
import * as sharp from "sharp";
@Controller("images")
export class ImagesController {
constructor(private readonly imagesService: ImagesService) {}
@Post("process")
@UseInterceptors(FileInterceptor("file"))
async uploadAndProcessFile(
@UploadedFile() file: Express.Multer.File,
@Body()
body: {
technique: string;
format: keyof sharp.FormatEnum;
}
) {
const base64Image = await this.imagesService.processImage(
file,
body.technique,
body.format
);
return {
message: "File uploaded and processed successfully",
imageBase64: base64Image,
};
}
}
Dans le code ci-dessus, nous utilisons le FileInterceptor
pour extraire le fichier téléchargé, tandis que le technique
et format
sont extraits du corps de la demande avec le @Body
décorateur. Ces paramètres sont ensuite transmis au processImage
méthode de ImagesService
pour le traitement.
Configurer le service d’images
À la fin de cette section, votre images.service.ts
Le fichier doit ressembler à ceci:
Mettre à jour le images.service.ts
dossier avec les éléments suivants:
import * as sharp from "sharp";
import { Injectable } from "@nestjs/common";
@Injectable()
export class ImagesService {
async processImage(
file: Express.Multer.File,
technique: string,
format: keyof sharp.FormatEnum
): Promise<Buffer> {
try {
const method = (this as any)[technique];
if (typeof method !== "function") {
throw new Error(
`Method "${technique}" is not defined or not a function`
);
}
return await method.call(this, file, format);
} catch (error) {
console.error(`Method "${technique}" is not defined or not a function`);
throw new Error(
`Failed to process image with technique "${technique}": ${error.message}`
);
}
}
}
Dans le code ci-dessus, le processImage
recherche et appelle un matching
Méthode dans le ImagesService
classe basée sur le technique
passé. Cela donne la flexibilité d’utiliser différentes méthodes de manipulation d’images avec un seul itinéraire basé sur la valeur du technique
dans le corps de la demande.
Brouiller une image
Maintenant que nous avons mis en place le processImage
Méthode, nous pouvons ajouter toute autre méthode nécessaire pour la manipulation d’image au ImagesService
classe, et il peut être utilisé en faisant passer son nom comme valeur de la technique dans le corps de la demande.
Ajoutons le blur()
Méthode pour brouiller une image:
async blur(file: Express.Multer.File, format: keyof sharp.FormatEnum) {
const processedBuffer = await sharp(file.buffer)
.resize(300, 300)
.blur(10)
.toFormat(format)
.toBuffer()
return `data:image/${format};base64,${processedBuffer.toString('base64')}`;
}
Le code ci-dessus prend le tampon d’une image (les données d’image brutes) et la transmet à Sharp. Le resize()
La méthode redimensionne alors l’image à 300×300 pixels. Ensuite, le blur()
La méthode applique un effet flou avec une résistance de 9, bien que la méthode puisse prendre des valeurs de 0,3-1000.
Ensuite, nous convertissons l’image au format spécifié et générons l’image traitée sous forme de tampon. Enfin, le tampon est codé à Base64 et envoyé sous forme de chaîne d’URL de données.
Le résultat lorsqu’il est appelé ci-dessous:
Faire tourner une image
Ensuite, nous ajouterons le rotate()
Méthode pour faire pivoter une image:
async rotate(file: Express.Multer.File, format: keyof sharp.FormatEnum) {
const processedBuffer = await sharp(file.buffer)
.resize(300, 300)
.rotate(140, { background: "#ddd" })
.toFormat(format)
.toBuffer()
return `data:image/${format};base64,${processedBuffer.toString('base64')}`;
}
Le rotate()
La méthode prend l’angle de rotation et peut également prendre une couleur d’arrière-plan personnalisée pour les angles non 90 °.
Lorsqu’il est appelé, le résultat est:
Il est important de noter que chaque transformation se produit sur l’image telle qu’elle existe à cette étape, donc si nous avions tourné l’image avant de le redimensionner, nous aurions un résultat différent, comme indiqué ci-dessous.
Tenter une image
Ajoutons le tint()
Méthode pour teinter une image:
async tint(file: Express.Multer.File, format: keyof sharp.FormatEnum) {
const processedBuffer = await sharp(file.buffer)
.resize(300, 300)
.tint({ r: 150, g: 27, b: 200 })
.toFormat(format)
.toBuffer()
return `data:image/${format};base64,${processedBuffer.toString('base64')}`;
}
Le tint()
La méthode modifie la couleur d’une image en appliquant une teinte spécifiée basée sur les valeurs rouges, vertes et bleues (RVB). La plage pour chaque valeur est de 0 à 255.
Lorsqu’il est appelé, le résultat est:
Convertir l’image en niveaux de gris
Ensuite, ajoutons le grayscale()
Méthode pour convertir une image en niveaux de gris:
async grayscale(file: Express.Multer.File, format: keyof sharp.FormatEnum) {
const processedBuffer = await sharp(file.buffer)
.resize(300, 300)
.grayscale()
.toFormat(format)
.toBuffer()
return `data:image/${format};base64,${processedBuffer.toString('base64')}`;
}
Le grayscale()
et greyscale()
Les méthodes suppriment toutes les informations de couleur et représentent l’image à l’aide de nuances de gris.
Lorsqu’il est appelé, le résultat est:
Retourner une image
Ajoutons le flip()
Méthode pour retourner une image:
async flip(file: Express.Multer.File, format: keyof sharp.FormatEnum) {
const processedBuffer = await sharp(file.buffer)
.resize(300, 300)
.flip()
.toFormat(format)
.toBuffer()
return `data:image/${format};base64,${processedBuffer.toString('base64')}`;
}
Le flip()
La méthode inverse verticalement une image. Lorsqu’il est appelé, le résultat est:
Floping une image
Nous pouvons utiliser le flop()
Méthode pour flop une image:
async flop(file: Express.Multer.File, format: keyof sharp.FormatEnum) {
const processedBuffer = await sharp(file.buffer)
.resize(300, 300)
.flop()
.toFormat(format)
.toBuffer()
return `data:image/${format};base64,${processedBuffer.toString('base64')}`;
}
Cette méthode inverse horizontalement une image. Lorsqu’il est appelé, le résultat est:
Cramper une image
Ensuite, ajoutons le crop()
Méthode pour recadrer une image:
async crop(file: Express.Multer.File, format: keyof sharp.FormatEnum) {
const processedBuffer = await sharp(file.buffer)
.extract({ left: 140, width: 1800, height: 1800, top: 140 })
.resize(300, 300)
.toFormat(format)
.toBuffer()
return `data:image/${format};base64,${processedBuffer.toString('base64')}`;
}
Le extract()
La méthode nous permet de décrire une boîte à l’intérieur de l’image pour conserver le reste.
- gauche – la position horizontale où la boîte doit commencer
- largeur – la largeur de la boîte
- haut – la position verticale à laquelle la boîte doit commencer
- hauteur – la hauteur de la boîte
Lorsqu’il est appelé, le résultat est:
Comme mentionné ci-dessus, l’ordre lors du enchaînement des méthodes nets est importante. C’est pourquoi nous avons appelé extract()
avant resize()
– ailleurs, nous obtiendrions un résultat différent.
Création d’une image composite
Enfin, ajoutons le createComposite
méthode:
async createComposite(file: Express.Multer.File, format: keyof sharp.FormatEnum) {
const greyHouse = await sharp(file.buffer)
.resize(150, 150)
.grayscale()
.toBuffer()
const processedBuffer = await sharp(file.buffer)
.composite([
{
input: greyHouse,
top: 50,
left: 50,
},
])
.resize(300, 300)
.toFormat(format)
.toBuffer()
return `data:image/${format};base64,${processedBuffer.toString('base64')}`;
}
Le composite()
La méthode prend un tableau d’objets de superposition contenant input
, top
et left
propriétés. Il positionne chaque superposition en utilisant le top
et left
propriétés.
Dans le code ci-dessus, nous créons une petite version en niveaux de gris de l’image à utiliser comme superposition. Lorsqu’il est appelé, le résultat est:
Serveur de départ
Maintenant que nous avons terminé la configuration, nous pouvons démarrer notre serveur. Enregistrez tous les fichiers et démarrez le serveur NESTJS en exécutant la commande suivante:
npm run start
Vous devriez voir ceci:
Pour accéder à notre index.html
Page, accédez à http: // localhost: 3000 / index.html.
Conclusion
Les images jouent un rôle important sur le Web. Par conséquent, les optimiser et utiliser d’autres techniques de manipulation d’images avec des bibliothèques comme des cadres nets et backend comme NESTJS est important.
Après avoir créé l’application Web de manipulation d’image, vous devriez être capable de brouiller, de tourner, de teinte, de vous convertir en niveaux de gris, flip, flop, recadrer, créer une image composite et convertir des images en un format différent.
Source link