Udostępnij za pośrednictwem


Omówienie odczytywania i zapisywania metadanych obrazu

Ten temat zawiera omówienie sposobu używania interfejsów API składnika Windows Imaging (WIC) do odczytywania i zapisywania metadanych osadzonych w plikach obrazów.

Ten temat zawiera następujące sekcje.

Warunki wstępne

Aby zrozumieć ten temat, należy zapoznać się z systemem metadanych WIC zgodnie z opisem w WIC Metadata Overview. Należy również zapoznać się z językiem zapytań używanym do odczytywania i zapisywania metadanych, zgodnie z opisem w temacie Metadata Query Language Overview.

Wprowadzenie

Usługa WIC udostępnia deweloperom aplikacji składniki modelu obiektów składników (COM) do odczytywania i zapisywania metadanych osadzonych w plikach obrazów. Istnieją dwa sposoby odczytywania i zapisywania metadanych:

  • Użycie czytnika/zapisującego zapytania i wyrażenia zapytania do zapytań o bloki metadanych w przypadku zagnieżdżonych bloków lub określonych metadanych w bloku.
  • Używanie programu obsługi metadanych (czytnika metadanych lub modułu zapisywania metadanych) w celu uzyskania dostępu do zagnieżdżonych bloków metadanych lub określonych metadanych w blokach metadanych.

Najprostszym z nich jest użycie czytnika/modułu zapisywania zapytań i wyrażenia zapytania w celu uzyskania dostępu do metadanych. Czytnik zapytań (IWICMetadataQueryReader) służy do odczytywania metadanych, podczas gdy moduł zapisywania zapytań (IWICMetadataQueryWriter) służy do zapisywania metadanych. Oba te elementy używają wyrażenia zapytania do odczytywania lub zapisywania żądanych metadanych. W tle czytnik zapytań (i moduł zapisujący) używa obsługiwacza metadanych do uzyskania dostępu do metadanych opisanych przez wyrażenie zapytania.

Bardziej zaawansowaną metodą jest bezpośredni dostęp do procedur obsługi metadanych. Procedura obsługi metadanych jest uzyskiwana z poszczególnych ramek przy użyciu czytnika bloków (IWICMetadataBlockReader) lub modułu zapisywania bloków (IWICMetadataBlockWriter). Dostępne są dwa typy procedur obsługi metadanych: czytnik metadanych (IWICMetadataReader) i moduł zapisywania metadanych (IWICMetadataWriter).

Poniższy diagram zawartości pliku obrazu JPEG jest używany w poniższych przykładach w tym temacie. Obraz reprezentowany przez ten diagram został utworzony przy użyciu programu Microsoft Paint; metadane oceny zostały dodane przy użyciu funkcji Galeria zdjęć systemu Windows Vista.

ilustracja obrazu jpeg z metadanych oceny

Odczytywanie metadadata przy użyciu czytnika zapytań

Najprostszym sposobem odczytywania metadanych jest użycie interfejsu czytnika zapytań, IWICMetadataQueryReader. Czytnik zapytań umożliwia odczytywanie bloków metadanych i elementów w blokach metadanych przy użyciu wyrażenia zapytania.

Istnieją trzy sposoby uzyskiwania czytnika zapytań: za pomocą dekodera mapy bitowej (IWICBitmapDecoder), za pośrednictwem poszczególnych ramek (IWICBitmapFrameDecode) lub za pośrednictwem modułu zapisywania zapytań (IWICMetadataQueryWriter).

Uzyskiwanie czytnika zapytań

Poniższy przykładowy kod pokazuje, jak uzyskać dekoder mapy bitowej z fabryki obrazów i pobrać pojedynczą ramkę mapy bitowej. Ten kod wykonuje również pracę instalatora wymaganą do uzyskania czytnika zapytań z zdekodowanej ramki.

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); 
}

