Dans cet article, nous allons explorer la création d’une application de ligne de commande (CLI) en C pour la conversion d’images. Ce projet vous permettra de comprendre les concepts fondamentaux liés à la manipulation d’images, de découvrir les bibliothèques adaptées à ce type de tâches, et d’appliquer des techniques de programmation C modernes.
L’objectif principal est de développer une application capable de convertir des images d’un format à un autre, comme de PNG à JPEG, en exploitant des bibliothèques populaires. Nous aborderons également l’ajout de fonctionnalités avancées, telles que le redimensionnement ou l’ajustement de la qualité, afin d’enrichir l’expérience utilisateur.
En suivant ce guide, vous acquerrez une compréhension approfondie des outils et des étapes nécessaires à la création d’un tel programme, tout en explorant les potentialités offertes par le langage C dans le domaine du traitement d’images.
Préparation de l’environnement de développement
Choix des outils et configuration
Pour commencer à développer une application CLI en C pour la conversion d’images, il est essentiel de disposer des outils et bibliothèques appropriés. Voici ce dont vous aurez besoin :
Compilateur C
Assurez-vous que vous avez un compilateur C installé. Les options populaires incluent :
- GCC (GNU Compiler Collection) : Standard sur de nombreuses distributions Linux.
- Clang : Alternative moderne et rapide.
- MSVC (Microsoft Visual C++) : Pour les environnements Windows.
Éditeur de texte ou IDE
Choisissez un éditeur ou un IDE adapté :
- VS Code : Léger, extensible, et compatible avec plusieurs outils C.
- CLion : IDE complet pour le développement C/C++.
- Vim/Emacs : Idéal pour les utilisateurs avancés.
Gestionnaire de paquets
Un gestionnaire de paquets facilite l’installation des bibliothèques nécessaires :
- Linux :
apt
,yum
oudnf
selon votre distribution. - Mac :
brew
via Homebrew. - Windows :
vcpkg
ouchoco
(Chocolatey).
Installation des bibliothèques nécessaires
libjpeg et libpng
Ces bibliothèques sont largement utilisées pour manipuler les images JPEG et PNG. Installez-les avec les commandes suivantes :
- Linux (Debian-based) :
sudo apt update && sudo apt install libjpeg-dev libpng-dev
- Mac (Homebrew) :
brew install jpeg libpng
- Windows (vcpkg) :
vcpkg install libjpeg-turbo libpng
ImageMagick
Pour des fonctionnalités avancées, ImageMagick est une excellente option :
- Linux :
sudo apt update && sudo apt install imagemagick libmagickwand-dev
- Mac :
brew install imagemagick
- Windows : Téléchargez le binaire depuis le site officiel.
Configuration de l’environnement
- Variables d’environnement : Ajoutez les bibliothèques à votre
PATH
ou configurezLD_LIBRARY_PATH
pour Linux/Mac etLIB
pour Windows. - Tester l’installation : Vérifiez que les bibliothèques sont correctement installées :
pkg-config --modversion libjpeg
Si vous utilisez ImageMagick, testez avec :
magick -version
Création du projet
Configurez votre projet avec un système de build comme CMake :
- Créez un fichier
CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(ImageConverter)
find_package(PkgConfig REQUIRED)
pkg_check_modules(JPEG REQUIRED libjpeg)
pkg_check_modules(PNG REQUIRED libpng)
add_executable(ImageConverter main.c)
target_include_directories(ImageConverter PRIVATE ${JPEG_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS})
target_link_libraries(ImageConverter PRIVATE ${JPEG_LIBRARIES} ${PNG_LIBRARIES})
- Générez le projet :
mkdir build && cd build
cmake ..
make
Votre environnement est maintenant prêt pour commencer à développer une application CLI en C pour la conversion d’images.
Les bases du traitement d’images en C
Comprendre la structure des images
Avant de manipuler des images, il est essentiel de comprendre leur structure. Les images sont des représentations numériques composées de pixels, où chaque pixel contient des informations de couleur. Ces informations sont stockées dans différents formats :
- JPEG : Format compressé avec perte, adapté aux photographies.
- PNG : Format compressé sans perte, idéal pour les images avec transparence.
- BMP : Format non compressé, utilisé pour des manipulations rapides.
Formats de couleur
- RGB : Les pixels sont représentés par trois composantes (Rouge, Vert, Bleu).
- RGBA : Ajout d’une composante Alpha pour gérer la transparence.
Lire et écrire des images en C
Pour manipuler des images en C, les bibliothèques comme libjpeg
ou libpng
sont nécessaires. Voici un exemple de lecture et d’écriture d’images en utilisant libjpeg
pour des fichiers JPEG.
Exemple : Lecture d’une image JPEG
#include <stdio.h>
#include <jpeglib.h>
void read_jpeg(const char *filename) {
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *infile = fopen(filename, "rb");
if (!infile) {
fprintf(stderr, "Impossible d'ouvrir le fichier %s\n", filename);
return;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
printf("Image Dimensions : %d x %d\n", cinfo.output_width, cinfo.output_height);
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
}
Exemple : Écriture d’une image JPEG
#include <stdio.h>
#include <jpeglib.h>
void write_jpeg(const char *filename, unsigned char *data, int width, int height) {
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *outfile = fopen(filename, "wb");
if (!outfile) {
fprintf(stderr, "Impossible d'ouvrir le fichier %s\n", filename);
return;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 90, TRUE);
jpeg_start_compress(&cinfo, TRUE);
while (cinfo.next_scanline < cinfo.image_height) {
unsigned char *row = data + (cinfo.next_scanline * width * 3);
jpeg_write_scanlines(&cinfo, &row, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
fclose(outfile);
}
Manipuler les pixels
Une fois l’image lue en mémoire, les pixels peuvent être modifiés directement. Par exemple, pour convertir une image en niveaux de gris :
Conversion en niveaux de gris
void convert_to_grayscale(unsigned char *data, int width, int height) {
for (int i = 0; i < width * height * 3; i += 3) {
unsigned char gray = 0.3 * data[i] + 0.59 * data[i + 1] + 0.11 * data[i + 2];
data[i] = data[i + 1] = data[i + 2] = gray;
}
}
Conclusion
Les bibliothèques comme libjpeg
et libpng
offrent des interfaces robustes pour lire et écrire des images en C. Comprendre les concepts de base tels que les formats de fichier et les structures de pixels est essentiel pour manipuler efficacement les images. Cette base permet de construire des fonctionnalités plus avancées dans une application CLI de conversion d’images.
Bibliothèques populaires pour la conversion d’images
Présentation des bibliothèques courantes
Pour développer une application de conversion d’images en C, il est crucial de choisir une bibliothèque adaptée à vos besoins. Voici une comparaison des bibliothèques les plus populaires, leurs fonctionnalités et leurs cas d’utilisation.
1. libjpeg
Libjpeg est une bibliothèque bien établie pour manipuler des images au format JPEG.
- Avantages :
- Performances élevées pour les images JPEG.
- Prise en charge de la compression et de la décompression.
- Compatible avec la plupart des projets en C.
- Inconvénients :
- Limitée aux fichiers JPEG.
Exemple d’utilisation :
#include <jpeglib.h>
/* Voir les exemples précédents pour la lecture et l'écriture d'images JPEG */
2. libpng
Libpng est utilisée pour travailler avec des images au format PNG.
- Avantages :
- Prise en charge des images sans perte.
- Gestion des transparences avec le canal alpha.
- Inconvénients :
- Plus complexe à manipuler que libjpeg.
Exemple d’utilisation :
#include <png.h>
/* Fonctionnalités similaires pour lire, manipuler et enregistrer des fichiers PNG */
3. ImageMagick
ImageMagick est une solution tout-en-un pour le traitement d’images. Elle prend en charge une vaste gamme de formats.
- Avantages :
- Supporte de nombreux formats (JPEG, PNG, GIF, TIFF, etc.).
- Fonctionnalités avancées comme le redimensionnement, la rotation et l’ajustement des couleurs.
- Peut être utilisé à la fois comme bibliothèque (MagickWand) ou outil CLI.
- Inconvénients :
- Plus lourd que libjpeg ou libpng.
- Courbe d’apprentissage plus élevée.
Exemple d’utilisation avec MagickWand :
#include <wand/MagickWand.h>
void convert_image(const char *input, const char *output) {
MagickWand *wand = NewMagickWand();
MagickReadImage(wand, input);
MagickWriteImage(wand, output);
DestroyMagickWand(wand);
}
4. OpenCV
OpenCV est une bibliothèque plus orientée vers la vision par ordinateur, mais elle inclut également des outils pour manipuler les images.
- Avantages :
- Large éventail de fonctionnalités (filtrage, détection d’objets, etc.).
- Support natif des conversions de format.
- Inconvénients :
- Moins adaptée aux projets légers.
Exemple d’utilisation :
#include <opencv2/opencv.hpp>
using namespace cv;
void convert_image(const char *input, const char *output) {
Mat image = imread(input);
imwrite(output, image);
}
Tableau comparatif des bibliothèques
Bibliothèque | Formats pris en charge | Facilité d’utilisation | Fonctionnalités avancées | Poids |
---|---|---|---|---|
libjpeg | JPEG | Facile | Basique | Léger |
libpng | PNG | Moyen | Basique | Léger |
ImageMagick | Multi-formats (JPEG, PNG…) | Moyen | Avancées | Modéré |
OpenCV | Multi-formats (JPEG, PNG…) | Moyen | Très avancées | Lourd |
Recommandations
- Si vous travaillez uniquement avec JPEG ou PNG, libjpeg et libpng sont des choix optimaux.
- Pour des projets nécessitant une prise en charge multi-formats ou des fonctionnalités avancées, utilisez ImageMagick.
- Si votre application s’étend au-delà de la simple conversion d’images, envisagez OpenCV pour ses capacités élargies.
Choisir la bonne bibliothèque garantit une implémentation efficace et simplifie les futures extensions de votre projet.
Implémentation d’une application simple
Créer une application CLI pour convertir une image
Dans cette section, nous allons implémenter une application simple en C qui charge une image au format PNG et la convertit en JPEG en utilisant les bibliothèques libpng
et libjpeg
. Cette application accepte les noms de fichiers en entrée et en sortie comme arguments de ligne de commande.
Étapes principales
- Lire l’image source (PNG) à l’aide de
libpng
. - Convertir les données en mémoire.
- Enregistrer l’image convertie (JPEG) avec
libjpeg
.
Code complet de l’application
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
#include <jpeglib.h>
void convert_png_to_jpeg(const char *input_file, const char *output_file) {
FILE *fp_in = fopen(input_file, "rb");
if (!fp_in) {
fprintf(stderr, "Impossible d'ouvrir le fichier %s\n", input_file);
exit(1);
}
// Lire l'image PNG
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!png_ptr || !info_ptr) {
fprintf(stderr, "Erreur d'allocation pour libpng\n");
fclose(fp_in);
exit(1);
}
if (setjmp(png_jmpbuf(png_ptr))) {
fprintf(stderr, "Erreur lors de la lecture de l'image PNG\n");
fclose(fp_in);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
exit(1);
}
png_init_io(png_ptr, fp_in);
png_read_info(png_ptr, info_ptr);
int width = png_get_image_width(png_ptr, info_ptr);
int height = png_get_image_height(png_ptr, info_ptr);
png_bytep row_pointers[height];
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
unsigned char *image_data = (unsigned char *)malloc(rowbytes * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = image_data + i * rowbytes;
}
png_read_image(png_ptr, row_pointers);
fclose(fp_in);
// Écrire l'image JPEG
FILE *fp_out = fopen(output_file, "wb");
if (!fp_out) {
fprintf(stderr, "Impossible d'ouvrir le fichier %s\n", output_file);
free(image_data);
exit(1);
}
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fp_out);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 90, TRUE);
jpeg_start_compress(&cinfo, TRUE);
unsigned char *rgb_row = (unsigned char *)malloc(width * 3);
while (cinfo.next_scanline < cinfo.image_height) {
unsigned char *row_ptr = row_pointers[cinfo.next_scanline];
for (int i = 0, j = 0; i < width * 4; i += 4, j += 3) {
// Convertir RGBA à RGB
rgb_row[j] = row_ptr[i];
rgb_row[j + 1] = row_ptr[i + 1];
rgb_row[j + 2] = row_ptr[i + 2];
}
jpeg_write_scanlines(&cinfo, &rgb_row, 1);
}
free(rgb_row);
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
fclose(fp_out);
free(image_data);
printf("Conversion terminée : %s -> %s\n", input_file, output_file);
}
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Utilisation : %s <fichier_png> <fichier_jpeg>\n", argv[0]);
return 1;
}
convert_png_to_jpeg(argv[1], argv[2]);
return 0;
}
Explication du code
Lecture de l’image PNG
- La bibliothèque
libpng
est utilisée pour lire les données de l’image en mémoire. - Les données sont stockées en tant que tableau de lignes (
row_pointers
), qui contient les pixels au format RGBA.
Conversion en JPEG
- La bibliothèque
libjpeg
est utilisée pour écrire les données de l’image en JPEG. - Les pixels RGBA sont convertis en RGB avant d’être écrits dans le fichier de sortie.
Tester l’application
Compilez et exécutez le programme :
gcc -o image_converter main.c -lpng -ljpeg
./image_converter input.png output.jpeg
Conclusion
Ce programme simple montre comment intégrer libpng
et libjpeg
pour créer une application CLI capable de convertir des images. Les prochaines étapes pourraient inclure l’ajout d’options pour la résolution ou le format de sortie via des arguments de ligne de commande.
Ajout de fonctionnalités avancées
Amélioration de l’application
Pour rendre l’application CLI plus utile et conviviale, il est possible d’ajouter des fonctionnalités avancées. Ces options permettront de personnaliser le processus de conversion d’images, comme la redimension, le recadrage ou la modification de la qualité.
1. Ajout d’une option de redimension
Le redimensionnement consiste à modifier les dimensions d’une image tout en préservant ses proportions ou en les adaptant. Voici comment l’ajouter :
Exemple de redimensionnement
Utilisez une fonction pour interpoler les pixels et produire une nouvelle taille :
#include <stdlib.h>
#include <string.h>
unsigned char *resize_image(unsigned char *data, int orig_width, int orig_height, int new_width, int new_height) {
unsigned char *resized_data = (unsigned char *)malloc(new_width * new_height * 3);
for (int y = 0; y < new_height; y++) {
for (int x = 0; x < new_width; x++) {
int orig_x = x * orig_width / new_width;
int orig_y = y * orig_height / new_height;
int orig_idx = (orig_y * orig_width + orig_x) * 3;
int new_idx = (y * new_width + x) * 3;
memcpy(&resized_data[new_idx], &data[orig_idx], 3);
}
}
return resized_data;
}
Intégration dans le programme
Après avoir lu les données de l’image, appliquez la fonction de redimensionnement avant d’écrire les pixels en JPEG :
unsigned char *resized_data = resize_image(image_data, orig_width, orig_height, new_width, new_height);
// Passez `resized_data` à l'étape suivante.
2. Ajout d’une option de recadrage
Le recadrage permet de sélectionner une partie spécifique de l’image à enregistrer.
Exemple de recadrage
Voici une fonction pour extraire une région rectangulaire :
unsigned char *crop_image(unsigned char *data, int orig_width, int orig_height,
int crop_x, int crop_y, int crop_width, int crop_height) {
unsigned char *cropped_data = (unsigned char *)malloc(crop_width * crop_height * 3);
for (int y = 0; y < crop_height; y++) {
for (int x = 0; x < crop_width; x++) {
int orig_idx = ((crop_y + y) * orig_width + (crop_x + x)) * 3;
int crop_idx = (y * crop_width + x) * 3;
memcpy(&cropped_data[crop_idx], &data[orig_idx], 3);
}
}
return cropped_data;
}
Intégration dans le programme
Après la lecture de l’image, appliquez la fonction crop_image
:
unsigned char *cropped_data = crop_image(image_data, orig_width, orig_height, 50, 50, 200, 200);
3. Ajustement de la qualité JPEG
La qualité d’un fichier JPEG influence directement sa taille et sa fidélité visuelle. Vous pouvez offrir une option pour ajuster la qualité lors de la compression :
Modifier la qualité dans le code
Dans le code d’écriture JPEG :
jpeg_set_quality(&cinfo, quality, TRUE);
Ajoutez une option pour spécifier la qualité via les arguments de ligne de commande.
4. Gestion des arguments CLI
Pour permettre à l’utilisateur de spécifier ces options (taille, qualité, etc.), utilisez un parseur d’arguments.
Exemple d’utilisation d’arguments
#include <getopt.h>
int main(int argc, char *argv[]) {
int new_width = 0, new_height = 0, quality = 90;
int opt;
while ((opt = getopt(argc, argv, "w:h:q:")) != -1) {
switch (opt) {
case 'w': new_width = atoi(optarg); break;
case 'h': new_height = atoi(optarg); break;
case 'q': quality = atoi(optarg); break;
default:
fprintf(stderr, "Utilisation : %s [-w width] [-h height] [-q quality] input.png output.jpeg\n", argv[0]);
return 1;
}
}
if (optind + 2 > argc) {
fprintf(stderr, "Utilisation : %s [-w width] [-h height] [-q quality] input.png output.jpeg\n", argv[0]);
return 1;
}
const char *input_file = argv[optind];
const char *output_file = argv[optind + 1];
// Appeler les fonctions avec les arguments appropriés
return 0;
}
Conclusion
L’ajout de fonctionnalités avancées comme le redimensionnement, le recadrage ou l’ajustement de la qualité améliore considérablement l’utilité de votre application CLI. La gestion des arguments de ligne de commande rend l’outil plus flexible et intuitif pour les utilisateurs. Vous pouvez continuer à enrichir l’application en ajoutant d’autres fonctionnalités comme la rotation ou le traitement par lot.
Conclusion
Dans cet article, nous avons exploré les étapes nécessaires pour créer une application de ligne de commande en C capable de convertir des images. En utilisant les bibliothèques libpng
et libjpeg
, nous avons développé une solution simple qui peut être enrichie par des fonctionnalités avancées comme le redimensionnement, le recadrage ou l’ajustement de la qualité.
L’ajout de fonctionnalités avancées permet à cette application de répondre à des besoins variés, tout en restant performante et accessible via des arguments CLI. Grâce à ces outils et techniques, vous êtes désormais équipé pour développer des applications C robustes et pratiques pour le traitement d’images, tout en continuant à explorer des améliorations telles que le traitement par lot ou l’intégration de bibliothèques supplémentaires comme ImageMagick ou OpenCV.
Avec cette base solide, vous pouvez étendre l’application et l’adapter à des cas d’utilisation encore plus spécifiques. Bon développement !