Lesen und Schreiben von Metadaten
Einige Bilddateien enthalten Metadaten, die Sie lesen können, um Merkmale des Bilds zu bestimmen. Beispielsweise kann ein digitales Foto Metadaten enthalten, die Sie lesen können, um Marke und Modell der Kamera zu bestimmen, die zum Aufnehmen des Bilds verwendet wurde. Mit Windows GDI+ können Sie vorhandene Metadaten lesen und auch neue Metadaten in Imagedateien schreiben.
GDI+ bietet eine einheitliche Möglichkeit zum Speichern und Abrufen von Metadaten aus Bilddateien in verschiedenen Formaten. In GDI+ wird ein Metadatenelement als Eigenschaftselement bezeichnet. Sie können Metadaten speichern und abrufen, indem Sie die Methoden SetPropertyItem und GetPropertyItem der Image-Klasse aufrufen, und Sie müssen sich nicht um die Details der Speicherung dieser Metadaten in einem bestimmten Dateiformat kümmern.
GDI+ unterstützt derzeit Metadaten für die Dateiformate TIFF, JPEG, Exif und PNG. Das Exif-Format, das angibt, wie von digitalen Standkameras aufgenommene Bilder gespeichert werden sollen, basiert auf den Formaten TIFF und JPEG. Exif verwendet das TIFF-Format für unkomprimierte Pixeldaten und das JPEG-Format für komprimierte Pixeldaten.
GDI+ definiert einen Satz von Eigenschaftstags, die Eigenschaftselemente identifizieren. Bestimmte Tags sind universell; Das heißt, sie werden von allen dateiformaten unterstützt, die im vorherigen Absatz erwähnt werden. Andere Tags sind speziell und gelten nur für bestimmte Formate. Wenn Sie versuchen, ein Eigenschaftselement in einer Datei zu speichern, die dieses Eigenschaftselement nicht unterstützt, ignoriert GDI+ die Anforderung. Genauer gesagt gibt die Image::SetPropertyItem-Methode PropertyNotSupported zurück.
Sie können die Eigenschaftenelemente ermitteln, die in einer Imagedatei gespeichert sind, indem Sie Image::GetPropertyIdList aufrufen. Wenn Sie versuchen, ein Eigenschaftselement abzurufen, das sich nicht in der Datei befindet, ignoriert GDI+ die Anforderung. Genauer gesagt gibt die Image::GetPropertyItem-Methode PropertyNotFound zurück.
Lesen von Metadaten aus einer Datei
Die folgende Konsolenanwendung ruft die GetPropertySize-Methode eines Image-Objekts auf, um zu bestimmen, wie viele Metadatenelemente in der Datei FakePhoto.jpg sind.
#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;
}
Der vorherige Code hat zusammen mit einer bestimmten Datei FakePhoto.jpg die folgende Ausgabe erzeugt:
There are 7 pieces of metadata in the file.
The total size of the metadata is 436 bytes.
GDI+ speichert einzelne Metadaten in einem PropertyItem-Objekt . Sie können die GetAllPropertyItems-Methode der Image-Klasse aufrufen, um alle Metadaten aus einer Datei abzurufen. Die GetAllPropertyItems-Methode gibt ein Array von PropertyItem-Objekten zurück. Bevor Sie GetAllPropertyItems aufrufen, müssen Sie einen Puffer zuordnen, der groß genug ist, um dieses Array zu empfangen. Sie können die GetPropertySize-Methode der Image-Klasse aufrufen, um die Größe (in Bytes) des erforderlichen Puffers abzurufen.
Ein PropertyItem-Objekt verfügt über die folgenden vier öffentlichen Member:
BESCHREIBUNG | |
---|---|
id | Ein Tag, das das Metadatenelement identifiziert. Die Werte, die id zugewiesen werden können (PropertyTagImageTitle, PropertyTagEquipMake, PropertyTagExifExposureTime usw.), werden in Gdiplusimaging.h definiert. |
length | Die Länge des Arrays von Werten, auf das vom Wertdatenmember verwiesen wird, in Bytes. Beachten Sie, dass, wenn der Typdatenmember auf PropertyTagTypeASCII festgelegt ist, der Längendatenmember die Länge einer null-beendeten Zeichenfolge ist, einschließlich des NULL-Abschlussators. |
type | Der Datentyp der Werte im Array, auf das vom Wertdatenmember verwiesen wird. Konstanten (PropertyTagTypeByte, PropertyTagTypeASCII usw.), die verschiedene Datentypen darstellen, werden in Image Property Tag Type Constants beschrieben. |
value | Ein Zeiger auf ein Array von Werten. |
Die folgende Konsolenanwendung liest und zeigt die sieben Metadaten in der Datei FakePhoto.jpg an. Die Standard-Funktion basiert auf der Hilfsfunktion PropertyTypeFromWORD, die nach der Standard-Funktion angezeigt wird.
#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;
}
Die vorherige Konsolenanwendung erzeugt die folgende Ausgabe:
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
Die vorherige Ausgabe zeigt eine hexadezimale ID-Nummer für jedes Eigenschaftselement. Sie können diese ID-Nummern in Bildeigenschaftentagkonstanten nachschlagen und herausfinden, dass sie die folgenden Eigenschaftentags darstellen.
Hexadezimalwert | Eigenschaftstag |
---|---|
0x0320 0x010f 0x0110 0x9003 0x829a 0x5090 0x5091 |
PropertyTagImageTitle PropertyTagEquipMake PropertyTagEquipModel PropertyTagExifDTOriginal PropertyTagExifExposureTime PropertyTagLuminanceTable PropertyTagChrominanceTable |
Das zweite Eigenschaftselement (Index 1) in der Liste hat die ID PropertyTagEquipMake und den Typ PropertyTagTypeASCII. Im folgenden Beispiel, das eine Fortsetzung der vorherigen Konsolenanwendung darstellt, wird der Wert dieses Eigenschaftselements angezeigt:
printf("The equipment make is %s.\n", pPropBuffer[1].value);
Die obige Codezeile erzeugt die folgende Ausgabe:
The equipment make is Northwind Traders.
Das fünfte Eigenschaftselement (Index 4) in der Liste hat die ID PropertyTagExifExposureTime und den Typ PropertyTagTypeRational. Dieser Datentyp (PropertyTagTypeRational) ist ein Paar von LONGs. Im folgenden Beispiel, das eine Fortsetzung der vorherigen Konsolenanwendung darstellt, werden diese beiden LONG-Werte als Bruch angezeigt. Dieser Anteil, 1/125, ist die in Sekunden gemessene Belichtungszeit.
long* ptrLong = (long*)(pPropBuffer[4].value);
printf("The exposure time is %d/%d.\n", ptrLong[0], ptrLong[1]);
Der oben genannte Code erzeugt die folgende Ausgabe:
The exposure time is 1/125.
Schreiben von Metadaten in eine Datei
Um ein Metadatenelement in ein Image-Objekt zu schreiben, initialisieren Sie ein PropertyItem-Objekt , und übergeben Sie dann die Adresse dieses PropertyItem-Objekts an die SetPropertyItem-Methode des Image-Objekts .
Die folgende Konsolenanwendung schreibt ein Element (den Imagetitel) von Metadaten in ein Image-Objekt und speichert das Image dann in der Datenträgerdatei FakePhoto2.jpg. Die Standard-Funktion basiert auf der Hilfsfunktion GetEncoderClsid, die im Thema Abrufen des Klassenbezeichners für einen Encoder gezeigt wird.
#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;
}