Dekoder map bitowych dla pliku test.jpg jest uzyskiwany przy użyciu metody CreateDecoderFromFilename metody fabryki obrazowania. W tej metodzie czwarty parametr jest ustawiony na wartość WICDecodeMetadataCacheOnDemand z wyliczenia WICDecodeOptions. Poleca to dekoderowi buforowanie metadanych w momencie, gdy są one potrzebne, poprzez uzyskanie czytnika zapytań lub podstawowego czytnika metadanych. Użycie tej opcji pozwala na zachowanie strumienia metadanych wymaganych do szybkiego kodowania oraz umożliwia bezstratne dekodowanie obrazu JPEG. Alternatywnie możesz użyć drugiej WICDecodeOptions wartości WICDecodeMetadataCacheOnLoad, która buforuje osadzone metadane obrazu zaraz po załadowaniu obrazu.

Aby uzyskać czytnik zapytań ramki, wykonaj proste wywołanie metody GetMetadataQueryReader w ramce. Poniższy kod demonstruje to wywołanie.

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

Podobnie czytnik zapytań można również uzyskać na poziomie dekodera. Proste wywołanie metody GetMetadataQueryReader dekodera umożliwia uzyskanie czytnika zapytań. Czytnik zapytań dekodera, w przeciwieństwie do czytnika zapytań ramki, odczytuje metadane obrazu, który znajduje się poza poszczególnymi ramkami. Jednak ten scenariusz nie jest typowy, a formaty obrazów natywnych nie obsługują tej możliwości. Kodeki dostarczane przez WIC odczytują i zapisują metadane na poziomie klatki, nawet w formatach jedno-klatkowych, takich jak JPEG.

Odczytywanie metadanych

Przed przejściem do faktycznego odczytywania metadanych zapoznaj się z poniższym diagramem pliku JPEG, który zawiera osadzone bloki metadanych i rzeczywiste dane do pobrania. Ten diagram przedstawia objaśnienia dla określonych bloków metadanych i elementów w obrazie, prezentując wyrażenie zapytania metadanych dla każdego bloku lub elementu.

ilustracja obrazu jpeg z adnotacjami metadanych

Aby wysłać zapytanie o osadzone bloki metadanych lub określone elementy według nazwy, wywołaj metodę GetMetadataByName. Ta metoda przyjmuje wyrażenie zapytania i PROPVARIANT, w którym zwracany jest element metadanych. Poniższy kod wykonuje zapytania dotyczące zagnieżdżonego bloku metadanych i konwertuje składnik IUnknown dostarczony przez wartość PROPVARIANT do czytnika zapytań, jeśli zostanie znaleziony.

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
}

Wyrażenie zapytania "/app1/ifd" zapytuje o blok IFD zagnieżdżony w obrębie bloku App1. Plik obrazu JPEG zawiera zagnieżdżony blok metadanych IFD, więc PROPVARIANT jest zwracany z typem zmiennej (vt) VT_UNKNOWN oraz wskaźnikiem do interfejsu IUnknown (punkVal). Następnie wykonasz zapytanie dotyczące interfejsu IUnknown dla czytnika zapytań.

Poniższy kod przedstawia nowe zapytanie na podstawie nowego czytnika zapytań względem zagnieżdżonego bloku IFD.

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

Wyrażenie zapytania "/{ushort=18249}" przeszukuje blok IFD dla oceny MicrosoftPhoto znajdującej się pod tagiem 18249. Wartość PROPVARIANT będzie teraz zawierać typ wartości VT_UI2 i daną wartość 50.

Jednak nie jest konieczne uzyskanie zagnieżdżonego bloku przed wykonaniem zapytania o określone wartości danych. Na przykład zamiast wykonywać zapytania dotyczące zagnieżdżonego identyfikatora IFD, a następnie klasyfikacji MicrosoftPhoto, możesz zamiast tego użyć głównego bloku metadanych i zapytania pokazanego w poniższym kodzie, aby uzyskać te same informacje.

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

Oprócz wykonywania zapytań dotyczących określonych elementów metadanych w bloku metadanych można również wyliczyć wszystkie elementy metadanych w bloku metadanych (nie w tym elementów metadanych w zagnieżdżonych blokach metadanych). Aby wyliczyć elementy metadanych w bieżącym bloku, zostanie użyta metoda getEnumeration czytnika zapytań. Ta metoda uzyskuje interfejs IEnumString zawierający elementy metadanych z bieżącego bloku. Na przykład poniższy kod wylicza klasyfikację XMP i ocenę MicrosoftPhoto dla zagnieżdżonego bloku IFD uzyskanego wcześniej.

