Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Ускорение загрузки изображений


Автор: rubbiroid 24.3.2008, 02:34
Доброго времени суток!

Пишу каталогизатор фоток (C# .Net 2) и столкнулся с такой проблемой. Для испорта информации о фотке использую стандартный Bitmap и оттуда потом уже получаю разрешение и превьюшку.
Код

Bitmap PhotoBitmap = new Bitmap(File.FullName);
this.Height = (UInt16)PhotoBitmap.Height;
this.Width = (UInt16)PhotoBitmap.Width;
.
.
.
this.PhotoThumb = (Bitmap)PhotoBitmap.GetThumbnailImage(_newWidth, _newHeight, null, IntPtr.Zero);


Все работает хорошо... но медленно... Особенно если в цикле нужно обработать пару сотен фотографий.  Согласно профайлеру 99% времени уходит на 
Код

Bitmap PhotoBitmap = new Bitmap(File.FullName);

Как бы ускорить этот процесс?
З.Ы. Как вариант использовать самописный "декодер" Jpeg и подчитывать только размеры и превьюшку. Но как декодировать саму превьюшку? Я пока не нашел ничего более подробного чем "далее идет упакованные данные превьюшки" (перевод вольный).

Автор: Voyager 24.3.2008, 10:52
Не знаю как насчет ускорить, но можно вынести обработку в треды, и при открытии окна превьюшки будут открываться поочередно (в смысле визуально), как в Windows и разных программах аля AcdSee (приложение висеть в ожидании окончания цикла не будет).

Автор: vponomarov 24.3.2008, 11:03
rubbiroid, можно позаимствовать идею создания привьюшек у горячо любимой винды.
т.е. создавать привьюшки только один раз, а при повторном заходе в каталог грузить их откуда-нибудь а не создавать заново.
еще можно попробовать разобраться как загружать привьюшки из файлов thumbs.db которые создает винда
короче вариантов много smile 

Автор: rubbiroid 24.3.2008, 13:16
vponomarov, Ну так оно и делается. Просто изначально ГДИ, как я понял, загружает ВЕСЬ файл в память (про декодирование не знаю, но мне кажется, что и декодирует). Соответственно, на это уходит много времени - ибо фотки по 2-3 метра. Если же подчитывать только заголовок Jpeg и парсить его ручками, то на это уйдет куда меньше времени ибо не 3 метра загружать надо и не 6МП декодировать. Как подчтать ручками размеры я вроде нашел, но вот что сделать с превьюшкой, которая зашита в фотку, я не знаю. Если кто скинет статейку про jpeg, где описана полная структура файла с EXIF и как что оттуда можно достать (типа Пошаговое создание собственного декодера JPEG) - буду безумно благодарен.
Voyager, Вариант тоже был, вот только никогда не писал многопоточек... Да и если сделать 2 потока (ну или по количеству процессоров), то все начнет упираться в скорость винта. Поэтому и хотель бы получить нужные мне данные НЕ загружая весь файл и НЕ докодируя его целиком.

З.Ы. Кто-нить случаем знает, как определить количество процессоров в системе?

Автор: QryStaL 24.3.2008, 14:02
Код

Environment.ProcessorCount

Автор: vponomarov 24.3.2008, 14:21
Цитата

Voyager, Вариант тоже был, вот только никогда не писал многопоточек... Да и если сделать 2 потока (ну или по количеству процессоров), то все начнет упираться в скорость винта. Поэтому и хотель бы получить нужные мне данные НЕ загружая весь файл и НЕ докодируя его целиком.

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

Цитата

Ну так оно и делается

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

Автор: rubbiroid 24.3.2008, 15:39
QryStaL, Пасибо!

Сделал тестовое приложение с многопоточностью. Прирост производительности с двумя потоками почти 100%. Но все равно не хочется загружать весь файл.


vponomarov, моя прога хранит превьюшки в себе. Так что я их получаю только 1 раз. И вот этот один раз на больших каталогах может идти несколько минут. К примеру на 200 фотках - 93 секунды (в 1 поток) на Core2Duo E4300. А если проц послабее? Вот поэтому и не хочется грузить весь файл. Да и смысла в этом особо нет, ибо он мне не нужен (ну, только если в нем самом нет превьюшки и ее надо ручками создавать)

Автор: Kefir 24.3.2008, 16:04
ты хочешь создавать превью без открытия изображения?  smile или я в танке? В итоге ведь получается, что как ни крути - всё равно один раз по всем картинкам пробежать надо. Вот тут-то ты и выхватываешь всё что тебе надо из картинок и записываешь... Или где?

Автор: rubbiroid 24.3.2008, 16:21
Kefir, В Jpeg'ах кроме основной картинки хранится еще и превьюшка. Так вот мне она и нужна. 
Мне не нужно декодировать все изображение. Только эту маленькую кртинку. А GDI при создании Битмапа из файла декодирует его, что мне абсолютно не надо.

Автор: Rififi 24.3.2008, 16:32
rubbiroid, 
поскольку gdi+ при загрузке изображения прокачивает его целиком в память, более оптимальным вариантом будет ручное выдирание exif-тэгов из файла. Правда если там preview отсутствует, то его по-любому надо будет самостоятельно делать. Спецификация на exif здесь: http://exif.org/specifications.html

Автор: Kefir 24.3.2008, 16:41
Есть с чего начать - http://www.sentex.net/~mwandel/jhead/
Эта программулька по описанию занимается именно тем, что тебе надо. Покопайся в сырцах и перепиши как тебе надо.

Автор: rubbiroid 24.3.2008, 18:14
Kefir, Пасибо, посмотрю.

Автор: QryStaL 30.3.2008, 00:47
 smile 

Код

string path = "D:/test.jpg";
Stream fs = File.OpenRead(path);
Image temp = Image.FromStream(fs, false, false);
Image result = temp.GetThumbnailImage(100, 100, null, IntPtr.Zero);

Автор: Kefir 30.3.2008, 01:57
QryStaL, чем, собстевенно сей метод отличается от сабжевого?

Автор: QryStaL 30.3.2008, 02:05
Kefir, Быстродействием.

200 фотографий (3 МП) обрабатываются меньше секунды.
Pentium 4 3GHz (Одноядерный с HT).

Автор: rubbiroid 30.3.2008, 14:05
На маленьких фотках у меня тоже все быстро работает. Только вот у меня фотки 6 МП. И там не все так быстро уже.
Решил проблему написание собствнного EXIF парсера и добавлением многопоточности. Правда ускорение получилось именно на фотках - там где есть EXIF 2.2 с тумбой и нету JFIF. Скорость - около 350-400 фоток в секунду. Если нужно - могу скинуть код.

Автор: QryStaL 30.3.2008, 17:45
rubbiroid, ты мой код хоть пробовал? Я взял 400 фотографий размером 7Мп, запустил на одноядерном процессоре. Результат - 3 секунды (это без многопоточности). А кода - 4 строчки. Или мы не ищем легких путей?

Автор: rubbiroid 30.3.2008, 19:59
Запускал... Результат такой же как и с моим первым кодом...
Только вот мне не 100 на 100 тумба нужна, а с правильным соотношением сторон (но не более 160*120). Кроме этого еще нужно получить размеры фотки и дату, когда она была сделана. А потом все добавить в коллекцию. 
Выложи весь твой код, я добавлю еще свою обработку и сравню быстродействие.

Автор: QryStaL 30.3.2008, 22:13
Код

Stream fs = File.OpenRead(file);
Image temp = Image.FromStream(fs, false, false);
int imW = temp.Width;
int imH = temp.Height;
int thumbW = 0;
int thumbH = 0;
double mult = 0;
mult = Math.Max((double)imW / 160, (double)imH / 120);
thumbW = (int)(imW / mult);
thumbH = (int)(imH / mult);
PropertyItem pi = temp.GetPropertyItem(0x0132);
string dateTimeCreated = Encoding.ASCII.GetString(pi.Value).TrimEnd(new char[] { '\0' });
Image result = temp.GetThumbnailImage(thumbW, thumbH, null, IntPtr.Zero);

Автор: rubbiroid 30.3.2008, 22:54
В первый раз не заметил, как ты создавал Image. С отключенной проверкой все работате очень быстро. 
Ну... зато теперь я знаю структуру Jpeg'a smile)))

З.Ы. Кто-нить знает, что майкрософт понимает под "ValidateImageData"? Ведь именно из-за этой проверки все так и тормозило.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)