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;

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

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