IEnumString *metadataItems = NULL;

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

Aby uzyskać więcej informacji na temat identyfikowania odpowiednich tagów dla różnych formatów obrazów i formatów metadanych, zobacz Native Image Format Metadata Queries.

Dodatkowe metody czytnika zapytań

Oprócz odczytywania metadanych można również uzyskać dodatkowe informacje o czytniku zapytań i uzyskać metadane za pomocą innych środków. Czytnik zapytań udostępnia dwie metody, które udostępniają informacje o czytniku zapytań, GetContainerFormat i GetLocation.

Za pomocą osadzonego czytnika zapytań można użyć GetContainerFormat w celu określenia typu bloku metadanych i wywołać GetLocation, aby uzyskać ścieżkę względem głównego bloku metadanych. Poniższy kod wysyła zapytanie do osadzonego czytnika zapytań o jego lokalizację.

// 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);
}

Wywołanie polecenia GetContainerFormat dla osadzonego czytnika zapytań zwraca identyfikator GUID w formacie metadanych IFD. Wywołanie metody GetLocation zwraca przestrzeń nazwową "/app1/ifd", która zawiera ścieżkę względną, z której będą wykonywane kolejne zapytania do nowego czytnika zapytań. Oczywiście powyższy kod nie jest bardzo przydatny, ale pokazuje, jak używać metody GetLocation do znajdowania zagnieżdżonych bloków metadanych.

Pisanie metadanych przy użyciu składnika zapisywania zapytań

Notatka

Niektóre przykłady kodu podane w tej sekcji nie są wyświetlane w kontekście rzeczywistych kroków wymaganych do pisania metadanych. Aby wyświetlić przykłady kodu w kontekście przykładu roboczego, zobacz samouczek Instrukcje: ponowne kodowanie obrazu za pomocą metadanych.

 

Głównym elementem do pisania metadanych jest zapis pytań (IWICMetadataQueryWriter). Moduł zapisywania zapytań umożliwia ustawianie i usuwanie bloków metadanych i elementów w bloku metadanych.

Podobnie jak w przypadku czytnika zapytań, istnieją trzy sposoby uzyskania pisarza zapytań: za pośrednictwem kodera mapy bitowej (IWICBitmapEncoder), poprzez jego indywidualne ramki (IWICBitmapFrameEncode) lub za pomocą kodera metadanych o wysokiej prędkości (IWICFastMetadataEncoder).

Uzyskiwanie narzędzia do pisania zapytań

Najczęstszym modułem zapisywania zapytań jest pojedyncza ramka mapy bitowej. Ten autor zapytań ustawia i usuwa bloki oraz elementy metadanych ramki obrazu. Aby uzyskać moduł zapisywania zapytań ramki obrazu, wywołaj metodę GetMetadataQueryWriter ramki. Poniższy kod przedstawia proste wywołanie metody w celu uzyskania narzędzia do zapisywania zapytań ramki.

IWICMetadataQueryWriter &pFrameQWriter = NULL;

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

Podobnie, generator zapytań można uzyskać również dla poziomu kodera. Proste wywołanie metody GetMetadataQueryWriter kodera pobiera moduł zapisywania zapytań kodera. Moduł zapisywania zapytań kodera, w przeciwieństwie do modułu zapisywania zapytań ramki, zapisuje metadane obrazu poza pojedynczą ramką. Jednak ten scenariusz nie jest typowy, a formaty obrazów natywnych nie obsługują tej możliwości. Rodzime kodeki obrazów dostarczane przez WIC odczytują i zapisują metadane na poziomie klatki nawet w przypadku formatów z jedną klatką, takich jak JPEG.

Można również uzyskać generator zapytań bezpośrednio z fabryki obrazowania (IWICImagingFactory). Istnieją dwie metody fabryki obrazów, które zwracają zapisujący zapytania: CreateQueryWriter oraz CreateQueryWriterFromReader.

