Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# Windows Forms
Войти
Регистрация
Восстановить пароль
 
Outwork
4 / 4 / 3
Регистрация: 05.08.2014
Сообщений: 54
#1

Редактирование метаданных изображения - C#/.NET 4.x

11.03.2015, 10:07. Просмотров 1161. Ответов 6
Метки нет (Все метки)

Добрый день коллеги программеры. Уже неделю бьюсь с не самой сложной, как мне поначалу казалось, проблемой. Чтение метаданных файла изображения (EXIF если быть точным) не является проблемой. Пользуюсь исключительно встроенными в .NET средствами - System.Drawing.Image.PropertyItems, для наилучшей совместимости. А вот изменение этих данных и их последующее сохранение обратно в файл вызывает, мягко говоря, затруднения. Вот пример функции для обработки данных EXIF:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
        public void SetEXIFData(string FilePath, string[] List)
        {
            try
            {
                using (FileStream fs = new FileStream(FilePath, FileMode.Open, FileAccess.ReadWrite))
                {
                    Image Img = Image.FromStream(fs);
                    Encoding _Encoding = Encoding.ASCII;
                    try
                    {
                        PropertyItem dateTimeOrigin = Img.GetPropertyItem(0x9003);
                        List[0] = EncodeDTtoEXIF(List[0]);
                        dateTimeOrigin.Value = _Encoding.GetBytes(List[0] + "\0");
                        Img.SetPropertyItem(dateTimeOrigin);
                    }
                    catch (Exception) { }
                    try
                    {
                        PropertyItem software = Img.GetPropertyItem(0x0131);
                        software.Value = _Encoding.GetBytes(List[1] + "\0");
                        Img.SetPropertyItem(software);
                    }
                    catch (Exception) { }
                    try
                    {
                        PropertyItem cameraMaker = Img.GetPropertyItem(0x010F);
                        cameraMaker.Value = _Encoding.GetBytes(List[2] + "\0");
                        Img.SetPropertyItem(cameraMaker);
                    }
                    catch (Exception) { }
                    try
                    {
                        PropertyItem cameraModel = Img.GetPropertyItem(0x0110);
                        cameraModel.Value = _Encoding.GetBytes(List[3] + "\0");
                        Img.SetPropertyItem(cameraModel);
                    }
                    catch (Exception) { }
                    try
                    {
                        PropertyItem description = Img.GetPropertyItem(0x010E);
                        description.Value = _Encoding.GetBytes(List[4] + "\0");
                        Img.SetPropertyItem(description);
                    }
                    catch (Exception) { }
                    try
                    {
                        PropertyItem comment = Img.GetPropertyItem(0x9286);
                        comment.Value = _Encoding.GetBytes(List[5] + "\0");
                        Img.SetPropertyItem(comment);
                    }
                    catch (Exception) { }
                    Img.Save(fs,ImageFormat.Jpeg);
                    fs.Close();
                }
            }
            catch (Exception img)
            {
                MessageBox.Show("Невозможно сохранить метаданные EXIF\nдля обрабатываемого изображения\nОшибка: " + img.Message);
            }
 
        }
В таком варианте файл сохраняется, однако его размер увеличивается вдвое, а вот метаданные остаются неизменными. Не могу понять в чем проблема, судя по логике все должно работать. Если кто сталкивался с такой проблемой или знает как ее решить, убедительная просьба помочь. Работа встала, зашел в тупик. Заранее всем ответившим спасибо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
11.03.2015, 10:07
Я подобрал для вас темы с готовыми решениями и ответами на вопрос .NET 4.x Редактирование метаданных изображения (C#):

Редактирование изображения.
Здравствуйте. Пишу программку, от нее требуется: 1) Выбирается изображение...

Делегаты, маркеров метаданных MethodDef или MemberRef
Не могу понять что это и с чем его едят. Если коротко то, у нас есть делегат...

Как добиться качественного рисования изображения поверх изображения picturebox?
есть код: PictureBox p = (PictureBox)sender; ...

Визуальное перелистывание изображения при переходе от одного изображения к другому
Здравствуйте,нужна помощь,как можно в C#,windows form создать приложение...

Редактирование метаданных аудио
Пытаюсь изменить или удалить метаданные сотни аудиозаписей, однако удаляется и...

Реально ли редактирование метаданных на php?
Свойства word-файлов если открыть там есть автор, дата создания, изменения и...

