Modifier une image transparente en C++
La page Structure d'un fichier TIFF non compressé détaille la structure d'un fichier TIFF doté d'un canal de transparence et non compressé. La présente page vient à la suite et montre comment modifier, à l'aide du langage C++, une image tiff transparente non compressée créée avec Gimp.
1) Créer une image tiff transparente non compressée
1.1) Créer une image 30x20 pixels
Créer une nouvelle image de 30 x 20 pixels avec Gimp. (Fichier/Nouvelle image...)
Ajouter un canal alpha (canal de transparence) à cette image (Calque/Transparence/Ajouter un canal alpha).
Passer en zoom 1600%. Afficher la grille (Affichage/Afficher la grille), après avoir configuré cette grille à 1 px en largeur et 1 px en hauteur (Edition/Préférence/Grille et Image/Configurer la grille). Peindre la première ligne en rouge et le dernier pixel de cette ligne en vert. Enregistrer cette image (Fichier/Export As...), sur C: avec le nom "modele_30_20.tif" par exemple. Enregistrer sans compression et en cochant l'option "Enregistrer les valeurs de couleur pour les pixels transparents".
Examiner le contenu du fichier image à l'aide d'un éditeur hexadécimal.
Vérifier la présence des 8 octets d'entête puis des 2400 octets rgba (la première ligne est en premier) puis des 284 octets constituant l'Image File Directory (IFD), soit un total de 2692 octets numérotés de 0 à 2691.
Vérifier avec un petit proramme C++ le nombre d'octets constituant le fichier.
#include <iostream>
#include <stdio.h>
using namespace std;
int main ()
{
FILE * pf;
int n;
pf = fopen("C:/modele_30_20.tif", "r");
if( pf == NULL ){cout << "Erreur ! Fichier manquant..." << endl; return(1);}
fseek(pf, 0, SEEK_END);
n = ftell(pf);
cout << "Nombre d'octets : " << n << endl;
fclose(pf);
return(0);
}
1.2) Créer une image 1200x800 pixels
En procédant de la même façon, créer une nouvelle image de 1200 x 800 pixels avec Gimp. Colorier respectivement en rouge, vert et bleu le dernier pixel de la première, de la deuxième et de la troisième ligne. Ce coloriage permet de faciliter ensuite le repérage des lignes correspondantes, dans le fichier image, à l'aide d'un éditeur hexadécimal.
Examiner le contenu du fichier image à l'aide d'un éditeur hexadécimal. Repérer les lignes 1,2 et 3 constituées de pixels blancs non transparents (FF FF FF FF) et terminées respectivement par un pixel rouge (FF 00 00 FF), vert (00 FF 00 FF) et bleu (00 00 FF FF).
Vérifier la présence des 8 octets d'entête puis des 3 840 000 octets rgba (la première ligne en premier) puis des 392 octets constituant l'Image File Directory (IFD), soit un total de 3 840 400 octets numérotés de 0 à 3 840 399.
Vérifier avec un petit proramme C++ le nombre d'octets constituant le fichier.
1.3) Conclusion
Une image de taille W x H pixels, créée et enregistrée avec Gimp sans compression et avec un canal de transparence, conduit à un fichier tiff présentant une taille de N octets avec N = 8 octets d'entête + W x H x 4 octets rgba + n octets IFD
Vérification
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main ()
{
FILE *pf;
unsigned char *t;
long nbytes;
int W, H, i, j, k, p, q, largeur, hauteur;
W = 1200;
H= 800;
//ouverture du fichier et calcul de sa taille
pf = fopen("C:/modele_1200_800.tif", "rb");
fseek(pf, 0, SEEK_END);//positionnement à la fin du fichier
nbytes = ftell(pf);
cout << "Nombre d'octets du fichier : " << nbytes << endl;
rewind(pf); //positionnement au début du fichier
//écriture des octets du fichier dans t
t = (unsigned char *)malloc((nbytes+1)*sizeof(unsigned char));
fread(t, nbytes, 1, pf);
fclose(pf);
//Traitement
p = W * H * 4 + 30; q = W * H * 4 + 42;
largeur = t[p] + 256 * t[p+1] + 256 * 256 * t[p+2] + 256 * 256* 256 * t[p+3];
hauteur = t[q] + 256 * t[q+1] + 256 * 256 * t[q+2] + 256 * 256* 256 * t[q+3];
cout << "largeur = " << largeur << endl;
cout << "hauteur = " << hauteur << endl;
free(t);
system("pause");
return (0);
}
2) Modifier l'image avec un programme C++
2.1) Ecrire le programme
Le programme lit le fichier tif octet par octet, du début à la fin. Il range ces octets séquentiellement dans un tableau t, créé de façon dynamique en réservant la mémoire nécessaire à l'aide de l'instruction malloc. La création du tableau t de façon dynamique est ici obligatoire car une création statique, à l'aide d'une simple déclaration "unsigned char t[4000000]", fonctionne seulement avec des tableaux de petites ou de moyennes tailles mais elle ne fonctionne pas avec des tableaux de très grandes tailles comme c'est le cas ici.
Les octets rgba de l'image sont ensuite modifiés directement dans le tableau t à l'aide de deux boucles de traitement. La première boucle trace un cadre extérieur avec une couleur, une transparence et une largeur choisies. La seconde boucle rend transparente la partie centrale de l'image qui est située à l'intérieur de la frontière délimitée par le cadre. Les octets du tableau t sont enfin recopiés séquentiellement dans le fichier "C:/modele_1200_800_sauv.tiff".
/*
Modification d'une image tiff créée avec Gimp
sans compression et avec canal de transparence
Auteur C.Turrier - Juillet 2016
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main ()
{
FILE *pf;
unsigned char *t;
long nbytes;
int W, H, i, j, k;
W = 1200;
H= 800;
//ouverture du fichier et calcul de sa taille
pf = fopen("C:/modele_1200_800.tif", "rb");
fseek(pf, 0, SEEK_END);//positionnement à la fin du fichier
nbytes = ftell(pf);
cout << "Nombre d'octets du fichier : " << nbytes << endl;
rewind(pf); //positionnement au début du fichier
//écriture des octets du fichier dans t
t = (unsigned char *)malloc((nbytes+1)*sizeof(unsigned char));
fread(t, nbytes, 1, pf);
fclose(pf);
//Traitement
for( i = 0; i < H; i++){
for( j = 0; j < W; j++){
//r pixel ij
k = 8 + i*W*4 + j*4; t[k]=206;
//g pixel ij
k = 8 + i*W*4 + j*4 + 1; t[k]= 201;
//b pixel ij
k = 8 + i*W*4 + j*4 + 2; t[k]= 198;
//a pixel ij
k = 8 + i*W*4 + j*4 + 3; t[k]= 224;
}}
for( i = 10; i < H-10; i++){
for( j = 10; j < W-10; j++){
//r pixel ij
k = 8 + i*W*4 + j*4; t[k]=0;
//g pixel ij
k = 8 + i*W*4 + j*4 + 1; t[k]= 0;
//b pixel ij
k = 8 + i*W*4 + j*4 + 2; t[k]= 0;
//a pixel ij
k = 8 + i*W*4 + j*4 + 3; t[k]= 0;
}}
//enregistrement du contenu de t dans un fichier
pf = fopen("C:/modele_1200_800_sauv.tif","w+b");
if( pf == NULL ){cout << "Erreur ! Fichier C:/modele_1200_800_sauv.tif manquant..." << endl; return(1);}
for (i=0; i < nbytes; i++){ fprintf (pf,"%c", t[i]);}
fclose(pf);
free(t);
system("pause");
return (0);
}
Télécharger le code source main.cpp
3.2) Exécuter le programme
Ouvrir avec Gimp l'image modifiée (C:/modele_1200_800_sauv.tif). Vérifier la présence du cadre extérieur et de la transparence de la partie centrale.
2.3) Utiliser l'image modifiée
L'image modifiée par le programme ci-dessus peut être ensuite utilisée avec Gimp pour encadrer une photo. Pour cela, ouvrir l'image avec Gimp, copier cette image dans le presse papier puis la coller dans un calque situé au dessus de celui de la photo. La couleur, la transparence et la largeur du cadre doivent avoir été préalalblement choisies pour être assorties à la photo (pour la couleur, utiliser l'outil pipette).
Dans l'image suivante, deux cadres ont été créés à l'aide du programme puis placés sur la photo à l'aide de Gimp. Un premier cadre clair transparent de 20 pixels de large et un second cadre transparent plus foncé de 10 pixels de large.