Я пытаюсь извлечь теги изображения из раздела описания изображения с помощью VB.NET. Теги изображений хранятся в разделе описания:
Теги, которые я сохранил:
StyleShootsModel=sam001;StyleShootsAspectRatio=2_3;StyleShootsPreset=Jacqueline;StyleShootsProducts=21FKA00012;StyleShootsFraming=CRP;StyleShootsEquipment=StyleShoots Live ();
Я попробовал следующий пример кода:
Public Shared Function GetDMetaTagFromImage(ByVal path As String) As DateTime
Using fs As FileStream = New FileStream(path, FileMode.Open, FileAccess.Read)
Using myImage As Image = Image.FromStream(fs, False, False)
Dim tagsValue As String = ""
Dim tags = myImage.PropertyItems.FirstOrDefault(Function(pi) pi.Id = &H9C9E)
If tags IsNot Nothing Then
tagsValue = Encoding.Unicode.GetString(tags.Value)
End If
Return tagsValue
End Using
End Using
End Function
Однако код, похоже, не работает должным образом. Как правильно извлечь теги изображений из раздела описания с помощью VB.NET?
@Джими, у меня возникли проблемы с определением моей ошибки в коде, который я пробовал ниже; несмотря на все мои усилия, я все еще не могу этого понять. Я новичок в этом, поэтому буду очень признателен за любую помощь.
'Public Enum PropertyItemType As Short PropertyTagTypeByte = 1 PropertyTagTypeASCII = 2 PropertyTagTypeShort = 3 PropertyTagTypeLong = 4 PropertyTagTypeRational = 5 PropertyTagTypeUndefined = 7 PropertyTagTypeSLONG = 9 PropertyTagTypeSRational = 10 Конец перечисления'
Использование myImage As Image = Image.FromFile(path) Dim propItems As PropertyItem() = myImage.PropertyItems Dim propItem As PropertyItem = propItems.FirstOrDefault(Function(pi) pi.Id = &H9C9E) If propItem IsNot Nothing then ' Декодируем значение свойства и удалите все теги нулевых символов = Encoding.UTF8.GetString(propItem.Value).Replace(vbNullChar, "").Trim() End If End using
Я предложил всегда проверять тип PropertyItem перед его обработкой. В любом случае, тип этого PropertyItem — byte[]
(Byte()
), поэтому использование Encoding.Unicode.GetString()
правильно. Неправильно то, что, поскольку результирующее значение представляет собой строку с нулевым завершением, вы пытаетесь вернуть объект DateTime в своей функции. Если вы сохранили дату в строковом формате, вам нужно получить значение как строку, удалить нулевой знак-терминатор, а затем преобразовать строку в объект DateTime, например, с помощью DateTime.TryParse()
-- Если у вас есть Option Strict OFF
, сразу установите его ON
.
@jimi, не могли бы вы просмотреть код, который я разместил ниже?
Как @Jimi Как уже упоминалось в комментарии, я попробовал использовать Bitmapframe и успешно прочитал все теги.
Using stream = File.OpenRead(path)
Dim frame = BitmapFrame.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None)
Dim metadata = DirectCast(frame.Metadata, BitmapMetadata)
Dim Keywords = metadata?.Keywords
If Keywords IsNot Nothing Then
For Each keyword As String In Keywords
Console.WriteLine(keyword)
Next
End If
End Using
Также я попробовал использовать пакет, упомянутый ниже, но он отлично работает для отдельных тегов.
Imports MetadataExtractor
Imports MetadataExtractor.Formats.Iptc
Public Shared Function GetKeywordsFromImage(ByVal path As String) As String
Dim directories As IEnumerable(Of MetadataExtractor.Directory) = ImageMetadataReader.ReadMetadata(path)
Dim keywordsValue As String = ""
Dim iptcDirectory = directories.OfType(Of IptcDirectory).FirstOrDefault()
If iptcDirectory IsNot Nothing Then
Dim tag = iptcDirectory.GetString(IptcDirectory.TagKeywords)
If tag IsNot Nothing Then
keywordsValue = tag
End If
End If
Return keywordsValue
End Function
Если вы сохранили теги с помощью диалогового окна «Система», то строки имеют кодировку Unicode (UTF16-LE). Следовательно, чтобы извлечь строку и удалить завершающий нулевой символ, у вас есть Encoding.Unicode.GetString(propItem.Value).TrimEnd(ChrW(0))
. Затем разделите содержимое на основе разделителя по умолчанию (;
).
@jimi Я попробовал несколько способов, но все равно постоянно получаю нулевое значение в поле propItem
Здесь нет полей, только локальные переменные. Если propItem
имеет значение null, набор свойств 0x09C9E
отсутствует. Как вы сохранили данные в этом PropertyItem? Вы уверены, что проверяете правильное изображение? -- Вероятно, вам следует опубликовать изображение где-нибудь (внутри ZIP-архива, чтобы избежать возможных изменений), чтобы его можно было протестировать. -- Кстати, вам не следует публиковать здесь свои попытки в качестве ответов, поскольку код не решает проблему. Вместо этого измените вопрос, добавив выполненные вами тесты. И, пожалуйста, укажите все подробности о процедуре, используемой для установки значений PropertyItem(s).
Более того, во время отладки кода прочитайте содержимое изображений PropertyItems
и укажите в теле вопроса, какие свойства содержит эта коллекция.
Я посмотрел на изображение, которое вы разместили. GDI+ не распознает этот фрагмент метаданных. Возможно, потому, что он был установлен в системе, отличной от Windows (в свойствах программного обеспечения указано Capture One 16 Macintosh
). Если вас устраивает пакет, который вы используете (вы на самом деле не публиковали ссылку на этот NuGet (?)), используйте его. Если вам интересно, System.Windows.Media.Imaging может прочитать эту информацию. Передайте поток файла в BitmapFrame
, а затем прочитайте свойство Metadata.Keywords
.
Например: using stream = File.OpenRead([Image Path]) dim frame = BitmapFrame.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None) dim tags = DirectCast(frame.Metadata, BitmapMetadata)?.Keywords end using
это отличный ответ @jimi. Поскольку я сохраняю несколько тегов, я могу прочитать каждый тег, просто повторяя ключевые слова. Using stream = File.OpenRead(path) Dim frame = BitmapFrame.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None) Dim metadata = DirectCast(frame.Metadata, BitmapMetadata) Dim Keywords = metadata?.Keywords If Keywords IsNot Nothing Then For Each keyword As String In Keywords MessageBox.Show(keyword) Next End If End Using
Прочтите примечания здесь: Дополнительный нулевой символ между символами в метаданных, кодирующих изображение JPG. Также есть ссылка на предыдущий аналогичный вопрос.