Freigeben über


Übersicht über Das Lesen und Schreiben von Bildmetadaten

In diesem Thema finden Sie eine Übersicht darüber, wie Sie mithilfe der WIC-APIs (Windows Imaging Component) Metadaten lesen und schreiben können, die in Bilddateien eingebettet sind.

Dieses Thema enthält folgende Abschnitte:

Voraussetzungen

Um dieses Thema zu verstehen, sollten Sie mit dem WIC-Metadatensystem vertraut sein, wie in der WIC-Metadatenübersicht beschrieben. Sie sollten auch mit der Abfragesprache vertraut sein, die zum Lesen und Schreiben von Metadaten verwendet wird, wie in Metadatenabfragesprache Übersichtbeschrieben.

Einleitung

WIC stellt Anwendungsentwicklern COM-Komponenten (Component Object Model) zur Verfügung, mit denen Metadaten aus Bilddateien gelesen und geschrieben werden können. Es gibt zwei Möglichkeiten zum Lesen und Schreiben von Metadaten:

  • Verwenden eines Abfrage-Lesers/-Schreibers und eines Abfrageausdrucks zum Abfragen von Metadatenblöcken nach geschachtelten Blöcken oder spezifischen Metadaten innerhalb eines Blocks.
  • Verwenden eines Metadatenhandlers (metadatenleser oder Metadatenschreiber) für den Zugriff auf die geschachtelten Metadatenblöcke oder spezifischen Metadaten innerhalb der Metadatenblöcke.

Am einfachsten verwenden Sie einen Abfrageleser/Writer und einen Abfrageausdruck, um auf die Metadaten zuzugreifen. Ein Abfrageleser (IWICMetadataQueryReader) wird zum Lesen von Metadaten verwendet, während ein Abfrage-Writer (IWICMetadataQueryWriter) zum Schreiben von Metadaten verwendet wird. Beide verwenden einen Abfrageausdruck, um die gewünschten Metadaten zu lesen oder zu schreiben. Hinter den Kulissen verwendet ein Abfrageleser (und Writer) einen Metadatenhandler, um auf die vom Abfrageausdruck beschriebenen Metadaten zuzugreifen.

Die komplexere Methode besteht darin, direkt auf die Metadatenhandler zuzugreifen. Ein Metadatenhandler wird aus den einzelnen Frames mithilfe eines Blocklesers (IWICMetadataBlockReader) oder eines Block Writers (IWICMetadataBlockWriter) abgerufen. Die beiden verfügbaren Typen von Metadatenhandlern sind der Metadatenleser (IWICMetadataReader) und der Metadatenschreiber (IWICMetadataWriter).

Das folgende Diagramm des Inhalts einer JPEG-Bilddatei wird in den Beispielen in diesem Thema verwendet. Das durch dieses Diagramm dargestellte Bild wurde mithilfe von Microsoft Paint erstellt; Die Bewertungsmetadaten wurden mithilfe der Fotogalerie-Funktion von Windows Vista hinzugefügt.

Abbildung des JPEG-Bilds mit Bewertungsmetadaten

Lesen von Metadadaten mithilfe eines Abfragelesers

Die einfachste Möglichkeit zum Lesen von Metadaten besteht darin, die Abfrageleserschnittstelle IWICMetadataQueryReader zu verwenden. Mit dem Abfrageleser können Sie Metadatenblöcke und Elemente in Metadatenblöcken mithilfe eines Abfrageausdrucks lesen.

Es gibt drei Möglichkeiten zum Abrufen eines Abfragelesers: über einen Bitmap-Decoder (IWICBitmapDecoder), über die einzelnen Frames (IWICBitmapFrameDecode) oder über einen Abfrageschreiber (IWICMetadataQueryWriter).

Abrufen eines Abfragelesers

Im folgenden Beispielcode wird gezeigt, wie Sie einen Bitmap-Decoder aus der Imaging Factory abrufen und einen einzelnen Bitmap-Frame abrufen. Dieser Code führt außerdem Setupaufgaben aus, die erforderlich sind, um einen Abfrageleser aus einem decodierten Frame abzurufen.

IWICImagingFactory *pFactory = NULL;
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pFrameDecode = NULL;
IWICMetadataQueryReader *pQueryReader = NULL;
IWICMetadataQueryReader *pEmbedReader = NULL;
PROPVARIANT value;

