Lecture et écriture de métadonnées
Certains fichiers image contiennent des métadonnées que vous pouvez lire pour déterminer les caractéristiques de l’image. Par exemple, une photo numérique peut contenir des métadonnées que vous pouvez lire pour déterminer la fabrique et le modèle de l’appareil photo utilisé pour capturer l’image. Avec Windows GDI+, vous pouvez lire les métadonnées existantes et écrire de nouvelles métadonnées dans des fichiers image.
GDI+ offre un moyen uniforme de stocker et de récupérer des métadonnées à partir de fichiers image dans différents formats. Dans GDI+, un élément de métadonnées est appelé élément de propriété. Vous pouvez stocker et récupérer des métadonnées en appelant les méthodes SetPropertyItem et GetPropertyItem de la classe Image , et vous n’avez pas à vous soucier des détails de la façon dont un format de fichier particulier stocke ces métadonnées.
GDI+ prend actuellement en charge les métadonnées pour les formats de fichiers TIFF, JPEG, Exif et PNG. Le format Exif, qui spécifie comment stocker des images capturées par des appareils photo fixes numériques, s’appuie sur les formats TIFF et JPEG. Exif utilise le format TIFF pour les données de pixels non compressées et le format JPEG pour les données de pixels compressées.
GDI+ définit un ensemble de balises de propriété qui identifient les éléments de propriété. Certaines balises sont à usage général ; autrement dit, ils sont pris en charge par tous les formats de fichier mentionnés dans le paragraphe précédent. Les autres balises sont à usage spécial et s’appliquent uniquement à certains formats. Si vous essayez d’enregistrer un élément de propriété dans un fichier qui ne prend pas en charge cet élément de propriété, GDI+ ignore la demande. Plus précisément, la méthode Image::SetPropertyItem retourne PropertyNotSupported.
Vous pouvez déterminer les éléments de propriété stockés dans un fichier image en appelant Image::GetPropertyIdList. Si vous essayez de récupérer un élément de propriété qui n’est pas dans le fichier, GDI+ ignore la demande. Plus précisément, la méthode Image::GetPropertyItem retourne PropertyNotFound.
Lecture des métadonnées à partir d’un fichier
L’application console suivante appelle la méthode GetPropertySize d’un objet Image pour déterminer le nombre d’éléments de métadonnées dans le fichier FakePhoto.jpg.
#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
INT main()
{
// Initialize <tla rid="tla_gdiplus"/>.
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
UINT size = 0;
UINT count = 0;
Bitmap* bitmap = new Bitmap(L"FakePhoto.jpg");
bitmap->GetPropertySize(&size, &count);
printf("There are %d pieces of metadata in the file.\n", count);
printf("The total size of the metadata is %d bytes.\n", size);
delete bitmap;
GdiplusShutdown(gdiplusToken);
return 0;
}
Le code précédent, ainsi qu’un fichier particulier, FakePhoto.jpg, ont produit la sortie suivante :
There are 7 pieces of metadata in the file.
The total size of the metadata is 436 bytes.
GDI+ stocke un élément de métadonnées individuel dans un objet PropertyItem . Vous pouvez appeler la méthode GetAllPropertyItems de la classe Image pour récupérer toutes les métadonnées d’un fichier. La méthode GetAllPropertyItems retourne un tableau d’objets PropertyItem . Avant d’appeler GetAllPropertyItems, vous devez allouer une mémoire tampon suffisamment grande pour recevoir ce tableau. Vous pouvez appeler la méthode GetPropertySize de la classe Image pour obtenir la taille (en octets) de la mémoire tampon requise.
Un objet PropertyItem a les quatre membres publics suivants :
Description | |
---|---|
id | Balise qui identifie l’élément de métadonnées. Les valeurs qui peuvent être attribuées à id (PropertyTagImageTitle, PropertyTagEquipMake, PropertyTagExifExposureTime, etc.) sont définies dans Gdiplusimaging.h. |
length | Longueur, en octets, du tableau de valeurs pointées par le membre de données de valeur . Notez que si le membre de données de type est défini sur PropertyTagTypeASCII, le membre de données de longueur correspond à la longueur d’une chaîne de caractères terminée par null, y compris la terminaison NULL. |
type | Type de données des valeurs du tableau pointé vers le membre de données value. Les constantes (PropertyTagTypeByte, PropertyTagTypeASCII, etc.) qui représentent différents types de données sont décrites dans Constantes de type de balise de propriété image. |
value | Pointeur vers un tableau de valeurs. |
L’application console suivante lit et affiche les sept éléments de métadonnées dans le fichier FakePhoto.jpg. La fonction main s’appuie sur la fonction d’assistance PropertyTypeFromWORD, qui s’affiche après la fonction main.
#include <windows.h>
#include <gdiplus.h>
#include <strsafe.h>
using namespace Gdiplus;
INT main()
{
// Initialize GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
UINT size = 0;
UINT count = 0;
#define MAX_PROPTYPE_SIZE 30
WCHAR strPropertyType[MAX_PROPTYPE_SIZE] = L"";
Bitmap* bitmap = new Bitmap(L"FakePhoto.jpg");
bitmap->GetPropertySize(&size, &count);
printf("There are %d pieces of metadata in the file.\n\n", count);
// GetAllPropertyItems returns an array of PropertyItem objects.
// Allocate a buffer large enough to receive that array.
PropertyItem* pPropBuffer =(PropertyItem*)malloc(size);
// Get the array of PropertyItem objects.
bitmap->GetAllPropertyItems(size, count, pPropBuffer);
// For each PropertyItem in the array, display the id, type, and length.
for(UINT j = 0; j < count; ++j)
{
// Convert the property type from a WORD to a string.
PropertyTypeFromWORD(
pPropBuffer[j].type, strPropertyType, MAX_PROPTYPE_SIZE);
printf("Property Item %d\n", j);
printf(" id: 0x%x\n", pPropBuffer[j].id);
wprintf(L" type: %s\n", strPropertyType);
printf(" length: %d bytes\n\n", pPropBuffer[j].length);
}
free(pPropBuffer);
delete bitmap;
GdiplusShutdown(gdiplusToken);
return 0;
} // main
// Helper function
HRESULT PropertyTypeFromWORD(WORD index, WCHAR* string, UINT maxChars)
{
HRESULT hr = E_FAIL;
WCHAR* propertyTypes[] = {
L"Nothing", // 0
L"PropertyTagTypeByte", // 1
L"PropertyTagTypeASCII", // 2
L"PropertyTagTypeShort", // 3
L"PropertyTagTypeLong", // 4
L"PropertyTagTypeRational", // 5
L"Nothing", // 6
L"PropertyTagTypeUndefined", // 7
L"Nothing", // 8
L"PropertyTagTypeSLONG", // 9
L"PropertyTagTypeSRational"}; // 10
hr = StringCchCopyW(string, maxChars, propertyTypes[index]);
return hr;
}
L’application console précédente produit la sortie suivante :
Property Item 0
id: 0x320
type: PropertyTagTypeASCII
length: 16 bytes
Property Item 1
id: 0x10f
type: PropertyTagTypeASCII
length: 17 bytes
Property Item 2
id: 0x110
type: PropertyTagTypeASCII
length: 7 bytes
Property Item 3
id: 0x9003
type: PropertyTagTypeASCII
length: 20 bytes
Property Item 4
id: 0x829a
type: PropertyTagTypeRational
length: 8 bytes
Property Item 5
id: 0x5090
type: PropertyTagTypeShort
length: 128 bytes
Property Item 6
id: 0x5091
type: PropertyTagTypeShort
length: 128 bytes
La sortie précédente affiche un numéro d’ID hexadécimal pour chaque élément de propriété. Vous pouvez rechercher ces numéros d’ID dans Constantes d’étiquette de propriété d’image et découvrir qu’ils représentent les balises de propriété suivantes.
Valeur hexadécimale | Balise de propriété |
---|---|
0x0320 0x010f 0x0110 0x9003 0x829a 0x5090 0x5091 |
PropertyTagImageTitle PropertyTagEquipMake PropertyTagEquipModel PropertyTagExifDTOriginal PropertyTagExifExposureTime PropertyTagLuminanceTable PropertyTagChrominanceTable |
Le deuxième élément de propriété (index 1) de la liste a l’id PropertyTagEquipMake et le type PropertyTagTypeASCII. L’exemple suivant, qui est une continuation de l’application console précédente, affiche la valeur de cet élément de propriété :
printf("The equipment make is %s.\n", pPropBuffer[1].value);
La ligne de code précédente produit la sortie suivante :
The equipment make is Northwind Traders.
Le cinquième élément de propriété (index 4) de la liste a l’id PropertyTagExifExposureTime et le type PropertyTagTypeRational. Ce type de données (PropertyTagTypeRational) est une paire de longs. L’exemple suivant, qui est une continuation de l’application console précédente, affiche ces deux valeurs LONG sous forme de fraction. Cette fraction, 1/125, correspond au temps d’exposition mesuré en secondes.
long* ptrLong = (long*)(pPropBuffer[4].value);
printf("The exposure time is %d/%d.\n", ptrLong[0], ptrLong[1]);
Le code ci-dessus génère la sortie suivante :
The exposure time is 1/125.
Écriture de métadonnées dans un fichier
Pour écrire un élément de métadonnées dans un objet Image , initialisez un objet PropertyItem , puis transmettez l’adresse de cet objet PropertyItem à la méthode SetPropertyItem de l’objet Image .
L’application console suivante écrit un élément (le titre de l’image) des métadonnées dans un objet Image , puis enregistre l’image dans le fichier disque FakePhoto2.jpg. La fonction main s’appuie sur la fonction d’assistance GetEncoderClsid, qui est présentée dans la rubrique Récupération de l’identificateur de classe pour un encodeur.
#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
INT main()
{
// Initialize <tla rid="tla_gdiplus"/>.
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Status stat;
CLSID clsid;
char propertyValue[] = "Fake Photograph";
Bitmap* bitmap = new Bitmap(L"FakePhoto.jpg");
PropertyItem* propertyItem = new PropertyItem;
// Get the CLSID of the JPEG encoder.
GetEncoderClsid(L"image/jpeg", &clsid);
propertyItem->id = PropertyTagImageTitle;
propertyItem->length = 16; // string length including NULL terminator
propertyItem->type = PropertyTagTypeASCII;
propertyItem->value = propertyValue;
bitmap->SetPropertyItem(propertyItem);
stat = bitmap->Save(L"FakePhoto2.jpg", &clsid, NULL);
if(stat == Ok)
printf("FakePhoto2.jpg saved successfully.\n");
delete propertyItem;
delete bitmap;
GdiplusShutdown(gdiplusToken);
return 0;
}