Category Archives: Coding

WPF и DPI

Не для кого не секрет, что в Висте можно менять DPI (dots-per-inch) для более удобной работы на мониторах с большим разрешением. Я не мог и подумать, что это может проявиться самым неожиданным образом при просмотре изображений под WPF. Любое изображение (обыкновенный JPEG) может нести в себе информацию о DPI внутри метаданных. По умолчанию равно 96 и именно это значение будет использоваться если данных нет.

Однако, некоторые программы для обработки фотографий решили, что неплохо бы 180 dpi прописать в jpg файлы. Если открыть такую фотку в классе Image, то размер ее окажется раза в два меньше ваших ожиданий (естественно, имеется ввиду режим без растяжения Stretch.None). И это еще пол беды. Хотя DPI у изображения в явном виде выставить нельзя, но можно обойти эту проблему либо использовав класс DrawingImage, либо получив PixelData и сгенерировав новый битмап из нее.

Далее меня ждал еще один сюрприз. Если выравнивание фотографии стоит по центру и разрешение ее не кратно двум, то мы получаем мыло изза того что центр изображения попадает между пикселами. Особенно это заметно при просмотре скриншетов текста. Опция SnapsToDevicePixels=Trueне помогает ничем! Пришлось в зависимости от кратности разрешения изображения изменять маргин на 1. В общем, еще то извращение, но прекрасно работает.

В завершении скажу, что пока искал решение вышеописанных проблем, наткнулся на блог, где написано, что вообще не стоит в wpf и silverlight использовать картинки с плохой масштабируемостью, то есть качество которых страдает от небольшого ресайза. Речь идет о любых изображениях с четкими гранями и текстом! Так что be aware!

Оно вышло! VS2008 и .NET 3.5

Финальные версии Visual Studio 2008 и .Net 3.5 уже можно скачать.

Отдельно оговаривается, что тулзы для Silverlight 1.1 не работают и нужно подождать недели две, пока выпустят новую версию Silverlight 1.1 Tools Alpha for Visual Studio. Предлогают пока сидеть на бете тем, для кого это критично.

Надо заметить, что третий дотнет еще не вошел в массы, а уже вышел 3.5.

F# – новый язык в Visual Studio

Новость не нова, но в скором времени в Visual Studio будет добавлен новый язык – F#.  Еще не объявлены сроки этого нововведения, но это не может не радовать.

Попробовать язык в действии можно уже сейчас. Лицензия позволяет создавать коммерческие приложения на его основе.

Описание:

F# is a variant of the ML programming language for .NET and has a core language that is similar to that of OCaml. It is a mixed functional/imperative/object-oriented programming language which is excellent for medium-advanced programmers and for teaching. In addition, you can access hundreds of .NET libraries using F#, and the F# code you write can be accessed from C# and other .NET languages. This release of F# includes a command line compiler as well as ‘F# for Visual Studio’, which provides interactive syntax highlighting, parsing, typechecking and intellisense for F# code inside Visual Studio 2003/2005/Orcas, and ‘F# Interactive’, a command-line top level environment for F#.

По языку уже написана книга: Expert F#.

 

Так что, возможно, у него большое будущее.

Чтение и запись метаданных (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