Чтение и запись метаданных (Exif) под WPF

Exif – один из форматов данных, в котором содержится дополнительная информация о изображении (JPEG, TIFF). Это может быть краткая информация о названии и авторе, или о том когда был сделан снимок. Это может быть также подробная информация о параметрах устройства, при помощи которого изображение было получено.

С чтением и записью Exif-а под WPF оказалось не совсем все очевидно. Вся проблема в многообразии форматов, а также в попытке микрософта все унифицировать и предложить свой формат.

Получить основную информацию достаточно легко:

Stream imageStreamSource = new FileStream(fn, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
BitmapDecoder decoder = BitmapDecoder.Create(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
InPlaceBitmapMetadataWriter pngInplace = decoder.Frames[0].CreateInPlaceBitmapMetadataWriter();

if (pngInplace != null)
{
if (pngInplace.CameraModel != null)
  tbExifInfo.Text = pngInplace.CameraModel.ToString();
else
  tbExifInfo.Text = "не указана";
}
else
  tbExifInfo.Text = "не возможно получить метаданные";

Вот с записью Exif возникают некоторые проблемы. В документации слабо освещен тот момент, что нужно обязательно указать отступ – место, которое выделяется для хранения данных:
Continue reading

Оптимизация кода на С# для многоядерных систем – легко!

Не для кого не секрет, что ближайшее будущее за многоядерными системами. И каждый кодер уже должен быть к этому готов.

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

Для того чтобы использовать все ядра процессора необходимо создать многопоточный алгоритм с числом потоков равным числу ядер. Обычно ядра два (Core Duo), поэтому я приведу пример для двух потоков.

Каждый поток представляет собой объект класса Thread. Во время создания потока необходимо указать точку входа – статический метод класса (Thread1Proc, Thread2Proc). Метод Start запускает поток, а Join ждет его завершения.

using System.Threading;
...

Thread t1 = new Thread(new ThreadStart(Thread1Proc));
Thread t2 = new Thread(new ThreadStart(Thread2Proc));
t1.Start();
t2.Start();

while ((t1.ThreadState != ThreadState.Stopped) && (t2.ThreadState != ThreadState.Stopped))
{
  //Here we could show some info about process
  Application.DoEvents();
  Thread.Sleep(1);
}

t1.Join();
t2.Join();

.....

public static void Thread1Proc()
{
//Do 1th half
}

public static void Thread2Proc()
{
//Do 2nd half
}

Такая оптимизация позволяет поднять скорость выполнения кода в два раза! Единственная проблема, что не всегда можно разбить код на две параллельные части.

Будем ждать 128-ми ядерных систем ))

Обработка исключений и производительность

Недавно опять столкнулся с существенной потерей производительности при использовании блока:

while (reader.Read())
{
try
{
// операции с reader.GetValue()
}
catch
{
// выставление значений по умолчанию
}
}

В этом блоке операция чтения заключена в try блок, и при любых ошибках при чтении переменным присваиваются некие значения по умолчанию. Например, если в базе данных не задано значение поля, то reader вернет null. В этом случае вылетит исключение при обработке и действие перейдет в catch блок, где можно выставить, например, числовой “0”.

Так вот, если у Вас в базе некое поле с данными еще не забито значениями, то вышеописанный код будет работать в 10 раз медленнее! Обработка исключений не дается дешево. Чтоб заставить код работать быстро в любом случае, надо учесть случаи когда выпадают наиболее часто встречаемые исключения и поставить дополнительные проверки в блоке try. Например, проверить при чтении не вернул ли reader null и сразу подменить его неким разумным значением.

“Подразумеваемое” в пользовательском интерфейсе

Нашел тут любопытную статью про УИ. Приведу особо заинтересовавший меня кусок:

13. В информационную структуру любого взаимодействия неявным образом включено «подразумеваемое» – правила, процедуры и способы, характерные для взаимодействий вообще либо для определенных классов (групп) взаимодействий.

14. К подразумеваемому относятся, в частности, правила, определяющие, что считать взаимодействием вообще; правила, процедуры и способы выбора цели; правила, процедуры и способы выбора участников взаимодействия.

15. Подразумеваемое есть нормативная часть взаимодействия. В общем виде подразумеваемое отвечает на вопрос «как здесь принято». Подразумеваемое есть ритуальная часть интерфейса.

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

17. Без учета подразумеваемого интерфейс будет заведомо малоэффективным или неработоспособным.

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

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

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

Тормоза WPF

