Библиотека .NET C # для перезаписи Exif без потерь?

Я нашел различный код и библиотеки для редактирования Exif.

Но они работают без потерь только тогда, когда ширина и высота изображения кратны 16.

Я ищу библиотеку (или даже способ сделать это сам) для редактирования только части Exif в файле JPEG (или добавления данных Exif, если они еще не существуют), оставляя другие данные неизмененными. Разве это не возможно?

Пока мне удалось найти только часть Exif (начинается с 0xFFE1), но я не понимаю, как читать данные.


person Aximili    schedule 24.06.2009    source источник
comment
Звучит многообещающе   -  person TaW    schedule 18.05.2017


Ответы (4)


Вот спецификации для формата обмена Exif, если вы планируете кодировать свою собственную библиотеку для редактирования тегов.

http://www.exif.org/specifications.html

Вот библиотека, написанная на Perl, которая отвечает вашим потребностям, из которой вы, возможно, сможете учиться:

http://www.sno.phy.queensu.ca/~phil/exiftool/

Вот достойная библиотека .NET для оценки Exif из The Code Project:

http://www.codeproject.com/KB/graphics/exiftagcol.aspx

person LBushkin    schedule 24.06.2009
comment
Сайт exif.org был переделан, и все гиперссылки загружают один и тот же контент, который на самом деле представляет собой всего лишь несколько сообщений в блогах. Ссылка на спецификации больше не ссылается на спецификации. Однако вы все равно можете получить к нему доступ через exif.org/Exif2-2.PDF и если это перестает работать, используйте веб-архив для просмотра более старой версии сайта, например https://web.archive.org/web/20080422021217/http://www.exif.org/Exif2-2..PDF. - person Sina Motamedi; 28.11.2018

Вы можете сделать это без какой-либо внешней библиотеки:

// Create image.
Image image1 = Image.FromFile("c:\\Photo1.jpg");

// Get a PropertyItem from image1. Because PropertyItem does not
// have public constructor, you first need to get existing PropertyItem
PropertyItem propItem = image1.GetPropertyItem(20624);

// Change the ID of the PropertyItem.
propItem.Id = 20625;

// Set the new PropertyItem for image1.
image1.SetPropertyItem(propItem);

// Save the image.
image1.Save("c:\\Photo1.jpg", ImageFormat.Jpg);

Список всех возможных идентификаторов PropertyItem (включая exif) можно найти здесь.

Обновление. Согласен, этот метод перекодирует изображение при сохранении. Но я вспомнил другой метод, в WinXP SP2 и более поздних версиях добавлены новые компоненты обработки изображений - WIC, и вы можете использовать их для записи метаданных без потерь - Практическое руководство: перекодируйте изображение JPEG с метаданными.

person arbiter    schedule 24.06.2009
comment
Это повторно сжимает изображение. Существует обходной путь, позволяющий избежать повторного сжатия путем двойного поворота изображения, но он работает только в том случае, если ширина и высота кратны 16. - person Aximili; 25.06.2009
comment
обновленная ссылка: msdn.microsoft.com/en- us / library / ee719794 (v = VS.85) .aspx - person BlackICE; 03.12.2010

Библиотека exiv2net (оболочка .NET поверх exiv2) может быть тем, что вы ищете за.

person Pawel Marciniak    schedule 30.11.2009

Я написал небольшой тест, в котором я сжимаю один файл много раз, чтобы увидеть ухудшение качества, и вы можете увидеть это при третьем-четвертом сжатии, что очень плохо.

Но, к счастью, если вы всегда используете один и тот же QualityLevel с JpegBitmapEncoder, деградации не будет.

В этом примере я в 100 раз переписываю ключевые слова в метаданных, и качество, похоже, не меняется.

private void LosslessJpegTest() {
  var original = "d:\\!test\\TestInTest\\20150205_123011.jpg";
  var copy = original;
  const BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile;

  for (int i = 0; i < 100; i++) {
    using (Stream originalFileStream = File.Open(copy, FileMode.Open, FileAccess.Read)) {
      BitmapDecoder decoder = BitmapDecoder.Create(originalFileStream, createOptions, BitmapCacheOption.None);

      if (decoder.CodecInfo == null || !decoder.CodecInfo.FileExtensions.Contains("jpg") || decoder.Frames[0] == null)
        continue;

      BitmapMetadata metadata = decoder.Frames[0].Metadata == null
        ? new BitmapMetadata("jpg")
        : decoder.Frames[0].Metadata.Clone() as BitmapMetadata;

      if (metadata == null) continue;

      var keywords = metadata.Keywords == null ? new List<string>() : new List<string>(metadata.Keywords);
      keywords.Add($"Keyword {i:000}");
      metadata.Keywords = new ReadOnlyCollection<string>(keywords);

      JpegBitmapEncoder encoder = new JpegBitmapEncoder {QualityLevel = 80};
      encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0], decoder.Frames[0].Thumbnail, metadata,
        decoder.Frames[0].ColorContexts));

      copy = original.Replace(".", $"_{i:000}.");

      using (Stream newFileStream = File.Open(copy, FileMode.Create, FileAccess.ReadWrite)) {
        encoder.Save(newFileStream);
      }
    }
  }
}
person MartinHoly    schedule 11.02.2016