// Initialize COM
CoInitialize(NULL);

// Initialize PROPVARIANT
PropVariantInit(&value);

//Create the COM imaging factory
HRESULT hr = CoCreateInstance(
    CLSID_WICImagingFactory,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_IWICImagingFactory,
    (LPVOID*)&pFactory);

// Create the decoder
if (SUCCEEDED(hr))
{
    hr = pFactory->CreateDecoderFromFilename(
        L"test.jpg",
        NULL,
        GENERIC_READ,
        WICDecodeMetadataCacheOnDemand,
        &pDecoder);
}

// Get a single frame from the image
if (SUCCEEDED(hr))
{
    hr = pDecoder->GetFrame(
         0,  //JPEG has only one frame.
         &pFrameDecode); 
}

Der Bitmap-Decoder für die test.jpg-Datei wird mithilfe der CreateDecoderFromFilename-Methode der Imaging Factory abgerufen. In dieser Methode wird der vierte Parameter auf den Wert WICDecodeMetadataCacheOnDemand aus der WICDecodeOptions-Aufzählung festgelegt. Dadurch wird der Decoder aufgefordert, die Metadaten zwischenzuspeichern, wenn die Metadaten benötigt werden; entweder durch Abrufen eines Abfragelesers oder des zugrunde liegenden Metadatenlesers. Mit dieser Option können Sie den Datenstrom in den Metadaten beibehalten, die für die schnelle Metadatencodierung erforderlich sind, und die verlustlose Decodierung des JPEG-Bilds ermöglicht. Alternativ können Sie den anderen WICDecodeOptions-Wert WICDecodeMetadataCacheOnLoad verwenden, der die eingebetteten Bildmetadaten zwischenspeichert, sobald das Bild geladen wird.

Um den Abfrageleser des Frames abzurufen, rufen Sie die GetMetadataQueryReader-Methode des Frames einfach auf. Der folgende Code veranschaulicht den Aufruf.

// Get the query reader
if (SUCCEEDED(hr))
{
    hr = pFrameDecode->GetMetadataQueryReader(&pQueryReader);
}

Ebenso kann ein Abfrageleser auch auf Decoderebene abgerufen werden. Ein einfacher Aufruf der GetMetadataQueryReader-Methode des Decoders ruft den Abfrageleser des Decoders ab. Der Abfrageleser eines Decoders liest im Gegensatz zum Abfrageleser eines Frames Metadaten für ein Bild, das sich außerhalb der einzelnen Frames befindet. Dieses Szenario ist jedoch nicht üblich, und die nativen Bildformate unterstützen diese Funktion nicht. Die systemeigenen Bild-CODECS, die von WIC bereitgestellt werden, lesen und schreiben Metadaten auf Frameebene auch für Einzelframeformate wie JPEG.

Lesen von Metadaten

Bevor Sie mit dem eigentlichen Lesen von Metadaten fortfahren, sehen Sie sich das folgende Diagramm einer JPEG-Datei an, die eingebettete Metadatenblöcke und tatsächliche Abzurufende Daten enthält. Dieses Diagramm stellt Beschriftungen für bestimmte Metadatenblöcke und Elemente innerhalb des Bildes bereit und beschreibt den Metadatenabfrageausdruck für jeden Block oder jedes Element.

Illustration einer JPEG-Abbildung mit Metadaten-Annotationen

Rufen Sie die GetMetadataByName-Methode auf, um eingebettete Metadatenblöcke oder bestimmte Elemente anhand des Namens abzufragen. Diese Methode verwendet einen Abfrageausdruck und einen PROPVARIANT , in dem das Metadatenelement zurückgegeben wird. Der folgende Code fragt nach einem geschachtelten Metadatenblock ab und konvertiert die IUnknown-Komponente , die vom PROPVARIANT-Wert bereitgestellt wird, in einen Abfrageleser, falls gefunden.

if (SUCCEEDED(hr))
{
    // Get the nested IFD reader
    hr = pQueryReader->GetMetadataByName(L"/app1/ifd", &value);
    if (value.vt == VT_UNKNOWN)
    {
        hr = value.punkVal->QueryInterface(IID_IWICMetadataQueryReader, (void **)&pEmbedReader);
    }
    PropVariantClear(&value); // Clear value for new query
}