CreateQueryWriter tworzy moduł zapisywania zapytań dla określonego formatu metadanych i dostawcy. Ten moduł zapisywania zapytań umożliwia zapisywanie metadanych dla określonego formatu metadanych i dodawanie ich do obrazu. Poniższy kod demonstruje wywołanie CreateQueryWriter w celu utworzenia modułu zapisywania zapytań XMP.

IWICMetadataQueryWriter *pXMPWriter = NULL;

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

W tym przykładzie przyjazna nazwa GUID_MetadataFormatXMP jest używana jako parametr guidMetadataFormat. Reprezentuje identyfikator GUID formatu metadanych XMP, a dostawca reprezentuje utworzoną przez firmę Microsoft procedurę obsługi. Alternatywnie, NULL może być przekazany jako parametr pguidVendor z tymi samymi wynikami, jeśli nie istnieje żadna inna procedura obsługi XMP. Jeśli niestandardowa procedura obsługi XMP jest zainstalowana wraz z natywną procedurą obsługi XMP, przekazanie NULL dla dostawcy doprowadzi do zwrócenia generatora zapytań z najniższym identyfikatorem GUID.

CreateQueryWriterFromReader jest podobna do metody CreateQueryWriter, z tą różnicą, że wstępnie wypełnia nowy moduł zapisywania zapytań danymi dostarczonymi przez czytnik zapytań. Jest to przydatne w przypadku ponownego kodowania obrazu przy zachowaniu istniejących metadanych lub usuwania niechcianych metadanych. Poniższy kod przedstawia wywołanie CreateQueryWriterFromReader.

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);

Dodawanie metadanych

Po uzyskaniu modułu zapisywania zapytań można go użyć do dodawania bloków i elementów metadanych. Aby napisać metadane, użyj metody SetMetadataByName modułu zapisywania zapytań. SetMetadataByName przyjmuje dwa parametry: wyrażenie zapytania (wzName) oraz wskaźnik do PROPVARIANT (pvarValue). Wyrażenie zapytania definiuje blok lub element, który ma być ustawiony, podczas gdy element PROPVARIANT udostępnia rzeczywistą wartość danych do ustawienia.

W poniższym przykładzie pokazano, jak dodać tytuł przy użyciu modułu zapisywania zapytań XMP uzyskanego wcześniej przy użyciu metody CreateQueryWriter.

// 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);
}

W tym przykładzie typ wartości (vt) jest ustawiony na VT_LPWSTR, wskazując, że ciąg będzie używany jako wartość danych. Ponieważ wartość jest typu ciąg znaków, pwszVal służy do ustawienia tytułu. SetMetadataByName jest następnie wywoływana przy użyciu wyrażenia zapytania "/dc:title" i nowo ustawionego PROPVARIANT. Użyte wyrażenie zapytania wskazuje, że należy ustawić właściwość tytułu w schemacie aparatu cyfrowego (dc). Należy zauważyć, że wyrażenie nie jest wyrażeniem "/xmp/dc:title"; Jest to spowodowane tym, że składnik zapisywania zapytań jest już specyficzny dla protokołu XMP i nie zawiera osadzonego bloku XMP, który sugeruje ciąg "/xmp/dc:title".

Do tego momentu nie dodano żadnych metadanych do ramki obrazu. Moduł zapisywania zapytań został po prostu wypełniony danymi. Aby dodać do ramki blok metadanych reprezentowany przez składnik zapisywania zapytań, ponownie wywołaj SetMetadataByName, używając składnika zapisywania zapytania jako wartości PROPVARIANT. Efektywnie kopiuje metadane z zapisywacza zapytań do ramki obrazu. Poniższy kod demonstruje, jak dodać wcześniej uzyskane metadane w module zapisywania zapytań XMP do głównego bloku metadanych ramki.

// 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);
    }
}

W tym przykładzie jest używany typ wartości (vt) VT_UNKOWN; wskazujący typ wartości interfejsu COM. Moduł pisania zapytań XMP (piXMPWriter) jest następnie używany jako wartość PROPVARIANT, a odwołanie do niego dodaje się za pomocą metody AddRef. Na koniec pisarz zapytań XMP jest ustawiany poprzez wywołanie metody SetMetadataByName i przekazanie wyrażenia zapytania "/", co wskazuje na blok główny, oraz nowo ustawioną wartość PROPVARIANT.

