Portable Imaging Library for .NET

Наверное все разработчики хоть раз сталкивались с задачей нарисовать или модифицировать изображение. В WP8 и WPF для решения этой задачи есть класс WriteableBitmap.

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

В процессе создания одного WP8-приложения, пришла идея написать для .NET класс, позволяющий работать с изображениями в фоновом потоке без применения "костылей". Так появилась небольшая библиотека Portable Imaging Library for .NET.

После такого длинного вступления перейдем к её подробностям.

Возможности Portable Imaging Library for .NET

  • Создание изображение заданного размера или его асинхронная загрузка;
  • Модификация изображения;
  • Асинхронное сохранение изображения;

Все это происходит без необходимости обращения к GUI потоку.

Кроме того, как подсказывает название, это Portable Class Library. А значит поддерживаются такие целевые платформы как .NET 4.5 (WPF, ASP.NET) / WP8 / Windows Store. И, разумеется, библиотеку можно использовать в проектах, ориентированных на PCL.

Однако, в текущей версии есть следующие ограничения:

  • Поддерживается только PNG формат, исключая grayscale PNG;
  • Сохранение возможно только в RGB (true color) и ARGB (true color with alpha) PNG формате.

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

Установка

Добавить библиотеку в свой проект можно с помощью консоли NuGet:

PM> Install-Package PortableImagingLibrary 

Использование

Библиотека достаточно проста,а её использование достаточно интуитивно. В этом можно будет убедиться на примерах чуть ниже.

Основным классом библиотеки является Image. Внутри него изображение хранится в 32bit ARGB формате и доступно для изменения в любой момент времени.

Чтобы обеспечить совместимость с различными целевыми платформами, для чтения и записи изображений используется Stream.

Давайте посмотрим на пару примеров:

Код для WP8

// Loading PNG image from WP8 resource

var image = new PngImage();

var uri = new Uri("Assets/Tiles/logo.png", UriKind.Relative);
StreamResourceInfo sri = Application.GetResourceStream(uri);
await image.LoadPngAsync(sri.Stream);

// Modifying

int x = 1;
int y = 1;

uint colorARGB = image.GetPixel(x,y); // Get color of the specified point.
colorARGB = colorARGB / 2; // Modifying color value.
image.SetPixel(x, y, colorARGB); // Set color for specified pixel.

// Saving PNG image into isolated storage

var fileName = "Shared/ShellContent/newLogo.png";
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication()) {
    using (var pngSteam = new IsolatedStorageFileStream(fileName, FileMode.Create, isoStore))
        await image.SavePngAsync(pngSteam, new PngSaveOptions() {
            BitDepth = 8, 
            ColorType = ColorType.TruecolorWithAlpha 
    });
    }
}

Код для .NET (WPF, ASP.NET)

/// Loading PNG image

var image = new Image();
using (var pngStream = new FileStream(pngFile, FileMode.Open, FileAccess.Read))
    await image.LoadPngAsync(pngStream);

/// Modifying

int x = 1;
int y = 1;

uint colorARGB = image.GetPixel(x,y); // Get color of the specified point.
colorARGB = colorARGB / 2; // Modifying color value.
image.SetPixel(x, y, colorARGB); // Set color for specified pixel.

/// Saving PNG image

using (var pngSteam = new FileStream(pngFile, FileMode.Create, FileAccess.Write)) {
    await image.SavePngAsync(pngSteam, new PngSaveOptions() {
        BitDepth = 8, 
        ColorType = ColorType.TruecolorWithAlpha 
    });
}

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

А теперь рассмотрим классы библиотеки подробнее.

Класс Image

Класс Image предоставляет основные операции с изображениями: загрузка, модификация и сохранение.

Конструкторы

  • Image() – конструктор по умолчанию.
  • Image(int width, int height) – конструктор, создающий изображение указанного размера.

Свойства

  • uint BackgroundColor { get; set; } – свойство, позволяющее получить или установить фоновый цвет.
  • int Width { get; } – ширина изображения.
  • int Height { get; } – высота изображения.

Методы

  • void SetPixel(int x, int y, uint colorARGB) – присваивает заданному пикселю (x,y) указанный цвет colorARGB.
  • uint GetPixel(int x, int y) – возвращает цвет заданного пикселя (x,y).
  • Task LoadPngAsync(Stream source) – асинхронно загружает изображение из PNG файла.
  • Task SavePngAsync(Stream target, PngSaveOptions options) – асинхронно сохраняет изображение в PNG файл.

Класс PngSaveOptions

Класс PngSaveOptions содержит параметры для сохранения изображения в PNG формат.

  • byte BitDepth { get; set; } – глубина изображения в битах на каждый цвет. В текущей версии поддерживается только 8 бит на канал (32-bit ARGB или 24-bit RGB изображения).
  • ColorType ColorType { get; set; } – тип изображения:
    • Greyscale (в данный момент не поддерживается);
    • Truecolor;
    • IndexedColor (в данный момент сохранение не поддерживается);
    • GreyscaleWithAlpha (в данный момент не поддерживается);
    • TruecolorWithAlpha;

Обратная связь

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

Комментарии (6) -

Андрей 25.07.2013 17:50:09

Андрей, поправьте в примере для .NET — там два раза Save, ни одного раза Load.

@ Андрей: Спасибо.

несколько бедноват функционал... есть более серьезные библиотеки...

@ Димка: Не спорю, но задачей было как раз получить небольшой класс, не привязанный к UI thread (как реализация из самого .NET). Если есть предложения по функционалу - пишите, рассмотрю и возможно дополню.

Поддерживается только PNG
----
ну вот это самое ограничивающие.... пнг хорош, но он большой..... еще бы jpg, jpeg, gif

PNG потому что основная задача при создании библиотеки была это работа под Windows Phone. Кстати, для части изображений как раз выгоднее PNG. Jpg возможно и стоит добавить, а вот в gif не вижу необходимости. Но пока все упирается во время.

Добавить комментарий