6
Австрал
79 / 57 / 11
Регистрация: 16.12.2013
Сообщений: 175
11.03.2015, 11:06 #2
Это потому, что вы себе всю карму испортили вот такими конструкциями:
C#
1
catch (Exception) { }
А если серьёзно, то в .NET реализованы совсем не все возможности разных форматов цифровых изображений. Если вы загрузите картинку с помощью FromStream, то в памяти получите уже совсем не то, что на диске было. Скорей всего, 24 bpp RGB. Если вы теперь запишете эту картинку в другой файл, то кодек применит параметры по умолчанию, например, перекодирует честный битмап в JPEG снова. Это приведёт к потерям и появлению дополнительных шумов. Ну, если только у вас не точно такой же кодек, которым изображение было закодировано, если этот кодек симметричный и если параметры компрессии случайно совпадут. Поэтому получается другой размер файла. Можно, конечно, поиграть с параметрами кодека, но это всё равно будет некошерно. Очень может быть, что исходная картинка закодирована уникальным кодеком дядюшки Лю и восстановить её без потерь из битмап не сможет даже Конфуций. Поэтому лучше честно вписывайте параметры Exif в бинарный файл. Не трогая при этом самих пикселей. Это не так уж трудно.
0
Outwork
4 / 4 / 3
Регистрация: 05.08.2014
Сообщений: 54
13.03.2015, 07:07  [ТС] #3
Австрал, спасибо за ответ!
Цитата Сообщение от Австрал Посмотреть сообщение
Поэтому получается другой размер файла.
В том то и дело, что размер увеличивается ровно в два раза. Я поначалу думал, что в Image добавляется еще один фрейм каждый раз при сохранении, но оказалось что при последующих сохранениях размер файла стабильно остается вдвое превышающим оригинальный файл.
Цитата Сообщение от Австрал Посмотреть сообщение
Это потому, что вы себе всю карму испортили вот такими конструкциями:
Код C#
1
catch (Exception) { }
Перехват исключений реализован с целью последующей реализации механизма записи лога.
Цитата Сообщение от Австрал Посмотреть сообщение
Можно, конечно, поиграть с параметрами кодека, но это всё равно будет некошерно. Очень может быть, что исходная картинка закодирована уникальным кодеком дядюшки Лю и восстановить её без потерь из битмап не сможет даже Конфуций
В примере MSDN все выглядит достаточно просто:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void DemonstratePropertyItem(PaintEventArgs e)
{
 
    // Create two images.
    Image image1 = Image.FromFile("c:\\FakePhoto1.jpg");
    Image image2 = Image.FromFile("c:\\FakePhoto2.jpg");
 
    // Get a PropertyItem from image1.
    PropertyItem propItem = image1.GetPropertyItem(20624);
 
    // Change the ID of the PropertyItem.
    propItem.Id = 20625;
 
    // Set the PropertyItem for image2.
    image2.SetPropertyItem(propItem);
 
    // Draw the image.
    e.Graphics.DrawImage(image2, 20.0F, 20.0F);
}
Цитата Сообщение от Австрал Посмотреть сообщение
Поэтому лучше честно вписывайте параметры Exif в бинарный файл.
Не совсем понял о чем речь. Если можно поподробнее опишите пожалуйста данную технику.
0
Австрал
79 / 57 / 11
Регистрация: 16.12.2013
Сообщений: 175
13.03.2015, 10:56 #4
Берёте спецификацию стандарта и в соответствии с ней записываете данные в выходной файл. Вот тут есть исходники, правда, на С++.

А что, правда вот именно ровно в два раза больше, а не в 2.01 и не в 1.99 раза? Че-то странно очень, если точно в 2 раза больше байт получается.

Добавлено через 45 минут
А! Так вы же в тот же самый FileStream сохраняете. Вот он и дописывает вторую картинку после первой в этот же файл. Когда вы это делаете второй раз, он считывает удвоенный файл только до половины, то есть, первую картинку. И останавливается посередине. Поэтому в дальнейшем файл не удваивается. Сохраняйте в отдельный файл, или скажите
C#
1
fs.Position = 0;
перед записью.
0
Outwork
4 / 4 / 3
Регистрация: 05.08.2014
Сообщений: 54
13.03.2015, 23:01  [ТС] #5
Цитата Сообщение от Австрал Посмотреть сообщение
скажите
Код C#
1
fs.Position = 0;
перед записью.
Не работает такой метод. Работает ровно также как и до изменения этого свойства перед записью.
Цитата Сообщение от Австрал Посмотреть сообщение
Сохраняйте в отдельный файл
Делал я подобную конструкцию, но даже в лучшей своей реализации она сильно тормозит работу программы. Это ведь надо сохранить в отдельный файл, закрыть поток, удалить оригинал, переименовать копию и переместить ее в директорию оригинала. Брррр....
Может есть более изящный способ?
0
Австрал
79 / 57 / 11
Регистрация: 16.12.2013
Сообщений: 175
14.03.2015, 05:53 #6
Тормозит, говорите? У вас там миллионы файлов, что ли? И fs.Position = 0 не работает, верно? Вы считаете ваш подход "изящным"? Вам к доктору, а не ко мне.
0
Outwork
4 / 4 / 3
Регистрация: 05.08.2014
Сообщений: 54
14.03.2015, 11:48  [ТС] #7
Цитата Сообщение от Австрал Посмотреть сообщение
Тормозит, говорите? У вас там миллионы файлов, что ли?
Файлов тысячи и они на USB носителях. Думаю понятно?..
Цитата Сообщение от Австрал Посмотреть сообщение
И fs.Position = 0 не работает, верно?
Абсолютно верно. У Вас работает? Проверяли?
Цитата Сообщение от Австрал Посмотреть сообщение
Вы считаете ваш подход "изящным"? Вам к доктору, а не ко мне.
Естественно! Открыть файл изменить значения метаданных и закрыть его с сохранением - намного более эстетичный подход нежели
Цитата Сообщение от Outwork Посмотреть сообщение
сохранить в отдельный файл, закрыть поток, удалить оригинал, переименовать копию и переместить ее в директорию оригинала
Если Вы несогласны тогда разговор с Вами считаю законченным. Спасибо за попытку помочь.
0
14.03.2015, 11:48
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.03.2015, 11:48
Привет! Вот еще темы с решениями:

Ошибка Метаданных "не найден идентификатор в справочнике Идентификатор объекта метаданных"
В общем ситуация следующая, только начал разбираться с 1С, скачал с оф сайта...

Редактирование изображения
Добрый день. Наверное я спрошу глупость, но , можно ли редактировать...

Редактирование размера изображения
Здравствуйте! Для практики делаю свой графический редактор, все функции...

Редактирование изображения элемента
Поможите советом, в поиске уже был. Есть схема, в ней есть несколько элементов,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru