Nokia недавно выпустила бета-версию Nokia Imaging SDK, позволяющего создавать приложения Windows Phone 8 с расширенными возможностями в работе с изображениями для смартфонов Nokia Lumia.
Nokia Imaging SDK включает библиотеку для манипуляций над изображениями, захваченными и сохраненными на устройствах Windows Phone, и содержит средства для кодирования и декодирования JPEG-изображений, применения фильтров и эффектов, кадрирования, поворота и масштабирования. Nokia Imaging SDK предоставляет более 50 готовых фильтров и эффектов. Вы можете применять не только эффекты вроде сепии, мультипликации, абриса (sketch) и т. д., но и автоматическое улучшение изображения, контроль яркости, контрастности, насыщенности и многое другое. SDK специально разработан для обработки изображений на мобильных устройствах с расчетом на максимальную производительность и эффективное использование памяти.
В этой статье я продемонстрирую применение эффекта абриса на примере приложения Paper Photo. Эффект абриса применяется в реальном времени к потоку данных, поступающих от видоискателя; это приложение также дает возможность пользователям захватывать изображения и сохранять их в каталоге с фотографиями, снятыми камерой смартфона (phone’s camera roll). Я разработал это приложение, используя Visual Studio 2012, Nokia Imaging SDK и Windows Phone 8 SDK. Приложение тестировалось на смартфоне Nokia Lumia 920.
Основы Nokia Imaging SDK
Nokia Imaging SDK создан в Nokia для того, чтобы предоставить вам полный доступ к мощной библиотеке средств манипуляций над изображениями, которая помогает легко и быстро создавать впечатляющие приложения для работы с изображениями. Как упоминалось, этот SDK спроектирован с расчетом на высокую производительность и использование небольшого объема памяти, что крайне важно, поскольку Microsoft и Nokia работают над созданием устройств следующего поколения, таких как Nokia Lumia 1020. Данный SDK уже используется в приложении Nokia для работы с изображениями — Creative Studio. SDK и библиотека доступны бесплатно (лицензионное соглашение см. по ссылке bit.ly/130tVHJ), и в настоящее время SDK поддерживает только приложения Windows Phone 8.
Nokia Imaging SDK предлагает следующие средства.
- Простой в использовании API, доступный как из управляемого кода, так и из неуправляемого. Это означает, что SDK предоставляется как библиотека Windows Phone Runtime, и вы можете вызывать методы библиотеки из C#, Visual Basic или C++. API включает набор классов и методов для различных операций над изображениями.
- Технология RAJPEG для доступа к данным изображения без декодирования всего JPEG-изображения, что обеспечивает невероятно быстрый предварительный просмотр, применение эффектов, кадрирование и поворачивание изображений высокого разрешения.
- Более 50 фильтров, эффектов и расширений. Некоторые из расширений позволяют программным способом регулировать RGB-уровни, контраст, яркость и насыщенность. Кроме того, при необходимости можно создавать собственные эффекты и фильтры. В дополнение к этим фильтрам и эффектам SDK также обеспечивает кадрирование, поворачивание и масштабирование с неограниченной функциональностью отмены любых операций.
- Несколько полнофункциональных приложений-примеров позволяют исследовать исходный код и изучить возможности SDK. Эти примеры охватывают многие возможности вроде манипуляций в реальном времени над свойствами фильтров и применением к фотоснимкам нескольких уровней фильтров.
- Обширная документация с краткими руководствами, проекты примеров, справочное руководство по API и несколько документов, где дается обзор некоторых основных концепций, понимание которых необходимо для создания приложений, работающих с изображениями.
Приступаем
Для своего приложения-примера я использовал на верхнем уровне следующие API из Nokia Imaging SDK:
- Nokia.Graphics;
- Nokia.Graphics.Imaging;
- Nokia.InteropServices.WindowsRuntime.
Nokia.Graphics.Imaging API содержит базовую функциональность Nokia Imaging SDK, в том числе все фильтры, эффекты и кодеки JPEG. Библиотека Nokia.InteropServices.WindowsRuntime используется на внутреннем уровне и является обязательной библиотекой, на которую нужно ссылаться в вашем проекте. Она содержит класс BufferFactory, используемый для создания экземпляра IBuffer. Этот SDK можно установить через диспетчер NuGet-пакетов в Visual Studio. Найти этот пакет можно поиском по NokiaImagingSDK.
Объектный граф этого приложения в основном состоит из трех ключевых классов, показанных на рис. 1. MainPage — это типичная страница приложения, реализованная в XAML-файле и парном ему файле исходного кода на C#. Класс MainPage реализует UI приложения, который включает MediaElement, отображающий видоискатель камеры с эффектом абриса (sketch effect). Класс MainPage также владеет экземплярами двух других ключевых классов: CameraStreamSource и NokiaSketchEffect. Первый из них наследует от MediaStreamSource и предоставляет данные от камеры, а NokiaSketchEffect реализует эффект абриса. Класс CameraStreamSource реализован Nokia вне Nokia Imaging SDK и предлагается разработчикам через приложения-примеры, созданные компанией.
Рис. 1. Схема классов для проекта Paper Photo
Объектный граф преобразуется в структуру кода, показанную на рис. 2.
Рис. 2. Структура решения в Visual Studio
Определение UI
UI этого приложения довольно прост (рис. 3). Основная страница отображает изображение с видоискателя камеры и содержит панель приложения с единственной кнопкой для захвата снимка с эффектом абриса.
Рис. 3. UI приложения Paper Photo
На рис. 4 показана XAML-разметка основной страницы. В ней используется элемент Grid для определения контейнера, задействованного для вывода изображения с видоискателя с примененным эффектом абриса.
Nokia Imaging SDK создан в Nokia для того, чтобы предоставить полный доступ к мощной библиотеке средств манипуляций над изображениями, которая помогает легко и быстро создавать впечатляющие приложения для работы с изображениями.
Рис. 4. XAML-разметка основной страницы
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1" Margin="8">
<Grid x:Name="MediaElementContainer" Margin="0"></Grid>
<StackPanel
x:Name="TitlePanel"
Grid.Row="0"
Margin="12,17,0,28">
<TextBlock
Text="{Binding Path=LocalizedResources.ApplicationTitle,
Source={StaticResource LocalizedStrings}}"
Style="{StaticResource PhoneTextNormalStyle}"
Margin="12,0"/>
</StackPanel>
</Grid>
</Grid>
Панель приложения создается с помощью разметки, представленной на рис. 5. Как видите, она определяет кнопку захвата и элемент меню About. Кнопка захвата связана с обработчиком событий щелчка.
Рис. 5. Разметка панели приложения
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar Opacity="0.4">
<shell:ApplicationBarIconButton x:Name="CaptureButton"
Text="Capture" IconUri="Assets/capture-button-icon.png"
Click="CaptureButton_Click" IsEnabled="True" />
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem
Click="OnAboutPageButtonClicked" Text="about" />
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
Windows Phone использует модель защиты на основе доступа к возможностям (capabilities-driven security model). Эта модель позволяет разрешать пользователям активацию определенной функциональности. В моем демонстрационном приложении нужно разрешить следующие возможности для пользователей.
- ID_CAP_ISV_CAMERA Обеспечивает доступ к камере на обратной стороне смартфона (основной) или на лицевой стороне.
- ID_CAP_MEDIALIB_PHOTO Обеспечивает доступ только для чтения к фотоснимкам в медийной библиотеке. Кроме того, дает возможность приложению сохранять снимки в каталоге фотографий, отснятых камерой (camera roll). Я продемонстрирую эту возможность позже, когда буду сохранять снимок в этом каталоге после применения эффекта абриса.
Приложение требует должного функционирования камеры на обратной стороне. Параметр ID_REQ_REARCAMERA выбирается для того, чтобы предотвратить установку приложения на смартфон без камеры на обратной стороне.
Применение эффекта абриса в реальном времени к изображению от видоискателя камеры
За применение этого эффекта в реальном времени к изображению от видоискателя камеры отвечает класс NokiaSketchEffect. Заметьте, что для получения нужного эффекта в моем приложении используется SketchMode.Gray. Функция GetSampleAsync класса CameraStreamSource отвечает за обработку буфера камеры с применением эффекта абриса, и с буфером предоставляется media-элемент. Метод GetSampleAsync вызывает метод NokiaSketchEffect.GetNewFrameAndApplyEffect, чтобы получить модифицированный буфер камеры. Код на рис. 6 показывает, как это делается.
Рис. 6. Получение модифицированного буфера камеры
public async Task GetNewFrameAndApplyEffect(IBuffer processedBuffer)
{
if (captureDevice == null)
{
return;
}
captureDevice.GetPreviewBufferArgb(cameraBitmap.Pixels);
Bitmap outputBtm = new Bitmap(
outputBufferSize,
ColorMode.Bgra8888,
(uint)outputBufferSize.Width * 4,
processedBuffer);
EditingSession session =
new EditingSession(cameraBitmap.AsBitmap());
session.AddFilter(FilterFactory.CreateSketchFilter(SketchMode.Gray));
await session.RenderToBitmapAsync(outputBtm);
}
Закрытая переменная captureDevice в функции принадлежит классу PhotoCaptureDevice, который находится в Windows.Phone.Media.Capture. Функция RenderToBitmapAsync предоставляется Nokia Imaging SDK для поддержки асинхронного рендеринга EditingSession в битовую карту. EditingSession — важный класс из Nokia Imaging SDK, представляющий сеанс редактирования обрабатываемого изображения. Объект EditingSession является сердцевиной SDK. В типичном рабочем процессе EditingSession создается на основе изображения, в этот сеанс добавляются фильтры или эффекты, а затем выполняется рендеринг EditingSession в битовую карту или в буфер памяти; после этого EditingSession закрывается. Код на рис. 6 показывает, как создается новая битовая карта, сопоставленная с аргументом processedBuffer, потом к ней применяется эффект абриса, а далее выполняется рендеринг в новый буфер. Наконец, метод CreateSketchFilter создает облик оконтуренного изображения. Эта функция принимает перечисление SketchMode в качестве аргумента, который передается фильтру абриса и определяет конкретный режим оконтуривания. Доступно два режима: абрис в оттенках серого и цветовой абрис. Как видите, в коде на рис. 6 я использовал SketchMode.Gray. Это позволяет приложению Paper Photo создавать изображения в оттенках серого.
Захват и сохранение картинки как JPEG-изображения в каталоге фотоснимков камеры
Пока что я показал, как применять эффект абриса в реальном времени к видоискателю. Теперь я расскажу о захвате картинки с видоискателя и последующем ее сохранении в каталоге фотоснимков, сделанных камерой устройства. Функция захвата сначала инициирует автофокусировку, а затем захватывает снимок. Вы можете обрабатывать не только функциональность захвата с панели приложения, но и захват, инициируемый аппаратным триггером.
Код на рис. 7 обеспечивает захват через кнопку камеры. Точнее, функция захвата включает или отключает аппаратную функцию спуска затвора. Класс CameraButtons предоставляет события, которые инициируются аппаратными кнопками затвора. Одно из таких событий — ShutterKeyHalfPressed, генерируемое при неполном нажатии аппаратной кнопки затвора и ее удержании в таком положении в течение примерно 800 мс. Другое событие — ShutterKeyPressed. Оно происходит, когда аппаратная кнопка затвора нажимается полностью. Функция SetCameraButtonsEnabled также обеспечивает удаление обработчиков этих событий, помогая освобождать память, связанную с камерой.
Рис. 7. Захват, инициируемый кнопкой камеры
private void SetCameraButtonsEnabled(bool enabled)
{
if (enabled)
{
Microsoft.Devices.CameraButtons.ShutterKeyHalfPressed
+= ShutterKeyHalfPressed;
Microsoft.Devices.CameraButtons.ShutterKeyPressed
+= ShutterKeyPressed;
}
else
{
Microsoft.Devices.CameraButtons.ShutterKeyHalfPressed
-= ShutterKeyHalfPressed;
Microsoft.Devices.CameraButtons.ShutterKeyPressed
-= ShutterKeyPressed;
}
}
Теперь я подробно объясню процесс захвата. В коде на рис. 8 объект camera представляет устройство захвата снимков, await-функция camera.FocusAsync инициирует автофокусировку, а метод StartCaptureAsync захватывает кадр. Но перед тем как вы сможете захватить кадр, вы должны подготовить последовательность захвата (capture sequence). Для этого вызовите PrepareCaptureSequenceAsync. Вы также создаете объект последовательности захвата с одним кадром, как видно из camera.CreateCaptureSequence(1). Значение 1 указывает количество кадров, которые будут захвачены сразу после того, как вы инициируете захват. Наконец, вы указываете свойства камеры и параметры снимка, используя метод KnownCameraPhotoProperties. LockedAutoFocusParameters устанавливается в None, сообщая, что фокус, выдержка и баланс белого будут настроены автоматически перед захватом.
Рис. 8. Процесс захвата
private async System.Threading.Tasks.Task Capture()
{
try
{
await camera.FocusAsync();
MemoryStream imageStream = new MemoryStream();
imageStream.Seek(0, SeekOrigin.Begin);
CameraCaptureSequence sequence = camera.CreateCaptureSequence(1);
sequence.Frames[0].CaptureStream = imageStream.AsOutputStream();
await camera.PrepareCaptureSequenceAsync(sequence);
await sequence.StartCaptureAsync();
camera.SetProperty(
KnownCameraPhotoProperties.LockedAutoFocusParameters,
AutoFocusParameters.None);
...
}
Следующий код показывает, как сохранить захваченный снимок в каталог фотоснимков камеры:
MediaLibrary library = new MediaLibrary();
EditingSession session =
new EditingSession(imageStream.GetWindowsRuntimeBuffer());
using (session)
{
session.AddFilter(FilterFactory.CreateSketchFilter(SketchMode.Gray));
IBuffer data = await session.RenderToJpegAsync();
library.SavePictureToCameraRoll(FileNamePrefix
+ DateTime.Now.ToString() + ".jpg",
data.AsStream());
}
Класс MediaLibrary предоставляется Microsoft.XNA.Framework.Media API и используется для сохранения снимков в медиа-библиотеке смартфона. Пространство имен Microsoft.XNA.Framework.Media содержит классы для перечисления, воспроизведения и просмотра песен, альбомов, списков проигрывания и картинок. Далее вы можете задействовать класс EditingSession из Nokia Imaging SDK, чтобы создать сеанс на основе буфера сжатого изображения и применить фильтр эффекта абриса перед сохранением картинки в каталоге фотоснимков камеры с помощью функции SavePictureToCameraRoll.
Интеграция с интерактивной линзой
В Windows Phone 8 можно создать интерактивную линзу (media lens), которая открывается из встроенного приложения камеры и запускает ваше приложение прямо в среде видоискателя. Для интеграции с интерактивной линзой приложение нужно зарегистрировать на расширение Camera_Capture_App. Это расширение объявляет ОС, что приложение Paper Photo может отображать видоискатель при запуске из приложения камеры. Расширения задаются в файле WMAppManifest.xml. Вы должны открыть этот файл в текстовом редакторе: щелкните файл правой кнопкой мыши и выберите Open With… | Text Editor. Расширение линзы указывается следующим элементом Extension (сразу после элемента Tokens внутри элемента Extensions):
<Extension ExtensionName="Camera_Capture_App"
ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5631}"
TaskID="_default" />
Теперь ваше приложение интегрировано с линзой и может сохранять картинки прямо в каталоге фотоснимков камеры на устройстве. Изображение на рис. 9 было снято встроенным приложением камеры, а изображение на рис. 10 — приложением Paper Photo с применением эффекта абриса.
Рис. 9. Обычное изображение, снятое встроенным приложением камеры
Рис. 10. Изображение, снятое приложением Paper Photo с применением эффекта абриса
Заключение
В этой статье я исследовал API-средства захвата фотоснимков, разработанные Microsoft и содержащиеся в новом Nokia Imaging SDK, для создания богатой функциональности обработки изображений. Я применял эффект абриса к картинке с видоискателя в реальном времени, а затем захватывал снимок и сохранял его в каталоге фотоснимков камеры на устройстве. Как видите, теперь вам доступна уйма средств, которыми можно пользоваться благодаря Nokia Imaging SDK, который упрощает создание приложений, подобных моему. Для краткости я опустил несколько мелких деталей, но вы можете увидеть их в сопутствующем исходном коде (github.com/Srikar-Doddi/PaperPhoto). Это лишь один пример использования Nokia Imaging SDK, но есть масса других средств, которые вы можете добавлять, и в совокупности их возможности безграничны. Надеюсь, что вы используете этот код в качестве отправной точки и добавите больше средств в свое приложение.