Notatka

Jeśli ramka zawiera już blok metadanych, który próbujesz dodać, dodawane metadane zostaną dodane i istniejące metadane zastąpione.

 

Usuwanie metadanych

Moduł zapisywania zapytań umożliwia również usuwanie metadanych przez wywołanie metody RemoveMetadataByName. RemoveMetadataByName przyjmuje wyrażenie zapytania i usuwa blok metadanych lub element, jeśli istnieje. Poniższy kod pokazuje, jak usunąć wcześniej dodany tytuł.

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

Poniższy kod pokazuje, jak usunąć cały blok metadanych XMP.

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

Kopiowanie metadanych na potrzeby ponownego kodowania

Notatka

Kod w tej sekcji jest prawidłowy tylko wtedy, gdy formaty obrazu źródłowego i docelowego są takie same. Nie można skopiować wszystkich metadanych obrazu w jednej operacji podczas kodowania do innego formatu obrazu.

 

Aby zachować metadane podczas ponownego kodowania obrazu w tym samym formacie obrazu, dostępne są metody kopiowania wszystkich metadanych w ramach jednej operacji. Każda z tych operacji jest zgodna z podobnym wzorcem; każda z nich wprowadza metadane dekodowanej ramki bezpośrednio do nowo kodowanej ramki.

Preferowaną metodą kopiowania metadanych jest zainicjowanie modułu zapisywania bloków nowej ramki za pomocą czytnika bloków zdekodowanej ramki. Poniższy kod demonstruje tę metodę.

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);
    }
}

W tym przykładzie czytnik bloków i składnik zapisywania bloków są uzyskiwane odpowiednio z ramki źródłowej i ramki docelowej. Moduł zapisywania bloków jest następnie inicjowany z czytnika bloków. Spowoduje to zainicjowanie czytnika bloków za pomocą wstępnie wypełnionych metadanych czytnika bloków.

Inną metodą kopiowania metadanych jest zapisanie bloku metadanych, do których odwołuje się czytnik zapytań przy użyciu modułu zapisywania zapytań kodera. Poniższy kod demonstruje tę metodę.

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);
        }
    }
}

W tym miejscu czytnik zapytań jest uzyskiwany z zdekodowanej ramki, a następnie używany jako wartość właściwości PROPVARIANT z typem wartości ustawionym na VT_UNKNOWN. Moduł zapisywania zapytań dla kodera jest uzyskiwany, a wyrażenie zapytania "/" służy do ustawiania metadanych na głównej ścieżce nawigacji. Tę metodę można również użyć podczas ustawiania zagnieżdżonych bloków metadanych, dostosowując wyrażenie zapytania do żądanej lokalizacji.

Podobnie można utworzyć moduł zapisywania zapytań na podstawie czytnika zapytań dekodowanej ramki przy użyciu metody CreateQueryWriterFromRead er fabryki obrazów. Generator zapytań utworzony w tej operacji zostanie wstępnie wypełniony metadanymi z czytnika zapytań, a następnie można go ustawić w ramie. Poniższy kod demonstruje operację kopiowania 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);
}

Ta metoda używa oddzielnego modułu zapisywania zapytań, który jest tworzony na podstawie danych czytnika zapytań. Ten nowy moduł zapisywania zapytań jest następnie ustawiany w ramce.

Ponownie te operacje kopiowania metadanych działają tylko wtedy, gdy obrazy źródłowe i docelowe mają ten sam format. Dzieje się tak, ponieważ różne formaty obrazów przechowują bloki metadanych w różnych lokalizacjach. Na przykład pliki JPEG i TIFF obsługują bloki metadanych XMP. Na obrazach JPEG blok XMP znajduje się w głównym bloku metadanych, jak pokazano w WIC Metadata Overview. Jednak na obrazie TIFF blok XMP jest zagnieżdżony w głównym bloku IFD. Na poniższym diagramie przedstawiono różnice między obrazem JPEG a obrazem TIFF z tymi samymi metadanymi klasyfikacji.

Porównanie JPEG i TIFF.

Szybkie kodowanie metadanych

