Po przyjrzeniu się dokładniej co znajduje się w zmodyfikowanej liście rzeczy niezbędnych do egzaminu zauważyłem punkt, który dotychczas nie poruszyłem w kursie. Dotyczy on metadanych obrazków.
Bitmap metadata
Jak wiemy obrazki mogą zawierać wiele informacji je określających. Z takich podstawowych to chociażby autor, tytuł czy komentarz. Jednak informacji tych jest znacznie więcej. Szybki rzut okna na szczegóły zdjęcia w Explolerze pokaże nam jak wiele informacji może zdjęcie przechowywać.
Dobrze widzicie. Jest tego aż 4 strony.
Jak się możemy do tych informacji dostać?
WPF wprowadza kilka dodatkowych klas, za pomocą których dostęp do tych danych jest możliwy. Zobaczmy prosty przykład, który sobie omówimy:
var fs = new FileStream(“pawel_lukasik_foto.jpg”, FileMode.Open, FileAccess.Read, FileShare.Read);
BitmapDecoder decoder = BitmapDecoder.Create(fs, BitmapCreateOptions.None, BitmapCacheOption.Default);
BitmapFrame frame = decoder.Frames[0];
var metadata = (System.Windows.Media.Imaging.BitmapMetadata)frame.Metadata;
Pominę omówienie linii pierwszej bo to chyba oczywiste. Kolejną czynnością, którą robimy jest stworzenie dekodera, który umożliwi nam dostęp do tych danych. Dekodera tworzymy za pomocą statycznej metody Create podając jako parametr nasz strumień. Pozostałe parametry to odpowiednio ustawienia tworzenia obiektu i cache’a. Mając tak stworzony obiekt możemy wyciągnąć z niego odpowiednią ramkę. Znajduje się ona pod indeksem 0. Wyciąganie ramki zrobione jest przy użyciu indeksera gdyż możliwe, że obrazek będzie zawierał więcej niż jedną ramkę metadanych. Po tym nie pozostaje nam już nic innego jak wyciągnąć metadane przy użyciu właściwości Metadata.
Pól jest naprawdę dużo i możemy ich po prostu użyć aby dostać się do tych danych
Array.ForEach(metadata.Author.ToArray(), Console.WriteLine);
Console.WriteLine(metadata.Rating);
Console.WriteLine(metadata.Comment);
Array.ForEach(metadata.Keywords.ToArray(), Console.WriteLine);
Console.WriteLine(metadata.Subject);
Co jeśli jednak znajdzie się właściwość, do której nie ma bezpośredniego dostępu? Tu przychodzi z pomocą MQL.
MQL
MQL to specjalny język (Metadata Query Language) stworzony z myślą o dostępie do tych danych. Wszystkie wartości za które wypisaliśmy za pomocą właściwości można by uzyskać za pomocą MQL’a. Omówienie języka znacznie wykracza poza ramy prostego posta, ale pokażmy sobie na przykładzie jak możemy odczytać jakąś właściwość:
if (metadata.ContainsQuery(“/app1/ifd/{ushort=18246}”))
{
var q = metadata.GetQuery(“/app1/ifd/{ushort=18246}”);
Console.WriteLine(q.ToString());
}
Powyższy kod odczyta nam to samo, co właściwość Rating. Zapytanie składa się ze ścieżki do odpowiedniego bloku danych (/app1/ifd) oraz identyfikatora pola (/{ushort=18246}). Więcej na ten temat w linkach poniżej.
Za pomocą MQL da się też modyfikować parametry. W teorii powinno działać to tak:
var writer = frame.CreateInPlaceBitmapMetadataWriter();
writer.SetQuery(“/app1/ifd/{ushort=18246}”, 3);
writer.TrySave();
Dlaczego piszę “w teorii”?. Dlatego, że dla plików jpg z jakichś względów nie działa. Śledzę wątki na forach, aby dość jak to zrobić aby działało, ale na chwilę obecną nie znalazłem działającego rozwiązania.
Na dziś to tyle. Miłej zabawy z MQL’em.
Linki:
Metadata Query Language Overview
BitmapMetadata class
Specyfikacja formatu EXIF
Founder of Octal Solutions a .NET software house.
Passionate dev, blogger, occasionally speaker, one of the leaders of Wroc.NET user group. Microsoft MVP. Podcaster – Ostrapila.pl