Der Abfrageausdruck "/app1/ifd" fragt nach dem im App1-Block geschachtelten IFD-Block ab. Die JPEG-Bilddatei enthält den GEschachtelten IFD-Metadatenblock, sodass der PROPVARIANT mit einem Variablentyp (vt) und einem Zeiger auf eine IUnknown-Schnittstelle (PunkVal) VT_UNKNOWN zurückgegeben wird. Anschließend fragen Sie die IUnknown-Schnittstelle für einen Abfrageleser ab.

Der folgende Code veranschaulicht eine neue Abfrage basierend auf dem neuen Abfrageleser relativ zum geschachtelten IFD-Block.

if (SUCCEEDED(hr))
{
    hr = pEmbedReader->GetMetadataByName(L"/{ushort=18249}", &value);
    PropVariantClear(&value); // Clear value for new query
}

Der Abfrageausdruck "/{ushort=18249}" fragt den IFD-Block für die unter Tag 18249 eingebettete MicrosoftPhoto-Bewertung ab. Der PROPVARIANT-Wert enthält nun einen Werttyp VT_UI2 und einen Datenwert von 50.

Es ist jedoch nicht erforderlich, vor der Abfrage nach bestimmten Datenwerten einen geschachtelten Block abzurufen. Statt beispielsweise die geschachtelte IFD und dann die MicrosoftPhoto-Bewertung abzufragen, können Sie stattdessen den Stammmetadatenblock und die im folgenden Code gezeigte Abfrage verwenden, um dieselben Informationen zu erhalten.

if (SUCCEEDED(hr))
{
    hr = pQueryReader->GetMetadataByName(L"/app1/ifd/{ushort=18249}", &value);
    PropVariantClear(&value);
}

Zusätzlich zum Abfragen bestimmter Metadatenelemente in einem Metadatenblock können Sie auch alle Metadatenelemente in einem Metadatenblock aufzählen (ohne Metadatenelemente in geschachtelten Metadatenblöcken). Zum Aufzählen der Metadatenelemente im aktuellen Block wird die GetEnumeration-Methode des Abfragelesers verwendet. Diese Methode ruft eine IEnumString-Schnittstelle ab, die mit den Metadatenelementen im aktuellen Block gefüllt ist. Der folgende Code listet beispielsweise die XMP-Bewertung und die MicrosoftPhoto-Bewertung für den geschachtelten IFD-Block auf, der zuvor abgerufen wurde.

IEnumString *metadataItems = NULL;

if (SUCCEEDED(hr))
{
    hr = pEmbedReader->GetEnumerator(&metadataItems);
}

Weitere Informationen zum Identifizieren geeigneter Tags für verschiedene Bildformate und Metadatenformate finden Sie unter Metadatenabfragen im nativen Bildformat.

Zusätzliche Abfragelesemethoden

Zusätzlich zum Lesen von Metadaten können Sie auch zusätzliche Informationen zum Abfrageleser abrufen und Metadaten auf andere Weise abrufen. Der Abfrageleser stellt zwei Methoden bereit, die Informationen zum Abfrageleser, GetContainerFormat und GetLocation bereitstellen.

Mit dem eingebetteten Abfrageleser können Sie GetContainerFormat verwenden, um den Typ des Metadatenblocks zu bestimmen, und Sie können GetLocation aufrufen, um den Pfad relativ zum Stammmetadatenblock abzurufen. Der folgende Code fragt den eingebetteten Abfrageleser nach seinem Speicherort ab.

// Determine the metadata block format

if (SUCCEEDED(hr))
{
    hr = pEmbedReader->GetContainerFormat(&containerGUID);
}

// Determine the query reader's location
if (SUCCEEDED(hr))
{
    UINT length;
    WCHAR readerNamespace[100];
    hr = pEmbedReader->GetLocation(100, readerNamespace, &length);
}

Der Aufruf von GetContainerFormat für den eingebetteten Abfrageleser gibt die IFD-Metadatenformat-GUID zurück. Der Aufruf von GetLocation gibt einen Namespace von "/app1/ifd" zurück, und stellt Ihnen den relativen Pfad bereit, von dem aus nachfolgende Abfragen an den neuen Abfrage-Leser ausgeführt werden. Natürlich ist der vorherige Code nicht sehr nützlich, aber es veranschaulicht, wie die GetLocation-Methode zum Suchen geschachtelter Metadatenblöcke verwendet wird.