Nie zawsze konieczne jest ponowne zakodowanie obrazu w celu zapisania nowych metadanych. Metadane można również zapisywać przy użyciu szybkiego kodera metadanych. Szybki koder metadanych może zapisywać ograniczoną ilość metadanych do obrazu bez ponownego kodowania obrazu. Jest to realizowane przez zapisywanie nowych metadanych w pustej przestrzeni dopełniającej, którą oferują niektóre formaty metadanych. Natywne formaty metadanych, które obsługują dopełnianie metadanych, to Exif, IFD, GPS i XMP.

Dodawanie dopełnienia do bloków metadanych

Zanim będzie można wykonać szybkie kodowanie metadanych, musi istnieć miejsce w bloku metadanych, aby zapisać więcej metadanych. Jeśli nie ma wystarczającej ilości miejsca w istniejącym obramowaniu, aby zapisać nowe metadane, szybkie kodowanie metadanych zakończy się niepowodzeniem. Aby dodać dopełnienie metadanych do obrazu, obraz musi zostać ponownie zakodowany. Możesz dodać wypełnienie w taki sam sposób, jak każdy inny element metadanych, używając wyrażenia zapytania, jeśli blok metadanych, który wypełniasz, to obsługuje. W poniższym przykładzie pokazano, jak dodać wypełnienie do bloku IFD osadzonego w bloku APP1.

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);
}

Aby dodać wypełnienie, utwórz PROPVARIANT typu VT_UI4 z wartością odpowiadającą liczbie bajtów do dodania. Typowa wartość to 4096 bajtów. Zapytania dotyczące metadanych dla plików JPEG, TIFF i JPEG-XR znajdują się w tej tabeli.

Format metadanych Zapytanie metadanych JPEG TIFF, JPEG-XR zapytanie metadanych
IFD /app1/ifd/PaddingSchema:Wypełnienie /ifd/PaddingSchema:Wypełnienie
EXIF /app1/ifd/exif/PaddingSchema:Padding /ifd/exif/PaddingSchema:Wypełnienie
XMP /xmp/PaddingSchema:Padding /ifd/xmp/PaddingSchema:Padding
GPS /app1/ifd/gps/PaddingSchema:Padding /ifd/gps/PaddingSchema:Padding

 

Uzyskiwanie szybkiego kodera metadanych

Jeśli masz obraz z wypełnieniem metadanych, można uzyskać szybki koder metadanych przy użyciu metod fabryki przetwarzania obrazów CreateFastMetadataEncoderFromDecoder i CreateFastMetadataEncoderFromFrameDecode.

Jak wskazuje nazwa, CreateFastMetadataEncoderFromDecoder tworzy szybki koder metadanych na potrzeby metadanych na poziomie dekodera. Natywne formaty obrazów udostępniane przez usługę WIC nie obsługują metadanych na poziomie dekodera, ale ta metoda jest udostępniana w przypadku opracowania takiego formatu obrazu w przyszłości.

Bardziej typowym scenariuszem jest uzyskanie szybkiego kodera metadanych z ramki obrazu przy użyciu CreateFastMetadataEncoderFromFrameDecode. Poniższy kod uzyskuje szybki koder metadanych odkodowanej ramki i zmienia wartość klasyfikacji w bloku App1.

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

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

Korzystanie z szybkiego kodera metadanych

Za pomocą szybkiego kodera metadanych można uzyskać zapisator zapytań. Dzięki temu można zapisywać metadane przy użyciu wyrażenia zapytania, jak pokazano wcześniej. Po ustawieniu metadanych w generatorze zapytań, zatwierdź szybki koder metadanych, aby sfinalizować aktualizację metadanych. Poniższy kod demonstruje ustawienie i zatwierdzenie zmian metadanych

    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();
    }
}

Jeśli zatwierdzenie zakończy się niepowodzeniem z jakiegokolwiek powodu, musisz ponownie zakodować obraz, aby upewnić się, że nowe metadane zostaną do niego dodane.

koncepcyjne

Składnik programu Windows Imaging — omówienie

Przegląd metadanych WIC

Przegląd języka zapytań metadanych

Rozszerzalność metadanych — omówienie

Instrukcje: ponowne kodowanie obrazu JPEG przy użyciu metadanych