Допустим Вы поместили в одну из ячеек Grid’а ListBox, в который загрузили список шрифтов, которые есть у вас в системе. При этом размер ячейки Вы не выставляли, а оставили автоматическим. Естественно, чтоб использовать на полную WPF, Вы сделаете отображение написания шрифтов прямо в листбоксе. Например, так:

 

И все это будет отлично работать. Но если у Вас в системе установлено 10 тысяч шрифтов, то все уже не будет так радужно. Появятся тормоза при прокрутке листбокса.

Однако, этих неприятностей можно избежать, если жестко задать размер ячейки, в которую Вы поместили ListBox со шрифтами. Эта операция убрала у меня все тормоза начисто.

Картинки в Silverlight и глюк Firefox

Обнаружил недавно глюк с отображением картинок в Firefox’е. Одно единственное изображение, которое я использовал в качестве исходного фона для таблицы цветов, не показывалось вообще. Я решил, что я что то делаю не правильно и покопался на на тему как правильно грузить картинки. Нашел три варианта, помимо просто указания файла в XAML коде:

Просто выставление свойства:

CoolImage.SetValue(Image.SourceProperty, "bg.jpg");

Динамический XAML:

CoolImage = (Image)XamlReader.Load(@"<Image Source=bg.jpg'>");

И, наконец, вариант с даунлоадером (наиболее гибкий):

Downloader loader = new Downloader();

// Subscribe to the downloaded event
loader.Completed += new EventHandler(DownloadCompleted);

// Download the image
loader.Open("GET", new Uri("bg.jpg", UriKind.Relative));
loader.Send();

//......................

private void DownloadCompleted(object sender, EventArgs e)
{
            CoolImage.SetSource(sender as Downloader, "");
}

Последний вариант самый оптимальный, так как позволяет контролировать весь процесс загрузки. Я добавил этот код в тест с цветами, но в Firefox картинка так и не отобразилась. Надеюсь это поправят уже к бета версии Silverlight.

Как заставить контролы Dave Relyea работать в Silverlight 1.1 Alpha Refresh

[ratings] Любой кто решит написать на Silverlight что-нибудь серьезное сейчас столкнется с проблемой поиска или написания своих контролов (TextBox, Button, etc). Так как свои контролы сейчас писать почему-то не хотелось я порылся в поисках готовых контролов в сети. Оказалось есть лишь 2 достойных альтернативы в данный момент, хотя они обе мне не нравятся:

Во первых, это – http://www.netikatech.com/ – Реализация WinForms для Silverlight и Flash. Но мне хотелось получить контролы WPF, а не WinForms.

Во вторых, это – контролы, которые реализовал Dave Relyea и выложил тут. Тут очень ограниченный набор, но хотя бы есть Grid и StackPanel. Это не полноценный набор, но для экспериментов с Alpha версией вполне сойдет.

Continue reading

Поиск книг на Silverlight

Наткнулся на отличный пример использования SilverLight: Поиск книг на Амазоне (Для просмотра нужно установить Microsoft Silverlight 1.1 Alpha Refresh)

Это приложение использует поисковое апи амазона для поиска книг схожих по тематике и показывает их связи друг с другом. Проще поиграться с этим примером, чтоб понять удобство подобного поиска. В дополнение ко всему этому прикручена физика Rag-doll.

Прочитать подробнее о примере можно тут. Там же есть ссылка на исходные тексты проекта.

Continue reading

140 цветов SilverLight

[ratings] Сразу после релиза новой версии Visual Studio вышла новая версия SilverLight 1.1 Alpha Refresh. Именно с этой версии я решил начать свое знакомство с SilverLight. Первое впечатление было несколько негативным, так как в SilverLight не оказалось многих вещей, которые я привык использовать в полноценном WPF. Например, в этой версии отсутствуют даже стандартные контролы для интерфейса. Надеюсь, все это будет дополнено к финальной версии, но на данный момент выбор XBap или SilverLight все еще очень актуален. Но уже стало очевидно, что будущее именно за SilverLight. Уже сейчас SilverLight поддерживает не только большинство браузеров на Windows и MacOS, но и даже под Mono группа отдельных разработчиков реализовала его поддержку.

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

Вот что в итоге получилось: таблица

При нажатии на любой цвет фон окрасится в него.

Дополнение:
Для просмотра нужно установить Microsoft Silverlight 1.1 Alpha RefreshMac или Windows. Автоматом сейчас ставится только SilverLight 1.0 RC1.

Continue reading