Schreiben von Metadaten mithilfe eines Abfrage-Writers

Hinweis

Einige der codebeispiele in diesem Abschnitt werden nicht im Kontext der tatsächlichen Schritte gezeigt, die zum Schreiben von Metadaten erforderlich sind. Informationen zum Anzeigen der Codebeispiele im Kontext eines Arbeitsbeispiels finden Sie im Lernprogramm "Vorgehensweise: Erneutes Codieren eines Bilds mit Metadaten".

 

Die Hauptkomponente zum Schreiben von Metadaten ist der Abfrage-Writer (IWICMetadataQueryWriter). Mit dem Abfrage-Writer können Sie Metadatenblöcke und -elemente innerhalb eines Metadatenblocks festlegen und entfernen.

Wie der Abfrageleser gibt es drei Methoden zum Abrufen eines Abfrage-Writers: über einen Bitmap-Encoder (IWICBitmapEncoder), über seine einzelnen Frames (IWICBitmapFrameEncode) oder über einen schnellen Metadaten-Encoder (IWICFastMetadataEncoder).

Abrufen eines Abfrageverfassers

Der häufigste Abfrage-Writer ist für einen einzelnen Frame einer Bitmap. Mit diesem Abfrage-Writer werden metadatenblöcke und -elemente eines Bildframes festgelegt und entfernt. Rufen Sie zum Abrufen des Abfrage-Writers eines Bildframes die GetMetadataQueryWriter-Methode des Frames auf. Der folgende Code veranschaulicht den einfachen Methodenaufruf zum Abrufen des Abfrage-Writers eines Frames.

IWICMetadataQueryWriter &pFrameQWriter = NULL;

//Obtain a query writer from the frame.
hr = pFrameEncode->GetMetadataQueryWriter(&pFrameQWriter);

Ebenso kann ein Abfrage-Writer auch für die Encoderebene abgerufen werden. Ein einfacher Aufruf der GetMetadataQueryWriter-Methode des Encoders ruft den Abfrage-Writer des Encoders ab. Der Abfrage-Writer eines Encoders schreibt im Gegensatz zum Abfrage-Writer eines Frames Metadaten für ein Bild außerhalb des einzelnen Frames. Dieses Szenario ist jedoch nicht üblich, und die nativen Bildformate unterstützen diese Funktion nicht. Die systemeigenen Bildcodecs, die von WIC bereitgestellt werden, lesen und schreiben Metadaten auf Frameebene auch für Einzelframeformate wie JPEG.

Sie können auch einen Abfrage-Writer direkt aus der Imaging Factory (IWICImagingFactory) abrufen. Es gibt zwei Imaging Factory-Methoden, die einen Abfrage-Writer zurückgeben: CreateQueryWriter und CreateQueryWriterFromReader.

CreateQueryWriter erstellt einen Abfrage-Writer für das angegebene Metadatenformat und den angegebenen Anbieter. Mit diesem Abfrage-Writer können Sie Metadaten für ein bestimmtes Metadatenformat schreiben und dem Bild hinzufügen. Der folgende Code veranschaulicht einen CreateQueryWriter-Aufruf zum Erstellen eines XMP-Abfrage-Writers.

IWICMetadataQueryWriter *pXMPWriter = NULL;

// Create XMP block
GUID vendor = GUID_VendorMicrosoft;
hr = pFactory->CreateQueryWriter(
        GUID_MetadataFormatXMP,
        &vendor,
        &pXMPWriter);

In diesem Beispiel wird der freundliche Anzeigename GUID_MetadataFormatXMP als Parameter guidMetadataFormat verwendet. Sie stellt die GUID des XMP-Metadatenformats dar, und der Anbieter stellt den von Microsoft erstellten Handler dar. Alternativ kann NULL als pguidVendor-Parameter mit denselben Ergebnissen übergeben werden, wenn kein anderer XMP-Handler vorhanden ist. Wenn ein benutzerdefinierter XMP-Handler zusammen mit dem systemeigenen XMP-Handler installiert wird, führt die Übergabe von NULL für den Anbieter dazu, dass der Abfrage-Writer mit der niedrigsten GUID zurückgegeben wird.

CreateQueryWriterFromReader ähnelt der CreateQueryWriter-Methode , mit der Ausnahme, dass der neue Abfrageschreiber mit den vom Abfrageleser bereitgestellten Daten vorab aufgefüllt wird. Dies ist nützlich, um ein Bild erneut zu codieren, während die vorhandenen Metadaten beibehalten werden, oder zum Entfernen unerwünschter Metadaten. Der folgende Code veranschaulicht einen CreateQueryWriterFromReader-Aufruf .

hr = pFrameDecode->GetMetadataQueryReader(&pFrameQReader);

// Copy metadata using query readers
if(SUCCEEDED(hr) && pFrameQReader)
{
    IWICMetadataQueryWriter *pNewWriter = NULL;

    GUID vendor = GUID_VendorMicrosoft;
    hr = pFactory->CreateQueryWriterFromReader(
        pFrameQReader,
        &vendor,
        &pNewWriter);

Hinzufügen von Metadaten

Nachdem Sie einen Abfrage-Writer erhalten haben, können Sie ihn verwenden, um Metadatenblöcke und -elemente hinzuzufügen. Zum Schreiben von Metadaten verwenden Sie die SetMetadataByName-Methode des Abfrageautors. SetMetadataByName akzeptiert zwei Parameter: einen Abfrageausdruck (wzName) und einen Zeiger auf eine PROPVARIANT (pvarValue). Der Abfrageausdruck definiert den festzulegenden Block oder Element, während der PROPVARIANT den tatsächlich festzulegenden Datenwert bereitstellt.

Das folgende Beispiel veranschaulicht das Hinzufügen eines Titels mithilfe des zuvor mithilfe der CreateQueryWriter-Methode abgerufenen XMP-Abfrageschreibers.

// Write metadata to the XMP writer
if (SUCCEEDED(hr))
{
    PROPVARIANT value;
    PropVariantInit(&value);

    value.vt = VT_LPWSTR;
    value.pwszVal = L"Metadata Test Image.";
   
    hr = pXMPWriter->SetMetadataByName(L"/dc:title", &value);

    PropVariantClear(&value);
}

In diesem Beispiel ist der Werttyp (vt) auf VT_LPWSTR gesetzt, was angibt, dass eine Zeichenfolge als Datenwert verwendet wird. Da der Werttyp eine Zeichenfolge ist, wird pwszVal verwendet, um den zu verwendenden Titel festzulegen. SetMetadataByName wird dann mit dem Abfrageausdruck "/dc:title" und dem neu festgelegten PROPVARIANT aufgerufen. Der verwendete Abfrageausdruck gibt an, dass die Titeleigenschaft im Digitalkameraschema (dc) festgelegt werden soll. Beachten Sie, dass der Ausdruck nicht "/xmp/dc:title" lautet; Dies liegt daran, dass der Abfrage-Writer bereits für XMP spezifisch ist und keinen eingebetteten XMP-Block enthält, der "/xmp/dc:title" vorschlagen würde.

Bis zu diesem Punkt haben Sie keine Metadaten zu einem Bildframe hinzugefügt. Sie haben einfach einen Abfrage-Writer mit Daten aufgefüllt. Wenn Sie einem Frame einen Metadatenblock hinzufügen möchten, der vom Anfrage-Schreiber dargestellt wird, rufen Sie erneut SetMetadataByName auf, wobei der Anfrage-Schreiber als Wert des PROPVARIANT verwendet wird. Dadurch werden die Metadaten im Abfrage-Writer effektiv in den Bildframe kopiert. Der folgende Code zeigt, wie die Metadaten im zuvor erhaltenen XMP-Abfrage-Writer zu einem Frame-Stammmetadatenblock hinzugefügt werden.

// Get the frame's query writer and write the XMP query writer to it
if (SUCCEEDED(hr))
{
    hr = pFrameEncode->GetMetadataQueryWriter(&pFrameQWriter);

    // Copy the metadata in the XMP query writer to the frame
    if (SUCCEEDED(hr))
    {
        PROPVARIANT value;

        PropVariantInit(&value);
        value.vt = VT_UNKNOWN;
        value.punkVal = pXMPWriter;
        value.punkVal->AddRef();

        hr = pFrameQWriter->SetMetadataByName(L"/", &value);

        PropVariantClear(&value);
    }
}

In diesem Beispiel wird ein Werttyp (vt) verwendet VT_UNKOWN , der einen COM-Schnittstellenwerttyp angibt. Der XMP-Abfrage-Writer (piXMPWriter) wird dann als Wert des PROPVARIANT verwendet und fügt einen Verweis darauf mithilfe der AddRef-Methode hinzu. Schließlich wird der XMP-Abfrage-Writer festgelegt, indem die SetMetadataByName-Methode des Frames aufgerufen und der Abfrageausdruck "/" übergeben wird, der den Stammblock angibt, und der neu festgelegte PROPVARIANT.

Hinweis

Wenn der Frame bereits den Metadatenblock enthält, den Sie hinzufügen möchten, werden die hinzuzufügenden Metadaten hinzugefügt und vorhandene Metadaten überschrieben.

 

Entfernen von Metadaten

Mit einem Abfrage-Writer können Sie auch Metadaten entfernen, indem Sie die RemoveMetadataByName-Methode aufrufen. RemoveMetadataByName akzeptiert einen Abfrageausdruck und entfernt den Metadatenblock oder das Element, sofern vorhanden. Der folgende Code veranschaulicht, wie der zuvor hinzugefügte Titel entfernt wird.

if (SUCCEEDED(hr))
{
    hr = pFrameQWriter->RemoveMetadataByName(L"/xmp/dc:title");
}

Der folgende Code veranschaulicht, wie der gesamte XMP-Metadatenblock entfernt wird.

if (SUCCEEDED(hr))
{
    hr = pFrameQWriter->RemoveMetadataByName(L"/xmp");
}

Kopieren von Metadaten für die erneute Codierung

Hinweis

Der Code in diesem Abschnitt ist nur gültig, wenn die Quell- und Zielbildformate identisch sind. Sie können nicht alle Metadaten eines Bilds in einem einzigen Vorgang kopieren, wenn Sie ein anderes Bildformat codieren.

 

Um Metadaten beim erneuten Codieren eines Bilds im selben Bildformat beizubehalten, stehen Methoden zum Kopieren aller Metadaten in einem einzigen Vorgang zur Verfügung. Jeder dieser Vorgänge folgt einem ähnlichen Muster; jeder legt die Metadaten des decodierten Frames direkt in den neuen Frame fest, der codiert wird.

Die bevorzugte Methode zum Kopieren von Metadaten besteht darin, den Block writer des neuen Frames mit dem Blockleser des decodierten Frames zu initialisieren. Der folgende Code veranschaulicht diese Methode.

if (SUCCEEDED(hr) && formatsEqual)
{
    // Copy metadata using metadata block reader/writer
    if (SUCCEEDED(hr))
    {
        pFrameDecode->QueryInterface(
            IID_IWICMetadataBlockReader,
            (void**)&pBlockReader);
    }
    if (SUCCEEDED(hr))
    {
        pFrameEncode->QueryInterface(
            IID_IWICMetadataBlockWriter,
            (void**)&pBlockWriter);
    }
    if (SUCCEEDED(hr))
    {
        pBlockWriter->InitializeFromBlockReader(pBlockReader);
    }
}

In diesem Beispiel werden der Blockleser bzw. der Blockschreiber aus dem Quellframe bzw. dem Zielframe abgerufen. Der Blockschreiber wird dann vom Blockleser initialisiert. Dadurch wird der Blockleser mit den bereits ausgefüllten Metadaten des Blocklesers initialisiert.

Eine weitere Methode zum Kopieren von Metadaten besteht darin, den Metadatenblock, auf den der Abfrageleser verweist, mithilfe des Abfrage-Writers des Encoders zu schreiben. Der folgende Code veranschaulicht diese Methode.

if (SUCCEEDED(hr) && formatsEqual)
{
    hr = pFrameDecode->GetMetadataQueryReader(&pFrameQReader);

    // Copy metadata using query readers
    if(SUCCEEDED(hr))
    {
        hr = pFrameEncode->GetMetadataQueryWriter(&pFrameQWriter);
        if (SUCCEEDED(hr))
        {
            PropVariantClear(&value);
            value.vt=VT_UNKNOWN;
            value.punkVal=pFrameQReader;
            value.punkVal->AddRef();
            hr = pFrameQWriter->SetMetadataByName(L"/", &value);
            PropVariantClear(&value);
        }
    }
}

Hier wird ein Abfrageleser aus dem decodierten Frame abgerufen und dann als Eigenschaftswert des PROPVARIANT verwendet, wobei ein Werttyp auf VT_UNKNOWN festgelegt ist. Der Abfrage-Writer für den Encoder wird abgerufen, und der Abfrageausdruck "/" wird verwendet, um die Metadaten im Stammnavigationspfad festzulegen. Sie können diese Methode auch verwenden, wenn Sie geschachtelte Metadatenblöcke festlegen, indem Sie den Abfrageausdruck an den gewünschten Speicherort anpassen.

Ebenso können Sie einen Abfrageschreiber basierend auf dem abfrageleser des decodierten Frames mithilfe der CreateQueryWriterFromReader-Methode der Imaging Factory erstellen. Der in diesem Vorgang erstellte Abfrage-Writer wird vorab mit den Metadaten des Abfragelesers aufgefüllt und kann dann im Frame festgelegt werden. Der folgende Code veranschaulicht den Kopiervorgang CreateQueryWriterFromReader .

IWICMetadataQueryWriter *pNewWriter = NULL;

GUID vendor = GUID_VendorMicrosoft;
hr = pFactory->CreateQueryWriterFromReader(
    pFrameQReader,
    &vendor,
    &pNewWriter);

if (SUCCEEDED(hr))
{
    // Get the frame's query writer
    hr = pFrameEncode->GetMetadataQueryWriter(&pFrameQWriter);
}

// Set the query writer to the frame.
if (SUCCEEDED(hr))
{
    PROPVARIANT value;

    PropVariantInit(&value);
    value.vt = VT_UNKNOWN;
    value.punkVal = pNewWriter;
    value.punkVal->AddRef();
    hr = pFrameQWriter->SetMetadataByName(L"/",&value);
}

Diese Methode verwendet einen separaten Abfrage-Writer, der basierend auf den Daten des Abfragelesers erstellt wird. Dieser neue Abfrage-Schreiber wird dann in den Rahmen eingefügt.

Auch hier funktionieren diese Vorgänge zum Kopieren von Metadaten nur, wenn die Quell- und Zielbilder das gleiche Format aufweisen. Dies liegt daran, dass unterschiedliche Bildformate die Metadatenblöcke an unterschiedlichen Speicherorten speichern. Sowohl JPEG als auch TIFF unterstützen beispielsweise XMP-Metadatenblöcke. In JPEG-Bildern befindet sich der XMP-Block im Stammmetadatenblock, wie in der WIC-Metadatenübersicht dargestellt. In einem TIFF-Bild ist der XMP-Block jedoch in einem IFD-Stammblock geschachtelt. Das folgende Diagramm veranschaulicht die Unterschiede zwischen einem JPEG-Bild und einem TIFF-Bild mit denselben Bewertungsmetadaten.

JPEG- und TIFF-Vergleich.

Schnelle Metadatencodierung

Es ist nicht immer erforderlich, ein Bild neu zu codieren, um neue Metadaten darin zu schreiben. Metadaten können auch mithilfe eines schnellen Metadaten-Encoders geschrieben werden. Ein schneller Metadaten-Encoder kann eine begrenzte Menge von Metadaten in ein Bild schreiben, ohne das Bild erneut zu codieren. Dies wird erreicht, indem die neuen Metadaten innerhalb des leeren Abstands geschrieben werden, der von einigen Metadatenformaten bereitgestellt wird. Die systemeigenen Metadatenformate, die den Metadatenabstand unterstützen, sind Exif, IFD, GPS und XMP.

Hinzufügen von Abstand zu Metadatenblöcken

Bevor Sie schnelle Metadatencodierung ausführen können, muss im Metadatenblock Platz vorhanden sein, um weitere Metadaten zu schreiben. Wenn nicht genügend Platz innerhalb des vorhandenen Abstands vorhanden ist, um die neuen Metadaten zu schreiben, schlägt die schnelle Metadatencodierung fehl. Um einem Bild Metadatenabstand hinzuzufügen, muss das Bild neu codiert werden. Sie können den Abstand auf die gleiche Weise hinzufügen, wie Sie ein anderes Metadatenelement hinzufügen würden, indem Sie einen Abfrageausdruck verwenden, wenn der Metadatenblock, den Sie auffüllen, dies unterstützt. Im folgenden Beispiel wird veranschaulicht, wie Sie einem in einem App1-Block eingebetteten IFD-Block Abstand hinzufügen.

if (SUCCEEDED(hr))
{
    // Add metadata padding
    PROPVARIANT padding;

    PropVariantInit(&padding);
    padding.vt = VT_UI4;
    padding.uiVal = 4096; // 4KB

    hr = pFrameQWriter->SetMetadataByName(L"/app1/ifd/PaddingSchema:padding", &padding);

    PropVariantClear(&padding);
}

Erstellen Sie zum Hinzufügen von Abstand einen PROPVARIANT vom Typ VT_UI4 und einen Wert, der der Anzahl der hinzuzufügenden Bytes des Abstands entspricht. Ein typischer Wert beträgt 4096 Byte. Die Metadatenabfragen für JPEG, TIFF und JPEG-XR befinden sich in dieser Tabelle.

Metadatenformat JPEG-Metadatenabfrage TIFF- JPEG-XR Metadatenabfrage
IFD /app1/ifd/PaddingSchema:Padding /ifd/PaddingSchema:Padding
EXIF /app1/ifd/exif/PaddingSchema:Padding /ifd/exif/PaddingSchema:Padding
XMP /xmp/PaddingSchema:Padding /ifd/xmp/PaddingSchema:Padding
GPS /app1/ifd/gps/PaddingSchema:Padding /ifd/gps/PaddingSchema:Padding

 

Erhalten eines schnellen Metadaten-Coders

Wenn Sie über ein Bild mit Einem Metadatenabstand verfügen, kann ein schneller Metadaten-Encoder mithilfe der Imaging Factory-Methoden CreateFastMetadataEncoderFromDecoder und CreateFastMetadataEncoderFromFrameDecoder abgerufen werden.

Wie der Name schon sagt, erstellt CreateFastMetadataEncoderFromDecoder einen schnellen Metadaten-Encoder für Metadaten auf Decoderebene. Die von WIC bereitgestellten nativen Bildformate unterstützen keine Metadaten auf Decoderebene, diese Methode wird jedoch bereitgestellt, falls in Zukunft ein solches Bildformat entwickelt wird.

Das häufigere Szenario ist das Abrufen eines schnellen Metadaten-Encoders aus einem Bildframe mithilfe von CreateFastMetadataEncoderFromFrameDecode. Der folgende Code ruft den schnellen Metadaten-Encoder eines decodierten Frames ab und ändert den Bewertungswert im App1-Block.

if (SUCCEEDED(hr))
{
    IWICFastMetadataEncoder *pFME = NULL;
    IWICMetadataQueryWriter *pFMEQW = NULL;

    hr = pFactory->CreateFastMetadataEncoderFromFrameDecode(
        pFrameDecode, 
        &pFME);
}

Verwenden des schnellen Metadaten-Encoders

Aus dem schnellen Metadaten-Encoder können Sie einen Abfrage-Writer abrufen. Auf diese Weise können Sie Metadaten mithilfe eines Abfrageausdrucks schreiben, wie zuvor gezeigt. Nachdem Metadaten im Abfrage-Editor festgelegt wurden, verwenden Sie den Fast-Metadaten-Encoder, um die Metadatenaktualisierung abzuschließen. Der folgende Code veranschaulicht das Festlegen und Commit der Metadatenänderungen.

    if (SUCCEEDED(hr))
    {
        hr = pFME->GetMetadataQueryWriter(&pFMEQW);
    }

    if (SUCCEEDED(hr))
    {
        // Add additional metadata
        PROPVARIANT value;

        PropVariantInit(&value);

        value.vt = VT_UI4;
        value.uiVal = 99;
        hr = pFMEQW->SetMetadataByName(L"/app1/ifd/{ushort=18249}", &value);

        PropVariantClear(&value);
    }

    if (SUCCEEDED(hr))
    {
        hr = pFME->Commit();
    }
}

Wenn commit aus irgendeinem Grund fehlschlägt, müssen Sie das Bild erneut codieren, um sicherzustellen, dass die neuen Metadaten dem Bild hinzugefügt werden.

Konzeptionelle

Übersicht über die Windows-Imageerstellungskomponente

WIC-Metadatenübersicht

übersicht über Metadatenabfragesprache

übersicht über Metadatenerweiterung

Vorgehensweise: Erneutes Codieren eines JPEG-Bilds mit Metadaten-